#include "compiler/PCodeUtilities.h" #include "compiler/CError.h" #include "compiler/CParser.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 &= ~(fPCodeFlag10 | fCommutative | fIsCSE); if ((pc->flags & (fPCodeFlag80000000 | fPCodeFlag40000000)) == fPCodeFlag40000000) { reg = 1; } else if ((pc->flags & (fPCodeFlag80000000 | fPCodeFlag40000000)) == (fPCodeFlag80000000 | fPCodeFlag40000000)) { reg = 6; } else { reg = 0; } if (pc->op == PC_ANDI || pc->op == PC_ANDIS) { pc->flags |= fPCodeFlag20000000; } else if (pc->op == PC_ADDI || pc->op == PC_ADDIC) { pc->flags |= fPCodeFlag10000000; pc->flags |= fPCodeFlag20000000; 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 |= fPCodeFlag20000000; 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 |= fPCodeFlag20000000; } } void pcsetsideeffects(PCode *pc) { pc->flags &= ~(fPCodeFlag10 | 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 & fPCodeFlag8) { pc->flags &= ~fPCodeFlag1; pc->flags |= fPCodeFlag8; } 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); } }