use of org.mapleir.ir.locals.Local in project maple-ir by LLVM-but-worse.
the class SSAGenPass method splitBlock.
private BasicBlock splitBlock(BasicBlock b, int to) {
/* eg. split the block as follows:
*
* NAME:
* stmt1
* stmt2
* stmt3
* stmt4
* stmt5
* jump L1, L2
* [jump edge to L1]
* [jump edge to L2]
* [exception edges]
*
* split at 3, create a new block (incoming
* immediate), transfer instruction from 0
* to index into new block, create immediate
* edge to old block, clone exception edges,
* redirect pred edges.
*
* 1/9/16: we also need to modify the last
* statement of the pred blocks to
* point to NAME'.
*
* NAME':
* stmt1
* stmt2
* stmt3
* [immediate to NAME]
* NAME:
* stmt4
* stmt5
* jump L1, L2
* [jump edge to L1]
* [jump edge to L2]
* [exception edges]
*/
// split block
ControlFlowGraph cfg = builder.graph;
BasicBlock newBlock = new BasicBlock(cfg, graphSize++, new LabelNode());
b.transferUp(newBlock, to);
cfg.addVertex(newBlock);
// redo ranges
for (ExceptionRange<BasicBlock> er : cfg.getRanges()) {
if (er.containsVertex(b))
er.addVertexBefore(b, newBlock);
}
// redirect b preds into newBlock and remove them.
Set<FlowEdge<BasicBlock>> oldEdges = new HashSet<>(cfg.getReverseEdges(b));
for (FlowEdge<BasicBlock> e : oldEdges) {
BasicBlock p = e.src();
FlowEdge<BasicBlock> c;
if (e instanceof TryCatchEdge) {
// b is ehandler
TryCatchEdge<BasicBlock> tce = (TryCatchEdge<BasicBlock>) e;
if (tce.dst() != tce.erange.getHandler()) {
System.err.println(builder.method.owner + "#" + builder.method.name);
System.err.println(cfg);
System.err.println("Very odd split case. please investigate");
System.err.println("Offending postsplit block: " + b);
System.err.println("Offending newblock: " + newBlock);
System.err.println("Offending edge: " + tce);
System.err.println("Offending erange: " + tce.erange);
}
if (tce.erange.getHandler() != newBlock) {
tce.erange.setHandler(newBlock);
cfg.addEdge(tce.src(), tce.clone(tce.src(), null));
cfg.removeEdge(tce.src(), tce);
}
} else {
c = e.clone(p, newBlock);
cfg.addEdge(p, c);
cfg.removeEdge(p, e);
}
// Fix flow instruction targets
if (!p.isEmpty()) {
Stmt last = p.get(p.size() - 1);
int op = last.getOpcode();
if (e instanceof ConditionalJumpEdge) {
if (op != Opcode.COND_JUMP)
throw new IllegalArgumentException("wrong flow instruction");
ConditionalJumpStmt j = (ConditionalJumpStmt) last;
// assertTarget(last, j.getTrueSuccessor(), b);
if (j.getTrueSuccessor() == b)
j.setTrueSuccessor(newBlock);
} else if (e instanceof UnconditionalJumpEdge) {
if (op != Opcode.UNCOND_JUMP)
throw new IllegalArgumentException("wrong flow instruction");
UnconditionalJumpStmt j = (UnconditionalJumpStmt) last;
assertTarget(j, j.getTarget(), b);
j.setTarget(newBlock);
} else if (e instanceof SwitchEdge) {
if (op != Opcode.SWITCH_JUMP)
throw new IllegalArgumentException("wrong flow instruction.");
SwitchStmt s = (SwitchStmt) last;
for (Entry<Integer, BasicBlock> en : s.getTargets().entrySet()) {
BasicBlock t = en.getValue();
if (t == b) {
en.setValue(newBlock);
}
}
}
}
}
if (!checkCloneHandler(newBlock)) {
System.err.println(cfg);
System.err.println(newBlock.getDisplayName());
System.err.println(b.getDisplayName());
throw new IllegalStateException("the new block should always need a handler..?");
}
// clone exception edges
for (FlowEdge<BasicBlock> e : cfg.getEdges(b)) {
if (e.getType() == FlowEdges.TRYCATCH) {
// second param is discarded (?)
TryCatchEdge<BasicBlock> c = ((TryCatchEdge<BasicBlock>) e).clone(newBlock, null);
cfg.addEdge(newBlock, c);
}
}
// create immediate to newBlock
cfg.addEdge(newBlock, new ImmediateEdge<>(newBlock, b));
// update assigns
Set<Local> assignedLocals = new HashSet<>();
for (Stmt stmt : b) if (stmt.getOpcode() == Opcode.LOCAL_STORE)
assignedLocals.add(((CopyVarStmt) stmt).getVariable().getLocal());
for (Stmt stmt : newBlock) {
if (stmt.getOpcode() == Opcode.LOCAL_STORE) {
Local copyLocal = ((CopyVarStmt) stmt).getVariable().getLocal();
Set<BasicBlock> set = builder.assigns.get(copyLocal);
set.add(newBlock);
if (!assignedLocals.contains(copyLocal))
set.remove(b);
}
}
return newBlock;
}
use of org.mapleir.ir.locals.Local in project maple-ir by LLVM-but-worse.
the class SSAGenPass method splitRanges.
private void splitRanges() {
// produce cleaner cfg
List<BasicBlock> order = new ArrayList<>(builder.graph.vertices());
NullPermeableHashMap<BasicBlock, Set<Local>> splits = new NullPermeableHashMap<>(SetCreator.getInstance());
for (ExceptionRange<BasicBlock> er : builder.graph.getRanges()) {
BasicBlock h = er.getHandler();
handlers.add(h);
Set<Local> ls = new HashSet<>(liveness.in(h));
for (BasicBlock b : er.get()) {
splits.getNonNull(b).addAll(ls);
}
}
for (Entry<BasicBlock, Set<Local>> e : splits.entrySet()) {
BasicBlock b = e.getKey();
Set<Local> ls = e.getValue();
ArrayList<Stmt> stmtsCopy = new ArrayList<>(b);
int i = 0;
boolean checkSplit = false;
for (int i1 = 0; i1 < stmtsCopy.size(); i1++) {
Stmt stmt = stmtsCopy.get(i1);
if (b.size() == i)
throw new IllegalStateException("s");
if (checkSplit && stmt.getOpcode() == Opcode.LOCAL_STORE) {
CopyVarStmt copy = (CopyVarStmt) stmt;
VarExpr v = copy.getVariable();
if (ls.contains(v.getLocal())) {
BasicBlock n = splitBlock(b, i);
order.add(order.indexOf(b), n);
i = 0;
checkSplit = false;
}
} else {
// do not split if we have only seen simple or synthetic copies (catch copy is synthetic)
if (stmt instanceof CopyVarStmt) {
CopyVarStmt copy = (CopyVarStmt) stmt;
int opc = copy.getExpression().getOpcode();
if (!copy.isSynthetic() && opc != Opcode.LOCAL_LOAD && opc != Opcode.CATCH) {
checkSplit = true;
}
} else {
checkSplit = true;
}
}
i++;
}
}
builder.graph.naturalise(order);
int po = 0;
for (BasicBlock b : SimpleDfs.preorder(builder.graph, builder.graph.getEntries().iterator().next())) {
insertion.put(b, 0);
process.put(b, 0);
preorder.put(b, po++);
}
}
use of org.mapleir.ir.locals.Local 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.locals.Local in project maple-ir by LLVM-but-worse.
the class SSAGenPass method unstackDefs.
private void unstackDefs(BasicBlock b) {
for (Stmt s : b) {
if (s.getOpcode() == Opcode.PHI_STORE || s.getOpcode() == Opcode.LOCAL_STORE) {
AbstractCopyStmt cvs = (AbstractCopyStmt) s;
Local l = cvs.getVariable().getLocal();
l = builder.graph.getLocals().get(l.getIndex(), l.isStack());
stacks.get(l).pop();
}
}
}
use of org.mapleir.ir.locals.Local in project maple-ir by LLVM-but-worse.
the class SSAGenPass method generate.
private VersionedLocal generate(AbstractCopyStmt copy) {
VarExpr v = copy.getVariable();
Local oldLocal = v.getLocal();
int index = oldLocal.getIndex();
boolean isStack = oldLocal.isStack();
LocalsPool handler = builder.graph.getLocals();
Local l = handler.get(index, isStack);
int subscript = counters.get(l);
stacks.get(l).push(subscript);
counters.put(l, subscript + 1);
VersionedLocal ssaL = handler.get(index, subscript, isStack);
if (OPTIMISE) {
makeValue(copy, ssaL);
}
v.setLocal(ssaL);
pool.defs.put(ssaL, copy);
types.put(ssaL, copy.getExpression().getType());
pool.uses.put(ssaL, new HashSet<>());
return ssaL;
}
Aggregations