2a92f9bf4d
In util/ncgg, add two more errors for tables using reglap: - "Two sizes of reg_float can't be same size" - "Missing reg_float of size %d to contain %s" In mach/proto/ncg, rename macro isregvar_size() to PICK_REGVAR(), so the macro doesn't look like a function. This macro sometimes doesn't evaluate its second argument. In mach/powerpc/ncg/mach.c, change type of lfs_set to uint32_t, and change the left shifts from 1U<<regno to (uint32_t)1<<regno, because 1U would be too small for machines with 16-bit int.
257 lines
4.8 KiB
C
257 lines
4.8 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>
|
|
|
|
static long framesize;
|
|
|
|
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;
|
|
}
|
|
|
|
con_mult(word sz)
|
|
{
|
|
|
|
if (argval != 4)
|
|
fatal("bad icon/ucon size");
|
|
fprintf(codefile,".data4 %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>
|
|
|
|
static void
|
|
emit_prolog(void)
|
|
{
|
|
fprintf(codefile, "mfspr r0, lr\n");
|
|
fprintf(codefile, "addi sp, sp, %ld\n", -framesize - 8);
|
|
fprintf(codefile, "stw fp, %ld(sp)\n", framesize);
|
|
fprintf(codefile, "stw r0, %ld(sp)\n", framesize + 4);
|
|
fprintf(codefile, "addi fp, sp, %ld\n", framesize);
|
|
}
|
|
|
|
void
|
|
prolog(full nlocals)
|
|
{
|
|
framesize = nlocals;
|
|
|
|
#ifdef REGVARS
|
|
/* f_regsave() will call emit_prolog() */
|
|
#else
|
|
emit_prolog();
|
|
#endif
|
|
}
|
|
|
|
void
|
|
mes(word type)
|
|
{
|
|
int argt ;
|
|
|
|
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 ;
|
|
}
|
|
}
|
|
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. */
|
|
|
|
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. */
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
f_regsave(void)
|
|
{
|
|
int reg;
|
|
|
|
emit_prolog();
|
|
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. */
|
|
|
|
regreturn(void)
|
|
{
|
|
saveloadregs("lwz", "lmw", "lfd");
|
|
}
|
|
|
|
#endif
|