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) {
|