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