mirror of
https://git.wuffs.org/MWCC
synced 2025-07-22 19:45:52 +00:00
385 lines
12 KiB
C
385 lines
12 KiB
C
#include "compiler/RegisterInfo.h"
|
|
#include "compiler/CodeGen.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/PCode.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/types.h"
|
|
|
|
short last_exception_register[RegClassMax];
|
|
short first_fe_temporary_register[RegClassMax];
|
|
short last_argument_register[RegClassMax];
|
|
short _FP_;
|
|
short _CALLER_SP_;
|
|
char *special_register_names[RegClassMax][RegisterMax];
|
|
static short used_regs_before_coloring;
|
|
static UInt8 save_state[RegisterMax];
|
|
|
|
short spr_to_sysreg[4] = {1, 8, 9, 0x100};
|
|
|
|
void asm_used_register(RegClass rclass, short reg) {
|
|
int i;
|
|
|
|
if ((reg < n_real_registers[rclass]) && (reg_state[rclass][reg] == RegState0)) {
|
|
if (reg == nonvolatile_registers[rclass][used_nonvolatile_registers[rclass]]) {
|
|
if (assignable_registers[rclass] > 0)
|
|
assignable_registers[rclass]--;
|
|
reg_state[rclass][reg] = RegState1;
|
|
used_nonvolatile_registers[rclass]++;
|
|
} else {
|
|
for (i = used_nonvolatile_registers[rclass]; i < n_nonvolatile_registers[rclass]; i++) {
|
|
if (reg == nonvolatile_registers[rclass][i]) {
|
|
reg_state[rclass][reg] = RegState1;
|
|
if (assignable_registers[rclass] > 0)
|
|
assignable_registers[rclass]--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void retain_register(Object *obj, RegClass rclass, short reg) {
|
|
VarInfo *vi;
|
|
|
|
CError_ASSERT(95, (short) reg < RegisterMax);
|
|
|
|
if (reg_state[rclass][reg] == RegState0) {
|
|
assignable_registers[rclass]--;
|
|
reg_state[rclass][reg] = RegState1;
|
|
if (reg == nonvolatile_registers[rclass][used_nonvolatile_registers[rclass]])
|
|
used_nonvolatile_registers[rclass]++;
|
|
}
|
|
|
|
if (obj) {
|
|
vi = Registers_GetVarInfo(obj);
|
|
vi->rclass = rclass;
|
|
vi->flags |= VarInfoFlag2;
|
|
vi->reg = reg;
|
|
}
|
|
}
|
|
|
|
void retain_GPR_pair(Object *obj, short reg, short regHi) {
|
|
VarInfo *vi;
|
|
|
|
retain_register(NULL, RegClass_GPR, reg);
|
|
retain_register(NULL, RegClass_GPR, regHi);
|
|
|
|
if (obj) {
|
|
vi = Registers_GetVarInfo(obj);
|
|
vi->rclass = RegClass_GPR;
|
|
vi->flags |= VarInfoFlag2 | VarInfoFlag4;
|
|
vi->reg = reg;
|
|
vi->regHi = regHi;
|
|
}
|
|
}
|
|
|
|
int is_register_object(Object *obj) {
|
|
return obj->sclass == OBJECT_SCLASS_101;
|
|
}
|
|
|
|
int GetABIFirstNonVolatile(RegClass rclass) {
|
|
switch (rclass) {
|
|
case RegClass_SPR: return 3;
|
|
case RegClass_CRFIELD: return 2;
|
|
case RegClass_VR: return 20;
|
|
case RegClass_GPR: return 13;
|
|
case RegClass_FPR: return 14;
|
|
default: return -1;
|
|
}
|
|
}
|
|
|
|
char GetRegisterClassName(RegClass rclass) {
|
|
switch (rclass) {
|
|
case RegClass_VR: return 'v';
|
|
case RegClass_GPR: return 'r';
|
|
case RegClass_FPR: return 'f';
|
|
default:
|
|
CError_FATAL(242);
|
|
return '?';
|
|
}
|
|
}
|
|
|
|
static int first_nonvolatile_reg(RegClass rclass) {
|
|
return GetABIFirstNonVolatile(rclass);
|
|
}
|
|
|
|
void setup_diagnostic_reg_strings(void) {
|
|
register_class_name[RegClass_SPR] = "SPR";
|
|
register_class_format[RegClass_SPR] = "spr%ld";
|
|
register_class_name[RegClass_CRFIELD] = "CRFIELD";
|
|
register_class_format[RegClass_CRFIELD] = "cr%ld";
|
|
register_class_name[RegClass_VR] = "VR";
|
|
register_class_format[RegClass_VR] = "vr%ld";
|
|
register_class_name[RegClass_FPR] = "FPR";
|
|
register_class_format[RegClass_FPR] = "f%ld";
|
|
register_class_name[RegClass_GPR] = "GPR";
|
|
register_class_format[RegClass_GPR] = "r%ld";
|
|
}
|
|
|
|
void init_target_registers(void) {
|
|
RegClass rclass;
|
|
int reg;
|
|
int end;
|
|
int tmp;
|
|
|
|
static int last_nonvolatile_reg[] = {3, 5, 31, 31, 31};
|
|
static int nonvol_reserve[] = {0, 0, 0, 4, 3};
|
|
|
|
for (rclass = 0; rclass < RegClassMax; rclass++) {
|
|
for (reg = 0; reg < RegisterMax; reg++)
|
|
special_register_names[rclass][reg] = NULL;
|
|
}
|
|
|
|
special_register_names[RegClass_SPR][0] = "XER";
|
|
special_register_names[RegClass_SPR][1] = "LR";
|
|
special_register_names[RegClass_SPR][2] = "CTR";
|
|
special_register_names[RegClass_SPR][3] = "VRSAVE";
|
|
special_register_names[RegClass_GPR][1] = "SP";
|
|
|
|
setup_diagnostic_reg_strings();
|
|
n_real_registers[RegClass_SPR] = 4;
|
|
n_real_registers[RegClass_CRFIELD] = 8;
|
|
n_real_registers[RegClass_VR] = 32;
|
|
n_real_registers[RegClass_FPR] = 32;
|
|
n_real_registers[RegClass_GPR] = 32;
|
|
reg_state[RegClass_GPR][1] = RegState2;
|
|
reg_state[RegClass_GPR][2] = RegState2;
|
|
reg_state[RegClass_CRFIELD][5] = RegState2;
|
|
|
|
for (rclass = 0; rclass < RegClassMax; rclass++) {
|
|
n_nonvolatile_registers[rclass] = 0;
|
|
if (last_nonvolatile_reg[rclass] >= 0) {
|
|
end = first_nonvolatile_reg(rclass);
|
|
for (reg = last_nonvolatile_reg[rclass]; reg >= end; reg--) {
|
|
if (reg_state[rclass][reg] == RegState0) {
|
|
tmp = n_nonvolatile_registers[rclass]++;
|
|
nonvolatile_registers[rclass][tmp] = reg;
|
|
}
|
|
}
|
|
}
|
|
|
|
assignable_registers[rclass] = n_nonvolatile_registers[rclass] - nonvol_reserve[rclass];
|
|
if (assignable_registers[rclass] < 0)
|
|
assignable_registers[rclass] = 0;
|
|
|
|
n_scratch_registers[rclass] = 0;
|
|
for (reg = 0; reg < n_real_registers[rclass]; reg++) {
|
|
if (reg < GetABIFirstNonVolatile(rclass) || reg > last_nonvolatile_reg[rclass]) {
|
|
if (reg_state[rclass][reg] == RegState0) {
|
|
tmp = n_scratch_registers[rclass]++;
|
|
scratch_registers[rclass][tmp] = reg;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_FP_ = -1;
|
|
_CALLER_SP_ = -1;
|
|
optimizing = (copts.optimizationlevel > 0) && !disable_optimizer;
|
|
}
|
|
|
|
void assign_register_by_type(Object *obj) {
|
|
VarInfo *vi;
|
|
Type *ty;
|
|
Boolean flag;
|
|
|
|
ty = obj->type;
|
|
vi = Registers_GetVarInfo(obj);
|
|
flag = 0;
|
|
vi->rclass = RegClassMax;
|
|
vi->reg = 0;
|
|
vi->regHi = 0;
|
|
|
|
if ((ty->type == TYPEINT) || (ty->type == TYPEENUM) || ((ty->type == TYPEPOINTER || ty->type == TYPEARRAY) && (ty->type != TYPEARRAY)) || ((ty->type == TYPEMEMBERPOINTER) && (ty->size == 4U))) {
|
|
if (((ty->type == TYPEINT) || (ty->type == TYPEENUM)) && (ty->size == 8))
|
|
flag = 1;
|
|
vi->rclass = RegClass_GPR;
|
|
} else if (ty->type == TYPEFLOAT) {
|
|
vi->rclass = RegClass_FPR;
|
|
} else if ((ty->type == TYPESTRUCT) && (TYPE_STRUCT(ty)->stype >= STRUCT_TYPE_4) && (TYPE_STRUCT(ty)->stype <= STRUCT_TYPE_E)) {
|
|
vi->rclass = RegClass_VR;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
if (vi->rclass < RegClassMax) {
|
|
if (flag) {
|
|
CError_ASSERT(520, vi->rclass == RegClass_GPR);
|
|
if (assignable_registers[vi->rclass] > 1)
|
|
assign_GPR_pair(obj);
|
|
} else {
|
|
if (assignable_registers[vi->rclass] > 0)
|
|
assign_register_to_variable(obj, vi->rclass);
|
|
}
|
|
}
|
|
}
|
|
|
|
void assign_GPR_pair(Object *obj) {
|
|
VarInfo *vi;
|
|
short reg;
|
|
short regHi;
|
|
|
|
vi = Registers_GetVarInfo(obj);
|
|
if (optimizing) {
|
|
reg = used_virtual_registers[RegClass_GPR]++;
|
|
regHi = used_virtual_registers[RegClass_GPR]++;
|
|
} else {
|
|
CError_ASSERT(554, assignable_registers[RegClass_GPR] >= 2);
|
|
reg = obtain_nonvolatile_register(RegClass_GPR);
|
|
regHi = obtain_nonvolatile_register(RegClass_GPR);
|
|
retain_GPR_pair(obj, reg, regHi);
|
|
}
|
|
|
|
vi->rclass = RegClass_GPR;
|
|
if (reg > 0 && regHi > 0) {
|
|
vi->flags |= VarInfoFlag2 | VarInfoFlag4;
|
|
vi->reg = reg;
|
|
vi->regHi = regHi;
|
|
} else {
|
|
CError_FATAL(567);
|
|
}
|
|
}
|
|
|
|
void open_fe_temp_registers(void) {
|
|
int r;
|
|
|
|
r = used_virtual_registers[RegClass_GPR];
|
|
first_fe_temporary_register[RegClass_GPR] = last_temporary_register[RegClass_GPR] = r;
|
|
r = used_virtual_registers[RegClass_FPR];
|
|
first_fe_temporary_register[RegClass_FPR] = last_temporary_register[RegClass_FPR] = r;
|
|
r = used_virtual_registers[RegClass_VR];
|
|
first_fe_temporary_register[RegClass_VR] = last_temporary_register[RegClass_VR] = r;
|
|
//first_fe_temporary_register[RegClass_GPR] = last_temporary_register[RegClass_GPR] = used_virtual_registers[RegClass_GPR];
|
|
//first_fe_temporary_register[RegClass_FPR] = last_temporary_register[RegClass_FPR] = used_virtual_registers[RegClass_FPR];
|
|
//first_fe_temporary_register[RegClass_VR] = last_temporary_register[RegClass_VR] = used_virtual_registers[RegClass_VR];
|
|
}
|
|
|
|
void set_last_exception_registers(void) {
|
|
last_exception_register[RegClass_GPR] = used_virtual_registers[RegClass_GPR] - 1;
|
|
last_exception_register[RegClass_FPR] = used_virtual_registers[RegClass_FPR] - 1;
|
|
last_exception_register[RegClass_VR] = used_virtual_registers[RegClass_VR] - 1;
|
|
}
|
|
|
|
static VarInfo *Registers_GetNewVarInfo(void) {
|
|
VarInfo *vi = galloc(sizeof(VarInfo));
|
|
memclrw(vi, sizeof(VarInfo));
|
|
return vi;
|
|
}
|
|
|
|
VarInfo *Registers_GetVarInfo(Object *obj) {
|
|
switch (obj->datatype) {
|
|
case DDATA:
|
|
if (!obj->u.data.info)
|
|
obj->u.data.info = Registers_GetNewVarInfo();
|
|
return obj->u.data.info;
|
|
case DNONLAZYPTR:
|
|
if (!obj->u.toc.info) {
|
|
CError_FATAL(639);
|
|
obj->u.toc.info = CodeGen_GetNewVarInfo();
|
|
}
|
|
return obj->u.toc.info;
|
|
case DLOCAL:
|
|
if (!obj->u.var.info)
|
|
CError_FATAL(647);
|
|
return obj->u.var.info;
|
|
case DABSOLUTE:
|
|
// not sure if this is the right union
|
|
if (!obj->u.data.info)
|
|
obj->u.data.info = Registers_GetNewVarInfo();
|
|
return obj->u.data.info;
|
|
default:
|
|
CError_FATAL(660);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
int used_vrstate_VRs(void) {
|
|
int count = 0;
|
|
int i;
|
|
for (i = 0; i < RegisterMax; i++) {
|
|
if (reg_state[RegClass_VR][i])
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
UInt32 colored_vrs_as_vrsave(PCodeBlock *block) {
|
|
PCode *pc;
|
|
UInt32 mask;
|
|
int i;
|
|
|
|
mask = 0;
|
|
if (copts.altivec_vrsave == 2)
|
|
return 0xFFFFFFFF;
|
|
if (copts.altivec_vrsave == 0)
|
|
return 0;
|
|
|
|
while (block) {
|
|
for (pc = block->firstPCode; pc; pc = pc->nextPCode) {
|
|
if (pc->flags & (fPCodeFlag40000000 | fPCodeFlag80000000)) {
|
|
for (i = 0; i < pc->argCount; i++) {
|
|
if (pc->args[i].kind == PCOp_REGISTER && pc->args[i].arg == RegClass_VR)
|
|
mask |= 1 << (31 - pc->args[i].data.reg.reg);
|
|
}
|
|
}
|
|
}
|
|
block = block->nextBlock;
|
|
}
|
|
|
|
return mask;
|
|
}
|
|
|
|
void save_before_coloring_nonvolatile_registers(RegClass rclass) {
|
|
used_regs_before_coloring = used_nonvolatile_registers[rclass];
|
|
memcpy(save_state, reg_state[rclass], sizeof(save_state));
|
|
}
|
|
|
|
void reset_nonvolatile_registers(RegClass rclass) {
|
|
used_nonvolatile_registers[rclass] = used_regs_before_coloring;
|
|
memcpy(reg_state[rclass], save_state, sizeof(save_state));
|
|
}
|
|
|
|
int is_nonvolatile_register(RegClass rclass, int reg) {
|
|
int i;
|
|
|
|
for (i = 0; i < n_nonvolatile_registers[rclass]; i++) {
|
|
if (reg == nonvolatile_registers[rclass][i])
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void init_endian(void) {
|
|
if (copts.little_endian) {
|
|
high_offset = 4;
|
|
low_offset = 0;
|
|
high_reg = 4;
|
|
low_reg = 3;
|
|
high_reg2 = 6;
|
|
low_reg2 = 5;
|
|
} else {
|
|
high_offset = 0;
|
|
low_offset = 4;
|
|
high_reg = 3;
|
|
low_reg = 4;
|
|
high_reg2 = 5;
|
|
low_reg2 = 6;
|
|
}
|
|
}
|
|
|
|
void update_asm_nonvolatile_registers(void) {
|
|
RegClass rclass;
|
|
int r31;
|
|
|
|
for (rclass = 0; rclass < RegClassMax; rclass++) {
|
|
for (r31 = n_nonvolatile_registers[rclass] - 1; r31 >= 0; r31--) {
|
|
if (reg_state[rclass][nonvolatile_registers[rclass][r31]] == RegState1)
|
|
break;
|
|
}
|
|
if (r31 > used_nonvolatile_registers[rclass])
|
|
used_nonvolatile_registers[rclass] = r31;
|
|
}
|
|
}
|