diff options
Diffstat (limited to 'compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c')
-rw-r--r-- | compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c | 345 |
1 files changed, 345 insertions, 0 deletions
diff --git a/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c new file mode 100644 index 0000000..b1f8ffb --- /dev/null +++ b/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.c @@ -0,0 +1,345 @@ +#include "compiler/PCodeUtilities.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CParser.h" +#include "compiler/CodeGen.h" +#include "compiler/Exceptions.h" +#include "compiler/PCode.h" +#include "compiler/PCodeInfo.h" +#include "compiler/Registers.h" +#include "compiler/enode.h" +#include "compiler/objects.h" + +void pcsetrecordbit(PCode *pc) { + int reg; + PCodeArg *arg; + short argCount; + int argIdx; + + pc->flags &= ~(fIsMove | fCommutative | fIsCSE); + if ((pc->flags & fOpTypeMask) == fOpTypeFPR) { + reg = 1; + } else if ((pc->flags & fOpTypeMask) == fOpTypeVR) { + reg = 6; + } else { + reg = 0; + } + + if (pc->op == PC_ANDI || pc->op == PC_ANDIS) { + pc->flags |= fRecordBit; + } else if (pc->op == PC_ADDI || pc->op == PC_ADDIC) { + pc->flags |= fSetsCarry; + pc->flags |= fRecordBit; + change_num_operands(pc, 5); + pc->op = PC_ADDICR; + + CError_ASSERT(76, pc->args[3].kind == PCOp_PLACEHOLDEROPERAND); + pc->args[3].kind = PCOp_REGISTER; + pc->args[3].arg = RegClass_SPR; + pc->args[3].data.reg.reg = 0; + pc->args[3].data.reg.effect = EffectWrite; + CError_ASSERT(80, pc->args[4].kind == PCOp_PLACEHOLDEROPERAND); + pc->args[4].kind = PCOp_REGISTER; + pc->args[4].arg = RegClass_CRFIELD; + pc->args[4].data.reg.reg = reg; + pc->args[4].data.reg.effect = EffectWrite; + } else { + arg = pc->args; + argIdx = argCount = pc->argCount; + while (arg->kind != PCOp_PLACEHOLDEROPERAND && argIdx) { + if (arg->kind == PCOp_REGISTER && arg->arg == RegClass_CRFIELD && arg->data.reg.reg == reg) { + arg->data.reg.effect |= EffectWrite; + pc->flags |= fRecordBit; + return; + } + arg++; + argIdx--; + } + + if (argIdx <= 0) { + arg = &pc->args[argCount]; + pc->argCount++; + } + + CError_ASSERT(105, arg->kind == PCOp_PLACEHOLDEROPERAND); + arg->kind = PCOp_REGISTER; + arg->arg = RegClass_CRFIELD; + arg->data.reg.reg = reg; + arg->data.reg.effect = EffectWrite; + if (pc->op != PC_ADDICR) + pc->flags |= fRecordBit; + } +} + +void pcsetsideeffects(PCode *pc) { + pc->flags &= ~(fIsMove | fCommutative | fIsCSE); + pc->flags |= fSideEffects; +} + +void pcsetlinkbit(PCode *pc) { + PCodeArg *arg; + int argIdx; + + switch (pc->op) { + case PC_B: + pc->op = PC_BL; + break; + case PC_BCTR: + pc->op = PC_BCTRL; + break; + case PC_BLR: + pc->op = PC_BLRL; + break; + } + + arg = pc->args; + argIdx = pc->argCount; + while (arg->kind != PCOp_PLACEHOLDEROPERAND && argIdx) { + if (arg->kind == PCOp_REGISTER && arg->arg == RegClass_SPR && arg->data.reg.reg == 1) { + arg->data.reg.effect |= EffectWrite; + pc->flags |= fLink; + return; + } + arg++; + argIdx--; + } + + CError_ASSERT(169, arg->kind == PCOp_PLACEHOLDEROPERAND); + arg->kind = PCOp_REGISTER; + arg->arg = RegClass_SPR; + arg->data.reg.reg = 1; + arg->data.reg.effect = EffectWrite; + + if (opcodeinfo[pc->op].flags & fIsCall) { + pc->flags &= ~fIsBranch; + pc->flags |= fIsCall; + } + pc->flags |= fLink; +} + +void branch_label(PCodeLabel *label) { + if (pclastblock->pcodeCount) { + pcbranch(pclastblock, label); + makepcblock(); + } + pclabel(pclastblock, label); +} + +void branch_conditional(short a, short compareop, short c, PCodeLabel *label) { + PCodeBlock *tmpblock; + PCodeLabel *tmplabel; + int r28; + + tmpblock = pclastblock; + tmplabel = makepclabel(); + + switch (compareop) { + case ENOTEQU: + c = !c; + case EEQU: + r28 = 2; + break; + case EGREATEREQU: + c = !c; + case ELESS: + r28 = 0; + break; + case ELESSEQU: + c = !c; + case EGREATER: + r28 = 1; + break; + } + + emitpcode(c ? PC_BT : PC_BF, a, r28, label); + pcbranch(pclastblock, label); + pcbranch(pclastblock, tmplabel); + makepcblock(); + pclabel(pclastblock, tmplabel); +} + +void branch_always(PCodeLabel *label) { + emitpcode(PC_B, label); + pcbranch(pclastblock, label); + makepcblock(); +} + +void branch_decrement_always(Opcode opcode, PCodeLabel *label) { + PCodeLabel *tmplabel = makepclabel(); + emitpcode(opcode, label); + pcbranch(pclastblock, label); + pcbranch(pclastblock, tmplabel); + makepcblock(); + pclabel(pclastblock, tmplabel); +} + +void branch_indirect(Object *obj) { + emitpcode(PC_BCTR, obj, 0); + makepcblock(); +} + +int branch_count_volatiles(void) { + int count = 0; + int i; + RegClass rclass; + + for (rclass = 0; rclass < RegClassMax; rclass++) { + for (i = 0; i < n_scratch_registers[rclass]; i++) { + count++; + } + } + + return count; +} + +PCodeArg *branch_record_volatiles(PCodeArg *arglist, UInt32 *masks) { + int i; + RegClass rclass; + + for (rclass = RegClassMax - 1; rclass >= 0; rclass--) { + for (i = 0; i < n_scratch_registers[rclass]; i++) { + arglist->kind = PCOp_REGISTER; + arglist->arg = rclass; + arglist->data.reg.reg = scratch_registers[rclass][i]; + arglist->data.reg.effect = EffectWrite; + if (masks[rclass] & (1 << scratch_registers[rclass][i])) + arglist->data.reg.effect |= EffectRead; + arglist++; + } + } + + return arglist; +} + +void branch_subroutine(Object *obj, short add_nop, UInt32 *masks) { + int count; + PCode *pc; + PCodeArg *arg; + + count = branch_count_volatiles(); + if (copts.exceptions && current_statement) + count += countexceptionactionregisters(current_statement->dobjstack); + + pc = makepcode(PC_BL, count, obj, 0); + arg = branch_record_volatiles(pc->args + 1, masks); + if (copts.exceptions && current_statement) + noteexceptionactionregisters(current_statement->dobjstack, arg); + appendpcode(pclastblock, pc); + + if (add_nop) + emitpcode(PC_NOP); + + branch_label(makepclabel()); + if (copts.exceptions && current_statement) + recordexceptionactions(pc, current_statement->dobjstack); +} + +void branch_subroutine_ctr(UInt32 *masks) { + int count; + PCode *pc; + PCodeArg *arg; + + count = branch_count_volatiles(); + if (copts.exceptions && current_statement) + count += countexceptionactionregisters(current_statement->dobjstack); + + pc = makepcode(PC_BCTRL, count); + arg = branch_record_volatiles(pc->args + 1, masks); + if (copts.exceptions && current_statement) + noteexceptionactionregisters(current_statement->dobjstack, arg); + appendpcode(pclastblock, pc); + + branch_label(makepclabel()); + if (copts.exceptions && current_statement) + recordexceptionactions(pc, current_statement->dobjstack); +} + +void add_immediate(short dest_reg, short base_reg, Object *obj, SInt16 offset) { + short tmp_reg = base_reg; + + if (obj && offset && obj->datatype != DLOCAL) { + tmp_reg = used_virtual_registers[RegClass_GPR]++; + add_immediate_lo(tmp_reg, base_reg, obj, 0, 1); + obj = NULL; + } + + if (!obj && !offset) + emitpcode(PC_MR, dest_reg, tmp_reg); + else + emitpcode(PC_ADDI, dest_reg, tmp_reg, obj, offset); +} + +PCode *add_immediate_lo(short dest_reg, short base_reg, Object *obj, SInt16 offset, char add_to_block) { + PCode *pc; + + CError_ASSERT(577, obj); + + pc = makepcode(PC_ADDI, dest_reg, base_reg, obj, offset); + if (add_to_block) + appendpcode(pclastblock, pc); + return pc; +} + +PCode *op_absolute_ha(short dest_reg, short base_reg, Object *obj, short offset, char add_to_block) { + PCode *pc; + int tmp_reg; + + if (obj->datatype == DLOCAL) { + pc = makepcode(PC_ADDIS, dest_reg, base_reg, obj, offset); + } else if (copts.codegen_pic) { + tmp_reg = base_reg; + CError_ASSERT(601, tmp_reg); + pc = makepcode(PC_ADDIS, dest_reg, tmp_reg, obj, offset); + } else { + CError_ASSERT(606, base_reg == 0); + pc = makepcode(PC_LIS, dest_reg, obj, offset); + } + + if (add_to_block) + appendpcode(pclastblock, pc); + return pc; +} + +void load_store_register(Opcode opcode, short dest_reg, short base_reg, Object *obj, SInt32 offset) { + short addi_tmp; + short offset_reg1; + short offset_reg2; + + offset_reg1 = base_reg; + if (obj && offset && obj->datatype != DLOCAL) { + offset_reg1 = used_virtual_registers[RegClass_GPR]++; + add_immediate_lo(offset_reg1, base_reg, obj, 0, 1); + obj = NULL; + } + + if (offset != (short)offset) { + if (opcode == PC_LWZ && dest_reg == 12) + offset_reg2 = 12; + else if (opcode == PC_LWZ && dest_reg == 11) + offset_reg2 = 11; + else + offset_reg2 = used_virtual_registers[RegClass_GPR]++; + + emitpcode(PC_ADDIS, offset_reg2, offset_reg1, 0, (short) ((offset >> 16) + ((offset & 0x8000) >> 15))); + offset = (short) offset; + offset_reg1 = offset_reg2; + } + + if (opcode == PC_STVX || opcode == PC_LVX) { + offset_reg2 = 0; + if (obj) { + addi_tmp = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_ADDI, addi_tmp, offset_reg1, obj, offset); + offset_reg1 = addi_tmp; + } else if (offset) { + offset_reg2 = used_virtual_registers[RegClass_GPR]++; + emitpcode(PC_LI, offset_reg2, offset); + } + if (!offset_reg2) + emitpcode(opcode, dest_reg, 0, offset_reg1); + else + emitpcode(opcode, dest_reg, offset_reg1, offset_reg2); + } else { + emitpcode(opcode, dest_reg, offset_reg1, obj, offset); + } +} |