summaryrefslogtreecommitdiff
path: root/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c')
-rw-r--r--compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c452
1 files changed, 452 insertions, 0 deletions
diff --git a/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c b/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c
new file mode 100644
index 0000000..69e7e43
--- /dev/null
+++ b/compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c
@@ -0,0 +1,452 @@
+#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.optimizesize)
+ 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.optimizesize)
+ 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 & fIsArgInit))
+ 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);
+
+ CError_ASSERT(128, 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:
+ CError_FATAL(187);
+ }
+
+ memclrw(&operand, sizeof(Operand));
+ operand.optype = OpndType_Symbol;
+ operand.object = node->spillTemporary;
+ CError_ASSERT(222, node->spillTemporary->datatype == DLOCAL);
+
+ coerce_to_addressable(&operand);
+
+ CError_ASSERT(233, operand.optype == OpndType_GPR_ImmOffset);
+
+ CError_ASSERT(237, 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:
+ CError_ASSERT(253, 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:
+ CError_ASSERT(320, 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:
+ CError_FATAL(333);
+ }
+}
+
+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:
+ CError_FATAL(391);
+ }
+
+ 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:
+ CError_FATAL(527);
+ }
+}
+
+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++) {
+ CError_ASSERT(563, 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 & fIsArgInit))
+ 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:
+ CError_FATAL(771);
+ }
+
+ 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 & fIsMove)
+ spillcopy(block, instr);
+ else if (instr->flags & fIsCall)
+ spillcall(block, instr);
+ else
+ spillinstruction(block, instr);
+ }
+ }
+ }
+}