< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java

Print this page
rev 52889 : 8214023: Update Graal


   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.core.aarch64;
  26 

  27 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;

  28 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
  29 
  30 import java.util.function.Function;
  31 
  32 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
  33 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
  34 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
  35 import org.graalvm.compiler.core.common.LIRKind;
  36 import org.graalvm.compiler.core.common.calc.Condition;
  37 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  38 import org.graalvm.compiler.debug.GraalError;
  39 import org.graalvm.compiler.lir.LIRFrameState;
  40 import org.graalvm.compiler.lir.LIRValueUtil;
  41 import org.graalvm.compiler.lir.LabelRef;
  42 import org.graalvm.compiler.lir.StandardOp;
  43 import org.graalvm.compiler.lir.SwitchStrategy;
  44 import org.graalvm.compiler.lir.Variable;
  45 import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
  46 import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
  47 import org.graalvm.compiler.lir.aarch64.AArch64ArrayCompareToOp;
  48 import org.graalvm.compiler.lir.aarch64.AArch64ArrayEqualsOp;
  49 import org.graalvm.compiler.lir.aarch64.AArch64ByteSwapOp;
  50 import org.graalvm.compiler.lir.aarch64.AArch64Compare;
  51 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow;
  52 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.BranchOp;
  53 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.CondMoveOp;

  54 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp;
  55 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.TableSwitchOp;
  56 import org.graalvm.compiler.lir.aarch64.AArch64LIRFlagsVersioned;
  57 import org.graalvm.compiler.lir.aarch64.AArch64Move;
  58 import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.AtomicReadAndAddOp;
  59 import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.AtomicReadAndAddLSEOp;
  60 import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.CompareAndSwapOp;
  61 import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.AtomicReadAndWriteOp;
  62 import org.graalvm.compiler.lir.aarch64.AArch64Move.MembarOp;
  63 import org.graalvm.compiler.lir.aarch64.AArch64PauseOp;
  64 import org.graalvm.compiler.lir.aarch64.AArch64SpeculativeBarrier;
  65 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  66 import org.graalvm.compiler.lir.gen.LIRGenerator;
  67 import org.graalvm.compiler.phases.util.Providers;
  68 
  69 import jdk.vm.ci.aarch64.AArch64;
  70 import jdk.vm.ci.aarch64.AArch64Kind;
  71 import jdk.vm.ci.code.CallingConvention;
  72 import jdk.vm.ci.code.RegisterValue;
  73 import jdk.vm.ci.meta.AllocatableValue;


  83     public AArch64LIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes) {
  84         super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
  85     }
  86 
  87     /**
  88      * Checks whether the supplied constant can be used without loading it into a register for store
  89      * operations, i.e., on the right hand side of a memory access.
  90      *
  91      * @param c The constant to check.
  92      * @return True if the constant can be used directly, false if the constant needs to be in a
  93      *         register.
  94      */
  95     protected static final boolean canStoreConstant(JavaConstant c) {
  96         // Our own code never calls this since we can't make a definite statement about whether or
  97         // not we can inline a constant without knowing what kind of operation we execute. Let's be
  98         // optimistic here and fix up mistakes later.
  99         return true;
 100     }
 101 
 102     /**












 103      * AArch64 cannot use anything smaller than a word in any instruction other than load and store.
 104      */
 105     @Override
 106     public <K extends ValueKind<K>> K toRegisterKind(K kind) {
 107         switch ((AArch64Kind) kind.getPlatformKind()) {
 108             case BYTE:
 109             case WORD:
 110                 return kind.changeType(AArch64Kind.DWORD);
 111             default:
 112                 return kind;
 113         }
 114     }
 115 
 116     @Override
 117     public void emitNullCheck(Value address, LIRFrameState state) {
 118         append(new AArch64Move.NullCheckOp(asAddressValue(address), state));
 119     }
 120 
 121     @Override
 122     public Variable emitAddress(AllocatableValue stackslot) {


 211      * falseValue.
 212      *
 213      * @param left Arbitrary value. Has to have same type as right. Non null.
 214      * @param right Arbitrary value. Has to have same type as left. Non null.
 215      * @param cond condition that decides whether to move trueValue or falseValue into result. Non
 216      *            null.
 217      * @param unorderedIsTrue defines whether floating-point comparisons consider unordered true or
 218      *            not. Ignored for integer comparisons.
 219      * @param trueValue arbitrary value same type as falseValue. Non null.
 220      * @param falseValue arbitrary value same type as trueValue. Non null.
 221      * @return value containing trueValue if cond + unorderedIsTrue is true, else falseValue. Non
 222      *         null.
 223      */
 224     @Override
 225     public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
 226         boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue);
 227         Condition finalCondition = mirrored ? cond.mirror() : cond;
 228         boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
 229         ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
 230         Variable result = newVariable(trueValue.getValueKind());






 231         append(new CondMoveOp(result, cmpCondition, loadReg(trueValue), loadReg(falseValue)));

 232         return result;
 233     }
 234 
 235     @Override
 236     public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
 237                     double trueDestinationProbability) {
 238         boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue);
 239         Condition finalCondition = mirrored ? cond.mirror() : cond;
 240         boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
 241         ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
 242         append(new BranchOp(cmpCondition, trueDestination, falseDestination, trueDestinationProbability));
 243     }
 244 
 245     private static ConditionFlag toConditionFlag(boolean isInt, Condition cond, boolean unorderedIsTrue) {
 246         return isInt ? toIntConditionFlag(cond) : toFloatConditionFlag(cond, unorderedIsTrue);
 247     }
 248 
 249     /**
 250      * Takes a Condition and unorderedIsTrue flag and returns the correct Aarch64 specific
 251      * ConditionFlag. Note: This is only correct if the emitCompare code for floats has correctly


 407             }
 408         }
 409         return false;
 410     }
 411 
 412     /**
 413      * Moves trueValue into result if (left & right) == 0, else falseValue.
 414      *
 415      * @param left Integer kind. Non null.
 416      * @param right Integer kind. Non null.
 417      * @param trueValue Integer kind. Non null.
 418      * @param falseValue Integer kind. Non null.
 419      * @return virtual register containing trueValue if (left & right) == 0, else falseValue.
 420      */
 421     @Override
 422     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
 423         assert ((AArch64Kind) left.getPlatformKind()).isInteger() && ((AArch64Kind) right.getPlatformKind()).isInteger();
 424         assert ((AArch64Kind) trueValue.getPlatformKind()).isInteger() && ((AArch64Kind) falseValue.getPlatformKind()).isInteger();
 425         ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(left.getValueKind(), AArch64ArithmeticOp.ANDS, true, left, right);
 426         Variable result = newVariable(trueValue.getValueKind());






 427         append(new CondMoveOp(result, ConditionFlag.EQ, load(trueValue), load(falseValue)));

 428         return result;
 429     }
 430 
 431     @Override
 432     public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
 433         append(createStrategySwitchOp(strategy, keyTargets, defaultTarget, key, newVariable(key.getValueKind()), AArch64LIRGenerator::toIntConditionFlag));
 434     }
 435 
 436     protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue,
 437                     Function<Condition, ConditionFlag> converter) {
 438         return new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter);
 439     }
 440 
 441     @Override
 442     protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
 443         append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().arch.getWordKind())), newVariable(key.getValueKind())));
 444     }
 445 
 446     @Override
 447     public Variable emitByteSwap(Value input) {




   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.core.aarch64;
  26 
  27 import static jdk.vm.ci.aarch64.AArch64.sp;
  28 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
  29 import static org.graalvm.compiler.lir.LIRValueUtil.isIntConstant;
  30 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
  31 
  32 import java.util.function.Function;
  33 
  34 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
  35 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
  36 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
  37 import org.graalvm.compiler.core.common.LIRKind;
  38 import org.graalvm.compiler.core.common.calc.Condition;
  39 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  40 import org.graalvm.compiler.debug.GraalError;
  41 import org.graalvm.compiler.lir.LIRFrameState;
  42 import org.graalvm.compiler.lir.LIRValueUtil;
  43 import org.graalvm.compiler.lir.LabelRef;
  44 import org.graalvm.compiler.lir.StandardOp;
  45 import org.graalvm.compiler.lir.SwitchStrategy;
  46 import org.graalvm.compiler.lir.Variable;
  47 import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
  48 import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
  49 import org.graalvm.compiler.lir.aarch64.AArch64ArrayCompareToOp;
  50 import org.graalvm.compiler.lir.aarch64.AArch64ArrayEqualsOp;
  51 import org.graalvm.compiler.lir.aarch64.AArch64ByteSwapOp;
  52 import org.graalvm.compiler.lir.aarch64.AArch64Compare;
  53 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow;
  54 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.BranchOp;
  55 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.CondMoveOp;
  56 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.CondSetOp;
  57 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp;
  58 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.TableSwitchOp;
  59 import org.graalvm.compiler.lir.aarch64.AArch64LIRFlagsVersioned;
  60 import org.graalvm.compiler.lir.aarch64.AArch64Move;
  61 import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.AtomicReadAndAddOp;
  62 import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.AtomicReadAndAddLSEOp;
  63 import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.CompareAndSwapOp;
  64 import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.AtomicReadAndWriteOp;
  65 import org.graalvm.compiler.lir.aarch64.AArch64Move.MembarOp;
  66 import org.graalvm.compiler.lir.aarch64.AArch64PauseOp;
  67 import org.graalvm.compiler.lir.aarch64.AArch64SpeculativeBarrier;
  68 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  69 import org.graalvm.compiler.lir.gen.LIRGenerator;
  70 import org.graalvm.compiler.phases.util.Providers;
  71 
  72 import jdk.vm.ci.aarch64.AArch64;
  73 import jdk.vm.ci.aarch64.AArch64Kind;
  74 import jdk.vm.ci.code.CallingConvention;
  75 import jdk.vm.ci.code.RegisterValue;
  76 import jdk.vm.ci.meta.AllocatableValue;


  86     public AArch64LIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes) {
  87         super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
  88     }
  89 
  90     /**
  91      * Checks whether the supplied constant can be used without loading it into a register for store
  92      * operations, i.e., on the right hand side of a memory access.
  93      *
  94      * @param c The constant to check.
  95      * @return True if the constant can be used directly, false if the constant needs to be in a
  96      *         register.
  97      */
  98     protected static final boolean canStoreConstant(JavaConstant c) {
  99         // Our own code never calls this since we can't make a definite statement about whether or
 100         // not we can inline a constant without knowing what kind of operation we execute. Let's be
 101         // optimistic here and fix up mistakes later.
 102         return true;
 103     }
 104 
 105     /**
 106      * If val denotes the stackpointer, move it to another location. This is necessary since most
 107      * ops cannot handle the stackpointer as input or output.
 108      */
 109     public AllocatableValue moveSp(AllocatableValue val) {
 110         if (val instanceof RegisterValue && ((RegisterValue) val).getRegister().equals(sp)) {
 111             assert val.getPlatformKind() == AArch64Kind.QWORD : "Stackpointer must be long";
 112             return emitMove(val);
 113         }
 114         return val;
 115     }
 116 
 117     /**
 118      * AArch64 cannot use anything smaller than a word in any instruction other than load and store.
 119      */
 120     @Override
 121     public <K extends ValueKind<K>> K toRegisterKind(K kind) {
 122         switch ((AArch64Kind) kind.getPlatformKind()) {
 123             case BYTE:
 124             case WORD:
 125                 return kind.changeType(AArch64Kind.DWORD);
 126             default:
 127                 return kind;
 128         }
 129     }
 130 
 131     @Override
 132     public void emitNullCheck(Value address, LIRFrameState state) {
 133         append(new AArch64Move.NullCheckOp(asAddressValue(address), state));
 134     }
 135 
 136     @Override
 137     public Variable emitAddress(AllocatableValue stackslot) {


 226      * falseValue.
 227      *
 228      * @param left Arbitrary value. Has to have same type as right. Non null.
 229      * @param right Arbitrary value. Has to have same type as left. Non null.
 230      * @param cond condition that decides whether to move trueValue or falseValue into result. Non
 231      *            null.
 232      * @param unorderedIsTrue defines whether floating-point comparisons consider unordered true or
 233      *            not. Ignored for integer comparisons.
 234      * @param trueValue arbitrary value same type as falseValue. Non null.
 235      * @param falseValue arbitrary value same type as trueValue. Non null.
 236      * @return value containing trueValue if cond + unorderedIsTrue is true, else falseValue. Non
 237      *         null.
 238      */
 239     @Override
 240     public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
 241         boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue);
 242         Condition finalCondition = mirrored ? cond.mirror() : cond;
 243         boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
 244         ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
 245         Variable result = newVariable(trueValue.getValueKind());
 246 
 247         if (isIntConstant(trueValue, 1) && isIntConstant(falseValue, 0)) {
 248             append(new CondSetOp(result, cmpCondition));
 249         } else if (isIntConstant(trueValue, 0) && isIntConstant(falseValue, 1)) {
 250             append(new CondSetOp(result, cmpCondition.negate()));
 251         } else {
 252             append(new CondMoveOp(result, cmpCondition, loadReg(trueValue), loadReg(falseValue)));
 253         }
 254         return result;
 255     }
 256 
 257     @Override
 258     public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
 259                     double trueDestinationProbability) {
 260         boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue);
 261         Condition finalCondition = mirrored ? cond.mirror() : cond;
 262         boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
 263         ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
 264         append(new BranchOp(cmpCondition, trueDestination, falseDestination, trueDestinationProbability));
 265     }
 266 
 267     private static ConditionFlag toConditionFlag(boolean isInt, Condition cond, boolean unorderedIsTrue) {
 268         return isInt ? toIntConditionFlag(cond) : toFloatConditionFlag(cond, unorderedIsTrue);
 269     }
 270 
 271     /**
 272      * Takes a Condition and unorderedIsTrue flag and returns the correct Aarch64 specific
 273      * ConditionFlag. Note: This is only correct if the emitCompare code for floats has correctly


 429             }
 430         }
 431         return false;
 432     }
 433 
 434     /**
 435      * Moves trueValue into result if (left & right) == 0, else falseValue.
 436      *
 437      * @param left Integer kind. Non null.
 438      * @param right Integer kind. Non null.
 439      * @param trueValue Integer kind. Non null.
 440      * @param falseValue Integer kind. Non null.
 441      * @return virtual register containing trueValue if (left & right) == 0, else falseValue.
 442      */
 443     @Override
 444     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
 445         assert ((AArch64Kind) left.getPlatformKind()).isInteger() && ((AArch64Kind) right.getPlatformKind()).isInteger();
 446         assert ((AArch64Kind) trueValue.getPlatformKind()).isInteger() && ((AArch64Kind) falseValue.getPlatformKind()).isInteger();
 447         ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(left.getValueKind(), AArch64ArithmeticOp.ANDS, true, left, right);
 448         Variable result = newVariable(trueValue.getValueKind());
 449 
 450         if (isIntConstant(trueValue, 1) && isIntConstant(falseValue, 0)) {
 451             append(new CondSetOp(result, ConditionFlag.EQ));
 452         } else if (isIntConstant(trueValue, 0) && isIntConstant(falseValue, 1)) {
 453             append(new CondSetOp(result, ConditionFlag.NE));
 454         } else {
 455             append(new CondMoveOp(result, ConditionFlag.EQ, load(trueValue), load(falseValue)));
 456         }
 457         return result;
 458     }
 459 
 460     @Override
 461     public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
 462         append(createStrategySwitchOp(strategy, keyTargets, defaultTarget, key, newVariable(key.getValueKind()), AArch64LIRGenerator::toIntConditionFlag));
 463     }
 464 
 465     protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue,
 466                     Function<Condition, ConditionFlag> converter) {
 467         return new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter);
 468     }
 469 
 470     @Override
 471     protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
 472         append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().arch.getWordKind())), newVariable(key.getValueKind())));
 473     }
 474 
 475     @Override
 476     public Variable emitByteSwap(Value input) {


< prev index next >