diff options
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c')
-rw-r--r-- | compiler_and_linker/BackEnd/PowerPC/RegisterAllocator/SpillCode.c | 452 |
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); + } + } + } +} |