mirror of https://git.wuffs.org/MWCC
346 lines
9.7 KiB
C
346 lines
9.7 KiB
C
#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);
|
|
}
|
|
}
|