48 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
49 import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
50 import org.graalvm.compiler.lir.ValueConsumer;
51 import org.graalvm.compiler.lir.Variable;
52 import org.graalvm.compiler.lir.constopt.ConstantTree.Flags;
53 import org.graalvm.compiler.lir.constopt.ConstantTree.NodeCost;
54 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
55 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
56 import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase;
57 import org.graalvm.compiler.options.NestedBooleanOptionKey;
58 import org.graalvm.compiler.options.Option;
59 import org.graalvm.compiler.options.OptionType;
60
61 import jdk.vm.ci.code.TargetDescription;
62 import jdk.vm.ci.meta.Constant;
63 import jdk.vm.ci.meta.Value;
64 import jdk.vm.ci.meta.ValueKind;
65
66 /**
67 * This optimization tries to improve the handling of constants by replacing a single definition of
68 * a constant, which is potentially scheduled into a block with high probability, with one or more
69 * definitions in blocks with a lower probability.
70 */
71 public final class ConstantLoadOptimization extends PreAllocationOptimizationPhase {
72
73 public static class Options {
74 // @formatter:off
75 @Option(help = "Enable constant load optimization.", type = OptionType.Debug)
76 public static final NestedBooleanOptionKey LIROptConstantLoadOptimization = new NestedBooleanOptionKey(LIROptimization, true);
77 // @formatter:on
78 }
79
80 @Override
81 protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) {
82 LIRGeneratorTool lirGen = context.lirGen;
83 new Optimization(lirGenRes.getLIR(), lirGen).apply();
84 }
85
86 private static final CounterKey constantsTotal = DebugContext.counter("ConstantLoadOptimization[total]");
87 private static final CounterKey phiConstantsSkipped = DebugContext.counter("ConstantLoadOptimization[PhisSkipped]");
88 private static final CounterKey singleUsageConstantsSkipped = DebugContext.counter("ConstantLoadOptimization[SingleUsageSkipped]");
89 private static final CounterKey usageAtDefinitionSkipped = DebugContext.counter("ConstantLoadOptimization[UsageAtDefinitionSkipped]");
254 */
255 @SuppressWarnings("try")
256 private void createConstantTree(DefUseTree tree) {
257 ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree);
258 constTree.set(Flags.SUBTREE, tree.getBlock());
259 tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock()));
260
261 if (constTree.get(Flags.USAGE, tree.getBlock())) {
262 // usage in the definition block -> no optimization
263 usageAtDefinitionSkipped.increment(debug);
264 return;
265 }
266
267 constTree.markBlocks();
268
269 NodeCost cost = ConstantTreeAnalyzer.analyze(debug, constTree, tree.getBlock());
270 int usageCount = cost.getUsages().size();
271 assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount();
272
273 if (debug.isLogEnabled()) {
274 try (Indent i = debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) {
275 debug.log("Usages result: %s", cost);
276 }
277
278 }
279
280 if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) {
281 try (DebugContext.Scope s = debug.scope("CLOmodify", constTree); Indent i = debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) {
282 // mark original load for removal
283 deleteInstruction(tree);
284 constantsOptimized.increment(debug);
285
286 // collect result
287 createLoads(tree, constTree, tree.getBlock());
288
289 } catch (Throwable e) {
290 throw debug.handle(e);
291 }
292 } else {
293 // no better solution found
294 materializeAtDefinitionSkipped.increment(debug);
295 }
296 debug.dump(DebugContext.DETAILED_LEVEL, constTree, "ConstantTree for %s", tree.getVariable());
297 }
298
299 private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlockBase<?> startBlock) {
300 Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>();
|
48 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
49 import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
50 import org.graalvm.compiler.lir.ValueConsumer;
51 import org.graalvm.compiler.lir.Variable;
52 import org.graalvm.compiler.lir.constopt.ConstantTree.Flags;
53 import org.graalvm.compiler.lir.constopt.ConstantTree.NodeCost;
54 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
55 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
56 import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase;
57 import org.graalvm.compiler.options.NestedBooleanOptionKey;
58 import org.graalvm.compiler.options.Option;
59 import org.graalvm.compiler.options.OptionType;
60
61 import jdk.vm.ci.code.TargetDescription;
62 import jdk.vm.ci.meta.Constant;
63 import jdk.vm.ci.meta.Value;
64 import jdk.vm.ci.meta.ValueKind;
65
66 /**
67 * This optimization tries to improve the handling of constants by replacing a single definition of
68 * a constant, which is potentially scheduled into a block with high frequency, with one or more
69 * definitions in blocks with a lower frequency.
70 */
71 public final class ConstantLoadOptimization extends PreAllocationOptimizationPhase {
72
73 public static class Options {
74 // @formatter:off
75 @Option(help = "Enable constant load optimization.", type = OptionType.Debug)
76 public static final NestedBooleanOptionKey LIROptConstantLoadOptimization = new NestedBooleanOptionKey(LIROptimization, true);
77 // @formatter:on
78 }
79
80 @Override
81 protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) {
82 LIRGeneratorTool lirGen = context.lirGen;
83 new Optimization(lirGenRes.getLIR(), lirGen).apply();
84 }
85
86 private static final CounterKey constantsTotal = DebugContext.counter("ConstantLoadOptimization[total]");
87 private static final CounterKey phiConstantsSkipped = DebugContext.counter("ConstantLoadOptimization[PhisSkipped]");
88 private static final CounterKey singleUsageConstantsSkipped = DebugContext.counter("ConstantLoadOptimization[SingleUsageSkipped]");
89 private static final CounterKey usageAtDefinitionSkipped = DebugContext.counter("ConstantLoadOptimization[UsageAtDefinitionSkipped]");
254 */
255 @SuppressWarnings("try")
256 private void createConstantTree(DefUseTree tree) {
257 ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree);
258 constTree.set(Flags.SUBTREE, tree.getBlock());
259 tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock()));
260
261 if (constTree.get(Flags.USAGE, tree.getBlock())) {
262 // usage in the definition block -> no optimization
263 usageAtDefinitionSkipped.increment(debug);
264 return;
265 }
266
267 constTree.markBlocks();
268
269 NodeCost cost = ConstantTreeAnalyzer.analyze(debug, constTree, tree.getBlock());
270 int usageCount = cost.getUsages().size();
271 assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount();
272
273 if (debug.isLogEnabled()) {
274 try (Indent i = debug.logAndIndent("Variable: %s, Block: %s, freq.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().getRelativeFrequency())) {
275 debug.log("Usages result: %s", cost);
276 }
277
278 }
279
280 if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().getRelativeFrequency()) {
281 try (DebugContext.Scope s = debug.scope("CLOmodify", constTree); Indent i = debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) {
282 // mark original load for removal
283 deleteInstruction(tree);
284 constantsOptimized.increment(debug);
285
286 // collect result
287 createLoads(tree, constTree, tree.getBlock());
288
289 } catch (Throwable e) {
290 throw debug.handle(e);
291 }
292 } else {
293 // no better solution found
294 materializeAtDefinitionSkipped.increment(debug);
295 }
296 debug.dump(DebugContext.DETAILED_LEVEL, constTree, "ConstantTree for %s", tree.getVariable());
297 }
298
299 private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlockBase<?> startBlock) {
300 Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>();
|