1 /*
2  * Copyright (c) 2015, 2020, 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 
26 package org.graalvm.compiler.core.aarch64;
27 
28 import static jdk.vm.ci.aarch64.AArch64Kind.DWORD;
29 import static jdk.vm.ci.aarch64.AArch64Kind.QWORD;
30 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
31 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
32 import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.BSR;
33 import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.CLZ;
34 import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.CTZ;
35 import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.POPCNT;
36 
37 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
38 import org.graalvm.compiler.core.common.LIRKind;
39 import org.graalvm.compiler.core.common.NumUtil;
40 import org.graalvm.compiler.core.common.calc.FloatConvert;
41 import org.graalvm.compiler.debug.GraalError;
42 import org.graalvm.compiler.lir.ConstantValue;
43 import org.graalvm.compiler.lir.LIRFrameState;
44 import org.graalvm.compiler.lir.Variable;
45 import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
46 import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool;
47 import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
48 import org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp;
49 import org.graalvm.compiler.lir.aarch64.AArch64Move;
50 import org.graalvm.compiler.lir.aarch64.AArch64Move.LoadOp;
51 import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreConstantOp;
52 import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp;
53 import org.graalvm.compiler.lir.aarch64.AArch64ReinterpretOp;
54 import org.graalvm.compiler.lir.aarch64.AArch64SignExtendOp;
55 import org.graalvm.compiler.lir.aarch64.AArch64Unary;
56 import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
57 
58 import jdk.vm.ci.aarch64.AArch64Kind;
59 import jdk.vm.ci.meta.AllocatableValue;
60 import jdk.vm.ci.meta.JavaConstant;
61 import jdk.vm.ci.meta.PlatformKind;
62 import jdk.vm.ci.meta.Value;
63 import jdk.vm.ci.meta.ValueKind;
64 
65 public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implements AArch64ArithmeticLIRGeneratorTool {
66 
AArch64ArithmeticLIRGenerator(AllocatableValue nullRegisterValue)67     public AArch64ArithmeticLIRGenerator(AllocatableValue nullRegisterValue) {
68         this.nullRegisterValue = nullRegisterValue;
69     }
70 
71     private final AllocatableValue nullRegisterValue;
72 
73     @Override
getLIRGen()74     public AArch64LIRGenerator getLIRGen() {
75         return (AArch64LIRGenerator) super.getLIRGen();
76     }
77 
mustReplaceNullWithNullRegister(JavaConstant nullConstant)78     public boolean mustReplaceNullWithNullRegister(JavaConstant nullConstant) {
79         /* Uncompressed null pointers only */
80         return nullRegisterValue != null && JavaConstant.NULL_POINTER.equals(nullConstant);
81     }
82 
getNullRegisterValue()83     public AllocatableValue getNullRegisterValue() {
84         return nullRegisterValue;
85     }
86 
87     @Override
isNumericInteger(PlatformKind kind)88     protected boolean isNumericInteger(PlatformKind kind) {
89         return ((AArch64Kind) kind).isInteger();
90     }
91 
92     @Override
emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags)93     protected Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
94         if (isNumericInteger(a.getPlatformKind())) {
95             AArch64ArithmeticOp op = setFlags ? AArch64ArithmeticOp.ADDS : AArch64ArithmeticOp.ADD;
96             return emitBinary(resultKind, op, true, a, b);
97         } else {
98             assert !setFlags : "Cannot set flags on floating point arithmetic";
99             return emitBinary(resultKind, AArch64ArithmeticOp.FADD, true, a, b);
100         }
101     }
102 
103     @Override
emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags)104     protected Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
105         if (isNumericInteger(a.getPlatformKind())) {
106             AArch64ArithmeticOp op = setFlags ? AArch64ArithmeticOp.SUBS : AArch64ArithmeticOp.SUB;
107             return emitBinary(resultKind, op, false, a, b);
108         } else {
109             assert !setFlags : "Cannot set flags on floating point arithmetic";
110             return emitBinary(resultKind, AArch64ArithmeticOp.FSUB, false, a, b);
111         }
112     }
113 
emitExtendMemory(boolean isSigned, AArch64Kind memoryKind, int resultBits, AArch64AddressValue address, LIRFrameState state)114     public Value emitExtendMemory(boolean isSigned, AArch64Kind memoryKind, int resultBits, AArch64AddressValue address, LIRFrameState state) {
115         // Issue a zero extending load of the proper bit size and set the result to
116         // the proper kind.
117         Variable result = getLIRGen().newVariable(LIRKind.value(resultBits == 32 ? AArch64Kind.DWORD : AArch64Kind.QWORD));
118 
119         int targetSize = resultBits <= 32 ? 32 : 64;
120         switch (memoryKind) {
121             case BYTE:
122             case WORD:
123             case DWORD:
124             case QWORD:
125                 getLIRGen().append(new AArch64Unary.MemoryOp(isSigned, targetSize,
126                                 memoryKind.getSizeInBytes() * 8, result, address, state));
127                 break;
128             default:
129                 throw GraalError.shouldNotReachHere();
130         }
131         return result;
132     }
133 
134     @Override
emitMul(Value a, Value b, boolean setFlags)135     public Value emitMul(Value a, Value b, boolean setFlags) {
136         AArch64ArithmeticOp intOp = setFlags ? AArch64ArithmeticOp.MULVS : AArch64ArithmeticOp.MUL;
137         return emitBinary(LIRKind.combine(a, b), getOpCode(a, intOp, AArch64ArithmeticOp.FMUL), true, a, b);
138     }
139 
140     @Override
emitMulHigh(Value a, Value b)141     public Value emitMulHigh(Value a, Value b) {
142         assert isNumericInteger(a.getPlatformKind());
143         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.SMULH, true, a, b);
144     }
145 
146     @Override
emitUMulHigh(Value a, Value b)147     public Value emitUMulHigh(Value a, Value b) {
148         assert isNumericInteger(a.getPlatformKind());
149         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UMULH, true, a, b);
150     }
151 
emitMNeg(Value a, Value b)152     public Value emitMNeg(Value a, Value b) {
153         assert isNumericInteger(a.getPlatformKind()) && isNumericInteger(b.getPlatformKind());
154         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.MNEG, true, a, b);
155     }
156 
157     @Override
emitDiv(Value a, Value b, LIRFrameState state)158     public Value emitDiv(Value a, Value b, LIRFrameState state) {
159         return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.DIV, AArch64ArithmeticOp.FDIV), false, asAllocatable(a), asAllocatable(b));
160     }
161 
162     @Override
emitRem(Value a, Value b, LIRFrameState state)163     public Value emitRem(Value a, Value b, LIRFrameState state) {
164         return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.REM, AArch64ArithmeticOp.FREM), false, asAllocatable(a), asAllocatable(b));
165     }
166 
167     @Override
emitUDiv(Value a, Value b, LIRFrameState state)168     public Value emitUDiv(Value a, Value b, LIRFrameState state) {
169         assert isNumericInteger(a.getPlatformKind());
170         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UDIV, false, asAllocatable(a), asAllocatable(b));
171     }
172 
173     @Override
emitURem(Value a, Value b, LIRFrameState state)174     public Value emitURem(Value a, Value b, LIRFrameState state) {
175         assert isNumericInteger(a.getPlatformKind());
176         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.UREM, false, asAllocatable(a), asAllocatable(b));
177     }
178 
179     @Override
emitAnd(Value a, Value b)180     public Value emitAnd(Value a, Value b) {
181         assert isNumericInteger(a.getPlatformKind());
182         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.AND, true, a, b);
183     }
184 
185     @Override
emitOr(Value a, Value b)186     public Value emitOr(Value a, Value b) {
187         assert isNumericInteger(a.getPlatformKind());
188         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.OR, true, a, b);
189     }
190 
191     @Override
emitXor(Value a, Value b)192     public Value emitXor(Value a, Value b) {
193         assert isNumericInteger(a.getPlatformKind());
194         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.XOR, true, a, b);
195     }
196 
197     @Override
emitShl(Value a, Value b)198     public Value emitShl(Value a, Value b) {
199         assert isNumericInteger(a.getPlatformKind());
200         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.SHL, false, a, b);
201     }
202 
203     @Override
emitShr(Value a, Value b)204     public Value emitShr(Value a, Value b) {
205         assert isNumericInteger(a.getPlatformKind());
206         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.ASHR, false, a, b);
207     }
208 
209     @Override
emitUShr(Value a, Value b)210     public Value emitUShr(Value a, Value b) {
211         assert isNumericInteger(a.getPlatformKind());
212         return emitBinary(LIRKind.combine(a, b), AArch64ArithmeticOp.LSHR, false, a, b);
213     }
214 
215     @Override
emitFloatConvert(FloatConvert op, Value inputVal)216     public Value emitFloatConvert(FloatConvert op, Value inputVal) {
217         PlatformKind resultPlatformKind = getFloatConvertResultKind(op);
218         LIRKind resultLirKind = LIRKind.combine(inputVal).changeType(resultPlatformKind);
219         Variable result = getLIRGen().newVariable(resultLirKind);
220         getLIRGen().append(new AArch64FloatConvertOp(op, result, asAllocatable(inputVal)));
221         return result;
222     }
223 
emitIntegerMAdd(Value a, Value b, Value c, boolean isI2L)224     Value emitIntegerMAdd(Value a, Value b, Value c, boolean isI2L) {
225         return emitMultiplyAddSub(isI2L ? AArch64ArithmeticOp.SMADDL : AArch64ArithmeticOp.MADD, a, b, c);
226     }
227 
emitIntegerMSub(Value a, Value b, Value c, boolean isI2L)228     Value emitIntegerMSub(Value a, Value b, Value c, boolean isI2L) {
229         return emitMultiplyAddSub(isI2L ? AArch64ArithmeticOp.SMSUBL : AArch64ArithmeticOp.MSUB, a, b, c);
230     }
231 
emitMultiplyAddSub(AArch64ArithmeticOp op, Value a, Value b, Value c)232     private Value emitMultiplyAddSub(AArch64ArithmeticOp op, Value a, Value b, Value c) {
233         assert a.getPlatformKind() == b.getPlatformKind();
234         Variable result;
235         if (op == AArch64ArithmeticOp.SMADDL || op == AArch64ArithmeticOp.SMSUBL) {
236             // For signed multiply int and then add/sub long.
237             assert a.getPlatformKind() != c.getPlatformKind();
238             result = getLIRGen().newVariable(LIRKind.combine(c));
239         } else {
240             assert a.getPlatformKind() == c.getPlatformKind();
241             if (op == AArch64ArithmeticOp.FMADD) {
242                 // For floating-point Math.fma intrinsic.
243                 assert a.getPlatformKind() == AArch64Kind.SINGLE || a.getPlatformKind() == AArch64Kind.DOUBLE;
244             } else {
245                 // For int/long multiply add or sub.
246                 assert op == AArch64ArithmeticOp.MADD || op == AArch64ArithmeticOp.MSUB;
247                 assert isNumericInteger(a.getPlatformKind());
248             }
249             result = getLIRGen().newVariable(LIRKind.combine(a, b, c));
250         }
251 
252         AllocatableValue x = moveSp(asAllocatable(a));
253         AllocatableValue y = moveSp(asAllocatable(b));
254         AllocatableValue z = moveSp(asAllocatable(c));
255         getLIRGen().append(new AArch64ArithmeticOp.MultiplyAddSubOp(op, result, x, y, z));
256         return result;
257     }
258 
getFloatConvertResultKind(FloatConvert op)259     private static PlatformKind getFloatConvertResultKind(FloatConvert op) {
260         switch (op) {
261             case F2I:
262             case D2I:
263                 return AArch64Kind.DWORD;
264             case F2L:
265             case D2L:
266                 return AArch64Kind.QWORD;
267             case I2F:
268             case L2F:
269             case D2F:
270                 return AArch64Kind.SINGLE;
271             case I2D:
272             case L2D:
273             case F2D:
274                 return AArch64Kind.DOUBLE;
275             default:
276                 throw GraalError.shouldNotReachHere();
277         }
278     }
279 
280     @Override
emitReinterpret(LIRKind to, Value inputVal)281     public Value emitReinterpret(LIRKind to, Value inputVal) {
282         ValueKind<?> from = inputVal.getValueKind();
283         if (to.equals(from)) {
284             return inputVal;
285         }
286         Variable result = getLIRGen().newVariable(to);
287         getLIRGen().append(new AArch64ReinterpretOp(result, asAllocatable(inputVal)));
288         return result;
289     }
290 
291     @Override
emitNarrow(Value inputVal, int bits)292     public Value emitNarrow(Value inputVal, int bits) {
293         if (inputVal.getPlatformKind() == AArch64Kind.QWORD && bits <= 32) {
294             LIRKind resultKind = getResultLirKind(bits, inputVal);
295             long mask = NumUtil.getNbitNumberLong(bits);
296             Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask));
297             return emitBinary(resultKind, AArch64ArithmeticOp.AND, true, inputVal, maskValue);
298         } else {
299             return inputVal;
300         }
301     }
302 
303     @Override
emitZeroExtend(Value inputVal, int fromBits, int toBits)304     public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
305         assert fromBits <= toBits && toBits <= 64;
306         if (fromBits == toBits) {
307             return inputVal;
308         }
309         LIRKind resultKind = getResultLirKind(toBits, inputVal);
310         long mask = NumUtil.getNbitNumberLong(fromBits);
311         Value maskValue = new ConstantValue(resultKind, JavaConstant.forLong(mask));
312         return emitBinary(resultKind, AArch64ArithmeticOp.AND, true, inputVal, maskValue);
313     }
314 
315     @Override
emitSignExtend(Value inputVal, int fromBits, int toBits)316     public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
317         LIRKind resultKind = getResultLirKind(toBits, inputVal);
318         assert fromBits <= toBits && toBits <= 64;
319         if (fromBits == toBits) {
320             return inputVal;
321         } else if (isJavaConstant(inputVal)) {
322             JavaConstant javaConstant = asJavaConstant(inputVal);
323             long constant;
324             if (javaConstant.isNull()) {
325                 constant = 0;
326             } else {
327                 constant = javaConstant.asLong();
328             }
329             int shiftCount = QWORD.getSizeInBytes() * 8 - fromBits;
330             return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount));
331         }
332         Variable result = getLIRGen().newVariable(resultKind);
333         getLIRGen().append(new AArch64SignExtendOp(result, asAllocatable(inputVal), fromBits, toBits));
334         return result;
335     }
336 
getResultLirKind(int resultBitSize, Value... inputValues)337     private static LIRKind getResultLirKind(int resultBitSize, Value... inputValues) {
338         if (resultBitSize == 64) {
339             return LIRKind.combine(inputValues).changeType(QWORD);
340         } else {
341             // FIXME: I have no idea what this assert was ever for
342             // assert resultBitSize == 32;
343             return LIRKind.combine(inputValues).changeType(DWORD);
344         }
345     }
346 
emitBinary(ValueKind<?> resultKind, AArch64ArithmeticOp op, boolean commutative, Value a, Value b)347     protected Variable emitBinary(ValueKind<?> resultKind, AArch64ArithmeticOp op, boolean commutative, Value a, Value b) {
348         Variable result = getLIRGen().newVariable(resultKind);
349         if (isValidBinaryConstant(op, a, b)) {
350             emitBinaryConst(result, op, asAllocatable(a), asJavaConstant(b));
351         } else if (commutative && isValidBinaryConstant(op, b, a)) {
352             emitBinaryConst(result, op, asAllocatable(b), asJavaConstant(a));
353         } else {
354             emitBinaryVar(result, op, asAllocatable(a), asAllocatable(b));
355         }
356         return result;
357     }
358 
emitBinaryVar(Variable result, AArch64ArithmeticOp op, AllocatableValue a, AllocatableValue b)359     private void emitBinaryVar(Variable result, AArch64ArithmeticOp op, AllocatableValue a, AllocatableValue b) {
360         AllocatableValue x = moveSp(a);
361         AllocatableValue y = moveSp(b);
362         switch (op) {
363             case FREM:
364             case REM:
365             case UREM:
366                 getLIRGen().append(new AArch64ArithmeticOp.BinaryCompositeOp(op, result, x, y));
367                 break;
368             default:
369                 getLIRGen().append(new AArch64ArithmeticOp.BinaryOp(op, result, x, y));
370                 break;
371         }
372     }
373 
emitBinaryConst(Variable result, AArch64ArithmeticOp op, AllocatableValue a, JavaConstant b)374     public void emitBinaryConst(Variable result, AArch64ArithmeticOp op, AllocatableValue a, JavaConstant b) {
375         AllocatableValue x = moveSp(a);
376         getLIRGen().append(new AArch64ArithmeticOp.BinaryConstOp(op, result, x, b));
377     }
378 
isValidBinaryConstant(AArch64ArithmeticOp op, Value a, Value b)379     private static boolean isValidBinaryConstant(AArch64ArithmeticOp op, Value a, Value b) {
380         if (!isJavaConstant(b)) {
381             return false;
382         }
383         JavaConstant constValue = asJavaConstant(b);
384         switch (op.category) {
385             case LOGICAL:
386                 return isLogicalConstant(constValue);
387             case ARITHMETIC:
388                 return isArithmeticConstant(constValue);
389             case SHIFT:
390                 assert constValue.asLong() >= 0 && constValue.asLong() < a.getPlatformKind().getSizeInBytes() * Byte.SIZE;
391                 return true;
392             case NONE:
393                 return false;
394             default:
395                 throw GraalError.shouldNotReachHere();
396         }
397     }
398 
399     private static boolean isLogicalConstant(JavaConstant constValue) {
400         switch (constValue.getJavaKind()) {
401             case Int:
402                 return AArch64MacroAssembler.isLogicalImmediate(constValue.asInt());
403             case Long:
404                 return AArch64MacroAssembler.isLogicalImmediate(constValue.asLong());
405             default:
406                 return false;
407         }
408     }
409 
410     protected static boolean isArithmeticConstant(JavaConstant constValue) {
411         switch (constValue.getJavaKind()) {
412             case Int:
413             case Long:
414                 return AArch64MacroAssembler.isArithmeticImmediate(constValue.asLong());
415             case Object:
416                 return constValue.isNull();
417             default:
418                 return false;
419         }
420     }
421 
422     @Override
423     public Value emitNegate(Value inputVal) {
424         return emitUnary(getOpCode(inputVal, AArch64ArithmeticOp.NEG, AArch64ArithmeticOp.FNEG), inputVal);
425     }
426 
427     @Override
428     public Value emitNot(Value input) {
429         assert isNumericInteger(input.getPlatformKind());
430         return emitUnary(AArch64ArithmeticOp.NOT, input);
431     }
432 
433     @Override
434     public Value emitMathAbs(Value input) {
435         return emitUnary(getOpCode(input, AArch64ArithmeticOp.ABS, AArch64ArithmeticOp.FABS), input);
436     }
437 
438     @Override
439     public Value emitMathSqrt(Value input) {
440         assert input.getPlatformKind() == AArch64Kind.DOUBLE ||
441                         input.getPlatformKind() == AArch64Kind.SINGLE;
442         return emitUnary(AArch64ArithmeticOp.SQRT, input);
443     }
444 
445     @Override
446     public Variable emitBitScanForward(Value value) {
447         throw GraalError.unimplemented();
448     }
449 
450     @Override
451     public Value emitBitCount(Value operand) {
452         assert ((AArch64Kind) operand.getPlatformKind()).isInteger();
453         Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(AArch64Kind.DWORD));
454         getLIRGen().append(new AArch64BitManipulationOp(getLIRGen(), POPCNT, result, asAllocatable(operand)));
455         return result;
456     }
457 
458     @Override
459     public Value emitBitScanReverse(Value value) {
460         Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AArch64Kind.DWORD));
461         getLIRGen().append(new AArch64BitManipulationOp(getLIRGen(), BSR, result, asAllocatable(value)));
462         return result;
463     }
464 
465     @Override
466     public Value emitFusedMultiplyAdd(Value a, Value b, Value c) {
467         return emitMultiplyAddSub(AArch64ArithmeticOp.FMADD, a, b, c);
468     }
469 
470     @Override
471     public Value emitCountLeadingZeros(Value value) {
472         Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AArch64Kind.DWORD));
473         getLIRGen().append(new AArch64BitManipulationOp(getLIRGen(), CLZ, result, asAllocatable(value)));
474         return result;
475     }
476 
477     @Override
478     public Value emitCountTrailingZeros(Value value) {
479         Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AArch64Kind.DWORD));
480         getLIRGen().append(new AArch64BitManipulationOp(getLIRGen(), CTZ, result, asAllocatable(value)));
481         return result;
482     }
483 
484     private Variable emitUnary(AArch64ArithmeticOp op, Value inputVal) {
485         AllocatableValue input = asAllocatable(inputVal);
486         Variable result = getLIRGen().newVariable(LIRKind.combine(input));
487         getLIRGen().append(new AArch64ArithmeticOp.UnaryOp(op, result, input));
488         return result;
489     }
490 
491     private AllocatableValue moveSp(AllocatableValue val) {
492         return getLIRGen().moveSp(val);
493     }
494 
495     /**
496      * Returns the opcode depending on the platform kind of val.
497      */
498     private AArch64ArithmeticOp getOpCode(Value val, AArch64ArithmeticOp intOp, AArch64ArithmeticOp floatOp) {
499         return isNumericInteger(val.getPlatformKind()) ? intOp : floatOp;
500     }
501 
502     @Override
503     public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
504         AArch64AddressValue loadAddress = getLIRGen().asAddressValue(address);
505         Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
506         getLIRGen().append(new LoadOp((AArch64Kind) kind.getPlatformKind(), result, loadAddress, state));
507         return result;
508     }
509 
510     @Override
511     public Variable emitVolatileLoad(LIRKind kind, Value address, LIRFrameState state) {
512         AllocatableValue loadAddress = asAllocatable(address);
513         Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
514         getLIRGen().append(new AArch64Move.VolatileLoadOp((AArch64Kind) kind.getPlatformKind(), result, loadAddress, state));
515         return result;
516     }
517 
518     @Override
519     public void emitStore(ValueKind<?> lirKind, Value address, Value inputVal, LIRFrameState state) {
520         AArch64AddressValue storeAddress = getLIRGen().asAddressValue(address);
521         AArch64Kind kind = (AArch64Kind) lirKind.getPlatformKind();
522 
523         if (isJavaConstant(inputVal) && kind.isInteger()) {
524             JavaConstant c = asJavaConstant(inputVal);
525             if (c.isDefaultForKind()) {
526                 // We can load 0 directly into integer registers
527                 getLIRGen().append(new StoreConstantOp(kind, storeAddress, c, state));
528                 return;
529             }
530         }
531         AllocatableValue input = asAllocatable(inputVal);
532         getLIRGen().append(new StoreOp(kind, storeAddress, input, state));
533     }
534 
535     @Override
536     public void emitVolatileStore(ValueKind<?> lirKind, Value addressVal, Value inputVal, LIRFrameState state) {
537         AArch64Kind kind = (AArch64Kind) lirKind.getPlatformKind();
538         AllocatableValue input = asAllocatable(inputVal);
539         AllocatableValue address = asAllocatable(addressVal);
540         getLIRGen().append(new AArch64Move.VolatileStoreOp(kind, address, input, state));
541     }
542 
543     @Override
544     public Value emitRound(Value value, RoundingMode mode) {
545         AArch64ArithmeticOp op;
546         switch (mode) {
547             case NEAREST:
548                 op = AArch64ArithmeticOp.FRINTN;
549                 break;
550             case UP:
551                 op = AArch64ArithmeticOp.FRINTP;
552                 break;
553             case DOWN:
554                 op = AArch64ArithmeticOp.FRINTM;
555                 break;
556             default:
557                 throw GraalError.shouldNotReachHere();
558         }
559 
560         return emitUnary(op, value);
561     }
562 }
563