mirror of https://git.wuffs.org/MWCC
265 lines
8.7 KiB
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;
|
|
}
|