< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerator.java

Print this page


   1 /*
   2  * Copyright (c) 2009, 2018, 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.gen;
  26 
  27 import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
  28 import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
  29 import static jdk.vm.ci.code.ValueUtil.isLegal;
  30 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
  31 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
  32 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
  33 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
  34 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
  35 
  36 import java.util.ArrayList;
  37 import java.util.List;

  38 
  39 import jdk.vm.ci.code.RegisterConfig;
  40 import org.graalvm.compiler.asm.Label;
  41 import org.graalvm.compiler.core.common.LIRKind;
  42 import org.graalvm.compiler.core.common.calc.Condition;
  43 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  44 import org.graalvm.compiler.core.common.spi.CodeGenProviders;
  45 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
  46 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
  47 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  48 import org.graalvm.compiler.core.common.type.Stamp;
  49 import org.graalvm.compiler.debug.GraalError;
  50 import org.graalvm.compiler.debug.TTY;
  51 import org.graalvm.compiler.graph.NodeSourcePosition;
  52 import org.graalvm.compiler.lir.ConstantValue;
  53 import org.graalvm.compiler.lir.LIR;
  54 import org.graalvm.compiler.lir.LIRFrameState;
  55 import org.graalvm.compiler.lir.LIRInstruction;
  56 import org.graalvm.compiler.lir.LIRVerifier;
  57 import org.graalvm.compiler.lir.LabelRef;
  58 import org.graalvm.compiler.lir.StandardOp;
  59 import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
  60 import org.graalvm.compiler.lir.StandardOp.LabelOp;
  61 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;

  62 import org.graalvm.compiler.lir.SwitchStrategy;
  63 import org.graalvm.compiler.lir.Variable;
  64 import org.graalvm.compiler.options.Option;
  65 import org.graalvm.compiler.options.OptionKey;
  66 import org.graalvm.compiler.options.OptionType;
  67 import org.graalvm.compiler.options.OptionValues;
  68 
  69 import jdk.vm.ci.code.CallingConvention;
  70 import jdk.vm.ci.code.CodeCacheProvider;
  71 import jdk.vm.ci.code.Register;
  72 import jdk.vm.ci.code.RegisterAttributes;

  73 import jdk.vm.ci.code.StackSlot;
  74 import jdk.vm.ci.code.TargetDescription;
  75 import jdk.vm.ci.meta.AllocatableValue;
  76 import jdk.vm.ci.meta.Constant;
  77 import jdk.vm.ci.meta.JavaConstant;
  78 import jdk.vm.ci.meta.JavaKind;
  79 import jdk.vm.ci.meta.MetaAccessProvider;
  80 import jdk.vm.ci.meta.PlatformKind;
  81 import jdk.vm.ci.meta.Value;
  82 import jdk.vm.ci.meta.ValueKind;
  83 
  84 /**
  85  * This class traverses the HIR instructions and generates LIR instructions from them.
  86  */
  87 public abstract class LIRGenerator implements LIRGeneratorTool {
  88 
  89     public static class Options {
  90         // @formatter:off
  91         @Option(help = "Print HIR along side LIR as the latter is generated", type = OptionType.Debug)
  92         public static final OptionKey<Boolean> PrintIRWithLIR = new OptionKey<>(false);


 432         assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
 433         Value[] argLocations = new Value[args.length];
 434         for (int i = 0; i < args.length; i++) {
 435             Value arg = args[i];
 436             AllocatableValue loc = linkageCc.getArgument(i);
 437             emitMove(loc, arg);
 438             argLocations[i] = loc;
 439         }
 440         res.setForeignCall(true);
 441         emitForeignCallOp(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
 442 
 443         if (isLegal(linkageCc.getReturn())) {
 444             return emitMove(linkageCc.getReturn());
 445         } else {
 446             return null;
 447         }
 448     }
 449 
 450     @Override
 451     public void emitStrategySwitch(JavaConstant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
 452         int keyCount = keyConstants.length;
 453         SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);





 454         long valueRange = keyConstants[keyCount - 1].asLong() - keyConstants[0].asLong() + 1;
 455         double tableSwitchDensity = keyCount / (double) valueRange;

 456         /*
 457          * This heuristic tries to find a compromise between the effort for the best switch strategy
 458          * and the density of a tableswitch. If the effort for the strategy is at least 4, then a
 459          * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers
 460          * gradually with additional effort.
 461          */
 462         if (strategy.getAverageEffort() < 4 || tableSwitchDensity < (1 / Math.sqrt(strategy.getAverageEffort()))) {
 463             emitStrategySwitch(strategy, value, keyTargets, defaultTarget);
 464         } else {
 465             int minValue = keyConstants[0].asInt();
 466             assert valueRange < Integer.MAX_VALUE;
 467             LabelRef[] targets = new LabelRef[(int) valueRange];
 468             for (int i = 0; i < valueRange; i++) {
 469                 targets[i] = defaultTarget;
 470             }
 471             for (int i = 0; i < keyCount; i++) {
 472                 targets[keyConstants[i].asInt() - minValue] = keyTargets[i];


















 473             }
 474             emitTableSwitch(minValue, defaultTarget, targets, value);
 475         }
 476     }
 477 
 478     @Override
 479     public abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
 480 
 481     protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);










 482 
 483     @Override
 484     public void beforeRegisterAllocation() {
 485     }
 486 
 487     /**
 488      * Gets a garbage value for a given kind.
 489      */
 490     protected abstract JavaConstant zapValueForKind(PlatformKind kind);
 491 
 492     @Override
 493     public LIRKind getLIRKind(Stamp stamp) {
 494         return stamp.getLIRKind(lirKindTool);
 495     }
 496 
 497     protected LIRKind getAddressKind(Value base, long displacement, Value index) {
 498         if (LIRKind.isValue(base) && (index.equals(Value.ILLEGAL) || LIRKind.isValue(index))) {
 499             return LIRKind.value(target().arch.getWordKind());
 500         } else if (base.getValueKind() instanceof LIRKind && base.getValueKind(LIRKind.class).isReference(0) && displacement == 0L && index.equals(Value.ILLEGAL)) {
 501             return LIRKind.reference(target().arch.getWordKind());


   1 /*
   2  * Copyright (c) 2009, 2019, 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.gen;
  26 
  27 import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
  28 import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
  29 import static jdk.vm.ci.code.ValueUtil.isLegal;
  30 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
  31 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
  32 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
  33 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
  34 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
  35 
  36 import java.util.ArrayList;
  37 import java.util.List;
  38 import java.util.Optional;
  39 

  40 import org.graalvm.compiler.asm.Label;
  41 import org.graalvm.compiler.core.common.LIRKind;
  42 import org.graalvm.compiler.core.common.calc.Condition;
  43 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  44 import org.graalvm.compiler.core.common.spi.CodeGenProviders;
  45 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
  46 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
  47 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  48 import org.graalvm.compiler.core.common.type.Stamp;
  49 import org.graalvm.compiler.debug.GraalError;
  50 import org.graalvm.compiler.debug.TTY;
  51 import org.graalvm.compiler.graph.NodeSourcePosition;
  52 import org.graalvm.compiler.lir.ConstantValue;
  53 import org.graalvm.compiler.lir.LIR;
  54 import org.graalvm.compiler.lir.LIRFrameState;
  55 import org.graalvm.compiler.lir.LIRInstruction;
  56 import org.graalvm.compiler.lir.LIRVerifier;
  57 import org.graalvm.compiler.lir.LabelRef;
  58 import org.graalvm.compiler.lir.StandardOp;
  59 import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
  60 import org.graalvm.compiler.lir.StandardOp.LabelOp;
  61 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
  62 import org.graalvm.compiler.lir.hashing.Hasher;
  63 import org.graalvm.compiler.lir.SwitchStrategy;
  64 import org.graalvm.compiler.lir.Variable;
  65 import org.graalvm.compiler.options.Option;
  66 import org.graalvm.compiler.options.OptionKey;
  67 import org.graalvm.compiler.options.OptionType;
  68 import org.graalvm.compiler.options.OptionValues;
  69 
  70 import jdk.vm.ci.code.CallingConvention;
  71 import jdk.vm.ci.code.CodeCacheProvider;
  72 import jdk.vm.ci.code.Register;
  73 import jdk.vm.ci.code.RegisterAttributes;
  74 import jdk.vm.ci.code.RegisterConfig;
  75 import jdk.vm.ci.code.StackSlot;
  76 import jdk.vm.ci.code.TargetDescription;
  77 import jdk.vm.ci.meta.AllocatableValue;
  78 import jdk.vm.ci.meta.Constant;
  79 import jdk.vm.ci.meta.JavaConstant;
  80 import jdk.vm.ci.meta.JavaKind;
  81 import jdk.vm.ci.meta.MetaAccessProvider;
  82 import jdk.vm.ci.meta.PlatformKind;
  83 import jdk.vm.ci.meta.Value;
  84 import jdk.vm.ci.meta.ValueKind;
  85 
  86 /**
  87  * This class traverses the HIR instructions and generates LIR instructions from them.
  88  */
  89 public abstract class LIRGenerator implements LIRGeneratorTool {
  90 
  91     public static class Options {
  92         // @formatter:off
  93         @Option(help = "Print HIR along side LIR as the latter is generated", type = OptionType.Debug)
  94         public static final OptionKey<Boolean> PrintIRWithLIR = new OptionKey<>(false);


 434         assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
 435         Value[] argLocations = new Value[args.length];
 436         for (int i = 0; i < args.length; i++) {
 437             Value arg = args[i];
 438             AllocatableValue loc = linkageCc.getArgument(i);
 439             emitMove(loc, arg);
 440             argLocations[i] = loc;
 441         }
 442         res.setForeignCall(true);
 443         emitForeignCallOp(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
 444 
 445         if (isLegal(linkageCc.getReturn())) {
 446             return emitMove(linkageCc.getReturn());
 447         } else {
 448             return null;
 449         }
 450     }
 451 
 452     @Override
 453     public void emitStrategySwitch(JavaConstant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {

 454         SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);
 455 
 456         int keyCount = keyConstants.length;
 457         double minDensity = 1 / Math.sqrt(strategy.getAverageEffort());
 458         Optional<Hasher> hasher = hasherFor(keyConstants, minDensity);
 459         double hashTableSwitchDensity = hasher.map(h -> keyCount / (double) h.cardinality()).orElse(0d);
 460         long valueRange = keyConstants[keyCount - 1].asLong() - keyConstants[0].asLong() + 1;
 461         double tableSwitchDensity = keyCount / (double) valueRange;
 462 
 463         /*
 464          * This heuristic tries to find a compromise between the effort for the best switch strategy
 465          * and the density of a tableswitch. If the effort for the strategy is at least 4, then a
 466          * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers
 467          * gradually with additional effort.
 468          */
 469         if (strategy.getAverageEffort() < 4d || (tableSwitchDensity < minDensity && hashTableSwitchDensity < minDensity)) {
 470             emitStrategySwitch(strategy, value, keyTargets, defaultTarget);
 471         } else {
 472             if (hashTableSwitchDensity > tableSwitchDensity) {
 473                 Hasher h = hasher.get();
 474                 int cardinality = h.cardinality();
 475                 LabelRef[] targets = new LabelRef[cardinality];
 476                 JavaConstant[] keys = new JavaConstant[cardinality];
 477                 for (int i = 0; i < cardinality; i++) {
 478                     keys[i] = JavaConstant.INT_0;
 479                     targets[i] = defaultTarget;
 480                 }
 481                 for (int i = 0; i < keyCount; i++) {
 482                     int idx = h.hash(keyConstants[i].asLong());
 483                     keys[idx] = keyConstants[i];
 484                     targets[idx] = keyTargets[i];
 485                 }
 486                 emitHashTableSwitch(h, keys, defaultTarget, targets, value);
 487             } else {
 488                 int minValue = keyConstants[0].asInt();
 489                 assert valueRange < Integer.MAX_VALUE;
 490                 LabelRef[] targets = new LabelRef[(int) valueRange];
 491                 for (int i = 0; i < valueRange; i++) {
 492                     targets[i] = defaultTarget;
 493                 }
 494                 for (int i = 0; i < keyCount; i++) {
 495                     targets[keyConstants[i].asInt() - minValue] = keyTargets[i];
 496                 }
 497                 emitTableSwitch(minValue, defaultTarget, targets, value);
 498             }

 499         }
 500     }
 501 
 502     @Override
 503     public abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
 504 
 505     protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);
 506 
 507     @SuppressWarnings("unused")
 508     protected Optional<Hasher> hasherFor(JavaConstant[] keyConstants, double minDensity) {
 509         return Optional.empty();
 510     }
 511 
 512     @SuppressWarnings("unused")
 513     protected void emitHashTableSwitch(Hasher hasher, JavaConstant[] keys, LabelRef defaultTarget, LabelRef[] targets, Value value) {
 514         throw new UnsupportedOperationException(getClass().getSimpleName() + " doesn't support hash table switches");
 515     }
 516 
 517     @Override
 518     public void beforeRegisterAllocation() {
 519     }
 520 
 521     /**
 522      * Gets a garbage value for a given kind.
 523      */
 524     protected abstract JavaConstant zapValueForKind(PlatformKind kind);
 525 
 526     @Override
 527     public LIRKind getLIRKind(Stamp stamp) {
 528         return stamp.getLIRKind(lirKindTool);
 529     }
 530 
 531     protected LIRKind getAddressKind(Value base, long displacement, Value index) {
 532         if (LIRKind.isValue(base) && (index.equals(Value.ILLEGAL) || LIRKind.isValue(index))) {
 533             return LIRKind.value(target().arch.getWordKind());
 534         } else if (base.getValueKind() instanceof LIRKind && base.getValueKind(LIRKind.class).isReference(0) && displacement == 0L && index.equals(Value.ILLEGAL)) {
 535             return LIRKind.reference(target().arch.getWordKind());


< prev index next >