# HG changeset patch # User Thomas Wuerthinger # Date 1423597448 -3600 # Node ID 51b6ea17aebe1c85f8be6da206c0176bb7bafc56 # Parent 30c8d110b281e910298c553998ab3f6bbd450e96# Parent 5ff79efdd04004fbfec5bbd1b17f7ea716783085 Merge. diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java --- 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 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> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.getBlocks().length, blockMap.startBlock); - List> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blockMap.getBlocks().length, blockMap.startBlock); + List linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.getBlocks().length, blockMap.startBlock); + List 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) { diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java --- 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; } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- 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; + private final DerivedOptionValue 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 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); } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java --- 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 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); diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java --- 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; } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java --- 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); /* diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- 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 cache, PhaseSuite 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 compileGraph(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, TargetDescription target, Map cache, PhaseSuite 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 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 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 > LIRGenerationResult emitLowLevel(TargetDescription target, List codeEmittingOrder, List 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(); diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java --- 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 createLowTier() { return new LowTier(); } + + public LowLevelPhaseSuite createLowLevelHighTier() { + return new LowLevelHighTier(); + } + + public LowLevelPhaseSuite createLowLevelMidTier() { + return new LowLevelMidTier(); + } + + public LowLevelPhaseSuite createLowLevelLowTier() { + return new LowLevelLowTier(); + } + } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java --- 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(); /** diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- 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); diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java --- 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); diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java --- 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); } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- 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 getGraphBuilderSuite(HotSpotProviders providers) { PhaseSuite 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); diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java --- 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 { - - private static final long serialVersionUID = -5755004498526945687L; +public class HotSpotSuitesProvider implements SuitesProvider { protected final DerivedOptionValue defaultSuites; protected final PhaseSuite defaultGraphBuilderSuite; + private final DerivedOptionValue defaultLowLevelSuites; protected final HotSpotGraalRuntimeProvider runtime; + private class SuitesSupplier implements OptionSupplier { + + private static final long serialVersionUID = -3444304453553320390L; + + public Suites get() { + return createSuites(); + } + + } + + private class LowLevelSuitesSupplier implements OptionSupplier { + + 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 getDefaultGraphBuilderSuite() { return defaultGraphBuilderSuite; } @@ -118,4 +135,12 @@ return gbs; } + public LowLevelSuites getDefaultLowLevelSuites() { + return defaultLowLevelSuites.getValue(); + } + + public LowLevelSuites createLowLevelSuites() { + return Suites.createDefaultLowLevelSuites(); + } + } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java --- 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 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); diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java --- 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); } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java --- 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 { +public class DefaultSuitesProvider implements SuitesProvider { private final DerivedOptionValue defaultSuites; private final PhaseSuite defaultGraphBuilderSuite; + private final DerivedOptionValue defaultLowLevelSuites; + + private class SuitesSupplier implements OptionSupplier { + + private static final long serialVersionUID = 2677805381215454728L; + + public Suites get() { + return createSuites(); + } + + } + + private class LowLevelSuitesSupplier implements OptionSupplier { + + 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(); + } + } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java --- 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 > void optimize(LIR lir, List codeEmittingOrder) { - ControlFlowOptimizer.deleteEmptyBlocks(lir, codeEmittingOrder); - } - - private ControlFlowOptimizer() { - } - - private static final DebugMetric BLOCKS_DELETED = Debug.metric("BlocksDeleted"); - - /** - * 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; - } - - List 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"; - 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(); + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder) { + LIR lir = lirGenRes.getLIR(); + new Optimizer(lir).deleteEmptyBlocks(codeEmittingOrder); } - private static void alignBlock(LIR lir, AbstractBlock block) { - if (!block.isAligned()) { - block.setAlign(true); + private static final class Optimizer> { + + private final LIR lir; + + private Optimizer(LIR lir) { + this.lir = lir; + } + + private static final DebugMetric BLOCKS_DELETED = Debug.metric("BlocksDeleted"); + + /** + * 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; + } + List 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 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 blocks) { + assert verifyBlocks(lir, blocks); + Iterator 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 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 > void deleteEmptyBlocks(LIR lir, List blocks) { - assert verifyBlocks(lir, blocks); - Iterator 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 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); - } } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java --- 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. - * + *

* 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. + *

* 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). - * + *

* This optimization affects all kind of moves (reg->reg, reg->stack and stack->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 > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder) { + LIR ir = lirGenRes.getLIR(); + Optimizer optimizer = new Optimizer(ir); List> blockList = ir.linearScanOrder(); // ignore the first block in the list (index 0 is not processed) @@ -67,213 +69,216 @@ } } - private final List> 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; + private static final class Optimizer { + private final List> edgeInstructionSeqences; + private LIR ir; - 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(); - - 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 predInstructions = ir.getLIRforBlock(pred); + /** + * 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 (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 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 seq = edgeInstructionSeqences.get(0); - if (seq.isEmpty()) { - return; - } - - LIRInstruction op = last(seq); - for (int i = 1; i < numPreds; ++i) { - List 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(); + + 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 predInstructions = ir.getLIRforBlock(pred); - // delete the instruction at the end of all predecessors - for (int i = 0; i < numPreds; i++) { - seq = edgeInstructionSeqences.get(i); - removeLast(seq); - } - } - } + 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; + } - /** - * 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) { + // ignore the unconditional branch at the end of the block + List seq = predInstructions.subList(0, predInstructions.size() - 1); + edgeInstructionSeqences.add(seq); + } + + // process lir-instructions while all predecessors end with the same instruction + while (true) { + List seq = edgeInstructionSeqences.get(0); + if (seq.isEmpty()) { + return; + } - edgeInstructionSeqences.clear(); - int numSux = block.getSuccessorCount(); - - List instructions = ir.getLIRforBlock(block); + LIRInstruction op = last(seq); + for (int i = 1; i < numPreds; ++i) { + List otherSeq = edgeInstructionSeqences.get(i); + if (otherSeq.isEmpty() || !same(op, last(otherSeq))) { + return; + } + } - assert numSux == 2 : "method should not be called otherwise"; + // insert the instruction at the beginning of the current block + ir.getLIRforBlock(block).add(1, op); - LIRInstruction lastInstruction = instructions.get(instructions.size() - 1); - if (lastInstruction.hasState()) { - // cannot optimize instructions when debug info is needed - return; + // delete the instruction at the end of all predecessors + for (int i = 0; i < numPreds; i++) { + seq = edgeInstructionSeqences.get(i); + removeLast(seq); + } + } } - 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 suxInstructions = ir.getLIRforBlock(sux); + /** + * 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) { - assert suxInstructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; + edgeInstructionSeqences.clear(); + int numSux = block.getSuccessorCount(); - 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"; + List instructions = ir.getLIRforBlock(block); - // ignore the label at the beginning of the block - List seq = suxInstructions.subList(1, suxInstructions.size()); - edgeInstructionSeqences.add(seq); - } + assert numSux == 2 : "method should not be called otherwise"; - // process LIR instructions while all successors begin with the same instruction - while (true) { - List 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 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 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 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 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 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 seq) { - return seq.get(0); - } + /** + * Gets the first element from a LIR instruction sequence. + */ + private static LIRInstruction first(List seq) { + return seq.get(0); + } + + /** + * Gets the last element from a LIR instruction sequence. + */ + private static LIRInstruction last(List seq) { + return seq.get(seq.size() - 1); + } - /** - * Gets the last element from a LIR instruction sequence. - */ - private static LIRInstruction last(List seq) { - return seq.get(seq.size() - 1); - } + /** + * Removes the first element from a LIR instruction sequence. + */ + private static void removeFirst(List seq) { + seq.remove(0); + } - /** - * Removes the first element from a LIR instruction sequence. - */ - private static void removeFirst(List seq) { - seq.remove(0); - } + /** + * Removes the last element from a LIR instruction sequence. + */ + private static void removeLast(List seq) { + seq.remove(seq.size() - 1); + } - /** - * Removes the last element from a LIR instruction sequence. - */ - private static void removeLast(List seq) { - seq.remove(seq.size() - 1); } } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java --- 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 > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder) { + LIR ir = lirGenRes.getLIR(); List> blocks = ir.codeEmittingOrder(); - NullCheckOptimizer.foldNullChecks(ir, blocks, implicitNullCheckLimit); - } - - private NullCheckOptimizer() { + NullCheckOptimizer.foldNullChecks(ir, blocks, target.implicitNullCheckLimit); } private static void foldNullChecks(LIR ir, List> blocks, int implicitNullCheckLimit) { @@ -63,4 +65,5 @@ } } } + } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java --- 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 > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List 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, BlockData> blockData = CollectionsFactory.newMap(); + private static final class Optimization { - Register[] callerSaveRegs; + Map, BlockData> blockData = CollectionsFactory.newMap(); + + Register[] callerSaveRegs; - /** - * Contains the register number for registers which can be optimized and -1 for the others. - */ - int[] eligibleRegs; + /** + * Contains the register number for registers which can be optimized and -1 for the others. + */ + int[] eligibleRegs; + + Map stackIndices = CollectionsFactory.newMap(); + + int numRegs; + + /* + * Pseudo value for a not yet assigned location. + */ + static final int INIT_VALUE = 0; - Map stackIndices = CollectionsFactory.newMap(); + /** + * The main method doing the elimination of redundant moves. + */ + private void doOptimize(LIR lir, FrameMap frameMap) { - int numRegs; + try (Indent indent = Debug.logAndIndent("eliminate redundant moves")) { + + callerSaveRegs = frameMap.getRegisterConfig().getCallerSaveRegisters(); - /* - * Pseudo value for a not yet assigned location. - */ - static final int INIT_VALUE = 0; + 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; + } + } - /** - * The main method doing the elimination of redundant moves. - */ - private void doOptimize(LIR lir, FrameMapBuilder frameMapBuilder) { + if (!solveDataFlow(lir)) { + return; + } + + eliminateMoves(lir); + } + } - try (Indent indent = Debug.logAndIndent("eliminate redundant moves")) { + /** + * 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; - callerSaveRegs = frameMapBuilder.getRegisterConfig().getCallerSaveRegisters(); + private void initBlockData(LIR lir) { + + List> blocks = lir.linearScanOrder(); + numRegs = 0; + + int maxStackLocations = COMPLEXITY_LIMIT / blocks.size(); - 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 : frameMapBuilder.getRegisterConfig().getAllocatableRegisters()) { - if (reg.number < numRegs) { - eligibleRegs[reg.number] = reg.number; + /* + * 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 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> 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 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; } - } + + /** + * Deletes all move instructions where the target location already contains the source + * value. + */ + private void eliminateMoves(LIR lir) { + + try (Indent indent = Debug.logAndIndent("eliminate moves")) { - /** - * 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; + List> blocks = lir.linearScanOrder(); + + for (AbstractBlock block : blocks) { + + try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) { - private void initBlockData(LIR lir) { + List instructions = lir.getLIRforBlock(block); + BlockData data = blockData.get(block); + boolean hasDead = false; - List> blocks = lir.linearScanOrder(); - numRegs = 0; - - int maxStackLocations = COMPLEXITY_LIMIT / blocks.size(); + // Reuse the entry state for iteration, we don't need it later. + int[] iterState = data.entryState; - /* - * 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 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; + // 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); - } - } - - /** - * 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> blocks = lir.linearScanOrder(); + private int updateState(final int[] state, LIRInstruction op, int initValueNum) { - int numIter = 0; + 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; + } + } - /* - * 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")) { + int valueNum = initValueNum; + + if (op.destroysCallerSavedRegisters()) { + Debug.log("kill all caller save regs"); - 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; + for (Register reg : callerSaveRegs) { + if (reg.number < numRegs) { + // Kind.Object is the save default + state[reg.number] = encodeValueNum(valueNum++, true); } - int valueNum = data.entryValueNum; - assert valueNum > 0; - boolean newState = false; + } + } + + /* + * Value procedure for the instruction's output and temp values + */ + class OutputValueConsumer implements ValueConsumer { - if (block == blocks.get(0) || block.isExceptionEntry()) { + int opValueNum; + + OutputValueConsumer(int opValueNum) { + this.opValueNum = opValueNum; + } + + @Override + public void visitValue(Value operand, OperandMode mode, EnumSet flags) { + int stateIdx = getStateIdx(operand); + if (stateIdx >= 0) { /* - * 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 + * Assign a unique number to the output or temp location. */ - 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 instructions = lir.getLIRforBlock(block); - - for (LIRInstruction op : instructions) { - valueNum = updateState(iterState, op, valueNum); - } - changed = true; - } - } - if (firstRound) { - currentValueNum = valueNum; + state[stateIdx] = encodeValueNum(opValueNum++, !operand.getLIRKind().isValue()); + Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]); } } - firstRound = false; - } - numIter++; - - if (numIter > 5) { - /* - * This is _very_ seldom. - */ - return false; } - } while (changed); + 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; - } - - /** - * Deletes all move instructions where the target location already contains the source value. - */ - private void eliminateMoves(LIR lir) { - - try (Indent indent = Debug.logAndIndent("eliminate moves")) { - - List> blocks = lir.linearScanOrder(); - - for (AbstractBlock block : blocks) { - - try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) { - - List 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; + /** + * 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; + } - // Add the values which are "consumed" by clearValues and - // mergeState in solveDataFlow - int valueNum = data.entryValueNum + data.entryState.length; + 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]; + } + } - 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 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); } } } - } - /** - * 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]; } - } - - 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); - } - } - } - - /* - * 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 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]); - } - } + return -1; } - - 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; + if (isStackSlot(location)) { + StackSlot slot = (StackSlot) location; + Integer index = stackIndices.get(slot); + if (index != null) { + return index.intValue() + numRegs; } - 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; - } - 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 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; } } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java --- 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" 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; + final BlockMap 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 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. diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java --- /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 > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder) { + new LinearScan(target, lirGenRes).allocate(); + } + +} diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java --- 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(); - } - - private final LIR lir; - private final FrameMap frameMap; - private final RegisterAttributes[] registerAttributes; - private final BlockMap liveInMap; - private final BlockMap 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()); + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder) { + new Marker(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build(); } - private void build() { - Deque> 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 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 static final class Marker { + private final LIR lir; + private final FrameMap frameMap; + private final RegisterAttributes[] registerAttributes; + private final BlockMap liveInMap; + private final BlockMap liveOutMap; + 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()); } - } - /** - * 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> worklist) { - if (updateOutBlock(block)) { - try (Indent indent = Debug.logAndIndent("handle block %s", block)) { - BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone()); + private void build() { + Deque> 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 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 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 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> worklist) { + if (updateOutBlock(block)) { + try (Indent indent = Debug.logAndIndent("handle block %s", block)) { + BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone()); + List 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 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 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 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 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; - } - } - - /** - * 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()); + /** + * 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]; } - 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]; } } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java --- 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 > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, LIRGeneratorTool lirGen) { + new Optimization(lirGenRes.getLIR(), lirGen).apply(); } - private LIR lir; - private LIRGeneratorTool lirGen; - private VariableMap map; - private BitSet phiConstants; - private BitSet defined; - private BlockMap> blockMap; - private BlockMap 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 map; + private final BitSet phiConstants; + private final BitSet defined; + private final BlockMap> blockMap; + private final BlockMap insertionBuffers; + + 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); - } + 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); + 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); + // insert moves, delete null instructions and reset instruction ids + lir.getControlFlowGraph().getBlocks().forEach(this::rewriteBlock); - assert verifyStates(); - } catch (Throwable e) { - throw Debug.handle(e); + assert verifyStates(); + } catch (Throwable e) { + throw Debug.handle(e); + } } } - } - private boolean verifyStates() { - map.forEach(this::verifyStateUsage); - return true; - } + private boolean verifyStates() { + map.forEach(this::verifyStateUsage); + return true; + } + + private void verifyStateUsage(DefUseTree tree) { + Variable var = tree.getVariable(); + ValueConsumer stateConsumer = new ValueConsumer() { - private void verifyStateUsage(DefUseTree tree) { - Variable var = tree.getVariable(); - ValueConsumer stateConsumer = new ValueConsumer() { - - @Override - public void visitValue(Value operand, OperandMode mode, EnumSet 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); + @Override + public void visitValue(Value operand, OperandMode mode, EnumSet 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; + private static boolean isConstantLoad(LIRInstruction inst) { + if (!(inst instanceof MoveOp)) { + return false; + } + MoveOp move = (MoveOp) inst; + return isConstant(move.getInput()) && isVariable(move.getResult()); } - MoveOp move = (MoveOp) inst; - return isConstant(move.getInput()) && isVariable(move.getResult()); - } - private void addUsageToBlockMap(UseEntry entry) { - AbstractBlock block = entry.getBlock(); - List list = blockMap.get(block); - if (list == null) { - list = new ArrayList<>(); - blockMap.put(block, list); + private void addUsageToBlockMap(UseEntry entry) { + AbstractBlock block = entry.getBlock(); + List list = blockMap.get(block); + if (list == null) { + list = new ArrayList<>(); + blockMap.put(block, list); + } + list.add(entry); } - list.add(entry); - } - /** - * Collects def-use information for a {@code block}. - */ - private void analyzeBlock(AbstractBlock block) { - try (Indent indent = Debug.logAndIndent("Block: %s", block)) { + /** + * 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; - 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(); + 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 { - // 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); + assert defined.get(var.index) : "phi but not defined? " + var; } - } else { - assert defined.get(var.index) : "phi but not defined? " + var; } - } - }; + }; - 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); + 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); + 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; - } - constTree.markBlocks(); + /** + * 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())); - 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 (constTree.get(Flags.USAGE, tree.getBlock())) { + // usage in the definition block -> no optimization + usageAtDefinitionSkipped.increment(); + return; } + 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()); } - 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> 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> 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 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(); + private void insertLoad(JavaConstant constant, LIRKind kind, AbstractBlock block, List 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()); + } } - // delete instructions - List instructions = lir.getLIRforBlock(block); - boolean hasDead = false; - for (LIRInstruction inst : instructions) { - if (inst == null) { - hasDead = true; - } else { - inst.setId(-1); + /** + * 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 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)); } } - 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 instructions = lir.getLIRforBlock(block); + insertionBuffer.init(instructions); + } + return insertionBuffer; } } - - 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 instructions = lir.getLIRforBlock(block); - insertionBuffer.init(instructions); - } - return insertionBuffer; - } } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java --- 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(); diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java --- 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(); diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelHighTier.java --- /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 { + public LowLevelHighTier() { + if (ConstantLoadOptimization.Options.ConstantLoadOptimization.getValue()) { + appendPhase(new ConstantLoadOptimization()); + } + } +} diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelHighTierPhase.java --- /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 { + + public static final class LowLevelHighTierContext { + private final LIRGeneratorTool lirGen; + + public LowLevelHighTierContext(LIRGeneratorTool lirGen) { + this.lirGen = lirGen; + } + + } + + @Override + protected final > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, LowLevelHighTierContext context) { + run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.lirGen); + } + + protected abstract > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, LIRGeneratorTool lirGen); + +} diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelLowTier.java --- /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 { + public LowLevelLowTier() { + appendPhase(new EdgeMoveOptimizer()); + appendPhase(new ControlFlowOptimizer()); + appendPhase(new RedundantMoveElimination()); + appendPhase(new NullCheckOptimizer()); + } +} diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelLowTierPhase.java --- /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 { + + public static final class LowLevelLowTierContext { + } + + @Override + protected final > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, LowLevelLowTierContext context) { + run(target, lirGenRes, codeEmittingOrder, linearScanOrder); + } + + protected abstract > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder); + +} diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelMidTier.java --- /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 { + 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()); + } +} diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelMidTierPhase.java --- /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 { + + public static final class LowLevelMidTierContext { + } + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, LowLevelMidTierContext context) { + run(target, lirGenRes, codeEmittingOrder, linearScanOrder); + } + + protected abstract > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder); + +} diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelPhase.java --- /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 { + + 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 > void apply(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, C context) { + apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, true); + } + + public final > void apply(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List 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 > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List 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; + } + +} diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelPhaseSuite.java --- /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 extends LowLevelPhase { + private final List> phases; + + public LowLevelPhaseSuite() { + phases = new ArrayList<>(); + } + + /** + * Add a new phase at the beginning of this suite. + */ + public final void prependPhase(LowLevelPhase phase) { + phases.add(0, phase); + } + + /** + * Add a new phase at the end of this suite. + */ + public final void appendPhase(LowLevelPhase phase) { + phases.add(phase); + } + + public final ListIterator> findPhase(Class> phaseClass) { + ListIterator> it = phases.listIterator(); + if (findNextPhase(it, phaseClass)) { + return it; + } else { + return null; + } + } + + public static boolean findNextPhase(ListIterator> it, Class> phaseClass) { + while (it.hasNext()) { + LowLevelPhase phase = it.next(); + if (phaseClass.isInstance(phase)) { + return true; + } + } + return false; + } + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, C context) { + for (LowLevelPhase phase : phases) { + phase.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context); + } + } + +} diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelSuites.java --- /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 highTier; + private final LowLevelPhaseSuite midTier; + private final LowLevelPhaseSuite lowTier; + + public LowLevelSuites(LowLevelPhaseSuite highTier, LowLevelPhaseSuite midTier, LowLevelPhaseSuite lowTier) { + this.highTier = highTier; + this.midTier = midTier; + this.lowTier = lowTier; + } + + public LowLevelPhaseSuite getHighTier() { + return highTier; + } + + public LowLevelPhaseSuite getMidTier() { + return midTier; + } + + public LowLevelPhaseSuite getLowTier() { + return lowTier; + } + +} diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java --- 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 > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder) { + lirGenRes.buildFrameMap(this); + } + public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) { try (TimerCloseable t = MainTimer.start()) { new Allocator(res.getLIR(), builder).allocate(); diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java --- 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 > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder) { + lirGenRes.buildFrameMap(this); + } public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) { StackSlot[] mapping = new StackSlot[builder.getNumberOfStackSlots()]; diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java --- 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 createMidTier(); PhaseSuite createLowTier(); + + LowLevelPhaseSuite createLowLevelHighTier(); + + LowLevelPhaseSuite createLowLevelMidTier(); + + LowLevelPhaseSuite createLowLevelLowTier(); } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java --- 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()); + } + } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/SuitesProvider.java --- 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 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(); + } diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- 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() { diff -r 30c8d110b281 -r 51b6ea17aebe graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- 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); }