MWCC/compiler_and_linker/BackEnd/PowerPC/CodeGenerator/PCodeUtilities.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);
}
}