1 /*
2  * Copyright (c) 2013, 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.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.gen.LIRGenerationResult;
65 import org.graalvm.compiler.lir.gen.LIRGenerator;
66 import org.graalvm.compiler.phases.util.Providers;
67 
68 import jdk.vm.ci.aarch64.AArch64;
69 import jdk.vm.ci.aarch64.AArch64Kind;
70 import jdk.vm.ci.code.CallingConvention;
71 import jdk.vm.ci.code.RegisterValue;
72 import jdk.vm.ci.meta.AllocatableValue;
73 import jdk.vm.ci.meta.JavaConstant;
74 import jdk.vm.ci.meta.JavaKind;
75 import jdk.vm.ci.meta.PlatformKind;
76 import jdk.vm.ci.meta.PrimitiveConstant;
77 import jdk.vm.ci.meta.Value;
78 import jdk.vm.ci.meta.ValueKind;
79 
80 public abstract class AArch64LIRGenerator extends LIRGenerator {
81 
AArch64LIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes)82     public AArch64LIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes) {
83         super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
84     }
85 
86     /**
87      * Checks whether the supplied constant can be used without loading it into a register for store
88      * operations, i.e., on the right hand side of a memory access.
89      *
90      * @param c The constant to check.
91      * @return True if the constant can be used directly, false if the constant needs to be in a
92      *         register.
93      */
canStoreConstant(JavaConstant c)94     protected static final boolean canStoreConstant(JavaConstant c) {
95         // Our own code never calls this since we can't make a definite statement about whether or
96         // not we can inline a constant without knowing what kind of operation we execute. Let's be
97         // optimistic here and fix up mistakes later.
98         return true;
99     }
100 
101     /**
102      * AArch64 cannot use anything smaller than a word in any instruction other than load and store.
103      */
104     @Override
toRegisterKind(K kind)105     public <K extends ValueKind<K>> K toRegisterKind(K kind) {
106         switch ((AArch64Kind) kind.getPlatformKind()) {
107             case BYTE:
108             case WORD:
109                 return kind.changeType(AArch64Kind.DWORD);
110             default:
111                 return kind;
112         }
113     }
114 
115     @Override
emitNullCheck(Value address, LIRFrameState state)116     public void emitNullCheck(Value address, LIRFrameState state) {
117         append(new AArch64Move.NullCheckOp(asAddressValue(address), state));
118     }
119 
120     @Override
emitAddress(AllocatableValue stackslot)121     public Variable emitAddress(AllocatableValue stackslot) {
122         Variable result = newVariable(LIRKind.value(target().arch.getWordKind()));
123         append(new AArch64Move.StackLoadAddressOp(result, stackslot));
124         return result;
125     }
126 
asAddressValue(Value address)127     public AArch64AddressValue asAddressValue(Value address) {
128         if (address instanceof AArch64AddressValue) {
129             return (AArch64AddressValue) address;
130         } else {
131             return new AArch64AddressValue(address.getValueKind(), asAllocatable(address), Value.ILLEGAL, 0, 1, AddressingMode.BASE_REGISTER_ONLY);
132         }
133     }
134 
135     @Override
emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue)136     public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
137         Variable prevValue = newVariable(expectedValue.getValueKind());
138         Variable scratch = newVariable(LIRKind.value(AArch64Kind.DWORD));
139         append(new CompareAndSwapOp(prevValue, loadReg(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
140         assert trueValue.getValueKind().equals(falseValue.getValueKind());
141         Variable result = newVariable(trueValue.getValueKind());
142         append(new CondMoveOp(result, ConditionFlag.EQ, asAllocatable(trueValue), asAllocatable(falseValue)));
143         return result;
144     }
145 
146     @Override
emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue)147     public Variable emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) {
148         Variable result = newVariable(newValue.getValueKind());
149         Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
150         append(new CompareAndSwapOp(result, loadNonCompareConst(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
151         return result;
152     }
153 
154     @Override
emitAtomicReadAndWrite(Value address, ValueKind<?> kind, Value newValue)155     public Value emitAtomicReadAndWrite(Value address, ValueKind<?> kind, Value newValue) {
156         Variable result = newVariable(kind);
157         Variable scratch = newVariable(kind);
158         append(new AtomicReadAndWriteOp((AArch64Kind) kind.getPlatformKind(), asAllocatable(result), asAllocatable(address), asAllocatable(newValue), asAllocatable(scratch)));
159         return result;
160     }
161 
162     @Override
emitAtomicReadAndAdd(Value address, ValueKind<?> kind, Value delta)163     public Value emitAtomicReadAndAdd(Value address, ValueKind<?> kind, Value delta) {
164         Variable result = newVariable(kind);
165         if (AArch64LIRFlagsVersioned.useLSE(target().arch)) {
166             append(new AtomicReadAndAddLSEOp((AArch64Kind) kind.getPlatformKind(), asAllocatable(result), asAllocatable(address), asAllocatable(delta)));
167         } else {
168             append(new AtomicReadAndAddOp((AArch64Kind) kind.getPlatformKind(), asAllocatable(result), asAllocatable(address), delta));
169         }
170         return result;
171     }
172 
173     @Override
emitMembar(int barriers)174     public void emitMembar(int barriers) {
175         int necessaryBarriers = target().arch.requiredBarriers(barriers);
176         if (target().isMP && necessaryBarriers != 0) {
177             append(new MembarOp(necessaryBarriers));
178         }
179     }
180 
181     @Override
emitJump(LabelRef label)182     public void emitJump(LabelRef label) {
183         assert label != null;
184         append(new StandardOp.JumpOp(label));
185     }
186 
187     @Override
emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability)188     public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability) {
189         append(new AArch64ControlFlow.BranchOp(ConditionFlag.VS, overflow, noOverflow, overflowProbability));
190     }
191 
192     /**
193      * Branches to label if (left & right) == 0. If negated is true branchse on non-zero instead.
194      *
195      * @param left Integer kind. Non null.
196      * @param right Integer kind. Non null.
197      * @param trueDestination destination if left & right == 0. Non null.
198      * @param falseDestination destination if left & right != 0. Non null
199      * @param trueSuccessorProbability hoistoric probability that comparison is true
200      */
201     @Override
emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability)202     public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability) {
203         assert ((AArch64Kind) left.getPlatformKind()).isInteger() && left.getPlatformKind() == right.getPlatformKind();
204         ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(LIRKind.combine(left, right), AArch64ArithmeticOp.ANDS, true, left, right);
205         append(new AArch64ControlFlow.BranchOp(ConditionFlag.EQ, trueDestination, falseDestination, trueSuccessorProbability));
206     }
207 
208     /**
209      * Conditionally move trueValue into new variable if cond + unorderedIsTrue is true, else
210      * falseValue.
211      *
212      * @param left Arbitrary value. Has to have same type as right. Non null.
213      * @param right Arbitrary value. Has to have same type as left. Non null.
214      * @param cond condition that decides whether to move trueValue or falseValue into result. Non
215      *            null.
216      * @param unorderedIsTrue defines whether floating-point comparisons consider unordered true or
217      *            not. Ignored for integer comparisons.
218      * @param trueValue arbitrary value same type as falseValue. Non null.
219      * @param falseValue arbitrary value same type as trueValue. Non null.
220      * @return value containing trueValue if cond + unorderedIsTrue is true, else falseValue. Non
221      *         null.
222      */
223     @Override
emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue)224     public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
225         boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue);
226         Condition finalCondition = mirrored ? cond.mirror() : cond;
227         boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
228         ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
229         Variable result = newVariable(trueValue.getValueKind());
230         append(new CondMoveOp(result, cmpCondition, loadReg(trueValue), loadReg(falseValue)));
231         return result;
232     }
233 
234     @Override
emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability)235     public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
236                     double trueDestinationProbability) {
237         boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue);
238         Condition finalCondition = mirrored ? cond.mirror() : cond;
239         boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
240         ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
241         append(new BranchOp(cmpCondition, trueDestination, falseDestination, trueDestinationProbability));
242     }
243 
toConditionFlag(boolean isInt, Condition cond, boolean unorderedIsTrue)244     private static ConditionFlag toConditionFlag(boolean isInt, Condition cond, boolean unorderedIsTrue) {
245         return isInt ? toIntConditionFlag(cond) : toFloatConditionFlag(cond, unorderedIsTrue);
246     }
247 
248     /**
249      * Takes a Condition and unorderedIsTrue flag and returns the correct Aarch64 specific
250      * ConditionFlag. Note: This is only correct if the emitCompare code for floats has correctly
251      * handled the case of 'EQ && unorderedIsTrue', respectively 'NE && !unorderedIsTrue'!
252      */
toFloatConditionFlag(Condition cond, boolean unorderedIsTrue)253     private static ConditionFlag toFloatConditionFlag(Condition cond, boolean unorderedIsTrue) {
254         switch (cond) {
255             case LT:
256                 return unorderedIsTrue ? ConditionFlag.LT : ConditionFlag.LO;
257             case LE:
258                 return unorderedIsTrue ? ConditionFlag.LE : ConditionFlag.LS;
259             case GE:
260                 return unorderedIsTrue ? ConditionFlag.PL : ConditionFlag.GE;
261             case GT:
262                 return unorderedIsTrue ? ConditionFlag.HI : ConditionFlag.GT;
263             case EQ:
264                 return ConditionFlag.EQ;
265             case NE:
266                 return ConditionFlag.NE;
267             default:
268                 throw GraalError.shouldNotReachHere();
269         }
270     }
271 
272     /**
273      * Takes a Condition and returns the correct Aarch64 specific ConditionFlag.
274      */
toIntConditionFlag(Condition cond)275     private static ConditionFlag toIntConditionFlag(Condition cond) {
276         switch (cond) {
277             case EQ:
278                 return ConditionFlag.EQ;
279             case NE:
280                 return ConditionFlag.NE;
281             case LT:
282                 return ConditionFlag.LT;
283             case LE:
284                 return ConditionFlag.LE;
285             case GT:
286                 return ConditionFlag.GT;
287             case GE:
288                 return ConditionFlag.GE;
289             case AE:
290                 return ConditionFlag.HS;
291             case BE:
292                 return ConditionFlag.LS;
293             case AT:
294                 return ConditionFlag.HI;
295             case BT:
296                 return ConditionFlag.LO;
297             default:
298                 throw GraalError.shouldNotReachHere();
299         }
300     }
301 
302     /**
303      * This method emits the compare instruction, and may reorder the operands. It returns true if
304      * it did so.
305      *
306      * @param a the left operand of the comparison. Has to have same type as b. Non null.
307      * @param b the right operand of the comparison. Has to have same type as a. Non null.
308      * @return true if mirrored (i.e. "b cmp a" instead of "a cmp b" was done).
309      */
emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue)310     protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) {
311         Value left;
312         Value right;
313         boolean mirrored;
314         AArch64Kind kind = (AArch64Kind) cmpKind;
315         if (kind.isInteger()) {
316             Value aExt = a;
317             Value bExt = b;
318 
319             int compareBytes = cmpKind.getSizeInBytes();
320             // AArch64 compares 32 or 64 bits: sign extend a and b as required.
321             if (compareBytes < a.getPlatformKind().getSizeInBytes()) {
322                 aExt = arithmeticLIRGen.emitSignExtend(a, compareBytes * 8, 64);
323             }
324             if (compareBytes < b.getPlatformKind().getSizeInBytes()) {
325                 bExt = arithmeticLIRGen.emitSignExtend(b, compareBytes * 8, 64);
326             }
327 
328             if (LIRValueUtil.isVariable(bExt)) {
329                 left = load(bExt);
330                 right = loadNonConst(aExt);
331                 mirrored = true;
332             } else {
333                 left = load(aExt);
334                 right = loadNonConst(bExt);
335                 mirrored = false;
336             }
337             append(new AArch64Compare.CompareOp(left, loadNonCompareConst(right)));
338         } else if (kind.isSIMD()) {
339             if (AArch64Compare.FloatCompareOp.isFloatCmpConstant(a, condition, unorderedIsTrue)) {
340                 left = load(b);
341                 right = a;
342                 mirrored = true;
343             } else if (AArch64Compare.FloatCompareOp.isFloatCmpConstant(b, condition, unorderedIsTrue)) {
344                 left = load(a);
345                 right = b;
346                 mirrored = false;
347             } else {
348                 left = load(a);
349                 right = loadReg(b);
350                 mirrored = false;
351             }
352             append(new AArch64Compare.FloatCompareOp(left, asAllocatable(right), condition, unorderedIsTrue));
353         } else {
354             throw GraalError.shouldNotReachHere();
355         }
356         return mirrored;
357     }
358 
359     /**
360      * If value is a constant that cannot be used directly with a gpCompare instruction load it into
361      * a register and return the register, otherwise return constant value unchanged.
362      */
loadNonCompareConst(Value value)363     protected Value loadNonCompareConst(Value value) {
364         if (!isCompareConstant(value)) {
365             return loadReg(value);
366         }
367         return value;
368     }
369 
370     /**
371      * Checks whether value can be used directly with a gpCompare instruction. This is <b>not</b>
372      * the same as {@link AArch64ArithmeticLIRGenerator#isArithmeticConstant(JavaConstant)}, because
373      * 0.0 is a valid compare constant for floats, while there are no arithmetic constants for
374      * floats.
375      *
376      * @param value any type. Non null.
377      * @return true if value can be used directly in comparison instruction, false otherwise.
378      */
isCompareConstant(Value value)379     public boolean isCompareConstant(Value value) {
380         if (isJavaConstant(value)) {
381             JavaConstant constant = asJavaConstant(value);
382             if (constant instanceof PrimitiveConstant) {
383                 final long longValue = constant.asLong();
384                 long maskedValue;
385                 switch (constant.getJavaKind()) {
386                     case Boolean:
387                     case Byte:
388                         maskedValue = longValue & 0xFF;
389                         break;
390                     case Char:
391                     case Short:
392                         maskedValue = longValue & 0xFFFF;
393                         break;
394                     case Int:
395                         maskedValue = longValue & 0xFFFF_FFFF;
396                         break;
397                     case Long:
398                         maskedValue = longValue;
399                         break;
400                     default:
401                         throw GraalError.shouldNotReachHere();
402                 }
403                 return AArch64MacroAssembler.isArithmeticImmediate(maskedValue);
404             } else {
405                 return constant.isDefaultForKind();
406             }
407         }
408         return false;
409     }
410 
411     /**
412      * Moves trueValue into result if (left & right) == 0, else falseValue.
413      *
414      * @param left Integer kind. Non null.
415      * @param right Integer kind. Non null.
416      * @param trueValue Integer kind. Non null.
417      * @param falseValue Integer kind. Non null.
418      * @return virtual register containing trueValue if (left & right) == 0, else falseValue.
419      */
420     @Override
emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue)421     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
422         assert ((AArch64Kind) left.getPlatformKind()).isInteger() && ((AArch64Kind) right.getPlatformKind()).isInteger();
423         assert ((AArch64Kind) trueValue.getPlatformKind()).isInteger() && ((AArch64Kind) falseValue.getPlatformKind()).isInteger();
424         ((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(left.getValueKind(), AArch64ArithmeticOp.ANDS, true, left, right);
425         Variable result = newVariable(trueValue.getValueKind());
426         append(new CondMoveOp(result, ConditionFlag.EQ, load(trueValue), load(falseValue)));
427         return result;
428     }
429 
430     @Override
emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget)431     public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
432         append(createStrategySwitchOp(strategy, keyTargets, defaultTarget, key, newVariable(key.getValueKind()), AArch64LIRGenerator::toIntConditionFlag));
433     }
434 
createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue, Function<Condition, ConditionFlag> converter)435     protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue,
436                     Function<Condition, ConditionFlag> converter) {
437         return new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter);
438     }
439 
440     @Override
emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key)441     protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
442         append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().arch.getWordKind())), newVariable(key.getValueKind())));
443     }
444 
445     @Override
emitByteSwap(Value input)446     public Variable emitByteSwap(Value input) {
447         Variable result = newVariable(LIRKind.combine(input));
448         append(new AArch64ByteSwapOp(result, input));
449         return result;
450     }
451 
452     @Override
emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2)453     public Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) {
454         LIRKind resultKind = LIRKind.value(AArch64Kind.DWORD);
455         // DMS TODO: check calling conversion and registers used
456         RegisterValue res = AArch64.r0.asValue(resultKind);
457         RegisterValue cnt1 = AArch64.r1.asValue(length1.getValueKind());
458         RegisterValue cnt2 = AArch64.r2.asValue(length2.getValueKind());
459         emitMove(cnt1, length1);
460         emitMove(cnt2, length2);
461         append(new AArch64ArrayCompareToOp(this, kind1, kind2, res, array1, array2, cnt1, cnt2));
462         Variable result = newVariable(resultKind);
463         emitMove(result, res);
464         return result;
465     }
466 
467     @Override
emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length)468     public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
469         Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD));
470         append(new AArch64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length)));
471         return result;
472     }
473 
474     @Override
zapValueForKind(PlatformKind kind)475     protected JavaConstant zapValueForKind(PlatformKind kind) {
476         long dead = 0xDEADDEADDEADDEADL;
477         switch ((AArch64Kind) kind) {
478             case BYTE:
479                 return JavaConstant.forByte((byte) dead);
480             case WORD:
481                 return JavaConstant.forShort((short) dead);
482             case DWORD:
483                 return JavaConstant.forInt((int) dead);
484             case QWORD:
485                 return JavaConstant.forLong(dead);
486             case SINGLE:
487                 return JavaConstant.forFloat(Float.intBitsToFloat((int) dead));
488             case DOUBLE:
489                 return JavaConstant.forDouble(Double.longBitsToDouble(dead));
490             default:
491                 throw GraalError.shouldNotReachHere();
492         }
493     }
494 
495     /**
496      * Loads value into virtual register. Contrary to {@link #load(Value)} this handles
497      * RegisterValues (i.e. values corresponding to fixed physical registers) correctly, by not
498      * creating an unnecessary move into a virtual register.
499      *
500      * This avoids generating the following code: mov x0, x19 # x19 is fixed thread register ldr x0,
501      * [x0] instead of: ldr x0, [x19].
502      */
loadReg(Value val)503     protected AllocatableValue loadReg(Value val) {
504         if (!(val instanceof Variable || val instanceof RegisterValue)) {
505             return emitMove(val);
506         }
507         return (AllocatableValue) val;
508     }
509 
510     @Override
emitPause()511     public void emitPause() {
512         append(new AArch64PauseOp());
513     }
514 
emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args)515     public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args);
516 }
517