changeset 19242:51b6ea17aebe

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Tue, 10 Feb 2015 20:44:08 +0100
parents 30c8d110b281 5ff79efdd040
children 006e321d592b 1b51524ff1c9
files graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java
diffstat 43 files changed, 1855 insertions(+), 1199 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Tue Feb 10 20:44:08 2015 +0100
@@ -28,10 +28,10 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.alloc.*;
 import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
@@ -41,10 +41,9 @@
 import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.alloc.lsra.*;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.stackslotalloc.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.phases.*;
 
 public class BaselineBytecodeParser extends AbstractBytecodeParser<Value, BaselineFrameStateBuilder> implements BytecodeParserTool {
@@ -80,11 +79,7 @@
         this.setCurrentFrameState(frameState);
     }
 
-    public LIRGenerationResult getLIRGenerationResult() {
-        return lirGenRes;
-    }
-
-    protected void build() {
+    protected LIRGenerationResult build() {
         if (PrintProfilingInformation.getValue()) {
             TTY.println("Profiling info for " + method.format("%H.%n(%p)"));
             TTY.println(MetaUtil.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), "  "));
@@ -123,8 +118,8 @@
             BaselineControlFlowGraph cfg = BaselineControlFlowGraph.compute(blockMap);
 
             // create the LIR
-            List<? extends AbstractBlock<?>> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.getBlocks().length, blockMap.startBlock);
-            List<? extends AbstractBlock<?>> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blockMap.getBlocks().length, blockMap.startBlock);
+            List<BciBlock> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.getBlocks().length, blockMap.startBlock);
+            List<BciBlock> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blockMap.getBlocks().length, blockMap.startBlock);
             LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder);
 
             RegisterConfig registerConfig = null;
@@ -150,21 +145,11 @@
                     throw Debug.handle(e);
                 }
 
-                try (Scope s = Debug.scope("Allocator")) {
-                    if (backend.shouldAllocateRegisters()) {
-                        LinearScan.allocate(target, lirGenRes);
-                    }
-                }
-                try (Scope s1 = Debug.scope("BuildFrameMap")) {
-                    // build frame map
-                    lirGenRes.buildFrameMap(new SimpleStackSlotAllocator());
-                    Debug.dump(lir, "After FrameMap building");
-                }
-                try (Scope s1 = Debug.scope("MarkLocations")) {
-                    if (backend.shouldAllocateRegisters()) {
-                        // currently we mark locations only if we do register allocation
-                        LocationMarker.markLocations(lir, lirGenRes.getFrameMap());
-                    }
+                try (Scope s = Debug.scope("LowLevelTier", this)) {
+                    LowLevelSuites lowLevelSuites = backend.getSuites().getDefaultLowLevelSuites();
+                    return GraalCompiler.emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, gen, lowLevelSuites);
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
                 }
 
             } catch (Throwable e) {
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Tue Feb 10 20:44:08 2015 +0100
@@ -26,19 +26,18 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.bytecode.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 
 /**
  * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph.
  */
-@SuppressWarnings("all")
 public class BaselineCompiler {
 
     public BaselineCompiler(GraphBuilderConfiguration graphBuilderConfig, MetaAccessProvider metaAccess) {
@@ -50,8 +49,8 @@
 
     private final GraphBuilderConfiguration graphBuilderConfig;
 
-    public CompilationResult generate(ResolvedJavaMethod method, int entryBCI, Backend backend, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner,
-                    CompilationResultBuilderFactory factory, OptimisticOptimizations optimisticOpts, Replacements replacements) {
+    public CompilationResult generate(ResolvedJavaMethod method, @SuppressWarnings("unused") int entryBCI, Backend backend, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner,
+                    CompilationResultBuilderFactory factory, OptimisticOptimizations optimisticOpts, @SuppressWarnings("unused") Replacements replacements) {
         assert method.getCode() != null : "method must contain bytecodes: " + method;
         TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
 
@@ -60,15 +59,16 @@
         BaselineBytecodeParser parser = new BaselineBytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, frameState, backend);
 
         // build blocks and LIR instructions
+        final LIRGenerationResult res;
         try {
-            parser.build();
+            res = parser.build();
         } finally {
             filter.remove();
         }
 
         // emitCode
         Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
-        GraalCompiler.emitCode(backend, assumptions, parser.getLIRGenerationResult(), compilationResult, installedCodeOwner, factory);
+        GraalCompiler.emitCode(backend, assumptions, res, compilationResult, installedCodeOwner, factory);
 
         return compilationResult;
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Tue Feb 10 20:44:08 2015 +0100
@@ -50,6 +50,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
@@ -89,6 +90,7 @@
     private final Providers providers;
     private final Backend backend;
     private final DerivedOptionValue<Suites> suites;
+    private final DerivedOptionValue<LowLevelSuites> lowLevelSuites;
 
     /**
      * Can be overridden by unit tests to verify properties of the graph.
@@ -164,10 +166,16 @@
         return ret;
     }
 
+    protected LowLevelSuites createLowLevelSuites() {
+        LowLevelSuites ret = backend.getSuites().createLowLevelSuites();
+        return ret;
+    }
+
     public GraalCompilerTest() {
         this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
         this.providers = getBackend().getProviders();
         this.suites = new DerivedOptionValue<>(this::createSuites);
+        this.lowLevelSuites = new DerivedOptionValue<>(this::createLowLevelSuites);
         installSubstitutions();
     }
 
@@ -188,6 +196,7 @@
         }
         this.providers = backend.getProviders();
         this.suites = new DerivedOptionValue<>(this::createSuites);
+        this.lowLevelSuites = new DerivedOptionValue<>(this::createLowLevelSuites);
         installSubstitutions();
     }
 
@@ -355,6 +364,10 @@
         return suites.getValue();
     }
 
+    protected LowLevelSuites getLowLevelSuites() {
+        return lowLevelSuites.getValue();
+    }
+
     protected Providers getProviders() {
         return providers;
     }
@@ -741,7 +754,8 @@
         lastCompiledGraph = graphToCompile;
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graphToCompile.method(), false);
         Request<CompilationResult> request = new Request<>(graphToCompile, cc, installedCodeOwner, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
-                        OptimisticOptimizations.ALL, getProfilingInfo(graphToCompile), getSpeculationLog(), getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        OptimisticOptimizations.ALL, getProfilingInfo(graphToCompile), getSpeculationLog(), getSuites(), getLowLevelSuites(), new CompilationResult(),
+                        CompilationResultBuilderFactory.Default);
         return GraalCompiler.compile(request);
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Tue Feb 10 20:44:08 2015 +0100
@@ -61,7 +61,7 @@
         final StructuredGraph graph = parseEager(method);
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
         final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
-                        OptimisticOptimizations.ALL, getProfilingInfo(graph), null, getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        OptimisticOptimizations.ALL, getProfilingInfo(graph), null, getSuites(), getLowLevelSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
             if (sp instanceof Call) {
@@ -84,7 +84,7 @@
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
         PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault());
         final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL,
-                        getProfilingInfo(graph), getSpeculationLog(), getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        getProfilingInfo(graph), getSpeculationLog(), getSuites(), getLowLevelSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
         int lineSPs = 0;
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java	Tue Feb 10 20:44:08 2015 +0100
@@ -58,7 +58,7 @@
         }
 
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
-        LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), getBackend().getTarget(), schedule, graph, null, cc, null);
+        LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), getBackend().getTarget(), schedule, graph, null, cc, null, getLowLevelSuites());
         return lirGen;
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java	Tue Feb 10 20:44:08 2015 +0100
@@ -35,6 +35,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
@@ -94,6 +95,11 @@
             Suites suites = backend.getSuites().createSuites();
 
             /*
+             * The low-level phases that are applied to the low-level representation.
+             */
+            LowLevelSuites lowLevelSuites = backend.getSuites().createLowLevelSuites();
+
+            /*
              * The calling convention for the machine code. You should have a very good reason
              * before you switch to a different calling convention than the one that the VM provides
              * by default.
@@ -117,7 +123,7 @@
             SpeculationLog speculationLog = null;
 
             /* Invoke the whole Graal compilation pipeline. */
-            GraalCompiler.compileGraph(graph, callingConvention, method, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites,
+            GraalCompiler.compileGraph(graph, callingConvention, method, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, lowLevelSuites,
                             compilationResult, factory);
 
             /*
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Feb 10 20:44:08 2015 +0100
@@ -41,12 +41,13 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.alloc.lsra.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.lir.constopt.*;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.stackslotalloc.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.phases.LowLevelHighTierPhase.LowLevelHighTierContext;
+import com.oracle.graal.lir.phases.LowLevelLowTierPhase.LowLevelLowTierContext;
+import com.oracle.graal.lir.phases.LowLevelMidTierPhase.LowLevelMidTierContext;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.spi.*;
@@ -143,6 +144,7 @@
         public final ProfilingInfo profilingInfo;
         public final SpeculationLog speculationLog;
         public final Suites suites;
+        public final LowLevelSuites lowLevelSuites;
         public final T compilationResult;
         public final CompilationResultBuilderFactory factory;
 
@@ -160,12 +162,13 @@
          * @param profilingInfo
          * @param speculationLog
          * @param suites
+         * @param lowLevelSuites
          * @param compilationResult
          * @param factory
          */
         public Request(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, TargetDescription target,
                         Map<ResolvedJavaMethod, StructuredGraph> cache, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo,
-                        SpeculationLog speculationLog, Suites suites, T compilationResult, CompilationResultBuilderFactory factory) {
+                        SpeculationLog speculationLog, Suites suites, LowLevelSuites lowLevelSuites, T compilationResult, CompilationResultBuilderFactory factory) {
             this.graph = graph;
             this.cc = cc;
             this.installedCodeOwner = installedCodeOwner;
@@ -178,6 +181,7 @@
             this.profilingInfo = profilingInfo;
             this.speculationLog = speculationLog;
             this.suites = suites;
+            this.lowLevelSuites = lowLevelSuites;
             this.compilationResult = compilationResult;
             this.factory = factory;
         }
@@ -203,9 +207,9 @@
      */
     public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
                     TargetDescription target, Map<ResolvedJavaMethod, StructuredGraph> cache, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
-                    ProfilingInfo profilingInfo, SpeculationLog speculationLog, Suites suites, T compilationResult, CompilationResultBuilderFactory factory) {
-        return compile(new Request<>(graph, cc, installedCodeOwner, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, compilationResult,
-                        factory));
+                    ProfilingInfo profilingInfo, SpeculationLog speculationLog, Suites suites, LowLevelSuites lowLevelSuites, T compilationResult, CompilationResultBuilderFactory factory) {
+        return compile(new Request<>(graph, cc, installedCodeOwner, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, lowLevelSuites,
+                        compilationResult, factory));
     }
 
     /**
@@ -218,7 +222,7 @@
         try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache())) {
             Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
             SchedulePhase schedule = emitFrontEnd(r.providers, r.target, r.graph, assumptions, r.cache, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.speculationLog, r.suites);
-            emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.target, r.compilationResult, r.factory, assumptions, schedule, null);
+            emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.target, r.compilationResult, r.factory, assumptions, schedule, null, r.lowLevelSuites);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -272,11 +276,12 @@
     }
 
     public static <T extends CompilationResult> void emitBackEnd(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Backend backend,
-                    TargetDescription target, T compilationResult, CompilationResultBuilderFactory factory, Assumptions assumptions, SchedulePhase schedule, RegisterConfig registerConfig) {
+                    TargetDescription target, T compilationResult, CompilationResultBuilderFactory factory, Assumptions assumptions, SchedulePhase schedule, RegisterConfig registerConfig,
+                    LowLevelSuites lowLevelSuites) {
         try (TimerCloseable a = BackEnd.start()) {
             LIRGenerationResult lirGen = null;
-            lirGen = emitLIR(backend, target, schedule, graph, stub, cc, registerConfig);
-            try (Scope s = Debug.scope("CodeGen", new Object[]{lirGen, lirGen.getLIR()})) {
+            lirGen = emitLIR(backend, target, schedule, graph, stub, cc, registerConfig, lowLevelSuites);
+            try (Scope s = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) {
                 emitCode(backend, assumptions, lirGen, compilationResult, installedCodeOwner, factory);
             } catch (Throwable e) {
                 throw Debug.handle(e);
@@ -297,7 +302,8 @@
         }
     }
 
-    public static LIRGenerationResult emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig) {
+    public static LIRGenerationResult emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc,
+                    RegisterConfig registerConfig, LowLevelSuites lowLevelSuites) {
         List<Block> blocks = schedule.getCFG().getBlocks();
         Block startBlock = schedule.getCFG().getStartBlock();
         assert startBlock != null;
@@ -336,59 +342,30 @@
                 throw Debug.handle(e);
             }
 
-            if (ConstantLoadOptimization.Options.ConstantLoadOptimization.getValue()) {
-                try (Scope s = Debug.scope("ConstantLoadOptimization", lir)) {
-                    ConstantLoadOptimization.optimize(lirGenRes.getLIR(), lirGen);
-                    Debug.dump(lir, "After constant load optimization");
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
-            }
-
-            try (Scope s = Debug.scope("Allocator", nodeLirGen)) {
-                if (backend.shouldAllocateRegisters()) {
-                    LinearScan.allocate(target, lirGenRes);
-                }
+            try (Scope s = Debug.scope("LowLevelTier", nodeLirGen)) {
+                return emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, lirGen, lowLevelSuites);
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
-
-            try (Scope s1 = Debug.scope("BuildFrameMap")) {
-                // build frame map
-                final StackSlotAllocator allocator;
-                if (LSStackSlotAllocator.Options.LSStackSlotAllocation.getValue()) {
-                    allocator = new LSStackSlotAllocator();
-                } else {
-                    allocator = new SimpleStackSlotAllocator();
-                }
-                lirGenRes.buildFrameMap(allocator);
-                Debug.dump(lir, "After FrameMap building");
-            }
-            try (Scope s1 = Debug.scope("MarkLocations")) {
-                if (backend.shouldAllocateRegisters()) {
-                    // currently we mark locations only if we do register allocation
-                    LocationMarker.markLocations(lir, lirGenRes.getFrameMap());
-                }
-            }
-
-            try (Scope s = Debug.scope("ControlFlowOptimizations")) {
-                EdgeMoveOptimizer.optimize(lir);
-                ControlFlowOptimizer.optimize(lir, codeEmittingOrder);
-                if (lirGen.canEliminateRedundantMoves()) {
-                    RedundantMoveElimination.optimize(lir, frameMapBuilder);
-                }
-                NullCheckOptimizer.optimize(lir, target.implicitNullCheckLimit);
-
-                Debug.dump(lir, "After control flow optimization");
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-            return lirGenRes;
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
     }
 
+    public static <T extends AbstractBlock<T>> LIRGenerationResult emitLowLevel(TargetDescription target, List<T> codeEmittingOrder, List<T> linearScanOrder, LIRGenerationResult lirGenRes,
+                    LIRGeneratorTool lirGen, LowLevelSuites lowLevelSuites) {
+        LowLevelHighTierContext highTierContext = new LowLevelHighTierContext(lirGen);
+        lowLevelSuites.getHighTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, highTierContext);
+
+        LowLevelMidTierContext midTierContext = new LowLevelMidTierContext();
+        lowLevelSuites.getMidTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, midTierContext);
+
+        LowLevelLowTierContext lowTierContext = new LowLevelLowTierContext();
+        lowLevelSuites.getLowTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, lowTierContext);
+
+        return lirGenRes;
+    }
+
     public static void emitCode(Backend backend, Assumptions assumptions, LIRGenerationResult lirGenRes, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner,
                     CompilationResultBuilderFactory factory) {
         FrameMap frameMap = lirGenRes.getFrameMap();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java	Tue Feb 10 20:44:08 2015 +0100
@@ -23,6 +23,10 @@
 package com.oracle.graal.compiler.phases;
 
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.phases.LowLevelHighTierPhase.*;
+import com.oracle.graal.lir.phases.LowLevelLowTierPhase.*;
+import com.oracle.graal.lir.phases.LowLevelMidTierPhase.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -40,4 +44,17 @@
     public PhaseSuite<LowTierContext> createLowTier() {
         return new LowTier();
     }
+
+    public LowLevelPhaseSuite<LowLevelHighTierContext> createLowLevelHighTier() {
+        return new LowLevelHighTier();
+    }
+
+    public LowLevelPhaseSuite<LowLevelMidTierContext> createLowLevelMidTier() {
+        return new LowLevelMidTier();
+    }
+
+    public LowLevelPhaseSuite<LowLevelLowTierContext> createLowLevelLowTier() {
+        return new LowLevelLowTier();
+    }
+
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Tue Feb 10 20:44:08 2015 +0100
@@ -101,8 +101,6 @@
     public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult, FrameMap frameMap, CompilationResult compilationResult,
                     CompilationResultBuilderFactory factory);
 
-    public abstract boolean shouldAllocateRegisters();
-
     public abstract StackIntrospection getStackIntrospection();
 
     /**
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Tue Feb 10 20:44:08 2015 +0100
@@ -62,11 +62,6 @@
     }
 
     @Override
-    public boolean shouldAllocateRegisters() {
-        return true;
-    }
-
-    @Override
     public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
         RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
         return new AMD64FrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Feb 10 20:44:08 2015 +0100
@@ -68,11 +68,6 @@
     }
 
     @Override
-    public boolean shouldAllocateRegisters() {
-        return true;
-    }
-
-    @Override
     public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
         RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
         return new SPARCFrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Tue Feb 10 20:44:08 2015 +0100
@@ -39,6 +39,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.options.*;
@@ -209,9 +210,12 @@
         try (OverrideScope s = OptionValue.override(ImmutableCode, compileAOT)) {
             CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
             // create suites everytime, as we modify options for the compiler
-            final Suites suitesLocal = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().createSuites();
+            SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites();
+            final Suites suitesLocal = suitesProvider.createSuites();
+            final LowLevelSuites lowLevelSuitesLocal = suitesProvider.createLowLevelSuites();
             final CompilationResult compResult = compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
-                            OptimisticOptimizations.ALL, getProfilingInfo(graph), getSpeculationLog(), suitesLocal, new CompilationResult(), CompilationResultBuilderFactory.Default);
+                            OptimisticOptimizations.ALL, getProfilingInfo(graph), getSpeculationLog(), suitesLocal, lowLevelSuitesLocal, new CompilationResult(),
+                            CompilationResultBuilderFactory.Default);
             addMethod(method, compResult);
         }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Tue Feb 10 20:44:08 2015 +0100
@@ -55,6 +55,7 @@
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
@@ -138,6 +139,10 @@
         return providers.getSuites().getDefaultSuites();
     }
 
+    protected LowLevelSuites getLowLevelSuites(HotSpotProviders providers) {
+        return providers.getSuites().getDefaultLowLevelSuites();
+    }
+
     protected PhaseSuite<HighTierContext> getGraphBuilderSuite(HotSpotProviders providers) {
         PhaseSuite<HighTierContext> suite = withSimpleDebugInfoIfRequested(providers.getSuites().getDefaultGraphBuilderSuite());
 
@@ -223,6 +228,7 @@
                         cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0));
                     }
                     Suites suites = getSuites(providers);
+                    LowLevelSuites lowLevelSuites = getLowLevelSuites(providers);
                     ProfilingInfo profilingInfo = getProfilingInfo();
                     OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo);
                     if (isOSR) {
@@ -231,7 +237,7 @@
                         optimisticOpts.remove(Optimization.RemoveNeverExecutedCode);
                     }
                     result = compileGraph(graph, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo,
-                                    method.getSpeculationLog(), suites, new CompilationResult(), CompilationResultBuilderFactory.Default);
+                                    method.getSpeculationLog(), suites, lowLevelSuites, new CompilationResult(), CompilationResultBuilderFactory.Default);
                 }
                 result.setId(getId());
                 result.setEntryBCI(entryBCI);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Tue Feb 10 20:44:08 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.java.GraphBuilderConfiguration.DebugInfoMode;
 import com.oracle.graal.java.GraphBuilderPlugins.InlineInvokePlugin;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
 import com.oracle.graal.phases.*;
@@ -40,28 +41,44 @@
 /**
  * HotSpot implementation of {@link SuitesProvider}.
  */
-public class HotSpotSuitesProvider implements SuitesProvider, OptionSupplier<Suites> {
-
-    private static final long serialVersionUID = -5755004498526945687L;
+public class HotSpotSuitesProvider implements SuitesProvider {
 
     protected final DerivedOptionValue<Suites> defaultSuites;
     protected final PhaseSuite<HighTierContext> defaultGraphBuilderSuite;
+    private final DerivedOptionValue<LowLevelSuites> defaultLowLevelSuites;
     protected final HotSpotGraalRuntimeProvider runtime;
 
+    private class SuitesSupplier implements OptionSupplier<Suites> {
+
+        private static final long serialVersionUID = -3444304453553320390L;
+
+        public Suites get() {
+            return createSuites();
+        }
+
+    }
+
+    private class LowLevelSuitesSupplier implements OptionSupplier<LowLevelSuites> {
+
+        private static final long serialVersionUID = -1558586374095874299L;
+
+        public LowLevelSuites get() {
+            return createLowLevelSuites();
+        }
+
+    }
+
     public HotSpotSuitesProvider(HotSpotGraalRuntimeProvider runtime) {
         this.runtime = runtime;
         this.defaultGraphBuilderSuite = createGraphBuilderSuite();
-        this.defaultSuites = new DerivedOptionValue<>(this);
+        this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
+        this.defaultLowLevelSuites = new DerivedOptionValue<>(new LowLevelSuitesSupplier());
     }
 
     public Suites getDefaultSuites() {
         return defaultSuites.getValue();
     }
 
-    public Suites get() {
-        return createSuites();
-    }
-
     public PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite() {
         return defaultGraphBuilderSuite;
     }
@@ -118,4 +135,12 @@
         return gbs;
     }
 
+    public LowLevelSuites getDefaultLowLevelSuites() {
+        return defaultLowLevelSuites.getValue();
+    }
+
+    public LowLevelSuites createLowLevelSuites() {
+        return Suites.createDefaultLowLevelSuites();
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Tue Feb 10 20:44:08 2015 +0100
@@ -37,6 +37,7 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
@@ -160,10 +161,11 @@
     private InstalledCode installNativeFunctionStub(long functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
         StructuredGraph g = getGraph(providers, factory, functionPointer, returnType, argumentTypes);
         Suites suites = providers.getSuites().createSuites();
+        LowLevelSuites lowLevelSuites = providers.getSuites().createLowLevelSuites();
         PhaseSuite<HighTierContext> phaseSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, g.method(), false);
         CompilationResult compResult = GraalCompiler.compileGraph(g, cc, g.method(), providers, backend, backend.getTarget(), null, phaseSuite, OptimisticOptimizations.ALL,
-                        DefaultProfilingInfo.get(TriState.UNKNOWN), null, suites, new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        DefaultProfilingInfo.get(TriState.UNKNOWN), null, suites, lowLevelSuites, new CompilationResult(), CompilationResultBuilderFactory.Default);
         InstalledCode installedCode;
         try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache(), g.method())) {
             installedCode = providers.getCodeCache().addMethod(g.method(), compResult, null, null);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Feb 10 20:44:08 2015 +0100
@@ -40,6 +40,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.schedule.*;
@@ -175,7 +176,9 @@
                     Suites suites = new Suites(new PhaseSuite<>(), defaultSuites.getMidTier(), defaultSuites.getLowTier());
                     SchedulePhase schedule = emitFrontEnd(providers, target, graph, assumptions, null, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
                                     getProfilingInfo(graph), null, suites);
-                    emitBackEnd(graph, Stub.this, incomingCc, getInstalledCodeOwner(), backend, target, compResult, CompilationResultBuilderFactory.Default, assumptions, schedule, getRegisterConfig());
+                    LowLevelSuites lowLevelSuites = providers.getSuites().getDefaultLowLevelSuites();
+                    emitBackEnd(graph, Stub.this, incomingCc, getInstalledCodeOwner(), backend, target, compResult, CompilationResultBuilderFactory.Default, assumptions, schedule,
+                                    getRegisterConfig(), lowLevelSuites);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Tue Feb 10 20:44:08 2015 +0100
@@ -22,30 +22,48 @@
  */
 package com.oracle.graal.java;
 
-import java.util.function.*;
-
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
+import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
-public class DefaultSuitesProvider implements SuitesProvider, Supplier<Suites> {
+public class DefaultSuitesProvider implements SuitesProvider {
 
     private final DerivedOptionValue<Suites> defaultSuites;
     private final PhaseSuite<HighTierContext> defaultGraphBuilderSuite;
+    private final DerivedOptionValue<LowLevelSuites> defaultLowLevelSuites;
+
+    private class SuitesSupplier implements OptionSupplier<Suites> {
+
+        private static final long serialVersionUID = 2677805381215454728L;
+
+        public Suites get() {
+            return createSuites();
+        }
+
+    }
+
+    private class LowLevelSuitesSupplier implements OptionSupplier<LowLevelSuites> {
+
+        private static final long serialVersionUID = 312070237227476252L;
+
+        public LowLevelSuites get() {
+            return createLowLevelSuites();
+        }
+
+    }
 
     public DefaultSuitesProvider() {
         this.defaultGraphBuilderSuite = createGraphBuilderSuite();
-        this.defaultSuites = new DerivedOptionValue<>(this::createSuites);
+        this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
+        this.defaultLowLevelSuites = new DerivedOptionValue<>(new LowLevelSuitesSupplier());
     }
 
     public Suites getDefaultSuites() {
         return defaultSuites.getValue();
     }
 
-    public Suites get() {
-        return createSuites();
-    }
-
     public Suites createSuites() {
         return Suites.createDefaultSuites();
     }
@@ -60,4 +78,12 @@
         return suite;
     }
 
+    public LowLevelSuites getDefaultLowLevelSuites() {
+        return defaultLowLevelSuites.getValue();
+    }
+
+    public LowLevelSuites createLowLevelSuites() {
+        return Suites.createDefaultLowLevelSuites();
+    }
+
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Tue Feb 10 20:44:08 2015 +0100
@@ -26,87 +26,98 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 
 /**
  * This class performs basic optimizations on the control flow graph after LIR generation.
  */
-public final class ControlFlowOptimizer {
+public final class ControlFlowOptimizer extends LowLevelLowTierPhase {
 
     /**
      * Performs control flow optimizations on the given LIR graph.
      */
-    public static <T extends AbstractBlock<T>> void optimize(LIR lir, List<T> codeEmittingOrder) {
-        ControlFlowOptimizer.deleteEmptyBlocks(lir, codeEmittingOrder);
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        LIR lir = lirGenRes.getLIR();
+        new Optimizer<B>(lir).deleteEmptyBlocks(codeEmittingOrder);
     }
 
-    private ControlFlowOptimizer() {
-    }
+    private static final class Optimizer<B extends AbstractBlock<B>> {
 
-    private static final DebugMetric BLOCKS_DELETED = Debug.metric("BlocksDeleted");
+        private final LIR lir;
 
-    /**
-     * Checks whether a block can be deleted. Only blocks with exactly one successor and an
-     * unconditional branch to this successor are eligable.
-     *
-     * @param block the block checked for deletion
-     * @return whether the block can be deleted
-     */
-    private static boolean canDeleteBlock(LIR lir, AbstractBlock<?> block) {
-        if (block.getSuccessorCount() != 1 || block.getPredecessorCount() == 0 || block.getSuccessors().iterator().next() == block) {
-            return false;
+        private Optimizer(LIR lir) {
+            this.lir = lir;
         }
 
-        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        private static final DebugMetric BLOCKS_DELETED = Debug.metric("BlocksDeleted");
 
-        assert instructions.size() >= 2 : "block must have label and branch";
-        assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label";
-        assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "last instruction must always be a branch";
-        assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) lir.getLIRforBlock(block.getSuccessors().iterator().next()).get(0)).getLabel() : "branch target must be the successor";
+        /**
+         * Checks whether a block can be deleted. Only blocks with exactly one successor and an
+         * unconditional branch to this successor are eligable.
+         *
+         * @param block the block checked for deletion
+         * @return whether the block can be deleted
+         */
+        private boolean canDeleteBlock(B block) {
+            if (block.getSuccessorCount() != 1 || block.getPredecessorCount() == 0 || block.getSuccessors().iterator().next() == block) {
+                return false;
+            }
 
-        // Block must have exactly one successor.
-        return instructions.size() == 2 && !instructions.get(instructions.size() - 1).hasState() && !block.isExceptionEntry();
-    }
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
 
-    private static void alignBlock(LIR lir, AbstractBlock<?> block) {
-        if (!block.isAligned()) {
-            block.setAlign(true);
-            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            assert instructions.size() >= 2 : "block must have label and branch";
             assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label";
-            StandardOp.LabelOp label = (StandardOp.LabelOp) instructions.get(0);
-            instructions.set(0, new StandardOp.LabelOp(label.getLabel(), true));
+            assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "last instruction must always be a branch";
+            assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) lir.getLIRforBlock(block.getSuccessors().iterator().next()).get(0)).getLabel() : "branch target must be the successor";
+
+            // Block must have exactly one successor.
+            return instructions.size() == 2 && !instructions.get(instructions.size() - 1).hasState() && !block.isExceptionEntry();
+        }
+
+        private void alignBlock(B block) {
+            if (!block.isAligned()) {
+                block.setAlign(true);
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label";
+                StandardOp.LabelOp label = (StandardOp.LabelOp) instructions.get(0);
+                instructions.set(0, new StandardOp.LabelOp(label.getLabel(), true));
+            }
+        }
+
+        private void deleteEmptyBlocks(List<B> blocks) {
+            assert verifyBlocks(lir, blocks);
+            Iterator<B> iterator = blocks.iterator();
+            while (iterator.hasNext()) {
+                B block = iterator.next();
+                if (canDeleteBlock(block)) {
+                    // adjust successor and predecessor lists
+                    B other = block.getSuccessors().iterator().next();
+                    for (AbstractBlock<B> pred : block.getPredecessors()) {
+                        Collections.replaceAll(pred.getSuccessors(), block, other);
+                    }
+                    for (int i = 0; i < other.getPredecessorCount(); i++) {
+                        if (other.getPredecessors().get(i) == block) {
+                            other.getPredecessors().remove(i);
+                            other.getPredecessors().addAll(i, block.getPredecessors());
+                        }
+                    }
+                    block.getSuccessors().clear();
+                    block.getPredecessors().clear();
+
+                    if (block.isAligned()) {
+                        alignBlock(other);
+                    }
+
+                    BLOCKS_DELETED.increment();
+                    iterator.remove();
+                }
+            }
+            assert verifyBlocks(lir, blocks);
         }
     }
-
-    private static <T extends AbstractBlock<T>> void deleteEmptyBlocks(LIR lir, List<T> blocks) {
-        assert verifyBlocks(lir, blocks);
-        Iterator<T> iterator = blocks.iterator();
-        while (iterator.hasNext()) {
-            T block = iterator.next();
-            if (canDeleteBlock(lir, block)) {
-                // adjust successor and predecessor lists
-                T other = block.getSuccessors().iterator().next();
-                for (AbstractBlock<T> pred : block.getPredecessors()) {
-                    Collections.replaceAll(pred.getSuccessors(), block, other);
-                }
-                for (int i = 0; i < other.getPredecessorCount(); i++) {
-                    if (other.getPredecessors().get(i) == block) {
-                        other.getPredecessors().remove(i);
-                        other.getPredecessors().addAll(i, block.getPredecessors());
-                    }
-                }
-                block.getSuccessors().clear();
-                block.getPredecessors().clear();
-
-                if (block.isAligned()) {
-                    alignBlock(lir, other);
-                }
-
-                BLOCKS_DELETED.increment();
-                iterator.remove();
-            }
-        }
-        assert verifyBlocks(lir, blocks);
-    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Tue Feb 10 20:44:08 2015 +0100
@@ -24,34 +24,36 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 
 /**
  * This class optimizes moves, particularly those that result from eliminating SSA form.
- *
+ * <p>
  * When a block has more than one predecessor, and all predecessors end with the
- * {@linkplain #same(LIRInstruction, LIRInstruction) same} sequence of {@linkplain MoveOp move}
- * instructions, then these sequences can be replaced with a single copy of the sequence at the
- * beginning of the block.
- *
+ * {@linkplain Optimizer#same(LIRInstruction, LIRInstruction) same} sequence of {@linkplain MoveOp
+ * move} instructions, then these sequences can be replaced with a single copy of the sequence at
+ * the beginning of the block.
+ * <p>
  * Similarly, when a block has more than one successor, then same sequences of moves at the
  * beginning of the successors can be placed once at the end of the block. But because the moves
  * must be inserted before all branch instructions, this works only when there is exactly one
  * conditional branch at the end of the block (because the moves must be inserted before all
  * branches, but after all compares).
- *
+ * <p>
  * This optimization affects all kind of moves (reg-&gt;reg, reg-&gt;stack and stack-&gt;reg).
  * Because this optimization works best when a block contains only a few moves, it has a huge impact
  * on the number of blocks that are totally empty.
  */
-public final class EdgeMoveOptimizer {
+public final class EdgeMoveOptimizer extends LowLevelLowTierPhase {
 
-    /**
-     * Optimizes moves on block edges.
-     */
-    public static void optimize(LIR ir) {
-        EdgeMoveOptimizer optimizer = new EdgeMoveOptimizer(ir);
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        LIR ir = lirGenRes.getLIR();
+        Optimizer optimizer = new Optimizer(ir);
 
         List<? extends AbstractBlock<?>> blockList = ir.linearScanOrder();
         // ignore the first block in the list (index 0 is not processed)
@@ -67,213 +69,216 @@
         }
     }
 
-    private final List<List<LIRInstruction>> edgeInstructionSeqences;
-    private LIR ir;
+    private static final class Optimizer {
+        private final List<List<LIRInstruction>> edgeInstructionSeqences;
+        private LIR ir;
 
-    public EdgeMoveOptimizer(LIR ir) {
-        this.ir = ir;
-        edgeInstructionSeqences = new ArrayList<>(4);
-    }
-
-    /**
-     * Determines if two operations are both {@linkplain MoveOp moves} that have the same
-     * {@linkplain MoveOp#getInput() source} and {@linkplain MoveOp#getResult() destination}
-     * operands.
-     *
-     * @param op1 the first instruction to compare
-     * @param op2 the second instruction to compare
-     * @return {@code true} if {@code op1} and {@code op2} are the same by the above algorithm
-     */
-    private static boolean same(LIRInstruction op1, LIRInstruction op2) {
-        assert op1 != null;
-        assert op2 != null;
-
-        if (op1 instanceof MoveOp && op2 instanceof MoveOp) {
-            MoveOp move1 = (MoveOp) op1;
-            MoveOp move2 = (MoveOp) op2;
-            if (move1.getInput().equals(move2.getInput()) && move1.getResult().equals(move2.getResult())) {
-                // these moves are exactly equal and can be optimized
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Moves the longest {@linkplain #same common} subsequence at the end all predecessors of
-     * {@code block} to the start of {@code block}.
-     */
-    private void optimizeMovesAtBlockEnd(AbstractBlock<?> block) {
-        for (AbstractBlock<?> pred : block.getPredecessors()) {
-            if (pred == block) {
-                // currently we can't handle this correctly.
-                return;
-            }
+        public Optimizer(LIR ir) {
+            this.ir = ir;
+            edgeInstructionSeqences = new ArrayList<>(4);
         }
 
-        // clear all internal data structures
-        edgeInstructionSeqences.clear();
+        /**
+         * Determines if two operations are both {@linkplain MoveOp moves} that have the same
+         * {@linkplain MoveOp#getInput() source} and {@linkplain MoveOp#getResult() destination}
+         * operands.
+         *
+         * @param op1 the first instruction to compare
+         * @param op2 the second instruction to compare
+         * @return {@code true} if {@code op1} and {@code op2} are the same by the above algorithm
+         */
+        private static boolean same(LIRInstruction op1, LIRInstruction op2) {
+            assert op1 != null;
+            assert op2 != null;
 
-        int numPreds = block.getPredecessorCount();
-        assert numPreds > 1 : "do not call otherwise";
-
-        // setup a list with the LIR instructions of all predecessors
-        for (AbstractBlock<?> pred : block.getPredecessors()) {
-            assert pred != null;
-            assert ir.getLIRforBlock(pred) != null;
-            List<LIRInstruction> predInstructions = ir.getLIRforBlock(pred);
-
-            if (pred.getSuccessorCount() != 1) {
-                // this can happen with switch-statements where multiple edges are between
-                // the same blocks.
-                return;
+            if (op1 instanceof MoveOp && op2 instanceof MoveOp) {
+                MoveOp move1 = (MoveOp) op1;
+                MoveOp move2 = (MoveOp) op2;
+                if (move1.getInput().equals(move2.getInput()) && move1.getResult().equals(move2.getResult())) {
+                    // these moves are exactly equal and can be optimized
+                    return true;
+                }
             }
-
-            assert pred.getSuccessors().iterator().next() == block : "invalid control flow";
-            assert predInstructions.get(predInstructions.size() - 1) instanceof StandardOp.JumpOp : "block must end with unconditional jump";
-
-            if (predInstructions.get(predInstructions.size() - 1).hasState()) {
-                // can not optimize instructions that have debug info
-                return;
-            }
-
-            // ignore the unconditional branch at the end of the block
-            List<LIRInstruction> seq = predInstructions.subList(0, predInstructions.size() - 1);
-            edgeInstructionSeqences.add(seq);
+            return false;
         }
 
-        // process lir-instructions while all predecessors end with the same instruction
-        while (true) {
-            List<LIRInstruction> seq = edgeInstructionSeqences.get(0);
-            if (seq.isEmpty()) {
-                return;
-            }
-
-            LIRInstruction op = last(seq);
-            for (int i = 1; i < numPreds; ++i) {
-                List<LIRInstruction> otherSeq = edgeInstructionSeqences.get(i);
-                if (otherSeq.isEmpty() || !same(op, last(otherSeq))) {
+        /**
+         * Moves the longest {@linkplain #same common} subsequence at the end all predecessors of
+         * {@code block} to the start of {@code block}.
+         */
+        private void optimizeMovesAtBlockEnd(AbstractBlock<?> block) {
+            for (AbstractBlock<?> pred : block.getPredecessors()) {
+                if (pred == block) {
+                    // currently we can't handle this correctly.
                     return;
                 }
             }
 
-            // insert the instruction at the beginning of the current block
-            ir.getLIRforBlock(block).add(1, op);
+            // clear all internal data structures
+            edgeInstructionSeqences.clear();
 
-            // delete the instruction at the end of all predecessors
-            for (int i = 0; i < numPreds; i++) {
-                seq = edgeInstructionSeqences.get(i);
-                removeLast(seq);
+            int numPreds = block.getPredecessorCount();
+            assert numPreds > 1 : "do not call otherwise";
+
+            // setup a list with the LIR instructions of all predecessors
+            for (AbstractBlock<?> pred : block.getPredecessors()) {
+                assert pred != null;
+                assert ir.getLIRforBlock(pred) != null;
+                List<LIRInstruction> predInstructions = ir.getLIRforBlock(pred);
+
+                if (pred.getSuccessorCount() != 1) {
+                    // this can happen with switch-statements where multiple edges are between
+                    // the same blocks.
+                    return;
+                }
+
+                assert pred.getSuccessors().iterator().next() == block : "invalid control flow";
+                assert predInstructions.get(predInstructions.size() - 1) instanceof StandardOp.JumpOp : "block must end with unconditional jump";
+
+                if (predInstructions.get(predInstructions.size() - 1).hasState()) {
+                    // can not optimize instructions that have debug info
+                    return;
+                }
+
+                // ignore the unconditional branch at the end of the block
+                List<LIRInstruction> seq = predInstructions.subList(0, predInstructions.size() - 1);
+                edgeInstructionSeqences.add(seq);
+            }
+
+            // process lir-instructions while all predecessors end with the same instruction
+            while (true) {
+                List<LIRInstruction> seq = edgeInstructionSeqences.get(0);
+                if (seq.isEmpty()) {
+                    return;
+                }
+
+                LIRInstruction op = last(seq);
+                for (int i = 1; i < numPreds; ++i) {
+                    List<LIRInstruction> otherSeq = edgeInstructionSeqences.get(i);
+                    if (otherSeq.isEmpty() || !same(op, last(otherSeq))) {
+                        return;
+                    }
+                }
+
+                // insert the instruction at the beginning of the current block
+                ir.getLIRforBlock(block).add(1, op);
+
+                // delete the instruction at the end of all predecessors
+                for (int i = 0; i < numPreds; i++) {
+                    seq = edgeInstructionSeqences.get(i);
+                    removeLast(seq);
+                }
             }
         }
-    }
 
-    /**
-     * Moves the longest {@linkplain #same common} subsequence at the start of all successors of
-     * {@code block} to the end of {@code block} just prior to the branch instruction ending
-     * {@code block}.
-     */
-    private void optimizeMovesAtBlockBegin(AbstractBlock<?> block) {
+        /**
+         * Moves the longest {@linkplain #same common} subsequence at the start of all successors of
+         * {@code block} to the end of {@code block} just prior to the branch instruction ending
+         * {@code block}.
+         */
+        private void optimizeMovesAtBlockBegin(AbstractBlock<?> block) {
 
-        edgeInstructionSeqences.clear();
-        int numSux = block.getSuccessorCount();
+            edgeInstructionSeqences.clear();
+            int numSux = block.getSuccessorCount();
 
-        List<LIRInstruction> instructions = ir.getLIRforBlock(block);
+            List<LIRInstruction> instructions = ir.getLIRforBlock(block);
 
-        assert numSux == 2 : "method should not be called otherwise";
+            assert numSux == 2 : "method should not be called otherwise";
 
-        LIRInstruction lastInstruction = instructions.get(instructions.size() - 1);
-        if (lastInstruction.hasState()) {
-            // cannot optimize instructions when debug info is needed
-            return;
-        }
-
-        LIRInstruction branch = lastInstruction;
-        if (!(branch instanceof StandardOp.BranchOp) || branch.hasOperands()) {
-            // Only blocks that end with a conditional branch are optimized.
-            // In addition, a conditional branch with operands (including state) cannot
-            // be optimized. Moving a successor instruction before such a branch may
-            // interfere with the operands of the branch. For example, a successive move
-            // instruction may redefine an input operand of the branch.
-            return;
-        }
-
-        // Now it is guaranteed that the block ends with a conditional branch.
-        // The instructions are inserted at the end of the block before the branch.
-        int insertIdx = instructions.size() - 1;
-
-        // setup a list with the lir-instructions of all successors
-        for (AbstractBlock<?> sux : block.getSuccessors()) {
-            List<LIRInstruction> suxInstructions = ir.getLIRforBlock(sux);
-
-            assert suxInstructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
-
-            if (sux.getPredecessorCount() != 1) {
-                // this can happen with switch-statements where multiple edges are between
-                // the same blocks.
-                return;
-            }
-            assert sux.getPredecessors().iterator().next() == block : "invalid control flow";
-
-            // ignore the label at the beginning of the block
-            List<LIRInstruction> seq = suxInstructions.subList(1, suxInstructions.size());
-            edgeInstructionSeqences.add(seq);
-        }
-
-        // process LIR instructions while all successors begin with the same instruction
-        while (true) {
-            List<LIRInstruction> seq = edgeInstructionSeqences.get(0);
-            if (seq.isEmpty()) {
+            LIRInstruction lastInstruction = instructions.get(instructions.size() - 1);
+            if (lastInstruction.hasState()) {
+                // cannot optimize instructions when debug info is needed
                 return;
             }
 
-            LIRInstruction op = first(seq);
-            for (int i = 1; i < numSux; i++) {
-                List<LIRInstruction> otherSeq = edgeInstructionSeqences.get(i);
-                if (otherSeq.isEmpty() || !same(op, first(otherSeq))) {
-                    // these instructions are different and cannot be optimized .
-                    // no further optimization possible
+            LIRInstruction branch = lastInstruction;
+            if (!(branch instanceof StandardOp.BranchOp) || branch.hasOperands()) {
+                // Only blocks that end with a conditional branch are optimized.
+                // In addition, a conditional branch with operands (including state) cannot
+                // be optimized. Moving a successor instruction before such a branch may
+                // interfere with the operands of the branch. For example, a successive move
+                // instruction may redefine an input operand of the branch.
+                return;
+            }
+
+            // Now it is guaranteed that the block ends with a conditional branch.
+            // The instructions are inserted at the end of the block before the branch.
+            int insertIdx = instructions.size() - 1;
+
+            // setup a list with the lir-instructions of all successors
+            for (AbstractBlock<?> sux : block.getSuccessors()) {
+                List<LIRInstruction> suxInstructions = ir.getLIRforBlock(sux);
+
+                assert suxInstructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
+
+                if (sux.getPredecessorCount() != 1) {
+                    // this can happen with switch-statements where multiple edges are between
+                    // the same blocks.
                     return;
                 }
+                assert sux.getPredecessors().iterator().next() == block : "invalid control flow";
+
+                // ignore the label at the beginning of the block
+                List<LIRInstruction> seq = suxInstructions.subList(1, suxInstructions.size());
+                edgeInstructionSeqences.add(seq);
             }
 
-            // insert instruction at end of current block
-            ir.getLIRforBlock(block).add(insertIdx, op);
-            insertIdx++;
+            // process LIR instructions while all successors begin with the same instruction
+            while (true) {
+                List<LIRInstruction> seq = edgeInstructionSeqences.get(0);
+                if (seq.isEmpty()) {
+                    return;
+                }
 
-            // delete the instructions at the beginning of all successors
-            for (int i = 0; i < numSux; i++) {
-                seq = edgeInstructionSeqences.get(i);
-                removeFirst(seq);
+                LIRInstruction op = first(seq);
+                for (int i = 1; i < numSux; i++) {
+                    List<LIRInstruction> otherSeq = edgeInstructionSeqences.get(i);
+                    if (otherSeq.isEmpty() || !same(op, first(otherSeq))) {
+                        // these instructions are different and cannot be optimized .
+                        // no further optimization possible
+                        return;
+                    }
+                }
+
+                // insert instruction at end of current block
+                ir.getLIRforBlock(block).add(insertIdx, op);
+                insertIdx++;
+
+                // delete the instructions at the beginning of all successors
+                for (int i = 0; i < numSux; i++) {
+                    seq = edgeInstructionSeqences.get(i);
+                    removeFirst(seq);
+                }
             }
         }
-    }
 
-    /**
-     * Gets the first element from a LIR instruction sequence.
-     */
-    private static LIRInstruction first(List<LIRInstruction> seq) {
-        return seq.get(0);
-    }
+        /**
+         * Gets the first element from a LIR instruction sequence.
+         */
+        private static LIRInstruction first(List<LIRInstruction> seq) {
+            return seq.get(0);
+        }
 
-    /**
-     * Gets the last element from a LIR instruction sequence.
-     */
-    private static LIRInstruction last(List<LIRInstruction> seq) {
-        return seq.get(seq.size() - 1);
-    }
+        /**
+         * Gets the last element from a LIR instruction sequence.
+         */
+        private static LIRInstruction last(List<LIRInstruction> seq) {
+            return seq.get(seq.size() - 1);
+        }
 
-    /**
-     * Removes the first element from a LIR instruction sequence.
-     */
-    private static void removeFirst(List<LIRInstruction> seq) {
-        seq.remove(0);
-    }
+        /**
+         * Removes the first element from a LIR instruction sequence.
+         */
+        private static void removeFirst(List<LIRInstruction> seq) {
+            seq.remove(0);
+        }
 
-    /**
-     * Removes the last element from a LIR instruction sequence.
-     */
-    private static void removeLast(List<LIRInstruction> seq) {
-        seq.remove(seq.size() - 1);
+        /**
+         * Removes the last element from a LIR instruction sequence.
+         */
+        private static void removeLast(List<LIRInstruction> seq) {
+            seq.remove(seq.size() - 1);
+        }
+
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Tue Feb 10 20:44:08 2015 +0100
@@ -24,18 +24,20 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
 import com.oracle.graal.lir.StandardOp.NullCheck;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 
-public final class NullCheckOptimizer {
+public final class NullCheckOptimizer extends LowLevelLowTierPhase {
 
-    public static void optimize(LIR ir, int implicitNullCheckLimit) {
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        LIR ir = lirGenRes.getLIR();
         List<? extends AbstractBlock<?>> blocks = ir.codeEmittingOrder();
-        NullCheckOptimizer.foldNullChecks(ir, blocks, implicitNullCheckLimit);
-    }
-
-    private NullCheckOptimizer() {
+        NullCheckOptimizer.foldNullChecks(ir, blocks, target.implicitNullCheckLimit);
     }
 
     private static void foldNullChecks(LIR ir, List<? extends AbstractBlock<?>> blocks, int implicitNullCheckLimit) {
@@ -63,4 +65,5 @@
             }
         }
     }
+
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Tue Feb 10 20:44:08 2015 +0100
@@ -35,15 +35,18 @@
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 
 /**
  * Removes move instructions, where the destination value is already in place.
  */
-public final class RedundantMoveElimination {
+public final class RedundantMoveElimination extends LowLevelLowTierPhase {
 
-    public static void optimize(LIR lir, FrameMapBuilder frameMapBuilder) {
-        RedundantMoveElimination redundantMoveElimination = new RedundantMoveElimination();
-        redundantMoveElimination.doOptimize(lir, frameMapBuilder);
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        Optimization redundantMoveElimination = new Optimization();
+        redundantMoveElimination.doOptimize(lirGenRes.getLIR(), lirGenRes.getFrameMap());
     }
 
     /**
@@ -57,7 +60,7 @@
      * The value numbers also contain information if it is an object kind value or not: if the
      * number is negative it is an object kind value.
      */
-    private static class BlockData {
+    private static final class BlockData {
 
         BlockData(int stateSize) {
             entryState = new int[stateSize];
@@ -82,436 +85,440 @@
         int entryValueNum;
     }
 
-    Map<AbstractBlock<?>, BlockData> blockData = CollectionsFactory.newMap();
+    private static final class Optimization {
 
-    Register[] callerSaveRegs;
+        Map<AbstractBlock<?>, BlockData> blockData = CollectionsFactory.newMap();
 
-    /**
-     * Contains the register number for registers which can be optimized and -1 for the others.
-     */
-    int[] eligibleRegs;
+        Register[] callerSaveRegs;
 
-    Map<StackSlot, Integer> stackIndices = CollectionsFactory.newMap();
+        /**
+         * Contains the register number for registers which can be optimized and -1 for the others.
+         */
+        int[] eligibleRegs;
 
-    int numRegs;
+        Map<StackSlot, Integer> stackIndices = CollectionsFactory.newMap();
 
-    /*
-     * Pseudo value for a not yet assigned location.
-     */
-    static final int INIT_VALUE = 0;
+        int numRegs;
 
-    /**
-     * The main method doing the elimination of redundant moves.
-     */
-    private void doOptimize(LIR lir, FrameMapBuilder frameMapBuilder) {
+        /*
+         * Pseudo value for a not yet assigned location.
+         */
+        static final int INIT_VALUE = 0;
 
-        try (Indent indent = Debug.logAndIndent("eliminate redundant moves")) {
+        /**
+         * The main method doing the elimination of redundant moves.
+         */
+        private void doOptimize(LIR lir, FrameMap frameMap) {
 
-            callerSaveRegs = frameMapBuilder.getRegisterConfig().getCallerSaveRegisters();
+            try (Indent indent = Debug.logAndIndent("eliminate redundant moves")) {
 
-            initBlockData(lir);
+                callerSaveRegs = frameMap.getRegisterConfig().getCallerSaveRegisters();
 
-            // Compute a table of the registers which are eligible for move optimization.
-            // Unallocatable registers should never be optimized.
-            eligibleRegs = new int[numRegs];
-            Arrays.fill(eligibleRegs, -1);
-            for (Register reg : frameMapBuilder.getRegisterConfig().getAllocatableRegisters()) {
-                if (reg.number < numRegs) {
-                    eligibleRegs[reg.number] = reg.number;
+                initBlockData(lir);
+
+                // Compute a table of the registers which are eligible for move optimization.
+                // Unallocatable registers should never be optimized.
+                eligibleRegs = new int[numRegs];
+                Arrays.fill(eligibleRegs, -1);
+                for (Register reg : frameMap.getRegisterConfig().getAllocatableRegisters()) {
+                    if (reg.number < numRegs) {
+                        eligibleRegs[reg.number] = reg.number;
+                    }
+                }
+
+                if (!solveDataFlow(lir)) {
+                    return;
+                }
+
+                eliminateMoves(lir);
+            }
+        }
+
+        /**
+         * The maximum number of locations * blocks. This is a complexity limit for the inner loop
+         * in {@link #mergeState} (assuming a small number of iterations in {@link #solveDataFlow}.
+         */
+        private static final int COMPLEXITY_LIMIT = 30000;
+
+        private void initBlockData(LIR lir) {
+
+            List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
+            numRegs = 0;
+
+            int maxStackLocations = COMPLEXITY_LIMIT / blocks.size();
+
+            /*
+             * Search for relevant locations which can be optimized. These are register or stack
+             * slots which occur as destinations of move instructions.
+             */
+            for (AbstractBlock<?> block : blocks) {
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                for (LIRInstruction op : instructions) {
+                    if (isEligibleMove(op)) {
+                        Value dest = ((MoveOp) op).getResult();
+                        if (isRegister(dest)) {
+                            int regNum = ((RegisterValue) dest).getRegister().number;
+                            if (regNum >= numRegs) {
+                                numRegs = regNum + 1;
+                            }
+                        } else if (isStackSlot(dest)) {
+                            StackSlot stackSlot = (StackSlot) dest;
+                            if (!stackIndices.containsKey(stackSlot) && stackIndices.size() < maxStackLocations) {
+                                stackIndices.put(stackSlot, stackIndices.size());
+                            }
+                        }
+                    }
                 }
             }
 
-            if (!solveDataFlow(lir)) {
-                return;
+            /*
+             * Now we know the number of locations to optimize, so we can allocate the block states.
+             */
+            int numLocations = numRegs + stackIndices.size();
+            Debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size());
+            for (AbstractBlock<?> block : blocks) {
+                BlockData data = new BlockData(numLocations);
+                blockData.put(block, data);
+            }
+        }
+
+        /**
+         * Calculates the entry and exit states for all basic blocks.
+         *
+         * @return Returns true on success and false if the the control flow is too complex.
+         */
+        private boolean solveDataFlow(LIR lir) {
+
+            try (Indent indent = Debug.logAndIndent("solve data flow")) {
+
+                List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
+
+                int numIter = 0;
+
+                /*
+                 * Iterate until there are no more changes.
+                 */
+                int currentValueNum = 1;
+                boolean firstRound = true;
+                boolean changed;
+                do {
+                    changed = false;
+                    try (Indent indent2 = Debug.logAndIndent("new iteration")) {
+
+                        for (AbstractBlock<?> block : blocks) {
+
+                            BlockData data = blockData.get(block);
+                            /*
+                             * Initialize the number for global value numbering for this block. It
+                             * is essential that the starting number for a block is consistent at
+                             * all iterations and also in eliminateMoves().
+                             */
+                            if (firstRound) {
+                                data.entryValueNum = currentValueNum;
+                            }
+                            int valueNum = data.entryValueNum;
+                            assert valueNum > 0;
+                            boolean newState = false;
+
+                            if (block == blocks.get(0) || block.isExceptionEntry()) {
+                                /*
+                                 * The entry block has undefined values. And also exception handler
+                                 * blocks: the LinearScan can insert moves at the end of an
+                                 * exception handler predecessor block (after the invoke, which
+                                 * throws the exception), and in reality such moves are not in the
+                                 * control flow in case of an exception. So we assume a save default
+                                 * for exception handler blocks.
+                                 */
+                                Debug.log("kill all values at entry of block %d", block.getId());
+                                clearValues(data.entryState, valueNum);
+                            } else {
+                                /*
+                                 * Merge the states of predecessor blocks
+                                 */
+                                for (AbstractBlock<?> predecessor : block.getPredecessors()) {
+                                    BlockData predData = blockData.get(predecessor);
+                                    newState |= mergeState(data.entryState, predData.exitState, valueNum);
+                                }
+                            }
+                            // Advance by the value numbers which are "consumed" by
+                            // clearValues and mergeState
+                            valueNum += data.entryState.length;
+
+                            if (newState || firstRound) {
+                                try (Indent indent3 = Debug.logAndIndent("update block %d", block.getId())) {
+
+                                    /*
+                                     * Derive the exit state from the entry state by iterating
+                                     * through all instructions of the block.
+                                     */
+                                    int[] iterState = data.exitState;
+                                    copyState(iterState, data.entryState);
+                                    List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+
+                                    for (LIRInstruction op : instructions) {
+                                        valueNum = updateState(iterState, op, valueNum);
+                                    }
+                                    changed = true;
+                                }
+                            }
+                            if (firstRound) {
+                                currentValueNum = valueNum;
+                            }
+                        }
+                        firstRound = false;
+                    }
+                    numIter++;
+
+                    if (numIter > 5) {
+                        /*
+                         * This is _very_ seldom.
+                         */
+                        return false;
+                    }
+
+                } while (changed);
+
             }
 
-            eliminateMoves(lir);
+            return true;
         }
-    }
 
-    /**
-     * The maximum number of locations * blocks. This is a complexity limit for the inner loop in
-     * {@link #mergeState} (assuming a small number of iterations in {@link #solveDataFlow}.
-     */
-    private static final int COMPLEXITY_LIMIT = 30000;
+        /**
+         * Deletes all move instructions where the target location already contains the source
+         * value.
+         */
+        private void eliminateMoves(LIR lir) {
 
-    private void initBlockData(LIR lir) {
+            try (Indent indent = Debug.logAndIndent("eliminate moves")) {
 
-        List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
-        numRegs = 0;
+                List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
 
-        int maxStackLocations = COMPLEXITY_LIMIT / blocks.size();
+                for (AbstractBlock<?> block : blocks) {
 
-        /*
-         * Search for relevant locations which can be optimized. These are register or stack slots
-         * which occur as destinations of move instructions.
-         */
-        for (AbstractBlock<?> block : blocks) {
-            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-            for (LIRInstruction op : instructions) {
-                if (isEligibleMove(op)) {
-                    Value dest = ((MoveOp) op).getResult();
-                    if (isRegister(dest)) {
-                        int regNum = ((RegisterValue) dest).getRegister().number;
-                        if (regNum >= numRegs) {
-                            numRegs = regNum + 1;
+                    try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) {
+
+                        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                        BlockData data = blockData.get(block);
+                        boolean hasDead = false;
+
+                        // Reuse the entry state for iteration, we don't need it later.
+                        int[] iterState = data.entryState;
+
+                        // Add the values which are "consumed" by clearValues and
+                        // mergeState in solveDataFlow
+                        int valueNum = data.entryValueNum + data.entryState.length;
+
+                        int numInsts = instructions.size();
+                        for (int idx = 0; idx < numInsts; idx++) {
+                            LIRInstruction op = instructions.get(idx);
+                            if (isEligibleMove(op)) {
+                                MoveOp moveOp = (MoveOp) op;
+                                int sourceIdx = getStateIdx(moveOp.getInput());
+                                int destIdx = getStateIdx(moveOp.getResult());
+                                if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) {
+                                    assert iterState[sourceIdx] != INIT_VALUE;
+                                    Debug.log("delete move %s", op);
+                                    instructions.set(idx, null);
+                                    hasDead = true;
+                                }
+                            }
+                            // It doesn't harm if updateState is also called for a deleted move
+                            valueNum = updateState(iterState, op, valueNum);
                         }
-                    } else if (isStackSlot(dest)) {
-                        StackSlot stackSlot = (StackSlot) dest;
-                        if (!stackIndices.containsKey(stackSlot) && stackIndices.size() < maxStackLocations) {
-                            stackIndices.put(stackSlot, stackIndices.size());
+                        if (hasDead) {
+                            instructions.removeAll(Collections.singleton(null));
                         }
                     }
                 }
             }
         }
 
-        /*
-         * Now we know the number of locations to optimize, so we can allocate the block states.
+        /**
+         * Updates the state for one instruction.
          */
-        int numLocations = numRegs + stackIndices.size();
-        Debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size());
-        for (AbstractBlock<?> block : blocks) {
-            BlockData data = new BlockData(numLocations);
-            blockData.put(block, data);
-        }
-    }
+        private int updateState(final int[] state, LIRInstruction op, int initValueNum) {
 
-    /**
-     * Calculates the entry and exit states for all basic blocks.
-     *
-     * @return Returns true on success and false if the the control flow is too complex.
-     */
-    private boolean solveDataFlow(LIR lir) {
+            try (final Indent indent = Debug.logAndIndent("update state for op %s, initial value num = %d", op, initValueNum)) {
+                if (isEligibleMove(op)) {
+                    /*
+                     * Handle the special case of a move instruction
+                     */
+                    MoveOp moveOp = (MoveOp) op;
+                    int sourceIdx = getStateIdx(moveOp.getInput());
+                    int destIdx = getStateIdx(moveOp.getResult());
+                    if (sourceIdx >= 0 && destIdx >= 0) {
+                        assert isObjectValue(state[sourceIdx]) || moveOp.getInput().getLIRKind().isValue() : "move op moves object but input is not defined as object";
+                        state[destIdx] = state[sourceIdx];
+                        Debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx);
+                        return initValueNum;
+                    }
+                }
 
-        try (Indent indent = Debug.logAndIndent("solve data flow")) {
+                int valueNum = initValueNum;
 
-            List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
+                if (op.destroysCallerSavedRegisters()) {
+                    Debug.log("kill all caller save regs");
 
-            int numIter = 0;
-
-            /*
-             * Iterate until there are no more changes.
-             */
-            int currentValueNum = 1;
-            boolean firstRound = true;
-            boolean changed;
-            do {
-                changed = false;
-                try (Indent indent2 = Debug.logAndIndent("new iteration")) {
-
-                    for (AbstractBlock<?> block : blocks) {
-
-                        BlockData data = blockData.get(block);
-                        /*
-                         * Initialize the number for global value numbering for this block. It is
-                         * essential that the starting number for a block is consistent at all
-                         * iterations and also in eliminateMoves().
-                         */
-                        if (firstRound) {
-                            data.entryValueNum = currentValueNum;
-                        }
-                        int valueNum = data.entryValueNum;
-                        assert valueNum > 0;
-                        boolean newState = false;
-
-                        if (block == blocks.get(0) || block.isExceptionEntry()) {
-                            /*
-                             * The entry block has undefined values. And also exception handler
-                             * blocks: the LinearScan can insert moves at the end of an exception
-                             * handler predecessor block (after the invoke, which throws the
-                             * exception), and in reality such moves are not in the control flow in
-                             * case of an exception. So we assume a save default for exception
-                             * handler blocks.
-                             */
-                            Debug.log("kill all values at entry of block %d", block.getId());
-                            clearValues(data.entryState, valueNum);
-                        } else {
-                            /*
-                             * Merge the states of predecessor blocks
-                             */
-                            for (AbstractBlock<?> predecessor : block.getPredecessors()) {
-                                BlockData predData = blockData.get(predecessor);
-                                newState |= mergeState(data.entryState, predData.exitState, valueNum);
-                            }
-                        }
-                        // Advance by the value numbers which are "consumed" by
-                        // clearValues and mergeState
-                        valueNum += data.entryState.length;
-
-                        if (newState || firstRound) {
-                            try (Indent indent3 = Debug.logAndIndent("update block %d", block.getId())) {
-
-                                /*
-                                 * Derive the exit state from the entry state by iterating through
-                                 * all instructions of the block.
-                                 */
-                                int[] iterState = data.exitState;
-                                copyState(iterState, data.entryState);
-                                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-
-                                for (LIRInstruction op : instructions) {
-                                    valueNum = updateState(iterState, op, valueNum);
-                                }
-                                changed = true;
-                            }
-                        }
-                        if (firstRound) {
-                            currentValueNum = valueNum;
+                    for (Register reg : callerSaveRegs) {
+                        if (reg.number < numRegs) {
+                            // Kind.Object is the save default
+                            state[reg.number] = encodeValueNum(valueNum++, true);
                         }
                     }
-                    firstRound = false;
-                }
-                numIter++;
-
-                if (numIter > 5) {
-                    /*
-                     * This is _very_ seldom.
-                     */
-                    return false;
                 }
 
-            } while (changed);
+                /*
+                 * Value procedure for the instruction's output and temp values
+                 */
+                class OutputValueConsumer implements ValueConsumer {
 
+                    int opValueNum;
+
+                    OutputValueConsumer(int opValueNum) {
+                        this.opValueNum = opValueNum;
+                    }
+
+                    @Override
+                    public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        int stateIdx = getStateIdx(operand);
+                        if (stateIdx >= 0) {
+                            /*
+                             * Assign a unique number to the output or temp location.
+                             */
+                            state[stateIdx] = encodeValueNum(opValueNum++, !operand.getLIRKind().isValue());
+                            Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]);
+                        }
+                    }
+                }
+
+                OutputValueConsumer outputValueConsumer = new OutputValueConsumer(valueNum);
+
+                op.visitEachTemp(outputValueConsumer);
+                /*
+                 * Semantically the output values are written _after_ the temp values
+                 */
+                op.visitEachOutput(outputValueConsumer);
+
+                valueNum = outputValueConsumer.opValueNum;
+
+                if (op.hasState()) {
+                    /*
+                     * All instructions with framestates (mostly method calls), may do garbage
+                     * collection. GC will rewrite all object references which are live at this
+                     * point. So we can't rely on their values. It would be sufficient to just kill
+                     * all values which are referenced in the state (or all values which are not),
+                     * but for simplicity we kill all values.
+                     */
+                    Debug.log("kill all object values");
+                    clearValuesOfKindObject(state, valueNum);
+                    valueNum += state.length;
+                }
+
+                return valueNum;
+            }
         }
 
-        return true;
-    }
+        /**
+         * The state merge function for dataflow joins.
+         */
+        private static boolean mergeState(int[] dest, int[] source, int defNum) {
+            assert dest.length == source.length;
+            boolean changed = false;
+            for (int idx = 0; idx < source.length; idx++) {
+                int phiNum = defNum + idx;
+                int dst = dest[idx];
+                int src = source[idx];
+                if (dst != src && src != INIT_VALUE && dst != encodeValueNum(phiNum, isObjectValue(dst))) {
+                    if (dst != INIT_VALUE) {
+                        dst = encodeValueNum(phiNum, isObjectValue(dst) || isObjectValue(src));
+                    } else {
+                        dst = src;
+                    }
+                    dest[idx] = dst;
+                    changed = true;
+                }
+            }
+            return changed;
+        }
 
-    /**
-     * Deletes all move instructions where the target location already contains the source value.
-     */
-    private void eliminateMoves(LIR lir) {
+        private static void copyState(int[] dest, int[] source) {
+            assert dest.length == source.length;
+            for (int idx = 0; idx < source.length; idx++) {
+                dest[idx] = source[idx];
+            }
+        }
 
-        try (Indent indent = Debug.logAndIndent("eliminate moves")) {
+        private static void clearValues(int[] state, int defNum) {
+            for (int idx = 0; idx < state.length; idx++) {
+                int phiNum = defNum + idx;
+                // Let the killed values assume to be object references: it's the save default.
+                state[idx] = encodeValueNum(phiNum, true);
+            }
+        }
 
-            List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
-
-            for (AbstractBlock<?> block : blocks) {
-
-                try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) {
-
-                    List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-                    BlockData data = blockData.get(block);
-                    boolean hasDead = false;
-
-                    // Reuse the entry state for iteration, we don't need it later.
-                    int[] iterState = data.entryState;
-
-                    // Add the values which are "consumed" by clearValues and
-                    // mergeState in solveDataFlow
-                    int valueNum = data.entryValueNum + data.entryState.length;
-
-                    int numInsts = instructions.size();
-                    for (int idx = 0; idx < numInsts; idx++) {
-                        LIRInstruction op = instructions.get(idx);
-                        if (isEligibleMove(op)) {
-                            MoveOp moveOp = (MoveOp) op;
-                            int sourceIdx = getStateIdx(moveOp.getInput());
-                            int destIdx = getStateIdx(moveOp.getResult());
-                            if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) {
-                                assert iterState[sourceIdx] != INIT_VALUE;
-                                Debug.log("delete move %s", op);
-                                instructions.set(idx, null);
-                                hasDead = true;
-                            }
-                        }
-                        // It doesn't harm if updateState is also called for a deleted move
-                        valueNum = updateState(iterState, op, valueNum);
-                    }
-                    if (hasDead) {
-                        instructions.removeAll(Collections.singleton(null));
-                    }
+        private static void clearValuesOfKindObject(int[] state, int defNum) {
+            for (int idx = 0; idx < state.length; idx++) {
+                int phiNum = defNum + idx;
+                if (isObjectValue(state[idx])) {
+                    state[idx] = encodeValueNum(phiNum, true);
                 }
             }
         }
-    }
 
-    /**
-     * Updates the state for one instruction.
-     */
-    private int updateState(final int[] state, LIRInstruction op, int initValueNum) {
-
-        try (final Indent indent = Debug.logAndIndent("update state for op %s, initial value num = %d", op, initValueNum)) {
-            if (isEligibleMove(op)) {
-                /*
-                 * Handle the special case of a move instruction
-                 */
-                MoveOp moveOp = (MoveOp) op;
-                int sourceIdx = getStateIdx(moveOp.getInput());
-                int destIdx = getStateIdx(moveOp.getResult());
-                if (sourceIdx >= 0 && destIdx >= 0) {
-                    assert isObjectValue(state[sourceIdx]) || moveOp.getInput().getLIRKind().isValue() : "move op moves object but input is not defined as object";
-                    state[destIdx] = state[sourceIdx];
-                    Debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx);
-                    return initValueNum;
+        /**
+         * Returns the index to the state arrays in BlockData for a specific location.
+         */
+        private int getStateIdx(Value location) {
+            if (isRegister(location)) {
+                int regNum = ((RegisterValue) location).getRegister().number;
+                if (regNum < numRegs) {
+                    return eligibleRegs[regNum];
                 }
+                return -1;
             }
-
-            int valueNum = initValueNum;
-
-            if (op.destroysCallerSavedRegisters()) {
-                Debug.log("kill all caller save regs");
-
-                for (Register reg : callerSaveRegs) {
-                    if (reg.number < numRegs) {
-                        // Kind.Object is the save default
-                        state[reg.number] = encodeValueNum(valueNum++, true);
-                    }
+            if (isStackSlot(location)) {
+                StackSlot slot = (StackSlot) location;
+                Integer index = stackIndices.get(slot);
+                if (index != null) {
+                    return index.intValue() + numRegs;
                 }
             }
-
-            /*
-             * Value procedure for the instruction's output and temp values
-             */
-            class OutputValueConsumer implements ValueConsumer {
-
-                int opValueNum;
-
-                OutputValueConsumer(int opValueNum) {
-                    this.opValueNum = opValueNum;
-                }
-
-                @Override
-                public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    int stateIdx = getStateIdx(operand);
-                    if (stateIdx >= 0) {
-                        /*
-                         * Assign a unique number to the output or temp location.
-                         */
-                        state[stateIdx] = encodeValueNum(opValueNum++, !operand.getLIRKind().isValue());
-                        Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]);
-                    }
-                }
-            }
-
-            OutputValueConsumer outputValueConsumer = new OutputValueConsumer(valueNum);
-
-            op.visitEachTemp(outputValueConsumer);
-            /*
-             * Semantically the output values are written _after_ the temp values
-             */
-            op.visitEachOutput(outputValueConsumer);
-
-            valueNum = outputValueConsumer.opValueNum;
-
-            if (op.hasState()) {
-                /*
-                 * All instructions with framestates (mostly method calls), may do garbage
-                 * collection. GC will rewrite all object references which are live at this point.
-                 * So we can't rely on their values. It would be sufficient to just kill all values
-                 * which are referenced in the state (or all values which are not), but for
-                 * simplicity we kill all values.
-                 */
-                Debug.log("kill all object values");
-                clearValuesOfKindObject(state, valueNum);
-                valueNum += state.length;
-            }
-
-            return valueNum;
-        }
-    }
-
-    /**
-     * The state merge function for dataflow joins.
-     */
-    private static boolean mergeState(int[] dest, int[] source, int defNum) {
-        assert dest.length == source.length;
-        boolean changed = false;
-        for (int idx = 0; idx < source.length; idx++) {
-            int phiNum = defNum + idx;
-            int dst = dest[idx];
-            int src = source[idx];
-            if (dst != src && src != INIT_VALUE && dst != encodeValueNum(phiNum, isObjectValue(dst))) {
-                if (dst != INIT_VALUE) {
-                    dst = encodeValueNum(phiNum, isObjectValue(dst) || isObjectValue(src));
-                } else {
-                    dst = src;
-                }
-                dest[idx] = dst;
-                changed = true;
-            }
-        }
-        return changed;
-    }
-
-    private static void copyState(int[] dest, int[] source) {
-        assert dest.length == source.length;
-        for (int idx = 0; idx < source.length; idx++) {
-            dest[idx] = source[idx];
-        }
-    }
-
-    private static void clearValues(int[] state, int defNum) {
-        for (int idx = 0; idx < state.length; idx++) {
-            int phiNum = defNum + idx;
-            // Let the killed values assume to be object references: it's the save default.
-            state[idx] = encodeValueNum(phiNum, true);
-        }
-    }
-
-    private static void clearValuesOfKindObject(int[] state, int defNum) {
-        for (int idx = 0; idx < state.length; idx++) {
-            int phiNum = defNum + idx;
-            if (isObjectValue(state[idx])) {
-                state[idx] = encodeValueNum(phiNum, true);
-            }
-        }
-    }
-
-    /**
-     * Returns the index to the state arrays in BlockData for a specific location.
-     */
-    private int getStateIdx(Value location) {
-        if (isRegister(location)) {
-            int regNum = ((RegisterValue) location).getRegister().number;
-            if (regNum < numRegs) {
-                return eligibleRegs[regNum];
-            }
             return -1;
         }
-        if (isStackSlot(location)) {
-            StackSlot slot = (StackSlot) location;
-            Integer index = stackIndices.get(slot);
-            if (index != null) {
-                return index.intValue() + numRegs;
+
+        /**
+         * Encodes a value number + the is-object information to a number to be stored in a state.
+         */
+        private static int encodeValueNum(int valueNum, boolean isObjectKind) {
+            assert valueNum > 0;
+            if (isObjectKind) {
+                return -valueNum;
             }
+            return valueNum;
         }
-        return -1;
-    }
 
-    /**
-     * Encodes a value number + the is-object information to a number to be stored in a state.
-     */
-    private static int encodeValueNum(int valueNum, boolean isObjectKind) {
-        assert valueNum > 0;
-        if (isObjectKind) {
-            return -valueNum;
+        /**
+         * Returns true if an encoded value number (which is stored in a state) refers to an object
+         * reference.
+         */
+        private static boolean isObjectValue(int encodedValueNum) {
+            return encodedValueNum < 0;
         }
-        return valueNum;
-    }
 
-    /**
-     * Returns true if an encoded value number (which is stored in a state) refers to an object
-     * reference.
-     */
-    private static boolean isObjectValue(int encodedValueNum) {
-        return encodedValueNum < 0;
-    }
-
-    /**
-     * Returns true for a move instruction which is a candidate for elimination.
-     */
-    private static boolean isEligibleMove(LIRInstruction op) {
-        if (op instanceof MoveOp) {
-            MoveOp moveOp = (MoveOp) op;
-            Value source = moveOp.getInput();
-            Value dest = moveOp.getResult();
-            /*
-             * Moves with mismatching kinds are not moves, but memory loads/stores!
-             */
-            return source.getLIRKind().equals(dest.getLIRKind());
+        /**
+         * Returns true for a move instruction which is a candidate for elimination.
+         */
+        private static boolean isEligibleMove(LIRInstruction op) {
+            if (op instanceof MoveOp) {
+                MoveOp moveOp = (MoveOp) op;
+                Value source = moveOp.getInput();
+                Value dest = moveOp.getResult();
+                /*
+                 * Moves with mismatching kinds are not moves, but memory loads/stores!
+                 */
+                return source.getLIRKind().equals(dest.getLIRKind());
+            }
+            return false;
         }
-        return false;
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Tue Feb 10 20:44:08 2015 +0100
@@ -56,7 +56,7 @@
  * >"Optimized Interval Splitting in a Linear Scan Register Allocator"</a> by Christian Wimmer and
  * Hanspeter Moessenboeck.
  */
-public final class LinearScan {
+final class LinearScan {
 
     final TargetDescription target;
     final LIRGenerationResult res;
@@ -109,7 +109,7 @@
         public BitSet liveKill;
     }
 
-    public final BlockMap<BlockData> blockData;
+    final BlockMap<BlockData> blockData;
 
     /**
      * List of blocks in linear-scan order. This is only correct as long as the CFG does not change.
@@ -161,7 +161,7 @@
      */
     private final int firstVariableNumber;
 
-    public LinearScan(TargetDescription target, LIRGenerationResult res) {
+    LinearScan(TargetDescription target, LIRGenerationResult res) {
         this.target = target;
         this.res = res;
         this.ir = res.getLIR();
@@ -178,13 +178,13 @@
         this.callKillsRegisters = this.frameMapBuilder.getRegisterConfig().areAllAllocatableRegistersCallerSaved();
     }
 
-    public int getFirstLirInstructionId(AbstractBlock<?> block) {
+    int getFirstLirInstructionId(AbstractBlock<?> block) {
         int result = ir.getLIRforBlock(block).get(0).id();
         assert result >= 0;
         return result;
     }
 
-    public int getLastLirInstructionId(AbstractBlock<?> block) {
+    int getLastLirInstructionId(AbstractBlock<?> block) {
         List<LIRInstruction> instructions = ir.getLIRforBlock(block);
         int result = instructions.get(instructions.size() - 1).id();
         assert result >= 0;
@@ -220,7 +220,7 @@
     /**
      * Gets the highest operand number for a register operand. This value will never change.
      */
-    public int maxRegisterNumber() {
+    int maxRegisterNumber() {
         return firstVariableNumber - 1;
     }
 
@@ -1374,7 +1374,7 @@
         sortedIntervals = combinedList;
     }
 
-    public void allocateRegisters() {
+    void allocateRegisters() {
         try (Indent indent = Debug.logAndIndent("allocate registers")) {
             Interval precoloredIntervals;
             Interval notPrecoloredIntervals;
@@ -1731,11 +1731,7 @@
         }
     }
 
-    public static void allocate(TargetDescription target, LIRGenerationResult res) {
-        new LinearScan(target, res).allocate();
-    }
-
-    private void allocate() {
+    void allocate() {
 
         /*
          * This is the point to enable debug logging for the whole register allocation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Tue Feb 10 20:44:08 2015 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.alloc.lsra;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
+
+public final class LinearScanPhase extends LowLevelMidTierPhase {
+
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        new LinearScan(target, lirGenRes).allocate();
+    }
+
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Tue Feb 10 20:44:08 2015 +0100
@@ -34,9 +34,15 @@
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 
-public final class LocationMarker {
+/**
+ * Mark all live references for a frame state. The frame state use this information to build the OOP
+ * maps.
+ */
+public final class LocationMarker extends LowLevelMidTierPhase {
 
     public static class Options {
         // @formatter:off
@@ -45,177 +51,177 @@
         // @formatter:on
     }
 
-    /**
-     * Mark all live references for a frame state. The frame state use this information to build the
-     * OOP maps.
-     */
-    public static void markLocations(LIR lir, FrameMap frameMap) {
-        new LocationMarker(lir, frameMap).build();
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        new Marker(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build();
     }
 
-    private final LIR lir;
-    private final FrameMap frameMap;
-    private final RegisterAttributes[] registerAttributes;
-    private final BlockMap<ReferenceMap> liveInMap;
-    private final BlockMap<ReferenceMap> liveOutMap;
+    private static final class Marker {
+        private final LIR lir;
+        private final FrameMap frameMap;
+        private final RegisterAttributes[] registerAttributes;
+        private final BlockMap<ReferenceMap> liveInMap;
+        private final BlockMap<ReferenceMap> liveOutMap;
 
-    private LocationMarker(LIR lir, FrameMap frameMap) {
-        this.lir = lir;
-        this.frameMap = frameMap;
-        this.registerAttributes = frameMap.getRegisterConfig().getAttributesMap();
-        liveInMap = new BlockMap<>(lir.getControlFlowGraph());
-        liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
-    }
+        private Marker(LIR lir, FrameMap frameMap) {
+            this.lir = lir;
+            this.frameMap = frameMap;
+            this.registerAttributes = frameMap.getRegisterConfig().getAttributesMap();
+            liveInMap = new BlockMap<>(lir.getControlFlowGraph());
+            liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
+        }
 
-    private void build() {
-        Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
-        for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
-            worklist.add(lir.getControlFlowGraph().getBlocks().get(i));
-        }
-        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
-            liveInMap.put(block, frameMap.initReferenceMap(true));
-        }
-        while (!worklist.isEmpty()) {
-            AbstractBlock<?> block = worklist.poll();
-            processBlock(block, worklist);
-        }
-        // finish states
-        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
-            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-            for (int i = instructions.size() - 1; i >= 0; i--) {
-                LIRInstruction inst = instructions.get(i);
-                inst.forEachState((op, info) -> info.finish(op, frameMap));
+        private void build() {
+            Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+            for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
+                worklist.add(lir.getControlFlowGraph().getBlocks().get(i));
             }
-
-        }
-    }
-
-    /**
-     * Merge outSet with in-set of successors.
-     */
-    private boolean updateOutBlock(AbstractBlock<?> block) {
-        ReferenceMap union = frameMap.initReferenceMap(true);
-        block.getSuccessors().forEach(succ -> union.updateUnion(liveInMap.get(succ)));
-        ReferenceMap outSet = liveOutMap.get(block);
-        // check if changed
-        if (outSet == null || !union.equals(outSet)) {
-            liveOutMap.put(block, union);
-            return true;
-        }
-        return false;
-    }
-
-    private void processBlock(AbstractBlock<?> block, Deque<AbstractBlock<?>> worklist) {
-        if (updateOutBlock(block)) {
-            try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
-                BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone());
+            for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+                liveInMap.put(block, frameMap.initReferenceMap(true));
+            }
+            while (!worklist.isEmpty()) {
+                AbstractBlock<?> block = worklist.poll();
+                processBlock(block, worklist);
+            }
+            // finish states
+            for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
                 List<LIRInstruction> instructions = lir.getLIRforBlock(block);
                 for (int i = instructions.size() - 1; i >= 0; i--) {
                     LIRInstruction inst = instructions.get(i);
-                    closure.processInstructionBottomUp(inst);
+                    inst.forEachState((op, info) -> info.finish(op, frameMap));
                 }
-                liveInMap.put(block, closure.getCurrentSet());
-                worklist.addAll(block.getPredecessors());
-            }
-        }
-    }
 
-    private static final EnumSet<OperandFlag> REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG);
-    private static final LIRKind REFERENCE_KIND = LIRKind.reference(Kind.Object);
-
-    private void forEachDestroyedCallerSavedRegister(LIRInstruction op, ValueConsumer consumer) {
-        if (op.destroysCallerSavedRegisters()) {
-            for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
-                consumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET);
-            }
-        }
-    }
-
-    private final class BlockClosure {
-        private final ReferenceMap currentSet;
-
-        private BlockClosure(ReferenceMap set) {
-            currentSet = set;
-        }
-
-        private ReferenceMap getCurrentSet() {
-            return currentSet;
-        }
-
-        /**
-         * Process all values of an instruction bottom-up, i.e. definitions before usages. Values
-         * that start or end at the current operation are not included.
-         */
-        private void processInstructionBottomUp(LIRInstruction op) {
-            try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
-                // kills
-                op.visitEachTemp(this::defConsumer);
-                op.visitEachOutput(this::defConsumer);
-                forEachDestroyedCallerSavedRegister(op, this::defConsumer);
-
-                // gen - values that are considered alive for this state
-                op.visitEachAlive(this::useConsumer);
-                op.visitEachState(this::useConsumer);
-                // mark locations
-                op.forEachState((inst, info) -> markLocation(inst, info, this.getCurrentSet()));
-                // gen
-                op.visitEachInput(this::useConsumer);
             }
         }
 
         /**
-         * @see InstructionValueConsumer
-         * @param operand
-         * @param mode
-         * @param flags
+         * Merge outSet with in-set of successors.
          */
-        private void useConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-            LIRKind kind = operand.getLIRKind();
-            if (shouldProcessValue(operand) && !kind.isValue() && !kind.isDerivedReference()) {
-                // no need to insert values and derived reference
-                Debug.log("set operand: %s", operand);
-                frameMap.setReference(operand, currentSet);
+        private boolean updateOutBlock(AbstractBlock<?> block) {
+            ReferenceMap union = frameMap.initReferenceMap(true);
+            block.getSuccessors().forEach(succ -> union.updateUnion(liveInMap.get(succ)));
+            ReferenceMap outSet = liveOutMap.get(block);
+            // check if changed
+            if (outSet == null || !union.equals(outSet)) {
+                liveOutMap.put(block, union);
+                return true;
+            }
+            return false;
+        }
+
+        private void processBlock(AbstractBlock<?> block, Deque<AbstractBlock<?>> worklist) {
+            if (updateOutBlock(block)) {
+                try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
+                    BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone());
+                    List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                    for (int i = instructions.size() - 1; i >= 0; i--) {
+                        LIRInstruction inst = instructions.get(i);
+                        closure.processInstructionBottomUp(inst);
+                    }
+                    liveInMap.put(block, closure.getCurrentSet());
+                    worklist.addAll(block.getPredecessors());
+                }
+            }
+        }
+
+        private static final EnumSet<OperandFlag> REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG);
+        private static final LIRKind REFERENCE_KIND = LIRKind.reference(Kind.Object);
+
+        private void forEachDestroyedCallerSavedRegister(LIRInstruction op, ValueConsumer consumer) {
+            if (op.destroysCallerSavedRegisters()) {
+                for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
+                    consumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET);
+                }
+            }
+        }
+
+        private final class BlockClosure {
+            private final ReferenceMap currentSet;
+
+            private BlockClosure(ReferenceMap set) {
+                currentSet = set;
+            }
+
+            private ReferenceMap getCurrentSet() {
+                return currentSet;
+            }
+
+            /**
+             * Process all values of an instruction bottom-up, i.e. definitions before usages.
+             * Values that start or end at the current operation are not included.
+             */
+            private void processInstructionBottomUp(LIRInstruction op) {
+                try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
+                    // kills
+                    op.visitEachTemp(this::defConsumer);
+                    op.visitEachOutput(this::defConsumer);
+                    forEachDestroyedCallerSavedRegister(op, this::defConsumer);
+
+                    // gen - values that are considered alive for this state
+                    op.visitEachAlive(this::useConsumer);
+                    op.visitEachState(this::useConsumer);
+                    // mark locations
+                    op.forEachState((inst, info) -> markLocation(inst, info, this.getCurrentSet()));
+                    // gen
+                    op.visitEachInput(this::useConsumer);
+                }
+            }
+
+            /**
+             * @see InstructionValueConsumer
+             * @param operand
+             * @param mode
+             * @param flags
+             */
+            private void useConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                LIRKind kind = operand.getLIRKind();
+                if (shouldProcessValue(operand) && !kind.isValue() && !kind.isDerivedReference()) {
+                    // no need to insert values and derived reference
+                    Debug.log("set operand: %s", operand);
+                    frameMap.setReference(operand, currentSet);
+                }
+            }
+
+            /**
+             * @see InstructionValueConsumer
+             * @param operand
+             * @param mode
+             * @param flags
+             */
+            private void defConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (shouldProcessValue(operand)) {
+                    Debug.log("clear operand: %s", operand);
+                    frameMap.clearReference(operand, currentSet);
+                } else {
+                    assert isIllegal(operand) || operand.getPlatformKind() != Kind.Illegal || mode == OperandMode.TEMP : String.format("Illegal PlatformKind is only allowed for TEMP mode: %s, %s",
+                                    operand, mode);
+                }
+            }
+
+            protected boolean shouldProcessValue(Value operand) {
+                return (isRegister(operand) && attributes(asRegister(operand)).isAllocatable() || isStackSlot(operand)) && operand.getPlatformKind() != Kind.Illegal;
             }
         }
 
         /**
-         * @see InstructionValueConsumer
-         * @param operand
-         * @param mode
-         * @param flags
+         * This method does the actual marking.
          */
-        private void defConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-            if (shouldProcessValue(operand)) {
-                Debug.log("clear operand: %s", operand);
-                frameMap.clearReference(operand, currentSet);
-            } else {
-                assert isIllegal(operand) || operand.getPlatformKind() != Kind.Illegal || mode == OperandMode.TEMP : String.format("Illegal PlatformKind is only allowed for TEMP mode: %s, %s",
-                                operand, mode);
+        private void markLocation(LIRInstruction op, LIRFrameState info, ReferenceMap refMap) {
+            if (!info.hasDebugInfo()) {
+                info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !frameMap.getRegisterConfig().areAllAllocatableRegistersCallerSaved());
             }
+            info.updateUnion(refMap);
         }
 
-        protected boolean shouldProcessValue(Value operand) {
-            return (isRegister(operand) && attributes(asRegister(operand)).isAllocatable() || isStackSlot(operand)) && operand.getPlatformKind() != Kind.Illegal;
+        /**
+         * Gets an object describing the attributes of a given register according to this register
+         * configuration.
+         *
+         * @see LinearScan#attributes
+         */
+        private RegisterAttributes attributes(Register reg) {
+            return registerAttributes[reg.number];
         }
-    }
 
-    /**
-     * This method does the actual marking.
-     */
-    private void markLocation(LIRInstruction op, LIRFrameState info, ReferenceMap refMap) {
-        if (!info.hasDebugInfo()) {
-            info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !frameMap.getRegisterConfig().areAllAllocatableRegistersCallerSaved());
-        }
-        info.updateUnion(refMap);
-    }
-
-    /**
-     * Gets an object describing the attributes of a given register according to this register
-     * configuration.
-     *
-     * @see LinearScan#attributes
-     */
-    private RegisterAttributes attributes(Register reg) {
-        return registerAttributes[reg.number];
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Tue Feb 10 20:44:08 2015 +0100
@@ -27,6 +27,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
@@ -38,6 +39,7 @@
 import com.oracle.graal.lir.constopt.ConstantTree.Flags;
 import com.oracle.graal.lir.constopt.ConstantTree.NodeCost;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 
 /**
@@ -45,7 +47,7 @@
  * a constant, which is potentially scheduled into a block with high probability, with one or more
  * definitions in blocks with a lower probability.
  */
-public final class ConstantLoadOptimization {
+public final class ConstantLoadOptimization extends LowLevelHighTierPhase {
 
     public static class Options {
         // @formatter:off
@@ -54,18 +56,11 @@
         // @formatter:on
     }
 
-    public static void optimize(LIR lir, LIRGeneratorTool lirGen) {
-        new ConstantLoadOptimization(lir, lirGen).apply();
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen) {
+        new Optimization(lirGenRes.getLIR(), lirGen).apply();
     }
 
-    private LIR lir;
-    private LIRGeneratorTool lirGen;
-    private VariableMap<DefUseTree> map;
-    private BitSet phiConstants;
-    private BitSet defined;
-    private BlockMap<List<UseEntry>> blockMap;
-    private BlockMap<LIRInsertionBuffer> insertionBuffers;
-
     private static final DebugMetric constantsTotal = Debug.metric("ConstantLoadOptimization[total]");
     private static final DebugMetric phiConstantsSkipped = Debug.metric("ConstantLoadOptimization[PhisSkipped]");
     private static final DebugMetric singleUsageConstantsSkipped = Debug.metric("ConstantLoadOptimization[SingleUsageSkipped]");
@@ -73,275 +68,285 @@
     private static final DebugMetric materializeAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[MaterializeAtDefinitionSkipped]");
     private static final DebugMetric constantsOptimized = Debug.metric("ConstantLoadOptimization[optimized]");
 
-    private ConstantLoadOptimization(LIR lir, LIRGeneratorTool lirGen) {
-        this.lir = lir;
-        this.lirGen = lirGen;
-        this.map = new VariableMap<>();
-        this.phiConstants = new BitSet();
-        this.defined = new BitSet();
-        this.insertionBuffers = new BlockMap<>(lir.getControlFlowGraph());
-        this.blockMap = new BlockMap<>(lir.getControlFlowGraph());
-    }
+    private static final class Optimization {
+        private final LIR lir;
+        private final LIRGeneratorTool lirGen;
+        private final VariableMap<DefUseTree> map;
+        private final BitSet phiConstants;
+        private final BitSet defined;
+        private final BlockMap<List<UseEntry>> blockMap;
+        private final BlockMap<LIRInsertionBuffer> insertionBuffers;
 
-    private void apply() {
-        try (Indent indent = Debug.logAndIndent("ConstantLoadOptimization")) {
-            try (Scope s = Debug.scope("BuildDefUseTree")) {
-                // build DefUseTree
-                lir.getControlFlowGraph().getBlocks().forEach(this::analyzeBlock);
-                // remove all with only one use
-                map.filter(t -> {
-                    if (t.usageCount() > 1) {
-                        return true;
-                    } else {
-                        singleUsageConstantsSkipped.increment();
-                        return false;
+        private Optimization(LIR lir, LIRGeneratorTool lirGen) {
+            this.lir = lir;
+            this.lirGen = lirGen;
+            this.map = new VariableMap<>();
+            this.phiConstants = new BitSet();
+            this.defined = new BitSet();
+            this.insertionBuffers = new BlockMap<>(lir.getControlFlowGraph());
+            this.blockMap = new BlockMap<>(lir.getControlFlowGraph());
+        }
+
+        private void apply() {
+            try (Indent indent = Debug.logAndIndent("ConstantLoadOptimization")) {
+                try (Scope s = Debug.scope("BuildDefUseTree")) {
+                    // build DefUseTree
+                    lir.getControlFlowGraph().getBlocks().forEach(this::analyzeBlock);
+                    // remove all with only one use
+                    map.filter(t -> {
+                        if (t.usageCount() > 1) {
+                            return true;
+                        } else {
+                            singleUsageConstantsSkipped.increment();
+                            return false;
+                        }
+                    });
+                    // collect block map
+                    map.forEach(tree -> tree.forEach(this::addUsageToBlockMap));
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+
+                try (Scope s = Debug.scope("BuildConstantTree")) {
+                    // create ConstantTree
+                    map.forEach(this::createConstantTree);
+
+                    // insert moves, delete null instructions and reset instruction ids
+                    lir.getControlFlowGraph().getBlocks().forEach(this::rewriteBlock);
+
+                    assert verifyStates();
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+            }
+        }
+
+        private boolean verifyStates() {
+            map.forEach(this::verifyStateUsage);
+            return true;
+        }
+
+        private void verifyStateUsage(DefUseTree tree) {
+            Variable var = tree.getVariable();
+            ValueConsumer stateConsumer = new ValueConsumer() {
+
+                @Override
+                public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    assert !operand.equals(var) : "constant usage through variable in frame state " + var;
+                }
+            };
+            for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+                for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                    // set instruction id to the index in the lir instruction list
+                    inst.visitEachState(stateConsumer);
+                }
+            }
+        }
+
+        private static boolean isConstantLoad(LIRInstruction inst) {
+            if (!(inst instanceof MoveOp)) {
+                return false;
+            }
+            MoveOp move = (MoveOp) inst;
+            return isConstant(move.getInput()) && isVariable(move.getResult());
+        }
+
+        private void addUsageToBlockMap(UseEntry entry) {
+            AbstractBlock<?> block = entry.getBlock();
+            List<UseEntry> list = blockMap.get(block);
+            if (list == null) {
+                list = new ArrayList<>();
+                blockMap.put(block, list);
+            }
+            list.add(entry);
+        }
+
+        /**
+         * Collects def-use information for a {@code block}.
+         */
+        private void analyzeBlock(AbstractBlock<?> block) {
+            try (Indent indent = Debug.logAndIndent("Block: %s", block)) {
+
+                InstructionValueConsumer loadConsumer = (instruction, value, mode, flags) -> {
+                    if (isVariable(value)) {
+                        Variable var = (Variable) value;
+
+                        if (!phiConstants.get(var.index)) {
+                            if (!defined.get(var.index)) {
+                                defined.set(var.index);
+                                if (isConstantLoad(instruction)) {
+                                    Debug.log("constant load: %s", instruction);
+                                    map.put(var, new DefUseTree(instruction, block));
+                                    constantsTotal.increment();
+                                }
+                            } else {
+                                // Variable is redefined, this only happens for constant loads
+                                // introduced by phi resolution -> ignore.
+                                DefUseTree removed = map.remove(var);
+                                if (removed != null) {
+                                    phiConstantsSkipped.increment();
+                                }
+                                phiConstants.set(var.index);
+                                Debug.log(3, "Removing phi variable: %s", var);
+                            }
+                        } else {
+                            assert defined.get(var.index) : "phi but not defined? " + var;
+                        }
                     }
-                });
-                // collect block map
-                map.forEach(tree -> tree.forEach(this::addUsageToBlockMap));
-            } catch (Throwable e) {
-                throw Debug.handle(e);
+                };
+
+                ValuePositionProcedure useProcedure = (instruction, position) -> {
+                    Value value = position.get(instruction);
+                    if (isVariable(value)) {
+                        Variable var = (Variable) value;
+                        if (!phiConstants.get(var.index)) {
+                            DefUseTree tree = map.get(var);
+                            if (tree != null) {
+                                tree.addUsage(block, instruction, position);
+                                Debug.log("usage of %s : %s", var, instruction);
+                            }
+                        }
+                    }
+                };
+
+                int opId = 0;
+                for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                    // set instruction id to the index in the lir instruction list
+                    inst.setId(opId++);
+                    inst.visitEachOutput(loadConsumer);
+                    inst.forEachInputPos(useProcedure);
+                    inst.forEachAlivePos(useProcedure);
+
+                }
+            }
+        }
+
+        /**
+         * Creates the dominator tree and searches for an solution.
+         */
+        private void createConstantTree(DefUseTree tree) {
+            ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree);
+            constTree.set(Flags.SUBTREE, tree.getBlock());
+            tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock()));
+
+            if (constTree.get(Flags.USAGE, tree.getBlock())) {
+                // usage in the definition block -> no optimization
+                usageAtDefinitionSkipped.increment();
+                return;
             }
 
-            try (Scope s = Debug.scope("BuildConstantTree")) {
-                // create ConstantTree
-                map.forEach(this::createConstantTree);
+            constTree.markBlocks();
 
-                // insert moves, delete null instructions and reset instruction ids
-                lir.getControlFlowGraph().getBlocks().forEach(this::rewriteBlock);
+            NodeCost cost = ConstantTreeAnalyzer.analyze(constTree, tree.getBlock());
+            int usageCount = cost.getUsages().size();
+            assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount();
 
-                assert verifyStates();
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-        }
-    }
-
-    private boolean verifyStates() {
-        map.forEach(this::verifyStateUsage);
-        return true;
-    }
-
-    private void verifyStateUsage(DefUseTree tree) {
-        Variable var = tree.getVariable();
-        ValueConsumer stateConsumer = new ValueConsumer() {
-
-            @Override
-            public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                assert !operand.equals(var) : "constant usage through variable in frame state " + var;
-            }
-        };
-        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
-            for (LIRInstruction inst : lir.getLIRforBlock(block)) {
-                // set instruction id to the index in the lir instruction list
-                inst.visitEachState(stateConsumer);
-            }
-        }
-    }
-
-    private static boolean isConstantLoad(LIRInstruction inst) {
-        if (!(inst instanceof MoveOp)) {
-            return false;
-        }
-        MoveOp move = (MoveOp) inst;
-        return isConstant(move.getInput()) && isVariable(move.getResult());
-    }
-
-    private void addUsageToBlockMap(UseEntry entry) {
-        AbstractBlock<?> block = entry.getBlock();
-        List<UseEntry> list = blockMap.get(block);
-        if (list == null) {
-            list = new ArrayList<>();
-            blockMap.put(block, list);
-        }
-        list.add(entry);
-    }
-
-    /**
-     * Collects def-use information for a {@code block}.
-     */
-    private void analyzeBlock(AbstractBlock<?> block) {
-        try (Indent indent = Debug.logAndIndent("Block: %s", block)) {
-
-            InstructionValueConsumer loadConsumer = (instruction, value, mode, flags) -> {
-                if (isVariable(value)) {
-                    Variable var = (Variable) value;
-
-                    if (!phiConstants.get(var.index)) {
-                        if (!defined.get(var.index)) {
-                            defined.set(var.index);
-                            if (isConstantLoad(instruction)) {
-                                Debug.log("constant load: %s", instruction);
-                                map.put(var, new DefUseTree(instruction, block));
-                                constantsTotal.increment();
-                            }
-                        } else {
-                            // Variable is redefined, this only happens for constant loads
-                            // introduced by phi resolution -> ignore.
-                            DefUseTree removed = map.remove(var);
-                            if (removed != null) {
-                                phiConstantsSkipped.increment();
-                            }
-                            phiConstants.set(var.index);
-                            Debug.log(3, "Removing phi variable: %s", var);
-                        }
-                    } else {
-                        assert defined.get(var.index) : "phi but not defined? " + var;
-                    }
+            if (Debug.isLogEnabled()) {
+                try (Indent i = Debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) {
+                    Debug.log("Usages result: %s", cost);
                 }
-            };
-
-            ValuePositionProcedure useProcedure = (instruction, position) -> {
-                Value value = position.get(instruction);
-                if (isVariable(value)) {
-                    Variable var = (Variable) value;
-                    if (!phiConstants.get(var.index)) {
-                        DefUseTree tree = map.get(var);
-                        if (tree != null) {
-                            tree.addUsage(block, instruction, position);
-                            Debug.log("usage of %s : %s", var, instruction);
-                        }
-                    }
-                }
-            };
-
-            int opId = 0;
-            for (LIRInstruction inst : lir.getLIRforBlock(block)) {
-                // set instruction id to the index in the lir instruction list
-                inst.setId(opId++);
-                inst.visitEachOutput(loadConsumer);
-                inst.forEachInputPos(useProcedure);
-                inst.forEachAlivePos(useProcedure);
 
             }
-        }
-    }
 
-    /**
-     * Creates the dominator tree and searches for an solution.
-     */
-    private void createConstantTree(DefUseTree tree) {
-        ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree);
-        constTree.set(Flags.SUBTREE, tree.getBlock());
-        tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock()));
+            if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) {
+                try (Scope s = Debug.scope("CLOmodify", constTree); Indent i = Debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) {
+                    // mark original load for removal
+                    deleteInstruction(tree);
+                    constantsOptimized.increment();
 
-        if (constTree.get(Flags.USAGE, tree.getBlock())) {
-            // usage in the definition block -> no optimization
-            usageAtDefinitionSkipped.increment();
-            return;
+                    // collect result
+                    createLoads(tree, constTree, tree.getBlock());
+
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+            } else {
+                // no better solution found
+                materializeAtDefinitionSkipped.increment();
+            }
+            Debug.dump(constTree, "ConstantTree for " + tree.getVariable());
         }
 
-        constTree.markBlocks();
-
-        NodeCost cost = ConstantTreeAnalyzer.analyze(constTree, tree.getBlock());
-        int usageCount = cost.getUsages().size();
-        assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount();
-
-        if (Debug.isLogEnabled()) {
-            try (Indent i = Debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) {
-                Debug.log("Usages result: %s", cost);
-            }
-
-        }
-
-        if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) {
-            try (Scope s = Debug.scope("CLOmodify", constTree); Indent i = Debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) {
-                // mark original load for removal
-                deleteInstruction(tree);
-                constantsOptimized.increment();
-
-                // collect result
-                createLoads(tree, constTree, tree.getBlock());
-
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-        } else {
-            // no better solution found
-            materializeAtDefinitionSkipped.increment();
-        }
-        Debug.dump(constTree, "ConstantTree for " + tree.getVariable());
-    }
-
-    private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlock<?> startBlock) {
-        Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
-        worklist.add(startBlock);
-        while (!worklist.isEmpty()) {
-            AbstractBlock<?> block = worklist.pollLast();
-            if (constTree.get(Flags.CANDIDATE, block)) {
-                constTree.set(Flags.MATERIALIZE, block);
-                // create and insert load
-                insertLoad(tree.getConstant(), tree.getVariable().getLIRKind(), block, constTree.getCost(block).getUsages());
-            } else {
-                for (AbstractBlock<?> dominated : block.getDominated()) {
-                    if (constTree.isMarked(dominated)) {
-                        worklist.addLast(dominated);
+        private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlock<?> startBlock) {
+            Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+            worklist.add(startBlock);
+            while (!worklist.isEmpty()) {
+                AbstractBlock<?> block = worklist.pollLast();
+                if (constTree.get(Flags.CANDIDATE, block)) {
+                    constTree.set(Flags.MATERIALIZE, block);
+                    // create and insert load
+                    insertLoad(tree.getConstant(), tree.getVariable().getLIRKind(), block, constTree.getCost(block).getUsages());
+                } else {
+                    for (AbstractBlock<?> dominated : block.getDominated()) {
+                        if (constTree.isMarked(dominated)) {
+                            worklist.addLast(dominated);
+                        }
                     }
                 }
             }
         }
-    }
 
-    private void insertLoad(JavaConstant constant, LIRKind kind, AbstractBlock<?> block, List<UseEntry> usages) {
-        assert usages != null && usages.size() > 0 : String.format("No usages %s %s %s", constant, block, usages);
-        // create variable
-        Variable variable = lirGen.newVariable(kind);
-        // create move
-        LIRInstruction move = lir.getSpillMoveFactory().createMove(variable, constant);
-        // insert instruction
-        getInsertionBuffer(block).append(1, move);
-        Debug.log("new move (%s) and inserted in block %s", move, block);
-        // update usages
-        for (UseEntry u : usages) {
-            u.getPosition().set(u.getInstruction(), variable);
-            Debug.log("patched instruction %s", u.getInstruction());
+        private void insertLoad(JavaConstant constant, LIRKind kind, AbstractBlock<?> block, List<UseEntry> usages) {
+            assert usages != null && usages.size() > 0 : String.format("No usages %s %s %s", constant, block, usages);
+            // create variable
+            Variable variable = lirGen.newVariable(kind);
+            // create move
+            LIRInstruction move = lir.getSpillMoveFactory().createMove(variable, constant);
+            // insert instruction
+            getInsertionBuffer(block).append(1, move);
+            Debug.log("new move (%s) and inserted in block %s", move, block);
+            // update usages
+            for (UseEntry u : usages) {
+                u.getPosition().set(u.getInstruction(), variable);
+                Debug.log("patched instruction %s", u.getInstruction());
+            }
+        }
+
+        /**
+         * Inserts the constant loads created in {@link #createConstantTree} and deletes the
+         * original definition.
+         */
+        private void rewriteBlock(AbstractBlock<?> block) {
+            // insert moves
+            LIRInsertionBuffer buffer = insertionBuffers.get(block);
+            if (buffer != null) {
+                assert buffer.initialized() : "not initialized?";
+                buffer.finish();
+            }
+
+            // delete instructions
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            boolean hasDead = false;
+            for (LIRInstruction inst : instructions) {
+                if (inst == null) {
+                    hasDead = true;
+                } else {
+                    inst.setId(-1);
+                }
+            }
+            if (hasDead) {
+                // Remove null values from the list.
+                instructions.removeAll(Collections.singleton(null));
+            }
+        }
+
+        private void deleteInstruction(DefUseTree tree) {
+            AbstractBlock<?> block = tree.getBlock();
+            LIRInstruction instruction = tree.getInstruction();
+            Debug.log("deleting instruction %s from block %s", instruction, block);
+            lir.getLIRforBlock(block).set(instruction.id(), null);
+        }
+
+        private LIRInsertionBuffer getInsertionBuffer(AbstractBlock<?> block) {
+            LIRInsertionBuffer insertionBuffer = insertionBuffers.get(block);
+            if (insertionBuffer == null) {
+                insertionBuffer = new LIRInsertionBuffer();
+                insertionBuffers.put(block, insertionBuffer);
+                assert !insertionBuffer.initialized() : "already initialized?";
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                insertionBuffer.init(instructions);
+            }
+            return insertionBuffer;
         }
     }
-
-    /**
-     * Inserts the constant loads created in {@link #createConstantTree} and deletes the original
-     * definition.
-     */
-    private void rewriteBlock(AbstractBlock<?> block) {
-        // insert moves
-        LIRInsertionBuffer buffer = insertionBuffers.get(block);
-        if (buffer != null) {
-            assert buffer.initialized() : "not initialized?";
-            buffer.finish();
-        }
-
-        // delete instructions
-        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-        boolean hasDead = false;
-        for (LIRInstruction inst : instructions) {
-            if (inst == null) {
-                hasDead = true;
-            } else {
-                inst.setId(-1);
-            }
-        }
-        if (hasDead) {
-            // Remove null values from the list.
-            instructions.removeAll(Collections.singleton(null));
-        }
-    }
-
-    private void deleteInstruction(DefUseTree tree) {
-        AbstractBlock<?> block = tree.getBlock();
-        LIRInstruction instruction = tree.getInstruction();
-        Debug.log("deleting instruction %s from block %s", instruction, block);
-        lir.getLIRforBlock(block).set(instruction.id(), null);
-    }
-
-    private LIRInsertionBuffer getInsertionBuffer(AbstractBlock<?> block) {
-        LIRInsertionBuffer insertionBuffer = insertionBuffers.get(block);
-        if (insertionBuffer == null) {
-            insertionBuffer = new LIRInsertionBuffer();
-            insertionBuffers.put(block, insertionBuffer);
-            assert !insertionBuffer.initialized() : "already initialized?";
-            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-            insertionBuffer.init(instructions);
-        }
-        return insertionBuffer;
-    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Tue Feb 10 20:44:08 2015 +0100
@@ -71,14 +71,6 @@
         this.cc = cc;
     }
 
-    /**
-     * Returns true if the redundant move elimination optimization should be done after register
-     * allocation.
-     */
-    public boolean canEliminateRedundantMoves() {
-        return true;
-    }
-
     @Override
     public TargetDescription target() {
         return getCodeCache().getTarget();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Tue Feb 10 20:44:08 2015 +0100
@@ -139,12 +139,6 @@
     Value loadNonConst(Value value);
 
     /**
-     * Returns true if the redundant move elimination optimization should be done after register
-     * allocation.
-     */
-    boolean canEliminateRedundantMoves();
-
-    /**
      * Determines if only oop maps are required for the code generated from the LIR.
      */
     boolean needOnlyOopMaps();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelHighTier.java	Tue Feb 10 20:44:08 2015 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.phases;
+
+import com.oracle.graal.lir.constopt.*;
+import com.oracle.graal.lir.phases.LowLevelHighTierPhase.*;
+
+public class LowLevelHighTier extends LowLevelPhaseSuite<LowLevelHighTierContext> {
+    public LowLevelHighTier() {
+        if (ConstantLoadOptimization.Options.ConstantLoadOptimization.getValue()) {
+            appendPhase(new ConstantLoadOptimization());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelHighTierPhase.java	Tue Feb 10 20:44:08 2015 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.phases;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+
+public abstract class LowLevelHighTierPhase extends LowLevelPhase<LowLevelHighTierPhase.LowLevelHighTierContext> {
+
+    public static final class LowLevelHighTierContext {
+        private final LIRGeneratorTool lirGen;
+
+        public LowLevelHighTierContext(LIRGeneratorTool lirGen) {
+            this.lirGen = lirGen;
+        }
+
+    }
+
+    @Override
+    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LowLevelHighTierContext context) {
+        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.lirGen);
+    }
+
+    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelLowTier.java	Tue Feb 10 20:44:08 2015 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.phases;
+
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.phases.LowLevelLowTierPhase.*;
+
+public class LowLevelLowTier extends LowLevelPhaseSuite<LowLevelLowTierContext> {
+    public LowLevelLowTier() {
+        appendPhase(new EdgeMoveOptimizer());
+        appendPhase(new ControlFlowOptimizer());
+        appendPhase(new RedundantMoveElimination());
+        appendPhase(new NullCheckOptimizer());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelLowTierPhase.java	Tue Feb 10 20:44:08 2015 +0100
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.phases;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+
+public abstract class LowLevelLowTierPhase extends LowLevelPhase<LowLevelLowTierPhase.LowLevelLowTierContext> {
+
+    public static final class LowLevelLowTierContext {
+    }
+
+    @Override
+    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LowLevelLowTierContext context) {
+        run(target, lirGenRes, codeEmittingOrder, linearScanOrder);
+    }
+
+    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelMidTier.java	Tue Feb 10 20:44:08 2015 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.phases;
+
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.phases.LowLevelMidTierPhase.*;
+import com.oracle.graal.lir.stackslotalloc.*;
+
+public class LowLevelMidTier extends LowLevelPhaseSuite<LowLevelMidTierContext> {
+    public LowLevelMidTier() {
+        appendPhase(new LinearScanPhase());
+
+        // build frame map
+        if (LSStackSlotAllocator.Options.LSStackSlotAllocation.getValue()) {
+            appendPhase(new LSStackSlotAllocator());
+        } else {
+            appendPhase(new SimpleStackSlotAllocator());
+        }
+        // currently we mark locations only if we do register allocation
+        appendPhase(new LocationMarker());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelMidTierPhase.java	Tue Feb 10 20:44:08 2015 +0100
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.phases;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+
+public abstract class LowLevelMidTierPhase extends LowLevelPhase<LowLevelMidTierPhase.LowLevelMidTierContext> {
+
+    public static final class LowLevelMidTierContext {
+    }
+
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LowLevelMidTierContext context) {
+        run(target, lirGenRes, codeEmittingOrder, linearScanOrder);
+    }
+
+    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelPhase.java	Tue Feb 10 20:44:08 2015 +0100
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.phases;
+
+import java.util.*;
+import java.util.regex.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.debug.DebugMemUseTracker.Closeable;
+import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
+
+/**
+ * Base class for all {@link LIR low-level} phases. Subclasses should be stateless. There will be
+ * one global instance for each phase that is shared for all compilations.
+ */
+public abstract class LowLevelPhase<C> {
+
+    private static final int PHASE_DUMP_LEVEL = 2;
+
+    private CharSequence name;
+
+    /**
+     * Records time spent within {@link #apply}.
+     */
+    private final DebugTimer timer;
+
+    /**
+     * Records memory usage within {@link #apply}.
+     */
+    private final DebugMemUseTracker memUseTracker;
+
+    private static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
+
+    private static boolean checkName(String name) {
+        assert name == null || NAME_PATTERN.matcher(name).matches() : "illegal phase name: " + name;
+        return true;
+    }
+
+    public LowLevelPhase() {
+        timer = Debug.timer("LowLevelPhaseTime_%s", getClass());
+        memUseTracker = Debug.memUseTracker("LowLevelPhaseMemUse_%s", getClass());
+    }
+
+    protected LowLevelPhase(String name) {
+        assert checkName(name);
+        this.name = name;
+        timer = Debug.timer("LowLevelPhaseTime_%s", getClass());
+        memUseTracker = Debug.memUseTracker("LowLevelPhaseMemUse_%s", getClass());
+    }
+
+    public final <B extends AbstractBlock<B>> void apply(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context) {
+        apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, true);
+    }
+
+    public final <B extends AbstractBlock<B>> void apply(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context, boolean dumpLIR) {
+        try (TimerCloseable a = timer.start(); Scope s = Debug.scope(getName(), this); Closeable c = memUseTracker.start()) {
+            run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
+            if (dumpLIR && Debug.isDumpEnabled(PHASE_DUMP_LEVEL)) {
+                Debug.dump(PHASE_DUMP_LEVEL, lirGenRes.getLIR(), "After phase %s", getName());
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context);
+
+    protected CharSequence createName() {
+        String className = LowLevelPhase.this.getClass().getName();
+        String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
+        if (s.endsWith("Phase")) {
+            s = s.substring(0, s.length() - "Phase".length());
+        }
+        return s;
+    }
+
+    public final CharSequence getName() {
+        if (name == null) {
+            name = createName();
+        }
+        return name;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelPhaseSuite.java	Tue Feb 10 20:44:08 2015 +0100
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.phases;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+
+public abstract class LowLevelPhaseSuite<C> extends LowLevelPhase<C> {
+    private final List<LowLevelPhase<C>> phases;
+
+    public LowLevelPhaseSuite() {
+        phases = new ArrayList<>();
+    }
+
+    /**
+     * Add a new phase at the beginning of this suite.
+     */
+    public final void prependPhase(LowLevelPhase<C> phase) {
+        phases.add(0, phase);
+    }
+
+    /**
+     * Add a new phase at the end of this suite.
+     */
+    public final void appendPhase(LowLevelPhase<C> phase) {
+        phases.add(phase);
+    }
+
+    public final ListIterator<LowLevelPhase<C>> findPhase(Class<? extends LowLevelPhase<C>> phaseClass) {
+        ListIterator<LowLevelPhase<C>> it = phases.listIterator();
+        if (findNextPhase(it, phaseClass)) {
+            return it;
+        } else {
+            return null;
+        }
+    }
+
+    public static <C> boolean findNextPhase(ListIterator<LowLevelPhase<C>> it, Class<? extends LowLevelPhase<C>> phaseClass) {
+        while (it.hasNext()) {
+            LowLevelPhase<C> phase = it.next();
+            if (phaseClass.isInstance(phase)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context) {
+        for (LowLevelPhase<C> phase : phases) {
+            phase.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelSuites.java	Tue Feb 10 20:44:08 2015 +0100
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.phases;
+
+import com.oracle.graal.lir.phases.LowLevelHighTierPhase.LowLevelHighTierContext;
+import com.oracle.graal.lir.phases.LowLevelLowTierPhase.LowLevelLowTierContext;
+import com.oracle.graal.lir.phases.LowLevelMidTierPhase.LowLevelMidTierContext;
+
+public class LowLevelSuites {
+
+    private final LowLevelPhaseSuite<LowLevelHighTierContext> highTier;
+    private final LowLevelPhaseSuite<LowLevelMidTierContext> midTier;
+    private final LowLevelPhaseSuite<LowLevelLowTierContext> lowTier;
+
+    public LowLevelSuites(LowLevelPhaseSuite<LowLevelHighTierContext> highTier, LowLevelPhaseSuite<LowLevelMidTierContext> midTier, LowLevelPhaseSuite<LowLevelLowTierContext> lowTier) {
+        this.highTier = highTier;
+        this.midTier = midTier;
+        this.lowTier = lowTier;
+    }
+
+    public LowLevelPhaseSuite<LowLevelHighTierContext> getHighTier() {
+        return highTier;
+    }
+
+    public LowLevelPhaseSuite<LowLevelMidTierContext> getMidTier() {
+        return midTier;
+    }
+
+    public LowLevelPhaseSuite<LowLevelLowTierContext> getLowTier() {
+        return lowTier;
+    }
+
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Tue Feb 10 20:44:08 2015 +0100
@@ -38,6 +38,7 @@
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 
 /**
@@ -50,7 +51,7 @@
  * {@link OperandFlag#UNINITIALIZED}. Otherwise the stack slot might be reused and its content
  * destroyed.
  */
-public final class LSStackSlotAllocator implements StackSlotAllocator {
+public final class LSStackSlotAllocator extends LowLevelMidTierPhase implements StackSlotAllocator {
 
     public static class Options {
         // @formatter:off
@@ -66,6 +67,11 @@
     private static final DebugTimer AllocateSlotsTimer = Debug.timer("LSStackSlotAllocator[AllocateSlots]");
     private static final DebugTimer AssignSlotsTimer = Debug.timer("LSStackSlotAllocator[AssignSlots]");
 
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        lirGenRes.buildFrameMap(this);
+    }
+
     public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) {
         try (TimerCloseable t = MainTimer.start()) {
             new Allocator(res.getLIR(), builder).allocate();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Tue Feb 10 20:44:08 2015 +0100
@@ -24,16 +24,24 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 
-public class SimpleStackSlotAllocator implements StackSlotAllocator {
+public class SimpleStackSlotAllocator extends LowLevelMidTierPhase implements StackSlotAllocator {
+
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        lirGenRes.buildFrameMap(this);
+    }
 
     public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) {
         StackSlot[] mapping = new StackSlot[builder.getNumberOfStackSlots()];
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Tue Feb 10 20:44:08 2015 +0100
@@ -23,6 +23,10 @@
 package com.oracle.graal.phases.tiers;
 
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.phases.LowLevelHighTierPhase.*;
+import com.oracle.graal.lir.phases.LowLevelLowTierPhase.*;
+import com.oracle.graal.lir.phases.LowLevelMidTierPhase.*;
 import com.oracle.graal.phases.*;
 
 public interface CompilerConfiguration extends Service {
@@ -32,4 +36,10 @@
     PhaseSuite<MidTierContext> createMidTier();
 
     PhaseSuite<LowTierContext> createLowTier();
+
+    LowLevelPhaseSuite<LowLevelHighTierContext> createLowLevelHighTier();
+
+    LowLevelPhaseSuite<LowLevelMidTierContext> createLowLevelMidTier();
+
+    LowLevelPhaseSuite<LowLevelLowTierContext> createLowLevelLowTier();
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Tue Feb 10 20:44:08 2015 +0100
@@ -28,6 +28,7 @@
 
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 
@@ -129,4 +130,21 @@
         return new Suites(config);
     }
 
+    public static LowLevelSuites createDefaultLowLevelSuites() {
+        String selected = CompilerConfiguration.getValue();
+        if (selected.equals("")) {
+            return new LowLevelSuites(defaultConfiguration.createLowLevelHighTier(), defaultConfiguration.createLowLevelMidTier(), defaultConfiguration.createLowLevelLowTier());
+        } else {
+            return createLowLevelSuites(selected);
+        }
+    }
+
+    public static LowLevelSuites createLowLevelSuites(String name) {
+        CompilerConfiguration config = configurations.get(name);
+        if (config == null) {
+            throw new GraalInternalError("unknown compiler configuration: " + name);
+        }
+        return new LowLevelSuites(config.createLowLevelHighTier(), config.createLowLevelMidTier(), config.createLowLevelLowTier());
+    }
+
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/SuitesProvider.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/SuitesProvider.java	Tue Feb 10 20:44:08 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.phases.tiers;
 
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.phases.*;
 
 public interface SuitesProvider {
@@ -42,4 +43,15 @@
      */
     PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite();
 
+    /**
+     * Get the default phase suites of this compiler.
+     */
+    LowLevelSuites getDefaultLowLevelSuites();
+
+    /**
+     * Create a new set of low-level phase suites. Initially, the suites are the same as the
+     * {@link #getDefaultLowLevelSuites default} suites.
+     */
+    LowLevelSuites createLowLevelSuites();
+
 }
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Tue Feb 10 20:44:08 2015 +0100
@@ -45,6 +45,7 @@
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
@@ -175,6 +176,7 @@
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites();
         Suites suites = suitesProvider.createSuites();
+        LowLevelSuites lowLevelSuites = suitesProvider.createLowLevelSuites();
         removeInliningPhase(suites);
         StructuredGraph graph = new StructuredGraph(javaMethod);
         new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
@@ -184,7 +186,7 @@
         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
         CompilationResultBuilderFactory factory = getOptimizedCallTargetInstrumentationFactory(backend.getTarget().arch.getName(), javaMethod);
         return compileGraph(graph, cc, javaMethod, providers, backend, providers.getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), null,
-                        suites, new CompilationResult(), factory);
+                        suites, lowLevelSuites, new CompilationResult(), factory);
     }
 
     private static Providers getGraalProviders() {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Feb 10 20:43:48 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Feb 10 20:44:08 2015 +0100
@@ -40,6 +40,7 @@
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -59,6 +60,7 @@
 
     private final Providers providers;
     private final Suites suites;
+    private final LowLevelSuites lowLevelSuites;
     private final PartialEvaluator partialEvaluator;
     private final Backend backend;
     private final GraphBuilderConfiguration config;
@@ -81,6 +83,7 @@
         ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backend.getProviders().getConstantReflection(), backend.getProviders().getMetaAccess());
         this.providers = backend.getProviders().copyWith(truffleReplacements).copyWith(constantReflection);
         this.suites = backend.getSuites().getDefaultSuites();
+        this.lowLevelSuites = backend.getSuites().getDefaultLowLevelSuites();
 
         ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
         GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault().withSkippedExceptionTypes(skippedExceptionTypes);
@@ -155,7 +158,7 @@
             CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
             CompilationResult compilationResult = new CompilationResult(name);
             result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, createGraphBuilderSuite(), Optimizations, getProfilingInfo(graph), speculationLog,
-                            suites, compilationResult, CompilationResultBuilderFactory.Default);
+                            suites, lowLevelSuites, compilationResult, CompilationResultBuilderFactory.Default);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }