use of org.mapleir.ir.cfg.builder.ssaopt.LatestValue in project maple-ir by LLVM-but-worse.
the class SSAGenPass method aggregateInitialisers.
private void aggregateInitialisers() {
for (BasicBlock b : builder.graph.vertices()) {
for (Stmt stmt : new ArrayList<>(b)) {
if (stmt.getOpcode() == Opcode.POP) {
PopStmt pop = (PopStmt) stmt;
Expr expr = pop.getExpression();
if (expr.getOpcode() == Opcode.INVOKE) {
InvocationExpr invoke = (InvocationExpr) expr;
if (invoke.getCallType() == InvocationExpr.CallType.SPECIAL && invoke.getName().equals("<init>")) {
Expr inst = invoke.getPhysicalReceiver();
if (inst.getOpcode() == Opcode.LOCAL_LOAD) {
VarExpr var = (VarExpr) inst;
VersionedLocal local = (VersionedLocal) var.getLocal();
AbstractCopyStmt def = pool.defs.get(local);
Expr rhs = def.getExpression();
if (rhs.getOpcode() == Opcode.ALLOC_OBJ) {
// replace pop(x.<init>()) with x := new Klass();
// remove x := new Klass;
// here we are assuming that the new object
// can't be used until it is initialised.
Expr[] args = invoke.getParameterExprs();
// we want to reuse the exprs, so free it first.
pop.deleteAt(0);
Expr[] newArgs = Arrays.copyOf(args, args.length);
for (int i = args.length - 1; i >= 0; i--) {
args[i].unlink();
}
// remove the old def
def.delete();
int index = b.indexOf(pop);
// add a copy statement before the pop (x = newExpr)
InitialisedObjectExpr newExpr = new InitialisedObjectExpr(invoke.getOwner(), invoke.getDesc(), newArgs);
CopyVarStmt newCvs = new CopyVarStmt(var, newExpr);
pool.defs.put(local, newCvs);
pool.uses.get(local).remove(var);
b.add(index, newCvs);
// remove the pop statement
b.remove(pop);
// update the latestval constraints
LatestValue lval = latest.get(local);
if (lval.hasConstraints()) {
/* need to check this out (shouldn't happen) */
System.out.println("Constraints:");
for (Constraint c : lval.getConstraints()) {
System.out.println(" " + c);
}
throw new IllegalStateException(lval.toString());
} else {
lval.makeConstraints(newExpr);
}
}
} else if (inst.getOpcode() == Opcode.ALLOC_OBJ) {
// replace pop(new Klass.<init>(args)) with pop(new Klass(args))
// UninitialisedObjectExpr obj = (UninitialisedObjectExpr) inst;
Expr[] args = invoke.getParameterExprs();
// we want to reuse the exprs, so free it first.
invoke.unlink();
for (Expr e : args) {
e.unlink();
}
Expr[] newArgs = Arrays.copyOf(args, args.length);
InitialisedObjectExpr newExpr = new InitialisedObjectExpr(invoke.getOwner(), invoke.getDesc(), newArgs);
// replace pop contents
// no changes to defs or uses
pop.setExpression(newExpr);
} else {
System.err.println(b);
System.err.println("Stmt: " + stmt.getDisplayName() + ". " + stmt);
System.err.println("Inst: " + inst);
System.err.println(builder.graph);
throw new RuntimeException("interesting1 " + inst.getClass());
}
}
}
}
}
}
}
use of org.mapleir.ir.cfg.builder.ssaopt.LatestValue in project maple-ir by LLVM-but-worse.
the class SSAGenPass method translateStmt.
private void translateStmt(VarExpr var, boolean resolve, boolean isPhi) {
/* Here we only remap local variable loads
* on the right hand side of a statement or
* expression. This means that if we are able
* to simply replace a local load which has
* a constant or deferred local value.
*
* However, if the value of the local is
* a complex expression we need to check that
* we can propagate it before we do.
*
* Since we will only replace a single
* local load in the original expression,
* only 1 variable is killed. However, there
* may be local load expressions in the
* propagated expression. To account for this,
* these local loads must be counted as new
* uses (except for when an expression is
* moved instead of copied to a use site).*/
Local l = var.getLocal();
VersionedLocal ssaL;
if (resolve) {
ssaL = latest(l.getIndex(), l.isStack());
} else {
ssaL = (VersionedLocal) l;
}
pool.uses.get(ssaL).add(var);
VersionedLocal newL = ssaL;
boolean exists = true;
if (OPTIMISE) {
if (latest.containsKey(ssaL)) {
/* Try to propagate a simple copy local
* to its use site. It is possible that
* a non simple copy (including phis)
* will not have a mapping. In this case
* they will not have an updated target.*/
LatestValue value = latest.get(ssaL);
boolean unpredictable = value.getType() == LatestValue.PARAM || value.getType() == LatestValue.PHI;
if (unpredictable && ssaL != value.getSuggestedValue()) {
VersionedLocal vl = (VersionedLocal) value.getSuggestedValue();
if (shouldPropagate(ssaL, vl)) {
newL = vl;
}
} else if (!isPhi && !unpredictable) {
Expr e = null;
AbstractCopyStmt def = pool.defs.get(ssaL);
Expr rval = (Expr) value.getSuggestedValue();
if (ConstraintUtil.isUncopyable(rval)) {
/* A variable might have a value
* that is uncopyable such as an
* invoke or allocation call.
*
* There are two ways this may happen:
* x = call();
* or
* x = call();
* y = x;
*
* we defer optimising the first
* case till the end.
*
* in the second case, we can
* propagate the source var (x)
* in place of the target (y). */
newL = tryDefer(value, ssaL);
} else {
AbstractCopyStmt from = def;
if (value.getSource() != null) {
from = pool.defs.get(value.getSource());
}
if (!value.hasConstraints() || (canTransferHandlers(def.getBlock(), var.getBlock()) && value.canPropagate(from, var.getRootParent(), var, false))) {
if (shouldCopy(rval)) {
e = rval;
} else {
newL = tryDefer(value, ssaL);
}
} else if (value.getRealValue() instanceof VersionedLocal) {
VersionedLocal realVal = (VersionedLocal) value.getRealValue();
if (shouldPropagate(ssaL, realVal)) {
newL = realVal;
} else {
shadowed.getNonNull(ssaL).add(realVal);
shadowed.getNonNull(realVal).add(ssaL);
}
}
}
if (e != null) {
// System.out.println("=====");
// System.out.println(" ssaL: " + ssaL);
// System.out.println(" bpar: " + var.getParent());
CodeUnit parent = var.getParent();
int idx = parent.indexOf(var);
parent.overwrite(e = e.copy(), idx);
// System.out.println(" def: " + def);
// System.out.println(" idx: " + idx);
// System.out.println(" val: " + value);
// System.out.println(" apar: " + parent);
// System.out.println(" e: " + e);
/* Remove the use of the var before
* we translate the children of the
* newly propagated expression.*/
pool.uses.get(ssaL).remove(var);
// System.out.println(" uses: " + pool.uses.get(ssaL));
/* Account for the new pool.uses.*/
collectUses(e);
/* Finally see if we can reduce
* this statement further.*/
translate(e, false, isPhi);
exists = false;
}
} else {
newL = ssaL;
}
} else {
throw new IllegalStateException("No (self) ancestors: " + l + " -> " + ssaL);
}
}
if (exists) {
if (OPTIMISE) {
// System.out.println("replace: " + ssaL + " with " + newL);
if (ssaL != newL) {
// System.out.println(ssaL + " --> " + newL);
pool.uses.get(ssaL).remove(var);
pool.uses.get(newL).add(var);
}
}
/* If the expression still exists, update
* or set both variable and type information.*/
var.setLocal(newL);
Type type = types.get(ssaL);
if (type == null) {
throw new IllegalStateException(var + ", " + ssaL + ", t=null");
} else {
var.setType(type);
}
}
}
use of org.mapleir.ir.cfg.builder.ssaopt.LatestValue in project maple-ir by LLVM-but-worse.
the class SSAGenPass method processDeferredTranslations.
private int processDeferredTranslations() {
int i = 0;
Iterator<Entry<VersionedLocal, Set<VarExpr>>> it = pool.uses.entrySet().iterator();
while (it.hasNext()) {
Entry<VersionedLocal, Set<VarExpr>> e = it.next();
VersionedLocal vl = e.getKey();
if (deferred.contains(vl) || vl.isStack()) {
Set<VarExpr> useSet = e.getValue();
AbstractCopyStmt def = pool.defs.get(vl);
if (def != null && useSet.size() == 1) {
/* In this case, the only place that the value
* of this assignment will be used is at the use site.
* Since that value can not be spread until this one
* is, we can propagate it.*/
if (def.getOpcode() != Opcode.PHI_STORE) {
VarExpr use = useSet.iterator().next();
LatestValue val = latest.get(vl);
// System.out.println();
// System.out.println();
// System.out.println(def);
// System.out.println(use);
/* phi var*/
Expr rhs = def.getExpression();
if (use.getParent() != null) {
if (canTransferHandlers(def.getBlock(), use.getBlock()) && val.canPropagate(def, use.getRootParent(), use, false)) {
CodeUnit parent = use.getParent();
if (rhs.getOpcode() == Opcode.CATCH) {
// CodeUnit rp = use.getRootParent();
// System.out.println("DENIED NIGGA");
// System.out.println("replace " + vl + " with " + rhs);
// System.out.println(" in " + parent);
// System.out.println(" kill def: " + def);
// System.out.println();
deferred.remove(vl);
continue;
// check to see if we're moving it to the
// first expression in the block, if we aren't
// then deny, otherwise we can get rid of the local.
// if(rp.getBlock().indexOf(rp) != 1 || rp.enumerateExecutionOrder().indexOf(use) != 0) {
//
// }
}
rhs.unlink();
def.delete();
pool.defs.remove(vl);
useSet.clear();
parent.overwrite(rhs, parent.indexOf(use));
i++;
it.remove();
}
}
}
}
}
}
return i;
}
use of org.mapleir.ir.cfg.builder.ssaopt.LatestValue in project maple-ir by LLVM-but-worse.
the class SSAGenPass method makeValue.
private void makeValue(AbstractCopyStmt copy, VersionedLocal ssaL) {
/* Attempts to find the 'value' of a local.
* The value can be the following types:
* param - assigned by caller method
* phi - set by a phi node
* const - compiletime constant
* var - runtime computed
*
* when a copy x = y, is visited,
* if y is a var, x inherits
* the value and value type.
* */
Expr e = copy.getExpression();
int opcode = e.getOpcode();
if (opcode == Opcode.LOCAL_LOAD) {
if (copy.isSynthetic()) {
/* equals itself (pure value).*/
LatestValue value = new LatestValue(builder.graph, LatestValue.PARAM, ssaL, null);
latest.put(ssaL, value);
} else {
/* i.e. x = y, where x and y are both variables.
*
* It is expected that the local uses of the copy
* (rhs) are visited before the target is.
*/
VarExpr rhs = (VarExpr) e;
VersionedLocal rhsL = (VersionedLocal) rhs.getLocal();
/* the rhsL must have been visited already
* and the lhsL must not have been.*/
if (!latest.containsKey(ssaL)) {
if (latest.containsKey(rhsL)) {
LatestValue anc = latest.get(rhsL);
// TODO: maybe advance the src local if we
// can validate an expr propagation to the
// new copy dst.
LatestValue value = new LatestValue(builder.graph, anc.getType(), rhsL, anc.getSuggestedValue(), anc.getSource());
value.importConstraints(anc);
latest.put(ssaL, value);
} else {
throw new IllegalStateException("Non anc parent: " + ssaL + " = " + rhsL + " (def: " + pool.defs.get(rhsL) + ")");
}
} else {
throw new IllegalStateException("Revisit def " + ssaL + " ( = " + rhsL + ")");
}
}
} else {
LatestValue value;
if (opcode == Opcode.CONST_LOAD) {
ConstantExpr ce = (ConstantExpr) e;
value = new LatestValue(builder.graph, LatestValue.CONST, ce, null);
} else if ((opcode & Opcode.CLASS_PHI) == Opcode.CLASS_PHI) {
value = new LatestValue(builder.graph, LatestValue.PHI, ssaL, null);
} else {
if (e.getOpcode() == Opcode.LOCAL_LOAD) {
throw new RuntimeException(copy + " " + e);
}
value = new LatestValue(builder.graph, LatestValue.VAR, e, ssaL);
value.makeConstraints(e);
}
latest.put(ssaL, value);
}
// System.out.println("made val " + ssaL + " -> " + latest.get(ssaL));
}
Aggregations