#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/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 && (unsigned char) instr->args[2].arg == 1) ) ) ) && instr->args[0].data.reg.reg >= n_real_registers[(char) 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 & (fPCodeFlag2 | fPCodeFlag4)) { if (PCODE_FLAG_SET_F(useInstr) & fPCodeFlag2000000) 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 { #line 225 CError_FATAL(); return 0; } if ( (useInstr->flags & fPCodeFlag4) && 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 ( op->kind == PCOp_REGISTER && op->arg == RegClass_GPR && (op->data.reg.effect & EffectWrite) && (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 ( op->kind == PCOp_REGISTER && op->arg == RegClass_GPR && (op->data.reg.effect & EffectWrite) && (op->data.reg.reg == reg2 || op->data.reg.reg == reg27) ) return 0; op++; } } } if ((useInstr->flags & (fPCodeFlag2 | fPCodeFlag4 | 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 & (fPCodeFlag2 | fPCodeFlag4)) { if (useInstr->args[2].kind != PCOp_REGISTER) { useInstr->op += 2; useInstr->flags |= fPCodeFlag20; } useInstr->args[1] = instr->args[1]; useInstr->args[2] = instr->args[2]; useInstr->alias = instr->alias; } else if (useInstr->op == PC_ADDI) { #line 338 CError_ASSERT(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 { #line 352 CError_FATAL(); } } 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 |= fPCodeFlag20; } 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 &= ~fPCodeFlag20; if (useInstr->flags & (fPCodeFlag2 | fPCodeFlag4 | 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 { #line 382 CError_FATAL(); } } } 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; }