1 /*
   2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.lir.alloc.trace;
  26 
  27 import java.util.ArrayList;
  28 
  29 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
  30 import org.graalvm.compiler.core.common.alloc.Trace;
  31 import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
  32 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  33 import org.graalvm.compiler.lir.alloc.trace.TraceAllocationPhase.TraceAllocationContext;
  34 import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPolicy.AllocationStrategy;
  35 import org.graalvm.compiler.lir.alloc.trace.bu.BottomUpAllocator;
  36 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase;
  37 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  38 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
  39 import org.graalvm.compiler.options.EnumOptionKey;
  40 import org.graalvm.compiler.options.Option;
  41 import org.graalvm.compiler.options.OptionKey;
  42 import org.graalvm.compiler.options.OptionType;
  43 import org.graalvm.compiler.options.OptionValues;
  44 
  45 import jdk.vm.ci.code.TargetDescription;
  46 import jdk.vm.ci.common.JVMCIError;
  47 import jdk.vm.ci.meta.AllocatableValue;
  48 import jdk.vm.ci.meta.PlatformKind;
  49 
  50 /**
  51  * Manages the selection of allocation strategies.
  52  */
  53 public final class DefaultTraceRegisterAllocationPolicy {
  54 
  55     public enum TraceRAPolicies {
  56         Default,
  57         LinearScanOnly,
  58         BottomUpOnly,
  59         AlmostTrivial,
  60         NumVariables,
  61         Ratio,
  62         Loops,
  63         MaxFreq,
  64         FreqBudget,
  65         LoopRatio,
  66         LoopBudget,
  67         LoopMaxFreq
  68     }
  69 
  70     public static class Options {
  71         // @formatter:off
  72         @Option(help = "Use special allocator for trivial blocks.", type = OptionType.Debug)
  73         public static final OptionKey<Boolean> TraceRAtrivialBlockAllocator = new OptionKey<>(true);
  74         @Option(help = "Use BottomUp if there is only one block with at most this number of instructions", type = OptionType.Debug)
  75         public static final OptionKey<Integer> TraceRAalmostTrivialSize = new OptionKey<>(2);
  76         @Option(help = "Use BottomUp for traces with low number of variables at block boundaries", type = OptionType.Debug)
  77         public static final OptionKey<Integer> TraceRAnumVariables = new OptionKey<>(null);
  78         @Option(help = "Use LSRA / BottomUp ratio", type = OptionType.Debug)
  79         public static final OptionKey<Double> TraceRAbottomUpRatio = new OptionKey<>(0.0);
  80         @Option(help = "Probability Threshold", type = OptionType.Debug)
  81         public static final OptionKey<Double> TraceRAprobalilityThreshold = new OptionKey<>(0.8);
  82         @Option(help = "Sum Probability Budget Threshold", type = OptionType.Debug)
  83         public static final OptionKey<Double> TraceRAsumBudget = new OptionKey<>(0.5);
  84         @Option(help = "TraceRA allocation policy to use.", type = OptionType.Debug)
  85         public static final EnumOptionKey<TraceRAPolicies> TraceRAPolicy = new EnumOptionKey<>(TraceRAPolicies.Default);
  86         // @formatter:on
  87     }
  88 
  89     public static final class TrivialTraceStrategy extends AllocationStrategy {
  90 
  91         public TrivialTraceStrategy(TraceRegisterAllocationPolicy plan) {
  92             plan.super();
  93         }
  94 
  95         @Override
  96         public boolean shouldApplyTo(Trace trace) {
  97             return TraceUtil.isTrivialTrace(getLIR(), trace);
  98         }
  99 
 100         @Override
 101         protected TraceAllocationPhase<TraceAllocationContext> initAllocator(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory,
 102                         RegisterAllocationConfig registerAllocationConfig, AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant,
 103                         GlobalLivenessInfo livenessInfo, ArrayList<AllocationStrategy> strategies) {
 104             return new TrivialTraceAllocator();
 105         }
 106     }
 107 
 108     public static class BottomUpStrategy extends AllocationStrategy {
 109 
 110         public BottomUpStrategy(TraceRegisterAllocationPolicy plan) {
 111             // explicitly specify the enclosing instance for the superclass constructor call
 112             plan.super();
 113         }
 114 
 115         @Override
 116         public boolean shouldApplyTo(Trace trace) {
 117             return !containsExceptionEdge(trace);
 118         }
 119 
 120         private static boolean containsExceptionEdge(Trace trace) {
 121             for (AbstractBlockBase<?> block : trace.getBlocks()) {
 122                 // check if one of the successors is an exception handler
 123                 for (AbstractBlockBase<?> succ : block.getSuccessors()) {
 124                     if (succ.isExceptionEntry()) {
 125                         return true;
 126                     }
 127                 }
 128             }
 129             return false;
 130         }
 131 
 132         @Override
 133         protected TraceAllocationPhase<TraceAllocationContext> initAllocator(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory,
 134                         RegisterAllocationConfig registerAllocationConfig, AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant,
 135                         GlobalLivenessInfo livenessInfo, ArrayList<AllocationStrategy> strategies) {
 136             return new BottomUpAllocator(target, lirGenRes, spillMoveFactory, registerAllocationConfig, cachedStackSlots, resultTraces, neverSpillConstant, livenessInfo);
 137         }
 138     }
 139 
 140     public static final class BottomUpAlmostTrivialStrategy extends BottomUpStrategy {
 141 
 142         private final int trivialTraceSize;
 143 
 144         public BottomUpAlmostTrivialStrategy(TraceRegisterAllocationPolicy plan) {
 145             // explicitly specify the enclosing instance for the superclass constructor call
 146             super(plan);
 147             trivialTraceSize = Options.TraceRAalmostTrivialSize.getValue(plan.getOptions());
 148         }
 149 
 150         @Override
 151         public boolean shouldApplyTo(Trace trace) {
 152             if (!super.shouldApplyTo(trace)) {
 153                 return false;
 154             }
 155             if (trace.size() != 1) {
 156                 return false;
 157             }
 158             return getLIR().getLIRforBlock(trace.getBlocks()[0]).size() <= trivialTraceSize;
 159         }
 160 
 161     }
 162 
 163     public static final class BottomUpNumVariablesStrategy extends BottomUpStrategy {
 164 
 165         private final int numVarLimit;
 166 
 167         public BottomUpNumVariablesStrategy(TraceRegisterAllocationPolicy plan) {
 168             // explicitly specify the enclosing instance for the superclass constructor call
 169             super(plan);
 170             Integer value = Options.TraceRAnumVariables.getValue(plan.getOptions());
 171             if (value != null) {
 172                 numVarLimit = value;
 173             } else {
 174                 /* Default to the number of allocatable word registers. */
 175                 PlatformKind wordKind = getTarget().arch.getWordKind();
 176                 int numWordRegisters = getRegisterAllocationConfig().getAllocatableRegisters(wordKind).allocatableRegisters.length;
 177                 numVarLimit = numWordRegisters;
 178             }
 179         }
 180 
 181         @Override
 182         public boolean shouldApplyTo(Trace trace) {
 183             if (!super.shouldApplyTo(trace)) {
 184                 return false;
 185             }
 186             GlobalLivenessInfo livenessInfo = getGlobalLivenessInfo();
 187             int maxNumVars = livenessInfo.getBlockIn(trace.getBlocks()[0]).length;
 188             for (AbstractBlockBase<?> block : trace.getBlocks()) {
 189                 maxNumVars = Math.max(maxNumVars, livenessInfo.getBlockOut(block).length);
 190             }
 191             return maxNumVars <= numVarLimit;
 192         }
 193 
 194     }
 195 
 196     public static final class BottomUpRatioStrategy extends BottomUpStrategy {
 197 
 198         private final double ratio;
 199 
 200         public BottomUpRatioStrategy(TraceRegisterAllocationPolicy plan) {
 201             // explicitly specify the enclosing instance for the superclass constructor call
 202             super(plan);
 203             ratio = Options.TraceRAbottomUpRatio.getValue(plan.getOptions());
 204         }
 205 
 206         @Override
 207         public boolean shouldApplyTo(Trace trace) {
 208             if (!super.shouldApplyTo(trace)) {
 209                 return false;
 210             }
 211             double numTraces = getTraceBuilderResult().getTraces().size();
 212             double traceId = trace.getId();
 213             assert ratio >= 0 && ratio <= 1.0 : "Ratio out of range: " + ratio;
 214             return (traceId / numTraces) >= ratio;
 215         }
 216 
 217     }
 218 
 219     public abstract static class BottomUpLoopStrategyBase extends BottomUpStrategy {
 220 
 221         public BottomUpLoopStrategyBase(TraceRegisterAllocationPolicy plan) {
 222             // explicitly specify the enclosing instance for the superclass constructor call
 223             super(plan);
 224         }
 225 
 226         @Override
 227         public final boolean shouldApplyTo(Trace trace) {
 228             if (!super.shouldApplyTo(trace)) {
 229                 return false;
 230             }
 231             if (getLIR().getControlFlowGraph().getLoops().isEmpty()) {
 232                 return shouldApplyToNoLoop(trace);
 233             }
 234             for (AbstractBlockBase<?> block : trace.getBlocks()) {
 235                 if (block.getLoopDepth() > 0) {
 236                     return false;
 237                 }
 238             }
 239             return true;
 240         }
 241 
 242         protected abstract boolean shouldApplyToNoLoop(Trace trace);
 243 
 244     }
 245 
 246     public static final class BottomUpLoopStrategy extends BottomUpLoopStrategyBase {
 247 
 248         public BottomUpLoopStrategy(TraceRegisterAllocationPolicy plan) {
 249             // explicitly specify the enclosing instance for the superclass constructor call
 250             super(plan);
 251         }
 252 
 253         @Override
 254         protected boolean shouldApplyToNoLoop(Trace trace) {
 255             // no loops at all -> use LSRA
 256             return false;
 257         }
 258 
 259     }
 260 
 261     public static final class BottomUpDelegatingLoopStrategy extends BottomUpLoopStrategyBase {
 262 
 263         private final BottomUpStrategy delegate;
 264 
 265         public BottomUpDelegatingLoopStrategy(TraceRegisterAllocationPolicy plan, BottomUpStrategy delegate) {
 266             // explicitly specify the enclosing instance for the superclass constructor call
 267             super(plan);
 268             this.delegate = delegate;
 269         }
 270 
 271         @Override
 272         protected boolean shouldApplyToNoLoop(Trace trace) {
 273             return delegate.shouldApplyTo(trace);
 274         }
 275 
 276     }
 277 
 278     public static final class BottomUpMaxFrequencyStrategy extends BottomUpStrategy {
 279 
 280         private final double maxMethodProbability;
 281         private final double probabilityThreshold;
 282 
 283         public BottomUpMaxFrequencyStrategy(TraceRegisterAllocationPolicy plan) {
 284             // explicitly specify the enclosing instance for the superclass constructor call
 285             super(plan);
 286             maxMethodProbability = maxProbability(getLIR().getControlFlowGraph().getBlocks());
 287             probabilityThreshold = Options.TraceRAprobalilityThreshold.getValue(plan.getOptions());
 288         }
 289 
 290         private static double maxProbability(AbstractBlockBase<?>[] blocks) {
 291             double max = 0;
 292             for (AbstractBlockBase<?> block : blocks) {
 293                 double probability = block.probability();
 294                 if (probability > max) {
 295                     max = probability;
 296                 }
 297             }
 298             return max;
 299         }
 300 
 301         @Override
 302         public boolean shouldApplyTo(Trace trace) {
 303             if (!super.shouldApplyTo(trace)) {
 304                 return false;
 305             }
 306             return maxProbability(trace.getBlocks()) / maxMethodProbability <= probabilityThreshold;
 307         }
 308 
 309     }
 310 
 311     public static final class BottomUpFrequencyBudgetStrategy extends BottomUpStrategy {
 312 
 313         private final double[] cumulativeTraceProbability;
 314         private final double budget;
 315 
 316         public BottomUpFrequencyBudgetStrategy(TraceRegisterAllocationPolicy plan) {
 317             // explicitly specify the enclosing instance for the superclass constructor call
 318             super(plan);
 319             ArrayList<Trace> traces = getTraceBuilderResult().getTraces();
 320             this.cumulativeTraceProbability = new double[traces.size()];
 321             double sumMethodProbability = init(traces, this.cumulativeTraceProbability);
 322             this.budget = sumMethodProbability * Options.TraceRAsumBudget.getValue(plan.getOptions());
 323         }
 324 
 325         private static double init(ArrayList<Trace> traces, double[] sumTraces) {
 326             double sumMethod = 0;
 327             for (Trace trace : traces) {
 328                 double traceSum = 0;
 329                 for (AbstractBlockBase<?> block : trace.getBlocks()) {
 330                     traceSum += block.probability();
 331                 }
 332                 sumMethod += traceSum;
 333                 // store cumulative sum for trace
 334                 sumTraces[trace.getId()] = sumMethod;
 335             }
 336             return sumMethod;
 337         }
 338 
 339         @Override
 340         public boolean shouldApplyTo(Trace trace) {
 341             if (!super.shouldApplyTo(trace)) {
 342                 return false;
 343             }
 344             double cumTraceProb = cumulativeTraceProbability[trace.getId()];
 345             return cumTraceProb > budget;
 346         }
 347 
 348     }
 349 
 350     public static final class TraceLinearScanStrategy extends AllocationStrategy {
 351 
 352         public TraceLinearScanStrategy(TraceRegisterAllocationPolicy plan) {
 353             // explicitly specify the enclosing instance for the superclass constructor call
 354             plan.super();
 355         }
 356 
 357         @Override
 358         public boolean shouldApplyTo(Trace trace) {
 359             return true;
 360         }
 361 
 362         @Override
 363         protected TraceAllocationPhase<TraceAllocationContext> initAllocator(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory,
 364                         RegisterAllocationConfig registerAllocationConfig, AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant,
 365                         GlobalLivenessInfo livenessInfo, ArrayList<AllocationStrategy> strategies) {
 366             return new TraceLinearScanPhase(target, lirGenRes, spillMoveFactory, registerAllocationConfig, resultTraces, neverSpillConstant, cachedStackSlots, livenessInfo);
 367         }
 368 
 369     }
 370 
 371     public static TraceRegisterAllocationPolicy allocationPolicy(TargetDescription target, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory,
 372                     RegisterAllocationConfig registerAllocationConfig, AllocatableValue[] cachedStackSlots, TraceBuilderResult resultTraces, boolean neverSpillConstant,
 373                     GlobalLivenessInfo livenessInfo, OptionValues options) {
 374         TraceRegisterAllocationPolicy plan = new TraceRegisterAllocationPolicy(target, lirGenRes, spillMoveFactory, registerAllocationConfig, cachedStackSlots, resultTraces, neverSpillConstant,
 375                         livenessInfo);
 376         if (Options.TraceRAtrivialBlockAllocator.getValue(options)) {
 377             plan.appendStrategy(new TrivialTraceStrategy(plan));
 378         }
 379         switch (Options.TraceRAPolicy.getValue(options)) {
 380             case Default:
 381             case LinearScanOnly:
 382                 break;
 383             case BottomUpOnly:
 384                 plan.appendStrategy(new BottomUpStrategy(plan));
 385                 break;
 386             case AlmostTrivial:
 387                 plan.appendStrategy(new BottomUpAlmostTrivialStrategy(plan));
 388                 break;
 389             case NumVariables:
 390                 plan.appendStrategy(new BottomUpNumVariablesStrategy(plan));
 391                 break;
 392             case Ratio:
 393                 plan.appendStrategy(new BottomUpRatioStrategy(plan));
 394                 break;
 395             case Loops:
 396                 plan.appendStrategy(new BottomUpLoopStrategy(plan));
 397                 break;
 398             case MaxFreq:
 399                 plan.appendStrategy(new BottomUpMaxFrequencyStrategy(plan));
 400                 break;
 401             case FreqBudget:
 402                 plan.appendStrategy(new BottomUpFrequencyBudgetStrategy(plan));
 403                 break;
 404             case LoopRatio:
 405                 plan.appendStrategy(new BottomUpDelegatingLoopStrategy(plan, new BottomUpRatioStrategy(plan)));
 406                 break;
 407             case LoopMaxFreq:
 408                 plan.appendStrategy(new BottomUpDelegatingLoopStrategy(plan, new BottomUpMaxFrequencyStrategy(plan)));
 409                 break;
 410             case LoopBudget:
 411                 plan.appendStrategy(new BottomUpDelegatingLoopStrategy(plan, new BottomUpFrequencyBudgetStrategy(plan)));
 412                 break;
 413             default:
 414                 throw JVMCIError.shouldNotReachHere();
 415         }
 416         // Fallback
 417         plan.appendStrategy(new TraceLinearScanStrategy(plan));
 418         return plan;
 419     }
 420 }