This turns EM `con 5000000000I8` into assembly `.data8 5000000000` for machines i386, i80, i86, m68020, powerpc, vc4. These are the only ncg machines in our build. i80 and i86 get con_mult(sz) for sz == 4 and sz == 8. The other machines only get sz == 8, because they have 4-byte words, and ncg only calls con_mult(sz) when sz is greater than the word size. The tab "\t" after .data4 or .data8 is like the tabs in the con_*() macros of mach/*/ncg/mach.h. i86 now uses .data4, like i80. Also, i86 and i386 now use the numeric string without converting it to an integer and back to a string.
		
			
				
	
	
		
			312 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			312 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * machine dependent back end routines for the PowerPC
 | 
						|
 */
 | 
						|
 | 
						|
#include <limits.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <stb.h>
 | 
						|
 | 
						|
static int writing_stabs = 0;
 | 
						|
 | 
						|
#ifdef REGVARS
 | 
						|
static long framesize;
 | 
						|
#endif
 | 
						|
 | 
						|
void
 | 
						|
con_part(int sz, word w)
 | 
						|
{
 | 
						|
	while (part_size % sz)
 | 
						|
		part_size++;
 | 
						|
	if (part_size == TEM_WSIZE)
 | 
						|
		part_flush();
 | 
						|
	if (sz == 1) {
 | 
						|
		w &= 0xFF;
 | 
						|
		w <<= 8 * (3 - part_size);
 | 
						|
		part_word |= w;
 | 
						|
	} else if (sz == 2) {
 | 
						|
		w &= 0xFFFF;
 | 
						|
		w <<= 8 * (2 - part_size);
 | 
						|
		part_word |= w;
 | 
						|
	} else {
 | 
						|
		assert(sz == 4);
 | 
						|
		part_word = w;
 | 
						|
	}
 | 
						|
	part_size += sz;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
con_mult(word sz) {
 | 
						|
 | 
						|
	if (sz != 8)
 | 
						|
		fatal("bad icon/ucon size");
 | 
						|
	fprintf(codefile,".data8\t%s\n", str);
 | 
						|
}
 | 
						|
 | 
						|
#define CODE_GENERATOR  
 | 
						|
#define IEEEFLOAT  
 | 
						|
#define FL_MSL_AT_LOW_ADDRESS	1
 | 
						|
#define FL_MSW_AT_LOW_ADDRESS	1
 | 
						|
#define FL_MSB_AT_LOW_ADDRESS	1
 | 
						|
#include <con_float>
 | 
						|
 | 
						|
void
 | 
						|
prolog(full nlocals)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	 * For N_LSYM and N_PSYM stabs, we want gdb to use fp, not sp.
 | 
						|
	 * The trick is to use "stwu sp, _(sp)" then "addi fp, sp, 0"
 | 
						|
	 * before we save lr with "stw r0, _(sp)".
 | 
						|
	 *
 | 
						|
	 * Tried with Apple's gdb-696.  Refer to
 | 
						|
	 *  - gdb-696/src/gdb/rs6000-tdep.c, skip_prologue(), line 1101
 | 
						|
	 *  - gdb-696/src/gdb/macosx/ppc-macosx-frameinfo.c,
 | 
						|
	 *    ppc_parse_instructions(), line 717
 | 
						|
	 * https://opensource.apple.com/release/developer-tools-25.html
 | 
						|
	 */
 | 
						|
	fprintf(codefile, "mfspr r0, lr\n");
 | 
						|
	if (writing_stabs) {
 | 
						|
		fprintf(codefile, "stwu sp, -8(sp)\n");  /* for gdb */
 | 
						|
		fprintf(codefile, "stw fp, 0(sp)\n");
 | 
						|
	} else
 | 
						|
		fprintf(codefile, "stwu fp, -8(sp)\n");
 | 
						|
	fprintf(codefile, "addi fp, sp, 0\n");           /* for gdb */
 | 
						|
	fprintf(codefile, "stw r0, 4(sp)\n");
 | 
						|
 | 
						|
#ifdef REGVARS
 | 
						|
	framesize = nlocals;
 | 
						|
	/* regsave() increases framesize; f_regsave() adjusts sp. */
 | 
						|
#else
 | 
						|
	if (nlocals)
 | 
						|
		fprintf(codefile, "addi sp, sp, %ld\n", -nlocals);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
mes(word type)
 | 
						|
{
 | 
						|
	int argt, a1, a2 ;
 | 
						|
 | 
						|
	switch ( (int)type ) {
 | 
						|
	case ms_ext :
 | 
						|
		for (;;) {
 | 
						|
			switch ( argt=getarg(
 | 
						|
			    ptyp(sp_cend)|ptyp(sp_pnam)|sym_ptyp) ) {
 | 
						|
			case sp_cend :
 | 
						|
				return ;
 | 
						|
			default:
 | 
						|
				strarg(argt) ;
 | 
						|
				fprintf(codefile,".define %s\n",argstr) ;
 | 
						|
				break ;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	case ms_stb:
 | 
						|
		argt = getarg(str_ptyp | cst_ptyp);
 | 
						|
		if (argt == sp_cstx)
 | 
						|
			fputs(".symb \"\", ", codefile);
 | 
						|
		else {
 | 
						|
			fprintf(codefile, ".symb \"%s\", ", str);
 | 
						|
			argt = getarg(cst_ptyp);
 | 
						|
		}
 | 
						|
		a1 = argval;
 | 
						|
		argt = getarg(cst_ptyp);
 | 
						|
		a2 = argval;
 | 
						|
		argt = getarg(cst_ptyp|nof_ptyp|sof_ptyp|ilb_ptyp|pro_ptyp);
 | 
						|
		if (a1 == N_PSYM) {
 | 
						|
			/* Change offset from AB into offset from
 | 
						|
			   the frame pointer.
 | 
						|
			*/
 | 
						|
			argval += 8;
 | 
						|
		}
 | 
						|
		fprintf(codefile, "%s, 0x%x, %d\n", strarg(argt), a1, a2);
 | 
						|
		argt = getarg(end_ptyp);
 | 
						|
		break;
 | 
						|
	case ms_std:
 | 
						|
		writing_stabs = 1;  /* set by first "mes 13,...,100,0" */
 | 
						|
		argt = getarg(str_ptyp | cst_ptyp);
 | 
						|
		if (argt == sp_cstx)
 | 
						|
			str[0] = '\0';
 | 
						|
		else {
 | 
						|
			argt = getarg(cst_ptyp);
 | 
						|
		}
 | 
						|
		swtxt();
 | 
						|
		fprintf(codefile, ".symd \"%s\", 0x%x,", str, (int) argval);
 | 
						|
		argt = getarg(cst_ptyp);
 | 
						|
		fprintf(codefile, "%d\n", (int) argval);
 | 
						|
		argt = getarg(end_ptyp);
 | 
						|
		break;
 | 
						|
	default :
 | 
						|
		while ( getarg(any_ptyp) != sp_cend ) ;
 | 
						|
		break ;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
char *segname[] = {
 | 
						|
	".sect .text",
 | 
						|
	".sect .data",
 | 
						|
	".sect .rom",
 | 
						|
	".sect .bss"
 | 
						|
};
 | 
						|
 | 
						|
#ifdef REGVARS
 | 
						|
 | 
						|
static long savedf[32];
 | 
						|
static long savedi[32];
 | 
						|
static int savedtop;
 | 
						|
static uint32_t lfs_set;
 | 
						|
 | 
						|
/* Calculate the register score of a local variable. */
 | 
						|
int
 | 
						|
regscore(long offset, int size, int type, int frequency, int totype)
 | 
						|
{
 | 
						|
	int score;
 | 
						|
 | 
						|
	switch (type) {
 | 
						|
		case reg_float:
 | 
						|
			/* Don't put reg_float in reg_any. */
 | 
						|
			if (totype != reg_float)
 | 
						|
				return -1;
 | 
						|
			assert(size == 4 || size == 8);
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			assert(size == 4);
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Clamp to avoid overflowing 16-bit int score. */
 | 
						|
	if (frequency > 8000)
 | 
						|
		frequency = 8000;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Each occurence of a regvar saves about 4 bytes by not
 | 
						|
	 * emitting a load or store instruction.  The overhead is
 | 
						|
	 * about 8 bytes to save and restore the register, plus
 | 
						|
	 * 4 bytes if the local is a parameter.
 | 
						|
	 */
 | 
						|
	score = 4 * frequency - 8 - ((offset >= 0) ? 4 : 0);
 | 
						|
#if 0
 | 
						|
	fprintf(codefile, "! local %ld score %d\n", offset, score);
 | 
						|
#endif
 | 
						|
	return score;
 | 
						|
}
 | 
						|
 | 
						|
/* Initialise regvar system for one function. */
 | 
						|
 | 
						|
void
 | 
						|
i_regsave(void)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i=0; i<32; i++) {
 | 
						|
		savedf[i] = LONG_MIN;
 | 
						|
		savedi[i] = LONG_MIN;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Set top of register save area, relative to fp. */
 | 
						|
	savedtop = -framesize;
 | 
						|
 | 
						|
	lfs_set = 0;  /* empty set */
 | 
						|
}
 | 
						|
 | 
						|
/* Mark a register as being saved. */
 | 
						|
 | 
						|
void
 | 
						|
regsave(const char* regname, long offset, int size)
 | 
						|
{
 | 
						|
	int regnum = atoi(regname + 1);
 | 
						|
 | 
						|
	assert(regnum >= 0 && regnum <= 31);
 | 
						|
	switch (regname[0]) {
 | 
						|
		case 'f':
 | 
						|
			savedf[regnum] = offset;
 | 
						|
			framesize += 8;
 | 
						|
			if (size == 4)
 | 
						|
				lfs_set |= ((uint32_t)1<<regnum);
 | 
						|
			break;
 | 
						|
		case 'r':
 | 
						|
			savedi[regnum] = offset;
 | 
						|
			framesize += 4;
 | 
						|
			break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
saveloadregs(const char* ops, const char* opm, const char *opf)
 | 
						|
{
 | 
						|
	long offset = savedtop;
 | 
						|
	int reg;
 | 
						|
 | 
						|
	/* Do floating-point registers. */
 | 
						|
	for (reg = 31; reg >= 0; reg--) {
 | 
						|
		if (savedf[reg] != LONG_MIN) {
 | 
						|
			offset -= 8;
 | 
						|
			fprintf(codefile, "%s f%d,%ld(fp)\n",
 | 
						|
				opf, reg, offset);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (savedi[31] != LONG_MIN && savedi[30] != LONG_MIN) {
 | 
						|
		/*
 | 
						|
		 * Do multiple registers from reg to r31.
 | 
						|
		 *
 | 
						|
		 * Using stmw or lmw reduces code size, but in some
 | 
						|
		 * processors, runs slower than the equivalent pile of
 | 
						|
		 * stw or lwz instructions.
 | 
						|
		 */
 | 
						|
		reg = 30;
 | 
						|
		while (reg > 0 && savedi[reg - 1] != LONG_MIN)
 | 
						|
			reg--;
 | 
						|
		offset -= (32 - reg) * 4;
 | 
						|
		fprintf(codefile, "%s r%d,%ld(fp)\n", opm, reg, offset);
 | 
						|
	} else
 | 
						|
		reg = 32;
 | 
						|
 | 
						|
	/* Do single general-purpose registers. */
 | 
						|
	for (reg--; reg >= 0; reg--) {
 | 
						|
		if (savedi[reg] != LONG_MIN) {
 | 
						|
			offset -= 4;
 | 
						|
			fprintf(codefile, "%s r%d,%ld(fp)\n",
 | 
						|
				ops, reg, offset);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
f_regsave(void)
 | 
						|
{
 | 
						|
	int reg;
 | 
						|
 | 
						|
	if (framesize)
 | 
						|
		fprintf(codefile, "addi sp, sp, %ld\n", -framesize);
 | 
						|
	saveloadregs("stw", "stmw", "stfd");
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Register variables with offset >= 0 must load an argument
 | 
						|
	 * from that offset.
 | 
						|
	 */
 | 
						|
	for (reg = 31; reg >= 0; reg--)
 | 
						|
		if (savedf[reg] >= 0)
 | 
						|
			fprintf(codefile, "%s f%d, %ld(fp)\n",
 | 
						|
				(lfs_set & ((uint32_t)1<<reg)) ? "lfs" : "lfd",
 | 
						|
				reg, savedf[reg]);
 | 
						|
 | 
						|
	for (reg = 31; reg >= 0; reg--)
 | 
						|
		if (savedi[reg] >= 0)
 | 
						|
			fprintf(codefile, "lwz r%d, %ld(fp)\n",
 | 
						|
				reg, savedi[reg]);
 | 
						|
}
 | 
						|
 | 
						|
/* Restore all saved registers. */
 | 
						|
 | 
						|
void
 | 
						|
regreturn(void)
 | 
						|
{
 | 
						|
	saveloadregs("lwz", "lmw", "lfd");
 | 
						|
}
 | 
						|
 | 
						|
#endif
 |