2022-12-29 12:32:55 +00:00

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;
}
}