MWCC/compiler_and_linker/unsorted/SpillCode.c

465 lines
14 KiB
C
Raw Normal View History

#include "compiler/SpillCode.h"
#include "compiler/CError.h"
#include "compiler/CMachine.h"
#include "compiler/CParser.h"
#include "compiler/CodeGen.h"
#include "compiler/CompilerTools.h"
#include "compiler/Coloring.h"
#include "compiler/InterferenceGraph.h"
#include "compiler/Operands.h"
#include "compiler/PCode.h"
#include "compiler/PCodeUtilities.h"
#include "compiler/Registers.h"
#include "compiler/RegisterInfo.h"
#include "compiler/StackFrame.h"
#include "compiler/objects.h"
static int last_unused_vreg_before_spilling;
static short rTEMP_for_VR_spill;
void estimatespillcosts(void) {
PCodeBlock *block;
PCode *instr;
IGNode *node;
PCodeArg *op;
int i;
int weight;
for (block = pcbasicblocks; block; block = block->nextBlock) {
if (copts.optimize_for_size)
weight = 1;
else
weight = block->loopWeight;
for (instr = block->firstPCode; instr; instr = instr->nextPCode) {
op = instr->args;
i = instr->argCount;
while (i--) {
if (PC_OP_IS_READ_ANY_REGISTER(op, coloring_class)) {
node = interferencegraph[op->data.reg.reg];
if (node->instr8 || copts.optimize_for_size)
node->spillCost += weight;
else
node->spillCost += weight * 2;
}
op++;
}
op = instr->args;
i = instr->argCount;
while (i--) {
if (PC_OP_IS_WRITE_ANY_REGISTER(op, coloring_class)) {
node = interferencegraph[op->data.reg.reg];
if (node->instr8 || (instr->flags & fPCodeFlag8000))
node->spillCost -= weight;
else
node->spillCost += weight;
}
op++;
}
}
}
}
static Object *makespilltemporary(Type *type) {
Object *obj = lalloc(sizeof(Object));
memclrw(obj, sizeof(Object));
obj->otype = OT_OBJECT;
obj->access = ACCESSPUBLIC;
obj->datatype = DLOCAL;
obj->type = type;
obj->name = CParser_GetUniqueName();
obj->u.var.info = CodeGen_GetNewVarInfo();
obj->u.var.uid = 0;
return obj;
}
static PCode *rematerialize_spilled_register(short reg, IGNode *node) {
PCode *instr = copypcode(node->instr8);
#line 128
CError_ASSERT(instr->args[0].kind == PCOp_REGISTER);
instr->args[0].data.reg.reg = reg;
return instr;
}
static void insert_load_spilled_register(PCode *instr, short reg, IGNode *node) {
Type *type;
Opcode opcode;
Object *object;
PCode *newInstr;
PCode *newInstr2;
SInt32 offset;
Operand operand;
type = node->spillTemporary->type;
switch (coloring_class) {
case RegClass_CRFIELD:
case RegClass_GPR:
switch (type->size) {
case 1:
opcode = PC_LBZ;
break;
case 2:
opcode = is_unsigned(type) ? PC_LHZ : PC_LHA;
break;
case 4:
opcode = PC_LWZ;
break;
case 8:
opcode = PC_LWZ;
break;
default:
#line 187
CError_FATAL();
}
memclrw(&operand, sizeof(Operand));
operand.optype = OpndType_Symbol;
operand.object = node->spillTemporary;
#line 222
CError_ASSERT(node->spillTemporary->datatype == DLOCAL);
coerce_to_addressable(&operand);
#line 233
CError_ASSERT(operand.optype == OpndType_GPR_ImmOffset);
#line 237
CError_ASSERT(node->spillTemporary->datatype == DLOCAL);
if (node->flags & fPairLow)
offset = low_offset;
else if (node->flags & fPairHigh)
offset = high_offset;
else
offset = 0;
insertpcodebefore(instr, makepcode(opcode, reg, operand.reg, operand.object, operand.immOffset + offset));
break;
case RegClass_FPR:
#line 253
CError_ASSERT(node->spillTemporary->datatype == DLOCAL);
if (node->flags & fPairLow)
offset = low_offset;
else if (node->flags & fPairHigh)
offset = high_offset;
else
offset = 0;
object = node->spillTemporary;
insertpcodebefore(
instr,
makepcode(
(type->size == 8) ? PC_LFD : PC_LFS,
reg,
local_base_register(object),
object,
offset
)
);
break;
case RegClass_VR:
#line 320
CError_ASSERT(node->spillTemporary->datatype == DLOCAL);
object = node->spillTemporary;
newInstr = makepcode(PC_ADDI, rTEMP_for_VR_spill, local_base_register(object), object, 0);
newInstr2 = makepcode(PC_LVX, reg, 0, rTEMP_for_VR_spill);
insertpcodebefore(instr, newInstr);
insertpcodeafter(newInstr, newInstr2);
break;
default:
#line 333
CError_FATAL();
}
}
static void insert_store_spilled_register(PCode *instr, Boolean flag, short reg, IGNode *node) {
Object *object; // r31
Opcode opcode; // r30
SInt32 offset; // r26
PCode *newInstr2; // r26
PCode *newInstr; // r25
Type *type; // r25
object = node->spillTemporary;
type = object->type;
switch (coloring_class) {
case RegClass_CRFIELD:
case RegClass_GPR:
switch (type->size) {
case 1:
opcode = PC_STB;
break;
case 2:
opcode = PC_STH;
break;
case 4:
opcode = PC_STW;
break;
case 8:
opcode = PC_STW;
break;
default:
#line 391
CError_FATAL();
}
if (node->flags & fPairLow)
offset = low_offset;
else if (node->flags & fPairHigh)
offset = high_offset;
else
offset = 0;
newInstr = makepcode(opcode, reg, local_base_register(object), object, offset);
if (flag)
insertpcodebefore(instr, newInstr);
else
insertpcodeafter(instr, newInstr);
break;
case RegClass_FPR:
newInstr = makepcode((type->size == 8) ? PC_STFD : PC_STFS, reg, local_base_register(object), object, 0);
if (flag)
insertpcodebefore(instr, newInstr);
else
insertpcodeafter(instr, newInstr);
break;
case RegClass_VR:
newInstr = makepcode(PC_ADDI, rTEMP_for_VR_spill, local_base_register(object), object, 0);
newInstr2 = makepcode(PC_STVX, reg, 0, rTEMP_for_VR_spill);
if (flag)
insertpcodebefore(instr, newInstr);
else
insertpcodeafter(instr, newInstr);
insertpcodeafter(newInstr, newInstr2);
break;
default:
#line 527
CError_FATAL();
}
}
static void spillinstruction(PCodeBlock *block, PCode *instr) {
int reg;
int reg2;
int regs;
IGNode *node;
PCodeArg *op;
int i;
PCodeArg *op2;
int j;
int readCounter;
int writeCounter;
Boolean flag;
regs = used_virtual_registers[coloring_class];
flag = 0;
for (i = 0, op = instr->args; i < instr->argCount; i++, op++) {
#line 563
CError_ASSERT(instr->block != NULL);
if (
PC_OP_IS_ANY_REGISTER(op, coloring_class) &&
(reg = op->data.reg.reg) < regs &&
((node = interferencegraph[op->data.reg.reg])->flags & fSpilled)
)
{
reg2 = used_virtual_registers[coloring_class]++;
readCounter = 0;
writeCounter = 0;
for (j = i, op2 = op; j < instr->argCount; j++, op2++) {
if (PC_OP_IS_REGISTER(op2, coloring_class, reg)) {
if (op2->data.reg.effect & EffectRead)
readCounter++;
if (op2->data.reg.effect & EffectWrite)
writeCounter++;
op2->data.reg.reg = reg2;
op2->data.reg.effect |= Effect40;
}
}
if (readCounter) {
if (node->instr8)
insertpcodebefore(instr, rematerialize_spilled_register(reg2, node));
else
insert_load_spilled_register(instr, reg2, node);
}
if (writeCounter) {
if (node->instr8 || (instr->flags & fPCodeFlag8000))
flag = 1;
else
insert_store_spilled_register(instr, 0, reg2, node);
}
}
}
if (flag)
deletepcode(instr);
}
static void spillcopy(PCodeBlock *block, PCode *instr) {
IGNode *node1;
IGNode *node2;
int reg;
node1 = interferencegraph[instr->args[1].data.reg.reg];
node2 = interferencegraph[instr->args[0].data.reg.reg];
if (node1->flags & fSpilled) {
if (node2->flags & fSpilled) {
reg = used_virtual_registers[coloring_class]++;
if (node1->instr8)
insertpcodebefore(instr, rematerialize_spilled_register(reg, node1));
else
insert_load_spilled_register(instr, reg, node1);
insert_store_spilled_register(instr, 1, reg, node2);
} else {
if (node1->instr8)
insertpcodebefore(instr, rematerialize_spilled_register(instr->args[0].data.reg.reg, node1));
else
insert_load_spilled_register(instr, instr->args[0].data.reg.reg, node1);
}
} else {
insert_store_spilled_register(instr, 1, instr->args[1].data.reg.reg, node2);
}
deletepcode(instr);
}
static void spillcall(PCodeBlock *block, PCode *instr) {
PCodeArg *opSrc;
PCodeArg *opDst;
int opCount;
int volatileCount;
int i;
opCount = instr->argCount;
volatileCount = branch_count_volatiles();
opDst = instr->args + volatileCount;
opSrc = instr->args + volatileCount;
for (i = volatileCount; i < opCount; i++) {
if (
PC_OP_IS_ANY_REGISTER(opSrc, coloring_class) &&
opSrc->data.reg.reg >= n_real_registers[coloring_class] &&
(interferencegraph[opSrc->data.reg.reg]->flags & fSpilled)
)
{
instr->argCount--;
} else {
*opDst = *opSrc;
opDst++;
}
opSrc++;
}
spillinstruction(block, instr);
}
static void assign_spill_locations(void) {
UInt32 i;
IGNode *node;
Type *type;
last_unused_vreg_before_spilling = used_virtual_registers[coloring_class];
for (i = n_real_registers[coloring_class]; i < last_unused_vreg_before_spilling; i++) {
node = interferencegraph[i];
if (node->flags & fCoalesced)
continue;
if (!(node->flags & fSpilled))
continue;
if (!node->spillTemporary) {
switch (coloring_class) {
case RegClass_GPR:
type = TYPE(&stunsignedlong);
break;
case RegClass_CRFIELD:
type = TYPE(&stunsignedlong);
break;
case RegClass_FPR:
type = TYPE(&stunsignedlong);
break;
case RegClass_VR:
type = TYPE(&stvectorunsignedchar);
break;
default:
#line 771
CError_FATAL();
}
node->spillTemporary = makespilltemporary(type);
}
if (node->spillTemporary->datatype == DLOCAL && !(node->spillTemporary->u.var.info->flags & VarInfoFlag1))
assign_local_memory(node->spillTemporary);
if (node->flags & fPairHigh)
Registers_GetVarInfo(node->spillTemporary)->regHi = Register0;
else
Registers_GetVarInfo(node->spillTemporary)->reg = Register0;
}
}
void insertspillcode(void) {
PCodeBlock *block;
PCode *instr;
PCode *nextInstr;
PCodeArg *op;
UInt32 i;
int flag;
rTEMP_for_VR_spill = 0;
assign_spill_locations();
for (block = pcbasicblocks; block; block = block->nextBlock) {
for (instr = block->firstPCode; instr; instr = nextInstr) {
nextInstr = instr->nextPCode;
flag = 0;
op = instr->args;
i = instr->argCount;
while (i--) {
if (
PC_OP_IS_ANY_REGISTER(op, coloring_class) &&
op->data.reg.reg < last_unused_vreg_before_spilling &&
(interferencegraph[op->data.reg.reg]->flags & fSpilled)
)
{
flag = 1;
break;
}
op++;
}
if (flag) {
if (coloring_class == RegClass_VR && rTEMP_for_VR_spill == 0)
rTEMP_for_VR_spill = used_virtual_registers[RegClass_GPR]++;
if (instr->flags & fPCodeFlag10)
spillcopy(block, instr);
else if (instr->flags & fPCodeFlag8)
spillcall(block, instr);
else
spillinstruction(block, instr);
}
}
}
}