001/*
002 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.compiler;
024
025import static com.oracle.graal.compiler.GraalCompiler.Options.*;
026import static com.oracle.graal.compiler.common.GraalOptions.*;
027import static com.oracle.graal.compiler.common.alloc.RegisterAllocationConfig.*;
028import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*;
029
030import java.util.*;
031
032import jdk.internal.jvmci.code.*;
033import jdk.internal.jvmci.code.CompilationResult.*;
034import com.oracle.graal.debug.*;
035import com.oracle.graal.debug.Debug.*;
036import jdk.internal.jvmci.meta.*;
037import jdk.internal.jvmci.options.*;
038import jdk.internal.jvmci.options.OptionValue.*;
039
040import com.oracle.graal.compiler.LIRGenerationPhase.LIRGenerationContext;
041import com.oracle.graal.compiler.common.alloc.*;
042import com.oracle.graal.compiler.common.cfg.*;
043import com.oracle.graal.compiler.target.*;
044import com.oracle.graal.lir.*;
045import com.oracle.graal.lir.alloc.lsra.*;
046import com.oracle.graal.lir.asm.*;
047import com.oracle.graal.lir.framemap.*;
048import com.oracle.graal.lir.gen.*;
049import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext;
050import com.oracle.graal.lir.phases.*;
051import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
052import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
053import com.oracle.graal.nodes.*;
054import com.oracle.graal.nodes.cfg.*;
055import com.oracle.graal.nodes.spi.*;
056import com.oracle.graal.phases.*;
057import com.oracle.graal.phases.common.*;
058import com.oracle.graal.phases.schedule.*;
059import com.oracle.graal.phases.tiers.*;
060import com.oracle.graal.phases.util.*;
061
062/**
063 * Static methods for orchestrating the compilation of a {@linkplain StructuredGraph graph}.
064 */
065public class GraalCompiler {
066
067    private static final DebugTimer FrontEnd = Debug.timer("FrontEnd");
068    private static final DebugTimer BackEnd = Debug.timer("BackEnd");
069    private static final DebugTimer EmitLIR = Debug.timer("EmitLIR");
070    private static final DebugTimer EmitCode = Debug.timer("EmitCode");
071
072    static class Options {
073
074        // @formatter:off
075        @Option(help = "Repeatedly run the LIR code generation pass to improve statistical profiling results.", type = OptionType.Debug)
076        public static final OptionValue<Integer> EmitLIRRepeatCount = new OptionValue<>(0);
077        // @formatter:on
078
079    }
080
081    /**
082     * Encapsulates all the inputs to a {@linkplain GraalCompiler#compile(Request) compilation}.
083     */
084    public static class Request<T extends CompilationResult> {
085        public final StructuredGraph graph;
086        public final CallingConvention cc;
087        public final ResolvedJavaMethod installedCodeOwner;
088        public final Providers providers;
089        public final Backend backend;
090        public final TargetDescription target;
091        public final PhaseSuite<HighTierContext> graphBuilderSuite;
092        public final OptimisticOptimizations optimisticOpts;
093        public final ProfilingInfo profilingInfo;
094        public final Suites suites;
095        public final LIRSuites lirSuites;
096        public final T compilationResult;
097        public final CompilationResultBuilderFactory factory;
098
099        /**
100         * @param graph the graph to be compiled
101         * @param cc the calling convention for calls to the code compiled for {@code graph}
102         * @param installedCodeOwner the method the compiled code will be associated with once
103         *            installed. This argument can be null.
104         * @param providers
105         * @param backend
106         * @param target
107         * @param graphBuilderSuite
108         * @param optimisticOpts
109         * @param profilingInfo
110         * @param suites
111         * @param lirSuites
112         * @param compilationResult
113         * @param factory
114         */
115        public Request(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, TargetDescription target,
116                        PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult,
117                        CompilationResultBuilderFactory factory) {
118            this.graph = graph;
119            this.cc = cc;
120            this.installedCodeOwner = installedCodeOwner;
121            this.providers = providers;
122            this.backend = backend;
123            this.target = target;
124            this.graphBuilderSuite = graphBuilderSuite;
125            this.optimisticOpts = optimisticOpts;
126            this.profilingInfo = profilingInfo;
127            this.suites = suites;
128            this.lirSuites = lirSuites;
129            this.compilationResult = compilationResult;
130            this.factory = factory;
131        }
132
133        /**
134         * Executes this compilation request.
135         *
136         * @return the result of the compilation
137         */
138        public T execute() {
139            return GraalCompiler.compile(this);
140        }
141    }
142
143    /**
144     * Requests compilation of a given graph.
145     *
146     * @param graph the graph to be compiled
147     * @param cc the calling convention for calls to the code compiled for {@code graph}
148     * @param installedCodeOwner the method the compiled code will be associated with once
149     *            installed. This argument can be null.
150     * @return the result of the compilation
151     */
152    public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
153                    TargetDescription target, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites,
154                    T compilationResult, CompilationResultBuilderFactory factory) {
155        return compile(new Request<>(graph, cc, installedCodeOwner, providers, backend, target, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory));
156    }
157
158    /**
159     * Services a given compilation request.
160     *
161     * @return the result of the compilation
162     */
163    public static <T extends CompilationResult> T compile(Request<T> r) {
164        assert !r.graph.isFrozen();
165        try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache())) {
166            SchedulePhase schedule = emitFrontEnd(r.providers, r.target, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
167            emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.target, r.compilationResult, r.factory, schedule, null, r.lirSuites);
168        } catch (Throwable e) {
169            throw Debug.handle(e);
170        }
171        return r.compilationResult;
172    }
173
174    public static ProfilingInfo getProfilingInfo(StructuredGraph graph) {
175        if (graph.method() != null) {
176            return graph.method().getProfilingInfo();
177        } else {
178            return DefaultProfilingInfo.get(TriState.UNKNOWN);
179        }
180    }
181
182    /**
183     * Builds the graph, optimizes it.
184     */
185    public static SchedulePhase emitFrontEnd(Providers providers, TargetDescription target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite,
186                    OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites) {
187        try (Scope s = Debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start()) {
188            HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts);
189            if (graph.start().next() == null) {
190                graphBuilderSuite.apply(graph, highTierContext);
191                new DeadCodeEliminationPhase(Optional).apply(graph);
192            } else {
193                Debug.dump(graph, "initial state");
194            }
195
196            suites.getHighTier().apply(graph, highTierContext);
197            graph.maybeCompress();
198
199            MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo);
200            suites.getMidTier().apply(graph, midTierContext);
201            graph.maybeCompress();
202
203            LowTierContext lowTierContext = new LowTierContext(providers, target);
204            suites.getLowTier().apply(graph, lowTierContext);
205            graph.maybeCompress();
206
207            SchedulePhase schedule = new SchedulePhase();
208            schedule.apply(graph);
209            Debug.dump(schedule, "Final HIR schedule");
210            return schedule;
211        } catch (Throwable e) {
212            throw Debug.handle(e);
213        }
214    }
215
216    public static <T extends CompilationResult> void emitBackEnd(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Backend backend,
217                    TargetDescription target, T compilationResult, CompilationResultBuilderFactory factory, SchedulePhase schedule, RegisterConfig registerConfig, LIRSuites lirSuites) {
218        try (Scope s = Debug.scope("BackEnd", schedule); DebugCloseable a = BackEnd.start()) {
219            // Repeatedly run the LIR code generation pass to improve statistical profiling results.
220            for (int i = 0; i < EmitLIRRepeatCount.getValue(); i++) {
221                SchedulePhase dummySchedule = new SchedulePhase();
222                dummySchedule.apply(graph);
223                emitLIR(backend, target, dummySchedule, graph, stub, cc, registerConfig, lirSuites);
224            }
225
226            LIRGenerationResult lirGen = null;
227            lirGen = emitLIR(backend, target, schedule, graph, stub, cc, registerConfig, lirSuites);
228            try (Scope s2 = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) {
229                int bytecodeSize = graph.method() == null ? 0 : graph.getBytecodeSize();
230                compilationResult.setHasUnsafeAccess(graph.hasUnsafeAccess());
231                emitCode(backend, graph.getAssumptions(), graph.method(), graph.getInlinedMethods(), bytecodeSize, lirGen, compilationResult, installedCodeOwner, factory);
232            } catch (Throwable e) {
233                throw Debug.handle(e);
234            }
235        } catch (Throwable e) {
236            throw Debug.handle(e);
237        }
238    }
239
240    public static LIRGenerationResult emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc,
241                    RegisterConfig registerConfig, LIRSuites lirSuites) {
242        try {
243            return emitLIR0(backend, target, schedule, graph, stub, cc, registerConfig, lirSuites);
244        } catch (OutOfRegistersException e) {
245            if (RegisterPressure.getValue() != null && !RegisterPressure.getValue().equals(ALL_REGISTERS)) {
246                try (OverrideScope s = OptionValue.override(RegisterPressure, ALL_REGISTERS)) {
247                    // retry with default register set
248                    return emitLIR0(backend, target, schedule, graph, stub, cc, registerConfig, lirSuites);
249                }
250            } else {
251                throw e;
252            }
253        }
254    }
255
256    private static LIRGenerationResult emitLIR0(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc,
257                    RegisterConfig registerConfig, LIRSuites lirSuites) {
258        try (Scope ds = Debug.scope("EmitLIR"); DebugCloseable a = EmitLIR.start()) {
259            List<Block> blocks = schedule.getCFG().getBlocks();
260            Block startBlock = schedule.getCFG().getStartBlock();
261            assert startBlock != null;
262            assert startBlock.getPredecessorCount() == 0;
263
264            LIR lir = null;
265            List<Block> codeEmittingOrder = null;
266            List<Block> linearScanOrder = null;
267            try (Scope s = Debug.scope("ComputeLinearScanOrder", lir)) {
268                codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.size(), startBlock);
269                linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.size(), startBlock);
270
271                lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder);
272                Debug.dump(lir, "After linear scan order");
273            } catch (Throwable e) {
274                throw Debug.handle(e);
275            }
276            FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig);
277            String compilationUnitName;
278            ResolvedJavaMethod method = graph.method();
279            if (method == null) {
280                compilationUnitName = "<unknown>";
281            } else {
282                compilationUnitName = method.format("%H.%n(%p)");
283            }
284            LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, graph.method(), stub);
285            LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes);
286            NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen);
287
288            // LIR generation
289            LIRGenerationContext context = new LIRGenerationContext(lirGen, nodeLirGen, graph, schedule);
290            try (Scope s = Debug.scope("LIRGeneration", nodeLirGen, lir)) {
291                new LIRGenerationPhase().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
292            } catch (Throwable e) {
293                throw Debug.handle(e);
294            }
295
296            try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) {
297                return emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig));
298            } catch (Throwable e) {
299                throw Debug.handle(e);
300            }
301        } catch (Throwable e) {
302            throw Debug.handle(e);
303        }
304    }
305
306    public static <T extends AbstractBlockBase<T>> LIRGenerationResult emitLowLevel(TargetDescription target, List<T> codeEmittingOrder, List<T> linearScanOrder, LIRGenerationResult lirGenRes,
307                    LIRGeneratorTool lirGen, LIRSuites lirSuites, RegisterAllocationConfig registerAllocationConfig) {
308        PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen);
309        lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, preAllocOptContext);
310
311        AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory(), registerAllocationConfig);
312        lirSuites.getAllocationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, allocContext);
313
314        PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext(lirGen);
315        lirSuites.getPostAllocationOptimizationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, postAllocOptContext);
316
317        return lirGenRes;
318    }
319
320    public static void emitCode(Backend backend, Assumptions assumptions, ResolvedJavaMethod rootMethod, Set<ResolvedJavaMethod> inlinedMethods, int bytecodeSize, LIRGenerationResult lirGenRes,
321                    CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner, CompilationResultBuilderFactory factory) {
322        try (DebugCloseable a = EmitCode.start()) {
323            FrameMap frameMap = lirGenRes.getFrameMap();
324            CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGenRes, frameMap, compilationResult, factory);
325            backend.emitCode(crb, lirGenRes.getLIR(), installedCodeOwner);
326            crb.finish();
327            if (assumptions != null && !assumptions.isEmpty()) {
328                compilationResult.setAssumptions(assumptions.toArray());
329            }
330            if (inlinedMethods != null) {
331                compilationResult.setMethods(rootMethod, inlinedMethods);
332                compilationResult.setBytecodeSize(bytecodeSize);
333            }
334
335            if (Debug.isMeterEnabled()) {
336                List<DataPatch> ldp = compilationResult.getDataPatches();
337                Kind[] kindValues = Kind.values();
338                DebugMetric[] dms = new DebugMetric[kindValues.length];
339                for (int i = 0; i < dms.length; i++) {
340                    dms[i] = Debug.metric("DataPatches-%s", kindValues[i]);
341                }
342
343                for (DataPatch dp : ldp) {
344                    Kind kind = Kind.Illegal;
345                    if (dp.reference instanceof ConstantReference) {
346                        VMConstant constant = ((ConstantReference) dp.reference).getConstant();
347                        kind = ((JavaConstant) constant).getKind();
348                    }
349                    dms[kind.ordinal()].add(1);
350                }
351
352                Debug.metric("CompilationResults").increment();
353                Debug.metric("CodeBytesEmitted").add(compilationResult.getTargetCodeSize());
354                Debug.metric("InfopointsEmitted").add(compilationResult.getInfopoints().size());
355                Debug.metric("DataPatches").add(ldp.size());
356                Debug.metric("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size());
357            }
358
359            Debug.dump(compilationResult, "After code generation");
360        }
361    }
362}