if (i.canRaiseException()) { Operation op = i.getOperation(); boolean isBranch = op == Operation.B_TRUE || op == Operation.B_FALSE; if (!isBranch) { state.unboxedDirtyVars.removeAll(i.getUsedVariables());
/** * Instructions are meant to be in a machine-readable format so offline tooling can parse the * debugging output. The format is: * * (result_op '=')? instr '(' (operand ',' )* operand? ';' (extra_arg ',')* extra_arg? ')' * extra_arg can either be plain value or in a key: value format. * @return a String */ @Override public String toString() { StringBuilder buf = new StringBuilder(isDead() ? "[DEAD]" : ""); if (this instanceof ResultInstr) buf.append(((ResultInstr) this).getResult()).append(" = "); Operand[] operands = getOperands(); buf.append(operation).append('('); toArgList(buf, operands); String[] extraArgs = toStringNonOperandArgs(); if (extraArgs.length >= 1) { if (operands.length > 0) buf.append(' '); buf.append(';'); toArgList(buf, extraArgs); } buf.append(')'); return buf.toString(); }
Operand val = instr.simplifyAndGetResult(s, valueMap); if (!instr.hasSideEffects()) { if (instr instanceof CopyInstr) { if (res.equals(val) && instr.canBeDeletedFromScope(s)) { instr.markDead();
/** * Can this instruction be deleted? LVA will preserve instructions based on whether operands (variables) * are living but even if there are no living variables then the instruction itself may not be able to be removed * during DCE for other reasons (like if it unconditionally has a side-effect) */ public boolean isDeletable() { return !(hasSideEffects() || operation.isDebugOp() || canRaiseException() || transfersControl()); }
/** * This method takes as input a map of operands to their values, and outputs * * If the value map provides a value for any of the instruction's operands * this method is expected to replace the original operands with the simplified values. * It is not required that it do so -- code correctness is not compromised by failure * to simplify */ public void simplifyOperands(Map<Operand, Operand> valueMap, boolean force) { if (getOperands() != EMPTY_OPERANDS) { System.out.println("simplifyOperands: Missing implementation for: " + this.getOperation()); throw new RuntimeException("simplifyOperands: Missing implementation for: " + this.getOperation()); } }
/** * This method takes as input a map of operands to their values, and outputs * * If the value map provides a value for any of the instruction's operands * this method is expected to replace the original operands with the simplified values. * It is not required that it do so -- code correctness is not compromised by failure * to simplify */ public void simplifyOperands(Map<Operand, Operand> valueMap, boolean force) { Operand[] operands = getOperands(); for (int i = 0; i < operands.length; i++) { setOperand(i, operands[i].getSimplifiedOperand(valueMap, force)); } }
while (instrs.hasNext()) { Instr i = instrs.next(); Operation iop = i.getOperation(); if (preCFG && iop.startsBasicBlock()) { valueMap = new HashMap<Operand,Operand>(); Operand val = i.simplifyAndGetResult(s, valueMap); if (!res.equals(val)) { recordSimplification(res, val, valueMap, simplificationMap); } else if (!i.hasSideEffects()) { if (i instanceof CopyInstr) { if (i.canBeDeleted(s)) { i.markDead(); instrs.remove(); if ((preCFG && iop.endsBasicBlock()) || (iop.isCall() && !i.isDead())) { valueMap = new HashMap<Operand,Operand>(); simplificationMap = new HashMap<Variable,List<Variable>>();
Map<TemporaryVariable, List<Instr>> tmpVarDefs = new HashMap<TemporaryVariable, List<Instr>>(); for (Instr i: s.getInstrs()) { for (Variable v: i.getUsedVariables()) { if (v instanceof TemporaryVariable) { TemporaryVariable tv = (TemporaryVariable)v; if (uses == null) { if (i instanceof CopyInstr) { i.markDead(); instrs.remove(); } else if (i instanceof CallInstr) { instrs.set(((CallInstr)i).discardResult()); } else { i.markUnusedResult(); CopyInstr ci = (CopyInstr)i; Operand src = ci.getSource(); i.markDead(); instrs.remove(); copyMap.put(v, src); Instr soleUse = uses.get(0); soleUse.simplifyOperands(copyMap, true); if ((uses.size() == 1) && (defs.size() == 1)) { Instr soleDef = defs.get(0); if (!soleDef.isDead()) { for (Variable v: i.getUsedVariables()) {
i.markDead(); living.clear(dv.getId()); } else if (i.canBeDeleted(scope)) { i.markDead(); it.remove(); if (v.isImplicitBlockArg()) lvp.getScope().markUnusedImplicitBlockArg(); } else if (i.canBeDeleted(scope)) { i.markDead(); it.remove(); } else { makeOutExceptionVariablesLiving(living); } else if (i.canRaiseException()) { makeOutExceptionVariablesLiving(living); if (!i.isDead()) markAllVariablesLive(lvp, living, i.getUsedVariables());
i.markDead(); living.clear(dv); } else if (i.isDeletable()) { i.markDead(); it.remove(); } else { } else if (i.isDeletable()) { i.markDead(); it.remove(); } else { if (i.canRaiseException()) makeOutExceptionVariablesLiving(); if (!i.isDead()) markAllVariablesLive(problem, i.getUsedVariables());
public boolean canBeDeleted(IRScope s) { if (hasSideEffects() || getOperation().isDebugOp() || getOperation().canRaiseException() || transfersControl()) { return false; } else if (this instanceof ResultInstr) { Variable r = ((ResultInstr)this).getResult(); if (s.bindingHasEscaped() && !r.getName().equals(Variable.BLOCK)) { // If the binding of this scope has escaped, then we have to preserve writes to // all local variables because anyone who uses the binding might query any of the // local variables from the binding. This is safe, but extremely conservative. return !(r instanceof LocalVariable); } else if (s.usesEval() && r.getName().equals(Variable.BLOCK)) { // If this scope (or any nested scope) has any evals, then the eval might have a yield which // would use %block. In that scenario, we cannot delete the '%block = recv_closure' instruction. // This is safe, but conservative. return false; } else if (s.usesZSuper() && getOperation().isArgReceive()) { // If this scope (or any nested scope) has a ZSuperInstr, then the arguments of this // scope could be used by any of those ZSuper instructions. If so, we cannot delete // the argument receive. return false; } else { return true; } } else { return true; } }
instr = instrs[ipc]; ipc++; Operation operation = instr.getOperation(); if (debug) { LOG.info("I: {}", instr); ipc = ((JumpInstr)instr).getJumpTarget().getTargetPC(); } else { ipc = instr.interpretAndGetNewIPC(context, currDynScope, self, temp, ipc); result = instr.interpret(context, currDynScope, self, temp, block); setResult(temp, currDynScope, instr, result); break;
private static boolean usesVariableAsNonClosureArg(Instr i, Variable v) { List<Variable> usedVariables = i.getUsedVariables(); return usedVariables.contains(v) && (!(i instanceof ClosureAcceptingInstr) || usedVariables.indexOf(v) != usedVariables.lastIndexOf(v) || v != ((ClosureAcceptingInstr) i).getClosureArg()); } }
Instr instr = instrs.next(); Instr newInstr = optInstr(s, instr, valueMap, simplificationMap); if (newInstr.isDead()) { instrs.remove(); } else if (newInstr != instr) { Operation iop = instr.getOperation(); if (iop.isCall() && !instr.isDead()) { valueMap = new HashMap<>(); simplificationMap = new HashMap<>();
Instr instr = instrs[ipc]; Operation operation = instr.getOperation(); if (debug) { Interpreter.LOG.info("I: " + ipc + ", R: " + rescuePCs[ipc] + " - " + instr + ">"); break; default: ipc = instr.interpretAndGetNewIPC(context, currDynScope, currScope, self, temp, ipc + 1); break;
@Override public void visit(Instr instr) { printAnsi(INSTR_COLOR, instr.getOperation().toString().toLowerCase()); boolean comma = false; for (Operand o : instr.getOperands()) { if (!comma) printAnsi(INSTR_COLOR, "("); if (comma) print(", "); comma = true; visit(o); } for (Field f : instr.dumpableFields()) { if (!comma) printAnsi(INSTR_COLOR, "("); if (comma) print(", "); comma = true; f.setAccessible(true); printAnsi(FIELD_COLOR, f.getName() + ": "); print(get(f, instr)); } if (comma) printAnsi(INSTR_COLOR, ")"); }
public List<Variable> getUsedVariables() { ArrayList<Variable> vars = new ArrayList<>(); for (Operand operand : getOperands()) { operand.addUsedVariables(vars); } return vars; }
/** * Clone the instruction for use in an inlining context (either when a scope is inlined into * another scope, or when a block has to be cloned because its associated call belongs to * an inlined scope). This requires renaming variables and labels to eliminate naming * conflicts. * * @param inlinerInfo This object manages renaming of variables and labels, handles * args and return values. * @return a new instruction that can be used in the target scope. */ public Instr cloneForInlining(InlinerInfo inlinerInfo) { throw new RuntimeException("cloneForInlining: Not implemented for: " + this.getOperation()); }
if (i.canRaiseException()) makeOutExceptionVariablesLiving(); markAllVariablesLive(problem, i.getUsedVariables());