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}