Skip to content

Commit

Permalink
IR: Humble start to compiler passes with deps
Browse files Browse the repository at this point in the history
  • Loading branch information
enebo committed Mar 7, 2012
1 parent 133d7bf commit 0d552ae
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 40 deletions.
Expand Up @@ -5,7 +5,7 @@
import org.jruby.compiler.ir.dataflow.analyses.BindingLoadPlacementProblem;
import org.jruby.compiler.ir.dataflow.analyses.BindingStorePlacementProblem;

public class AddBindingInstructions implements CompilerPass {
public class AddBindingInstructions extends CompilerPass {
public static String[] NAMES = new String[] { "add_binding", "add_binding_instructions" };

public String getLabel() {
Expand All @@ -16,8 +16,8 @@ public boolean isPreOrder() {
return false;
}

public void run(IRScope s) {
if (!(s instanceof IRMethod)) return;
public Object execute(IRScope s, Object... data) {
if (!(s instanceof IRMethod)) return null;

IRMethod m = (IRMethod) s;
// if (m.requiresBinding()) {
Expand All @@ -31,5 +31,7 @@ public void run(IRScope s) {
frp.compute_MOP_Solution();
frp.addLoads();
// }

return null;
}
}
11 changes: 8 additions & 3 deletions src/org/jruby/compiler/ir/compiler_pass/CFGBuilder.java
Expand Up @@ -2,7 +2,7 @@

import org.jruby.compiler.ir.IRScope;

public class CFGBuilder implements CompilerPass {
public class CFGBuilder extends CompilerPass {
public static String[] NAMES = new String[] { "cfg", "cfg_builder" };

public String getLabel() {
Expand All @@ -12,7 +12,12 @@ public boolean isPreOrder() {
return true;
}

public void run(IRScope scope) {
scope.buildCFG();
@Override
public Object previouslyRun(IRScope scope) {
return scope.getCFG();
}

public Object execute(IRScope scope, Object... data) {
return scope.buildCFG();
}
}
6 changes: 4 additions & 2 deletions src/org/jruby/compiler/ir/compiler_pass/CallSplitter.java
Expand Up @@ -2,7 +2,7 @@

import org.jruby.compiler.ir.IRScope;

public class CallSplitter implements CompilerPass {
public class CallSplitter extends CompilerPass {
public static String[] NAMES = new String[] {"split_calls"};

public String getLabel() {
Expand All @@ -13,7 +13,9 @@ public boolean isPreOrder() {
return true;
}

public void run(IRScope scope) {
public Object execute(IRScope scope, Object... data) {
scope.splitCalls();

return null;
}
}
94 changes: 90 additions & 4 deletions src/org/jruby/compiler/ir/compiler_pass/CompilerPass.java
@@ -1,13 +1,99 @@
package org.jruby.compiler.ir.compiler_pass;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jruby.compiler.ir.IRScope;
import org.jruby.compiler.ir.Tuple;

public interface CompilerPass {
public String getLabel();
//FIXME: Names are not so great
/**
*
* @author enebo
*/
public abstract class CompilerPass {
public List<Tuple<Class<CompilerPass>, DependencyType>> NO_DEPENDENCIES = new ArrayList<Tuple<Class<CompilerPass>, DependencyType>>();

public enum DependencyType {
RETRIEVE, // If the pass has been previously run just return that
RERUN // Unconditionally re-run dependent pass
}
public abstract String getLabel();

// Should we run this pass on the current scope before running it on nested scopes?
public boolean isPreOrder();
public abstract boolean isPreOrder();

/**
* Meat of an individual pass. run will call this after dependency
* resolution.
* @param scope is the scope to run this pass on
* @param dependencyData is the data supplied to this pass to use to execute the pass
*/
public abstract Object execute(IRScope scope, Object... dependencyData);

public List<Tuple<Class<CompilerPass>, DependencyType>> getDependencies() {
return NO_DEPENDENCIES;
}

/**
* If this pass has been previous run then return the data from that last run.
* @returns data or null if it needs to be run
*/
public Object previouslyRun(IRScope scope) {
return null;
}

// Run the pass on the passed in scope!
public void run(IRScope s);
public Object run(IRScope scope) {
// Make sure all dependencies are satisfied
List<Tuple<Class<CompilerPass>, DependencyType>> dependencies = getDependencies();
Object data[] = new Object[dependencies.size()];

for (int i = 0; i < data.length; i++) {
Tuple<Class<CompilerPass>, DependencyType> dependency = dependencies.get(i);

switch (dependency.b) { // type of dependency
case RETRIEVE:
data[i] = makeSureDependencyHasRunOnce(dependency.a, scope);
case RERUN:
data[i] = executeDependency(dependency.a, scope);
}
}

// System.out.println("Executing Pass: " + getLabel());
return execute(scope, data);
}

private Object makeSureDependencyHasRunOnce(Class<CompilerPass> passClass, IRScope scope) {
CompilerPass pass = createPassInstance(passClass);
Object data = pass.previouslyRun(scope);

return data == null ? pass.run(scope) : data;
}

private Object executeDependency(Class<CompilerPass> passClass, IRScope scope) {
return createPassInstance(passClass).run(scope);
}

private CompilerPass createPassInstance(Class<CompilerPass> passClass) {
try {
return (CompilerPass) passClass.getDeclaredConstructor().newInstance();
} catch (InstantiationException ex) {
Logger.getLogger(CompilerPass.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(CompilerPass.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalArgumentException ex) {
Logger.getLogger(CompilerPass.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(CompilerPass.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchMethodException ex) {
Logger.getLogger(CompilerPass.class.getName()).log(Level.SEVERE, null, ex);
} catch (SecurityException ex) {
Logger.getLogger(CompilerPass.class.getName()).log(Level.SEVERE, null, ex);
}

return null;
}
}
Expand Up @@ -10,7 +10,7 @@
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;

public class DominatorTreeBuilder implements CompilerPass {
public class DominatorTreeBuilder extends CompilerPass {
private static String[] NAMES = new String[] {"build_dominator", "dominator"};
private static final Logger LOG = LoggerFactory.getLogger("DominatorTreeBuilder");

Expand All @@ -22,12 +22,14 @@ public boolean isPreOrder() {
return false;
}

public void run(IRScope scope) {
public Object execute(IRScope scope, Object... data) {
try {
scope.buildDominatorTree(this);
} catch (Exception e) {
LOG.debug("Caught exception building dom tree for {}", scope.cfg());
}

return null;
}

public void buildDominatorTree(CFG cfg, LinkedList<BasicBlock> postOrderList, int maxNodeId) {
Expand Down
6 changes: 4 additions & 2 deletions src/org/jruby/compiler/ir/compiler_pass/IRPrinter.java
Expand Up @@ -5,7 +5,7 @@
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;

public class IRPrinter implements CompilerPass {
public class IRPrinter extends CompilerPass {
public static String[] NAMES = new String[] { "printer", "p" };

private static final Logger LOG = LoggerFactory.getLogger("IR_Printer");
Expand All @@ -19,7 +19,7 @@ public boolean isPreOrder() {
return true;
}

public void run(IRScope scope) {
public Object execute(IRScope scope, Object... data) {
LOG.info("----------------------------------------");
LOG.info(scope.toString());

Expand All @@ -32,5 +32,7 @@ public void run(IRScope scope) {
LOG.info("\n instrs:\n" + scope.toStringInstrs());
LOG.info("\n live variables:\n" + scope.toStringVariables());
}

return null;
}
}
12 changes: 7 additions & 5 deletions src/org/jruby/compiler/ir/compiler_pass/InlineTest.java
Expand Up @@ -13,7 +13,7 @@
import org.jruby.util.log.Logger;
import org.jruby.util.log.LoggerFactory;

public class InlineTest implements CompilerPass {
public class InlineTest extends CompilerPass {
public static String[] NAMES = new String[] { "inline_test" };

private static final Logger LOG = LoggerFactory.getLogger("InlineTest");
Expand Down Expand Up @@ -49,15 +49,15 @@ private IRScope getIRMethod(IRScope s) {
return ((InterpretedIRMethod) realMethod).getIRMethod();
}

public void run(IRScope s) {
if (!(s instanceof IRMethod)) return;
public Object execute(IRScope s, Object... data) {
if (!(s instanceof IRMethod)) return null;

IRScope mi = getIRMethod(s);

// Cannot inline something not IR
// FIXME: Add logging indicating aborted inline attempt
// just a test .. dont bother if we dont have a match!
if (mi == null) return;
if (mi == null) return null;

IRMethod method = ((IRMethod) s);
CFG cfg = method.cfg();
Expand All @@ -71,11 +71,13 @@ public void run(IRScope s) {
method.inlineMethod(mi, null, 0, b, call);
// Just inline once per scope -- this is a test after all!
// Because, the surrounding iterators will break with a concurrent modification exception if we proceed!
return;
return null;
}
}
}
}

return true;
}

}
6 changes: 4 additions & 2 deletions src/org/jruby/compiler/ir/compiler_pass/LinearizeCFG.java
Expand Up @@ -2,7 +2,7 @@

import org.jruby.compiler.ir.IRScope;

public class LinearizeCFG implements CompilerPass {
public class LinearizeCFG extends CompilerPass {
public static String[] NAMES = new String[] { "linearize", "linearize_cfg" };

public String getLabel() {
Expand All @@ -13,7 +13,9 @@ public boolean isPreOrder() {
return true;
}

public void run(IRScope scope) {
public Object execute(IRScope scope, Object... data) {
scope.buildLinearization();

return null;
}
}
Expand Up @@ -3,7 +3,7 @@
import org.jruby.compiler.ir.IRScope;
import org.jruby.compiler.ir.dataflow.analyses.LiveVariablesProblem;

public class LiveVariableAnalysis implements CompilerPass {
public class LiveVariableAnalysis extends CompilerPass {
public static String[] NAMES = new String[] { "lva", "LVA", "live_variable_analysis" };

public String getLabel() {
Expand All @@ -14,10 +14,17 @@ public boolean isPreOrder() {
return false;
}

public void run(IRScope scope) {
@Override
public Object previouslyRun(IRScope scope) {
return scope.getDataFlowSolution(LiveVariablesProblem.NAME);
}

public Object execute(IRScope scope, Object... data) {
LiveVariablesProblem lvp = new LiveVariablesProblem(scope);
lvp.compute_MOP_Solution();

scope.setDataFlowSolution(lvp.getName(), lvp);

return lvp;
}
}
@@ -1,13 +1,19 @@
package org.jruby.compiler.ir.compiler_pass.opts;

import java.util.ArrayList;
import java.util.List;
import org.jruby.compiler.ir.IRClosure;
import org.jruby.compiler.ir.IRScope;
import org.jruby.compiler.ir.Tuple;
import org.jruby.compiler.ir.compiler_pass.CompilerPass;
import org.jruby.compiler.ir.dataflow.DataFlowConstants;
import org.jruby.compiler.ir.compiler_pass.LiveVariableAnalysis;
import org.jruby.compiler.ir.dataflow.analyses.LiveVariablesProblem;

public class DeadCodeElimination implements CompilerPass {
public class DeadCodeElimination extends CompilerPass {
public static String[] NAMES = new String[] {"dce", "DCE", "dead_code"};
public static List<Tuple<Class<CompilerPass>, DependencyType>> DEPENDENCIES = new ArrayList<Tuple<Class<CompilerPass>, DependencyType>>() {{
add(new Tuple(LiveVariableAnalysis.class, CompilerPass.DependencyType.RETRIEVE));
}};

public String getLabel() {
return "Dead Code Elimination";
Expand All @@ -17,20 +23,19 @@ public boolean isPreOrder() {
return false;
}

public void run(IRScope scope) {
LiveVariablesProblem lvp = (LiveVariablesProblem) scope.getDataFlowSolution(DataFlowConstants.LVP_NAME);

if (lvp == null) {
lvp = new LiveVariablesProblem(scope);
lvp.compute_MOP_Solution();
scope.setDataFlowSolution(lvp.getName(), lvp);
}

lvp.markDeadInstructions();
@Override
public List<Tuple<Class<CompilerPass>, DependencyType>> getDependencies() {
return DEPENDENCIES;
}

@Override
public Object execute(IRScope scope, Object... data) {
((LiveVariablesProblem) data[0]).markDeadInstructions();

// Run on nested closures!
for (IRClosure cl: scope.getClosures()) {
run(cl);
}

return true;
}
}
Expand Up @@ -19,7 +19,7 @@
import org.jruby.compiler.ir.representations.BasicBlock;
import org.jruby.compiler.ir.representations.CFG;

public class LocalOptimizationPass implements CompilerPass {
public class LocalOptimizationPass extends CompilerPass {
public static String[] NAMES = new String[] { "lo", "LO", "local_optimization" };

public String getLabel() {
Expand All @@ -31,7 +31,7 @@ public boolean isPreOrder() {
return false;
}

public void run(IRScope s) {
public Object execute(IRScope s, Object... data) {
// Run this pass on nested closures first!
// This let us compute execute scope flags for a method based on what all nested closures do
for (IRClosure c: s.getClosures()) {
Expand All @@ -49,6 +49,8 @@ public void run(IRScope s) {
}
// Only after running local opts, compute various execution scope flags
s.computeScopeFlags();

return null;
}

private static void allocVar(Operand oldVar, IRScope s, List<TemporaryVariable> freeVarsList, Map<Operand, Operand> newVarMap) {
Expand Down

0 comments on commit 0d552ae

Please sign in to comment.