1 /* 2 * Copyright (c) 2015, 2016, 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.amd64; 24 25 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; 26 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; 27 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 28 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; 29 import static org.graalvm.compiler.lir.LIRValueUtil.differentRegisters; 30 import static org.graalvm.compiler.lir.LIRValueUtil.sameRegister; 31 import static jdk.vm.ci.code.ValueUtil.asRegister; 32 import static jdk.vm.ci.code.ValueUtil.isRegister; 33 import static jdk.vm.ci.code.ValueUtil.isStackSlot; 34 35 import org.graalvm.compiler.core.common.NumUtil; 36 import org.graalvm.compiler.asm.amd64.AMD64Address; 37 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; 38 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; 39 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp; 40 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; 41 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp; 42 import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; 43 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; 44 import org.graalvm.compiler.lir.LIRFrameState; 45 import org.graalvm.compiler.lir.LIRInstructionClass; 46 import org.graalvm.compiler.lir.Opcode; 47 import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck; 48 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 49 50 import jdk.vm.ci.code.site.DataSectionReference; 51 import jdk.vm.ci.meta.AllocatableValue; 52 import jdk.vm.ci.meta.JavaConstant; 53 import jdk.vm.ci.meta.Value; 54 55 /** 56 * AMD64 LIR instructions that have two inputs and one output. 57 */ 58 public class AMD64Binary { 59 60 /** 61 * Instruction that has two {@link AllocatableValue} operands. 62 */ 63 public static class TwoOp extends AMD64LIRInstruction { 64 public static final LIRInstructionClass<TwoOp> TYPE = LIRInstructionClass.create(TwoOp.class); 65 66 @Opcode private final AMD64RMOp opcode; 67 private final OperandSize size; 68 69 @Def({REG, HINT}) protected AllocatableValue result; 70 @Use({REG}) protected AllocatableValue x; 71 /** 72 * This argument must be Alive to ensure that result and y are not assigned to the same 73 * register, which would break the code generation by destroying y too early. 74 */ 75 @Alive({REG, STACK}) protected AllocatableValue y; 76 77 public TwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { 78 super(TYPE); 79 this.opcode = opcode; 80 this.size = size; 81 82 this.result = result; 83 this.x = x; 84 this.y = y; 85 } 86 87 @Override 88 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 89 AMD64Move.move(crb, masm, result, x); 90 if (isRegister(y)) { 91 opcode.emit(masm, size, asRegister(result), asRegister(y)); 92 } else { 93 assert isStackSlot(y); 94 opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y)); 95 } 96 } 97 } 98 99 /** 100 * Instruction that has three {@link AllocatableValue} operands. 101 */ 102 public static class ThreeOp extends AMD64LIRInstruction { 103 public static final LIRInstructionClass<ThreeOp> TYPE = LIRInstructionClass.create(ThreeOp.class); 104 105 @Opcode private final AMD64RRMOp opcode; 106 private final OperandSize size; 107 108 @Def({REG}) protected AllocatableValue result; 109 @Use({REG}) protected AllocatableValue x; 110 @Use({REG, STACK}) protected AllocatableValue y; 111 112 public ThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { 113 super(TYPE); 114 this.opcode = opcode; 115 this.size = size; 116 117 this.result = result; 118 this.x = x; 119 this.y = y; 120 } 121 122 @Override 123 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 124 if (isRegister(y)) { 125 opcode.emit(masm, size, asRegister(result), asRegister(x), asRegister(y)); 126 } else { 127 assert isStackSlot(y); 128 opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.asAddress(y)); 129 } 130 } 131 } 132 133 /** 134 * Commutative instruction that has two {@link AllocatableValue} operands. 135 */ 136 public static class CommutativeTwoOp extends AMD64LIRInstruction { 137 public static final LIRInstructionClass<CommutativeTwoOp> TYPE = LIRInstructionClass.create(CommutativeTwoOp.class); 138 139 @Opcode private final AMD64RMOp opcode; 140 private final OperandSize size; 141 142 @Def({REG, HINT}) protected AllocatableValue result; 143 @Use({REG, STACK}) protected AllocatableValue x; 144 @Use({REG, STACK}) protected AllocatableValue y; 145 146 public CommutativeTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { 147 super(TYPE); 148 this.opcode = opcode; 149 this.size = size; 150 151 this.result = result; 152 this.x = x; 153 this.y = y; 154 } 155 156 @Override 157 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 158 AllocatableValue input; 159 if (sameRegister(result, y)) { 160 input = x; 161 } else { 162 AMD64Move.move(crb, masm, result, x); 163 input = y; 164 } 165 166 if (isRegister(input)) { 167 opcode.emit(masm, size, asRegister(result), asRegister(input)); 168 } else { 169 assert isStackSlot(input); 170 opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input)); 171 } 172 } 173 } 174 175 /** 176 * Commutative instruction that has three {@link AllocatableValue} operands. 177 */ 178 public static class CommutativeThreeOp extends AMD64LIRInstruction { 179 public static final LIRInstructionClass<CommutativeThreeOp> TYPE = LIRInstructionClass.create(CommutativeThreeOp.class); 180 181 @Opcode private final AMD64RRMOp opcode; 182 private final OperandSize size; 183 184 @Def({REG}) protected AllocatableValue result; 185 @Use({REG}) protected AllocatableValue x; 186 @Use({REG, STACK}) protected AllocatableValue y; 187 188 public CommutativeThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { 189 super(TYPE); 190 this.opcode = opcode; 191 this.size = size; 192 193 this.result = result; 194 this.x = x; 195 this.y = y; 196 } 197 198 @Override 199 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 200 if (isRegister(y)) { 201 opcode.emit(masm, size, asRegister(result), asRegister(x), asRegister(y)); 202 } else { 203 assert isStackSlot(y); 204 opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.asAddress(y)); 205 } 206 } 207 } 208 209 /** 210 * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand. 211 */ 212 public static class ConstOp extends AMD64LIRInstruction { 213 public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class); 214 215 @Opcode private final AMD64MIOp opcode; 216 private final OperandSize size; 217 218 @Def({REG, HINT}) protected AllocatableValue result; 219 @Use({REG}) protected AllocatableValue x; 220 private final int y; 221 222 public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { 223 this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, result, x, y); 224 } 225 226 public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { 227 super(TYPE); 228 this.opcode = opcode; 229 this.size = size; 230 231 this.result = result; 232 this.x = x; 233 this.y = y; 234 } 235 236 @Override 237 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 238 AMD64Move.move(crb, masm, result, x); 239 opcode.emit(masm, size, asRegister(result), y); 240 } 241 } 242 243 /** 244 * Instruction that has one {@link AllocatableValue} operand and one 245 * {@link DataSectionReference} operand. 246 */ 247 public static class DataTwoOp extends AMD64LIRInstruction { 248 public static final LIRInstructionClass<DataTwoOp> TYPE = LIRInstructionClass.create(DataTwoOp.class); 249 250 @Opcode private final AMD64RMOp opcode; 251 private final OperandSize size; 252 253 @Def({REG, HINT}) protected AllocatableValue result; 254 @Use({REG}) protected AllocatableValue x; 255 private final JavaConstant y; 256 257 private final int alignment; 258 259 public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { 260 this(opcode, size, result, x, y, y.getJavaKind().getByteCount()); 261 } 262 263 public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) { 264 super(TYPE); 265 this.opcode = opcode; 266 this.size = size; 267 268 this.result = result; 269 this.x = x; 270 this.y = y; 271 272 this.alignment = alignment; 273 } 274 275 @Override 276 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 277 AMD64Move.move(crb, masm, result, x); 278 opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); 279 } 280 } 281 282 /** 283 * Instruction that has two {@link AllocatableValue} operands and one 284 * {@link DataSectionReference} operand. 285 */ 286 public static class DataThreeOp extends AMD64LIRInstruction { 287 public static final LIRInstructionClass<DataThreeOp> TYPE = LIRInstructionClass.create(DataThreeOp.class); 288 289 @Opcode private final AMD64RRMOp opcode; 290 private final OperandSize size; 291 292 @Def({REG}) protected AllocatableValue result; 293 @Use({REG}) protected AllocatableValue x; 294 private final JavaConstant y; 295 296 private final int alignment; 297 298 public DataThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { 299 this(opcode, size, result, x, y, y.getJavaKind().getByteCount()); 300 } 301 302 public DataThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) { 303 super(TYPE); 304 this.opcode = opcode; 305 this.size = size; 306 307 this.result = result; 308 this.x = x; 309 this.y = y; 310 311 this.alignment = alignment; 312 } 313 314 @Override 315 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 316 opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); 317 } 318 } 319 320 /** 321 * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue 322 * memory} operand. 323 */ 324 public static class MemoryTwoOp extends AMD64LIRInstruction implements ImplicitNullCheck { 325 public static final LIRInstructionClass<MemoryTwoOp> TYPE = LIRInstructionClass.create(MemoryTwoOp.class); 326 327 @Opcode private final AMD64RMOp opcode; 328 private final OperandSize size; 329 330 @Def({REG, HINT}) protected AllocatableValue result; 331 @Use({REG}) protected AllocatableValue x; 332 @Alive({COMPOSITE}) protected AMD64AddressValue y; 333 334 @State protected LIRFrameState state; 335 336 public MemoryTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { 337 super(TYPE); 338 this.opcode = opcode; 339 this.size = size; 340 341 this.result = result; 342 this.x = x; 343 this.y = y; 344 345 this.state = state; 346 } 347 348 @Override 349 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 350 AMD64Move.move(crb, masm, result, x); 351 if (state != null) { 352 crb.recordImplicitException(masm.position(), state); 353 } 354 opcode.emit(masm, size, asRegister(result), y.toAddress()); 355 } 356 357 @Override 358 public void verify() { 359 super.verify(); 360 assert differentRegisters(result, y) || sameRegister(x, y); 361 } 362 363 @Override 364 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 365 if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 366 state = nullCheckState; 367 return true; 368 } 369 return false; 370 } 371 } 372 373 /** 374 * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue 375 * memory} operand. 376 */ 377 public static class MemoryThreeOp extends AMD64LIRInstruction implements ImplicitNullCheck { 378 public static final LIRInstructionClass<MemoryThreeOp> TYPE = LIRInstructionClass.create(MemoryThreeOp.class); 379 380 @Opcode private final AMD64RRMOp opcode; 381 private final OperandSize size; 382 383 @Def({REG}) protected AllocatableValue result; 384 @Use({REG}) protected AllocatableValue x; 385 @Use({COMPOSITE}) protected AMD64AddressValue y; 386 387 @State protected LIRFrameState state; 388 389 public MemoryThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { 390 super(TYPE); 391 this.opcode = opcode; 392 this.size = size; 393 394 this.result = result; 395 this.x = x; 396 this.y = y; 397 398 this.state = state; 399 } 400 401 @Override 402 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 403 if (state != null) { 404 crb.recordImplicitException(masm.position(), state); 405 } 406 opcode.emit(masm, size, asRegister(result), asRegister(x), y.toAddress()); 407 } 408 409 @Override 410 public void verify() { 411 super.verify(); 412 assert differentRegisters(result, y) || sameRegister(x, y); 413 } 414 415 @Override 416 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 417 if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 418 state = nullCheckState; 419 return true; 420 } 421 return false; 422 } 423 } 424 425 /** 426 * Instruction with a separate result operand, one {@link AllocatableValue} input and one 32-bit 427 * immediate input. 428 */ 429 public static class RMIOp extends AMD64LIRInstruction { 430 public static final LIRInstructionClass<RMIOp> TYPE = LIRInstructionClass.create(RMIOp.class); 431 432 @Opcode private final AMD64RMIOp opcode; 433 private final OperandSize size; 434 435 @Def({REG}) protected AllocatableValue result; 436 @Use({REG, STACK}) protected AllocatableValue x; 437 private final int y; 438 439 public RMIOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { 440 super(TYPE); 441 this.opcode = opcode; 442 this.size = size; 443 444 this.result = result; 445 this.x = x; 446 this.y = y; 447 } 448 449 @Override 450 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 451 if (isRegister(x)) { 452 opcode.emit(masm, size, asRegister(result), asRegister(x), y); 453 } else { 454 assert isStackSlot(x); 455 opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), y); 456 } 457 } 458 } 459 }