MWCC/compiler_and_linker/unsorted/AddPropagation.c

265 lines
8.7 KiB
C

#include "compiler/AddPropagation.h"
#include "compiler/Alias.h"
#include "compiler/BitVectors.h"
#include "compiler/CopyPropagation.h"
#include "compiler/PCode.h"
#include "compiler/PCodeInfo.h"
#include "compiler/Registers.h"
#include "compiler/StackFrame.h"
#include "compiler/CError.h"
#include "compiler/CParser.h"
#include "compiler/objects.h"
int propagatedadds;
static int is_add(PCode *instr) {
return
(
instr->op == PC_ADD ||
(
instr->op == PC_ADDI &&
(
instr->args[2].kind == PCOp_IMMEDIATE ||
(instr->args[2].kind == PCOp_MEMORY && (PCOpMemoryArg) instr->args[2].arg == PCOpMemory1)
)
)
)
&&
instr->args[0].data.reg.reg >= n_real_registers[instr->args[0].arg];
}
static int addpropagatestouse(int candidateID, int useID) {
int reg2;
PCode *candidateInstr;
PCode *useInstr;
int reg1;
int reg27;
Object *object;
SInt32 offset;
int i;
PCode *instr;
PCodeArg *op;
candidateInstr = Candidates[candidateID].pcode;
useInstr = Uses[useID].pcode;
reg1 = candidateInstr->args[0].data.reg.reg;
reg2 = candidateInstr->args[1].data.reg.reg;
reg27 = reg2;
if (!useInstr->block) {
recursive_propagation = 1;
return 0;
}
if (useInstr->flags & (fIsRead | fIsWrite)) {
if (PCODE_FLAG_SET_F(useInstr) & fUpdatesPtr)
return 0;
} else if (useInstr->op == PC_ADDI) {
if (useInstr->args[2].kind != PCOp_IMMEDIATE)
return 0;
} else if (useInstr->op != PC_MR) {
return 0;
}
if (candidateInstr->op == PC_ADD) {
if (useInstr->argCount < 3) {
if (useInstr->op != PC_MR)
return 0;
} else if (useInstr->args[2].kind == PCOp_IMMEDIATE) {
if (useInstr->args[2].data.imm.value != 0)
return 0;
} else if (useInstr->args[2].kind == PCOp_REGISTER) {
if (
useInstr->args[1].kind != PCOp_REGISTER ||
useInstr->args[2].data.reg.reg != reg1 ||
useInstr->args[1].data.reg.reg != 0
)
return 0;
} else {
return 0;
}
object = NULL;
offset = 0;
if (candidateInstr->alias && candidateInstr->alias->type == AliasType0) {
object = candidateInstr->alias->object;
offset = candidateInstr->alias->offset;
}
reg27 = candidateInstr->args[2].data.reg.reg;
} else if (candidateInstr->op == PC_ADDI) {
if (candidateInstr->alias && candidateInstr->alias->type == AliasType0) {
object = candidateInstr->alias->object;
offset = candidateInstr->alias->offset;
} else if (candidateInstr->args[2].kind == PCOp_MEMORY) {
object = candidateInstr->args[2].data.mem.obj;
offset = candidateInstr->args[2].data.mem.offset;
} else if (candidateInstr->args[2].kind == PCOp_IMMEDIATE) {
object = NULL;
offset = candidateInstr->args[2].data.imm.value;
} else {
return 0;
}
if (useInstr->argCount < 3) {
if (useInstr->op != PC_MR)
return 0;
} else if (useInstr->args[2].kind == PCOp_IMMEDIATE) {
offset += useInstr->args[2].data.imm.value;
if (object) {
if (object->datatype == DLOCAL) {
if (!can_add_displ_to_local(object, offset))
return 0;
} else {
return 0;
}
} else if (!FITS_IN_SHORT(offset)) {
return 0;
}
} else {
return 0;
}
} else {
CError_FATAL(225);
return 0;
}
if (
(useInstr->flags & fIsWrite) &&
useInstr->args[0].kind == PCOp_REGISTER &&
useInstr->args[0].arg == RegClass_GPR &&
useInstr->args[0].data.reg.reg == reg1
)
return 0;
if (useInstr->args[1].data.reg.reg != reg1)
return 0;
if (candidateInstr->block == useInstr->block && precedes(candidateInstr, useInstr)) {
for (instr = candidateInstr->nextPCode; instr && instr != useInstr; instr = instr->nextPCode) {
op = instr->args;
i = instr->argCount;
while (i--) {
if (
PC_OP_IS_WRITE_ANY_REGISTER(op, RegClass_GPR) &&
(op->data.reg.reg == reg2 || op->data.reg.reg == reg27)
)
return 0;
op++;
}
}
} else {
if (!bitvectorgetbit(candidateID, propinfo[useInstr->block->blockIndex].vec8))
return 0;
for (instr = useInstr->block->firstPCode; instr; instr = instr->nextPCode) {
if (instr == useInstr)
break;
op = instr->args;
i = instr->argCount;
while (i--) {
if (
PC_OP_IS_WRITE_ANY_REGISTER(op, RegClass_GPR) &&
(op->data.reg.reg == reg2 || op->data.reg.reg == reg27)
)
return 0;
op++;
}
}
}
if ((useInstr->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000)) && object)
useInstr->alias = make_alias(object, offset, nbytes_loaded_or_stored_by(useInstr));
return 1;
}
static void propagateandremoveadd(int id) {
PCode *instr;
RegUseOrDef *list;
Candidate *candidate;
PCode *useInstr;
candidate = Candidates + id;
instr = candidate->pcode;
if (instr->op == PC_ADDI && instr->args[2].kind == PCOp_MEMORY)
instr->alias = make_alias(instr->args[2].data.mem.obj, instr->args[2].data.mem.offset, 1);
for (list = candidate->list; list; list = list->next) {
useInstr = Uses[list->id].pcode;
if (instr->op == PC_ADD) {
if (useInstr->flags & (fIsRead | fIsWrite)) {
if (useInstr->args[2].kind != PCOp_REGISTER) {
useInstr->op += 2;
useInstr->flags |= fIsPtrOp;
}
useInstr->args[1] = instr->args[1];
useInstr->args[2] = instr->args[2];
useInstr->alias = instr->alias;
} else if (useInstr->op == PC_ADDI) {
CError_ASSERT(338, useInstr->args[2].data.imm.value == 0);
change_opcode(useInstr, PC_ADD);
useInstr->args[1] = instr->args[1];
useInstr->args[2] = instr->args[2];
useInstr->alias = instr->alias;
} else if (useInstr->op == PC_MR) {
change_opcode(useInstr, PC_ADD);
useInstr->flags = instr->flags;
change_num_operands(useInstr, 3);
useInstr->args[1] = instr->args[1];
useInstr->args[2] = instr->args[2];
useInstr->alias = instr->alias;
} else {
CError_FATAL(352);
}
} else if (useInstr->op == PC_MR) {
change_opcode(useInstr, PC_ADDI);
useInstr->flags = instr->flags;
useInstr->alias = instr->alias;
change_num_operands(useInstr, 3);
useInstr->args[1] = instr->args[1];
useInstr->args[2] = instr->args[2];
} else {
useInstr->args[1] = instr->args[1];
if (instr->args[2].kind == PCOp_IMMEDIATE) {
SInt32 newValue = useInstr->args[2].data.imm.value + instr->args[2].data.imm.value;
useInstr->args[2] = instr->args[2];
useInstr->args[2].data.imm.value = newValue;
useInstr->flags |= fIsPtrOp;
} else if (instr->args[2].kind == PCOp_MEMORY) {
SInt32 newValue = useInstr->args[2].data.imm.value + instr->args[2].data.mem.offset;
useInstr->args[2] = instr->args[2];
useInstr->args[2].data.mem.offset = newValue;
useInstr->flags &= ~fIsPtrOp;
if (useInstr->flags & (fIsRead | fIsWrite | fPCodeFlag20000 | fPCodeFlag40000))
useInstr->alias = make_alias(
useInstr->args[2].data.mem.obj,
useInstr->args[2].data.mem.offset,
nbytes_loaded_or_stored_by(useInstr));
} else {
CError_FATAL(382);
}
}
}
deletepcode(instr);
propagatedadds = 1;
}
static Propagation add_prop = {
&is_add,
&addpropagatestouse,
&propagateandremoveadd,
"ADD",
"ADDS",
"a%ld",
0
};
void propagateaddinstructions(Object *proc) {
propagateinstructions(proc, &add_prop, (copts.optimizationlevel >= 4) ? 4 : 1, 1);
propagatedadds = propagated_instructions;
}