1 /* 2 * Copyright (c) 2013, 2015, 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 package org.graalvm.compiler.lir.aarch64; 24 25 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 26 import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.ARITHMETIC; 27 import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.LOGICAL; 28 import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.NONE; 29 import static org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ARMv8ConstantCategory.SHIFT; 30 import static jdk.vm.ci.aarch64.AArch64.zr; 31 import static jdk.vm.ci.code.ValueUtil.asRegister; 32 33 import org.graalvm.compiler.asm.aarch64.AArch64Assembler; 34 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; 35 import org.graalvm.compiler.debug.GraalError; 36 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; 37 import org.graalvm.compiler.lir.LIRInstructionClass; 38 import org.graalvm.compiler.lir.Opcode; 39 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 40 41 import jdk.vm.ci.code.Register; 42 import jdk.vm.ci.meta.AllocatableValue; 43 import jdk.vm.ci.meta.JavaConstant; 44 45 public enum AArch64ArithmeticOp { 46 // TODO At least add and sub *can* be used with SP, so this should be supported 47 NEG, 48 NOT, 49 ADD(ARITHMETIC), 50 ADDS(ARITHMETIC), 51 SUB(ARITHMETIC), 52 SUBS(ARITHMETIC), 53 MUL, 54 MULVS, 55 DIV, 56 SMULH, 57 UMULH, 58 REM, 59 UDIV, 60 UREM, 61 AND(LOGICAL), 62 ANDS(LOGICAL), 63 OR(LOGICAL), 64 XOR(LOGICAL), 65 SHL(SHIFT), 66 LSHR(SHIFT), 67 ASHR(SHIFT), 68 ABS, 69 70 FADD, 71 FSUB, 72 FMUL, 73 FDIV, 74 FREM, 75 FNEG, 76 FABS, 77 SQRT; 78 79 /** 80 * Specifies what constants can be used directly without having to be loaded into a register 81 * with the given instruction. 82 */ 83 public enum ARMv8ConstantCategory { 84 NONE, 85 LOGICAL, 86 ARITHMETIC, 87 SHIFT 88 } 89 90 public final ARMv8ConstantCategory category; 91 92 AArch64ArithmeticOp(ARMv8ConstantCategory category) { 93 this.category = category; 94 } 95 96 AArch64ArithmeticOp() { 97 this(NONE); 98 } 99 100 public static class UnaryOp extends AArch64LIRInstruction { 101 private static final LIRInstructionClass<UnaryOp> TYPE = LIRInstructionClass.create(UnaryOp.class); 102 103 @Opcode private final AArch64ArithmeticOp opcode; 104 @Def({REG}) protected AllocatableValue result; 105 @Use({REG}) protected AllocatableValue x; 106 107 public UnaryOp(AArch64ArithmeticOp opcode, AllocatableValue result, AllocatableValue x) { 108 super(TYPE); 109 this.opcode = opcode; 110 this.result = result; 111 this.x = x; 112 } 113 114 @Override 115 public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { 116 Register dst = asRegister(result); 117 Register src = asRegister(x); 118 int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; 119 switch (opcode) { 120 case NEG: 121 masm.sub(size, dst, zr, src); 122 break; 123 case FNEG: 124 masm.fneg(size, dst, src); 125 break; 126 case NOT: 127 masm.not(size, dst, src); 128 break; 129 case ABS: 130 masm.cmp(size, src, 0); 131 masm.csneg(size, dst, src, ConditionFlag.LT); 132 break; 133 case FABS: 134 masm.fabs(size, dst, src); 135 break; 136 case SQRT: 137 masm.fsqrt(size, dst, src); 138 break; 139 default: 140 throw GraalError.shouldNotReachHere("op=" + opcode.name()); 141 } 142 } 143 } 144 145 public static class BinaryConstOp extends AArch64LIRInstruction { 146 private static final LIRInstructionClass<BinaryConstOp> TYPE = LIRInstructionClass.create(BinaryConstOp.class); 147 148 @Opcode private final AArch64ArithmeticOp op; 149 @Def({REG}) protected AllocatableValue result; 150 @Use({REG}) protected AllocatableValue a; 151 private final JavaConstant b; 152 153 public BinaryConstOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, JavaConstant b) { 154 super(TYPE); 155 this.op = op; 156 this.result = result; 157 this.a = a; 158 this.b = b; 159 } 160 161 @Override 162 public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { 163 assert op.category != NONE; 164 Register dst = asRegister(result); 165 Register src = asRegister(a); 166 int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; 167 switch (op) { 168 case ADD: 169 // Don't use asInt() here, since we can't use asInt on a long variable, even 170 // if the constant easily fits as an int. 171 assert AArch64MacroAssembler.isArithmeticImmediate(b.asLong()); 172 masm.add(size, dst, src, (int) b.asLong()); 173 break; 174 case SUB: 175 // Don't use asInt() here, since we can't use asInt on a long variable, even 176 // if the constant easily fits as an int. 177 assert AArch64MacroAssembler.isArithmeticImmediate(b.asLong()); 178 masm.sub(size, dst, src, (int) b.asLong()); 179 break; 180 case ADDS: 181 assert AArch64MacroAssembler.isArithmeticImmediate(b.asLong()); 182 masm.adds(size, dst, src, (int) b.asLong()); 183 break; 184 case SUBS: 185 assert AArch64MacroAssembler.isArithmeticImmediate(b.asLong()); 186 masm.subs(size, dst, src, (int) b.asLong()); 187 break; 188 case AND: 189 // XXX Should this be handled somewhere else? 190 if (size == 32 && b.asLong() == 0xFFFF_FFFFL) { 191 masm.mov(size, dst, src); 192 } else { 193 masm.and(size, dst, src, b.asLong()); 194 } 195 break; 196 case ANDS: 197 masm.ands(size, dst, src, b.asLong()); 198 break; 199 case OR: 200 masm.or(size, dst, src, b.asLong()); 201 break; 202 case XOR: 203 masm.eor(size, dst, src, b.asLong()); 204 break; 205 case SHL: 206 masm.shl(size, dst, src, b.asLong()); 207 break; 208 case LSHR: 209 masm.lshr(size, dst, src, b.asLong()); 210 break; 211 case ASHR: 212 masm.ashr(size, dst, src, b.asLong()); 213 break; 214 default: 215 throw GraalError.shouldNotReachHere("op=" + op.name()); 216 } 217 } 218 } 219 220 public static class BinaryOp extends AArch64LIRInstruction { 221 private static final LIRInstructionClass<BinaryOp> TYPE = LIRInstructionClass.create(BinaryOp.class); 222 223 @Opcode private final AArch64ArithmeticOp op; 224 @Def({REG}) protected AllocatableValue result; 225 @Use({REG}) protected AllocatableValue a; 226 @Use({REG}) protected AllocatableValue b; 227 228 public BinaryOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, AllocatableValue b) { 229 super(TYPE); 230 this.op = op; 231 this.result = result; 232 this.a = a; 233 this.b = b; 234 } 235 236 @Override 237 public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { 238 Register dst = asRegister(result); 239 Register src1 = asRegister(a); 240 Register src2 = asRegister(b); 241 int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; 242 switch (op) { 243 case ADD: 244 masm.add(size, dst, src1, src2); 245 break; 246 case ADDS: 247 masm.adds(size, dst, src1, src2); 248 break; 249 case SUB: 250 masm.sub(size, dst, src1, src2); 251 break; 252 case SUBS: 253 masm.subs(size, dst, src1, src2); 254 break; 255 case MUL: 256 masm.mul(size, dst, src1, src2); 257 break; 258 case UMULH: 259 masm.umulh(size, dst, src1, src2); 260 break; 261 case SMULH: 262 masm.smulh(size, dst, src1, src2); 263 break; 264 case DIV: 265 masm.sdiv(size, dst, src1, src2); 266 break; 267 case UDIV: 268 masm.udiv(size, dst, src1, src2); 269 break; 270 case AND: 271 masm.and(size, dst, src1, src2); 272 break; 273 case ANDS: 274 masm.ands(size, dst, src1, src2); 275 break; 276 case OR: 277 masm.or(size, dst, src1, src2); 278 break; 279 case XOR: 280 masm.eor(size, dst, src1, src2); 281 break; 282 case SHL: 283 masm.shl(size, dst, src1, src2); 284 break; 285 case LSHR: 286 masm.lshr(size, dst, src1, src2); 287 break; 288 case ASHR: 289 masm.ashr(size, dst, src1, src2); 290 break; 291 case FADD: 292 masm.fadd(size, dst, src1, src2); 293 break; 294 case FSUB: 295 masm.fsub(size, dst, src1, src2); 296 break; 297 case FMUL: 298 masm.fmul(size, dst, src1, src2); 299 break; 300 case FDIV: 301 masm.fdiv(size, dst, src1, src2); 302 break; 303 case MULVS: 304 masm.mulvs(size, dst, src1, src2); 305 break; 306 default: 307 throw GraalError.shouldNotReachHere("op=" + op.name()); 308 } 309 } 310 } 311 312 /** 313 * Class used for instructions that have to reuse one of their arguments. This only applies to 314 * the remainder instructions at the moment, since we have to compute n % d using rem = n - 315 * TruncatingDivision(n, d) * d 316 * 317 * TODO (das) Replace the remainder nodes in the LIR. 318 */ 319 public static class BinaryCompositeOp extends AArch64LIRInstruction { 320 private static final LIRInstructionClass<BinaryCompositeOp> TYPE = LIRInstructionClass.create(BinaryCompositeOp.class); 321 @Opcode private final AArch64ArithmeticOp op; 322 @Def({REG}) protected AllocatableValue result; 323 @Alive({REG}) protected AllocatableValue a; 324 @Alive({REG}) protected AllocatableValue b; 325 326 public BinaryCompositeOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue a, AllocatableValue b) { 327 super(TYPE); 328 this.op = op; 329 this.result = result; 330 this.a = a; 331 this.b = b; 332 } 333 334 @Override 335 public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { 336 Register dst = asRegister(result); 337 Register src1 = asRegister(a); 338 Register src2 = asRegister(b); 339 int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; 340 switch (op) { 341 case REM: 342 masm.rem(size, dst, src1, src2); 343 break; 344 case UREM: 345 masm.urem(size, dst, src1, src2); 346 break; 347 case FREM: 348 masm.frem(size, dst, src1, src2); 349 break; 350 default: 351 throw GraalError.shouldNotReachHere(); 352 } 353 } 354 } 355 356 public static class AddSubShiftOp extends AArch64LIRInstruction { 357 private static final LIRInstructionClass<AddSubShiftOp> TYPE = LIRInstructionClass.create(AddSubShiftOp.class); 358 359 @Opcode private final AArch64ArithmeticOp op; 360 @Def(REG) protected AllocatableValue result; 361 @Use(REG) protected AllocatableValue src1; 362 @Use(REG) protected AllocatableValue src2; 363 private final AArch64MacroAssembler.ShiftType shiftType; 364 private final int shiftAmt; 365 366 /** 367 * Computes <code>result = src1 <op> src2 <shiftType> <shiftAmt></code>. 368 */ 369 public AddSubShiftOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AArch64MacroAssembler.ShiftType shiftType, int shiftAmt) { 370 super(TYPE); 371 assert op == ADD || op == SUB; 372 this.op = op; 373 this.result = result; 374 this.src1 = src1; 375 this.src2 = src2; 376 this.shiftType = shiftType; 377 this.shiftAmt = shiftAmt; 378 } 379 380 @Override 381 public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { 382 int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; 383 switch (op) { 384 case ADD: 385 masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), shiftType, shiftAmt); 386 break; 387 case SUB: 388 masm.sub(size, asRegister(result), asRegister(src1), asRegister(src2), shiftType, shiftAmt); 389 break; 390 default: 391 throw GraalError.shouldNotReachHere(); 392 } 393 } 394 } 395 396 public static class ExtendedAddShiftOp extends AArch64LIRInstruction { 397 private static final LIRInstructionClass<ExtendedAddShiftOp> TYPE = LIRInstructionClass.create(ExtendedAddShiftOp.class); 398 @Def(REG) protected AllocatableValue result; 399 @Use(REG) protected AllocatableValue src1; 400 @Use(REG) protected AllocatableValue src2; 401 private final AArch64Assembler.ExtendType extendType; 402 private final int shiftAmt; 403 404 /** 405 * Computes <code>result = src1 + extendType(src2) << shiftAmt</code>. 406 * 407 * @param extendType defines how src2 is extended to the same size as src1. 408 * @param shiftAmt must be in range 0 to 4. 409 */ 410 public ExtendedAddShiftOp(AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AArch64Assembler.ExtendType extendType, int shiftAmt) { 411 super(TYPE); 412 this.result = result; 413 this.src1 = src1; 414 this.src2 = src2; 415 this.extendType = extendType; 416 this.shiftAmt = shiftAmt; 417 } 418 419 @Override 420 public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { 421 int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE; 422 masm.add(size, asRegister(result), asRegister(src1), asRegister(src2), extendType, shiftAmt); 423 } 424 } 425 426 }