1 /* 2 * Copyright (c) 2015, 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.lir.amd64; 26 27 import static jdk.vm.ci.code.ValueUtil.asRegister; 28 import static jdk.vm.ci.code.ValueUtil.isRegister; 29 import static jdk.vm.ci.code.ValueUtil.isStackSlot; 30 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.DWORD; 31 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; 32 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 33 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; 34 35 import org.graalvm.compiler.asm.amd64.AMD64Address; 36 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; 37 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; 38 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MROp; 39 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; 40 import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize; 41 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; 42 import org.graalvm.compiler.core.common.NumUtil; 43 import org.graalvm.compiler.lir.LIRFrameState; 44 import org.graalvm.compiler.lir.LIRInstructionClass; 45 import org.graalvm.compiler.lir.Opcode; 46 import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck; 47 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 48 49 import jdk.vm.ci.code.site.DataSectionReference; 50 import jdk.vm.ci.meta.AllocatableValue; 51 import jdk.vm.ci.meta.Constant; 52 import jdk.vm.ci.meta.VMConstant; 53 import jdk.vm.ci.meta.Value; 54 55 /** 56 * AMD64 LIR instructions that have two input operands, but no output operand. 57 */ 58 public class AMD64BinaryConsumer { 59 60 /** 61 * Instruction that has two {@link AllocatableValue} operands. 62 */ 63 public static class Op extends AMD64LIRInstruction { 64 public static final LIRInstructionClass<Op> TYPE = LIRInstructionClass.create(Op.class); 65 66 @Opcode private final AMD64RMOp opcode; 67 private final OperandSize size; 68 69 @Use({REG}) protected AllocatableValue x; 70 @Use({REG, STACK}) protected AllocatableValue y; 71 Op(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y)72 public Op(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y) { 73 super(TYPE); 74 this.opcode = opcode; 75 this.size = size; 76 77 this.x = x; 78 this.y = y; 79 } 80 81 @Override emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)82 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 83 if (isRegister(y)) { 84 opcode.emit(masm, size, asRegister(x), asRegister(y)); 85 } else { 86 assert isStackSlot(y); 87 opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.asAddress(y)); 88 } 89 } 90 } 91 92 /** 93 * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand. 94 */ 95 public static class ConstOp extends AMD64LIRInstruction { 96 public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class); 97 98 @Opcode private final AMD64MIOp opcode; 99 private final OperandSize size; 100 101 @Use({REG, STACK}) protected AllocatableValue x; 102 private final int y; 103 ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue x, int y)104 public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue x, int y) { 105 this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y); 106 } 107 ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y)108 public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) { 109 this(TYPE, opcode, size, x, y); 110 } 111 ConstOp(LIRInstructionClass<? extends ConstOp> c, AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y)112 protected ConstOp(LIRInstructionClass<? extends ConstOp> c, AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) { 113 super(c); 114 this.opcode = opcode; 115 this.size = size; 116 117 this.x = x; 118 this.y = y; 119 } 120 121 @Override emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)122 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 123 if (isRegister(x)) { 124 opcode.emit(masm, size, asRegister(x), y, shouldAnnotate()); 125 } else { 126 assert isStackSlot(x); 127 opcode.emit(masm, size, (AMD64Address) crb.asAddress(x), y, shouldAnnotate()); 128 } 129 } 130 shouldAnnotate()131 protected boolean shouldAnnotate() { 132 return false; 133 } 134 } 135 136 /** 137 * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand 138 * that needs to be patched at runtime. 139 */ 140 public static class VMConstOp extends ConstOp { 141 public static final LIRInstructionClass<VMConstOp> TYPE = LIRInstructionClass.create(VMConstOp.class); 142 143 protected final VMConstant c; 144 VMConstOp(AMD64MIOp opcode, AllocatableValue x, VMConstant c)145 public VMConstOp(AMD64MIOp opcode, AllocatableValue x, VMConstant c) { 146 super(TYPE, opcode, DWORD, x, 0xDEADDEAD); 147 this.c = c; 148 } 149 150 @Override emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)151 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 152 crb.recordInlineDataInCode(c); 153 super.emitCode(crb, masm); 154 } 155 156 @Override shouldAnnotate()157 protected boolean shouldAnnotate() { 158 return true; 159 } 160 } 161 162 /** 163 * Instruction that has one {@link AllocatableValue} operand and one 164 * {@link DataSectionReference} operand. 165 */ 166 public static class DataOp extends AMD64LIRInstruction { 167 public static final LIRInstructionClass<DataOp> TYPE = LIRInstructionClass.create(DataOp.class); 168 169 @Opcode private final AMD64RMOp opcode; 170 private final OperandSize size; 171 172 @Use({REG}) protected AllocatableValue x; 173 private final Constant y; 174 175 private final int alignment; 176 DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y)177 public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y) { 178 this(opcode, size, x, y, size.getBytes()); 179 } 180 DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment)181 public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment) { 182 super(TYPE); 183 this.opcode = opcode; 184 this.size = size; 185 186 this.x = x; 187 this.y = y; 188 189 this.alignment = alignment; 190 } 191 192 @Override emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)193 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 194 opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); 195 } 196 } 197 198 /** 199 * Instruction that has an {@link AllocatableValue} as first input and a 200 * {@link AMD64AddressValue memory} operand as second input. 201 */ 202 public static class MemoryRMOp extends AMD64LIRInstruction implements ImplicitNullCheck { 203 public static final LIRInstructionClass<MemoryRMOp> TYPE = LIRInstructionClass.create(MemoryRMOp.class); 204 205 @Opcode private final AMD64RMOp opcode; 206 private final OperandSize size; 207 208 @Use({REG}) protected AllocatableValue x; 209 @Use({COMPOSITE}) protected AMD64AddressValue y; 210 211 @State protected LIRFrameState state; 212 MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state)213 public MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { 214 super(TYPE); 215 this.opcode = opcode; 216 this.size = size; 217 218 this.x = x; 219 this.y = y; 220 221 this.state = state; 222 } 223 224 @Override emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)225 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 226 if (state != null) { 227 crb.recordImplicitException(masm.position(), state); 228 } 229 opcode.emit(masm, size, asRegister(x), y.toAddress()); 230 } 231 232 @Override makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit)233 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 234 if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 235 state = nullCheckState; 236 return true; 237 } 238 return false; 239 } 240 } 241 242 /** 243 * Instruction that has a {@link AMD64AddressValue memory} operand as first input and an 244 * {@link AllocatableValue} as second input. 245 */ 246 public static class MemoryMROp extends AMD64LIRInstruction implements ImplicitNullCheck { 247 public static final LIRInstructionClass<MemoryMROp> TYPE = LIRInstructionClass.create(MemoryMROp.class); 248 249 @Opcode private final AMD64MROp opcode; 250 private final OperandSize size; 251 252 @Use({COMPOSITE}) protected AMD64AddressValue x; 253 @Use({REG}) protected AllocatableValue y; 254 255 @State protected LIRFrameState state; 256 MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state)257 public MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state) { 258 super(TYPE); 259 this.opcode = opcode; 260 this.size = size; 261 262 this.x = x; 263 this.y = y; 264 265 this.state = state; 266 } 267 268 @Override emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)269 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 270 if (state != null) { 271 crb.recordImplicitException(masm.position(), state); 272 } 273 opcode.emit(masm, size, x.toAddress(), asRegister(y)); 274 } 275 276 @Override makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit)277 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 278 if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 279 state = nullCheckState; 280 return true; 281 } 282 return false; 283 } 284 } 285 286 /** 287 * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate 288 * operand. 289 */ 290 public static class MemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck { 291 public static final LIRInstructionClass<MemoryConstOp> TYPE = LIRInstructionClass.create(MemoryConstOp.class); 292 293 @Opcode private final AMD64MIOp opcode; 294 private final OperandSize size; 295 296 @Use({COMPOSITE}) protected AMD64AddressValue x; 297 private final int y; 298 299 @State protected LIRFrameState state; 300 MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state)301 public MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { 302 this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y, state); 303 } 304 MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state)305 public MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { 306 this(TYPE, opcode, size, x, y, state); 307 } 308 MemoryConstOp(LIRInstructionClass<? extends MemoryConstOp> c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state)309 protected MemoryConstOp(LIRInstructionClass<? extends MemoryConstOp> c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { 310 super(c); 311 this.opcode = opcode; 312 this.size = size; 313 314 this.x = x; 315 this.y = y; 316 317 this.state = state; 318 } 319 320 @Override emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)321 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 322 if (state != null) { 323 crb.recordImplicitException(masm.position(), state); 324 } 325 opcode.emit(masm, size, x.toAddress(), y, shouldAnnotate()); 326 } 327 shouldAnnotate()328 protected boolean shouldAnnotate() { 329 return false; 330 } 331 332 @Override makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit)333 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 334 if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 335 state = nullCheckState; 336 return true; 337 } 338 return false; 339 } 340 getOpcode()341 public AMD64MIOp getOpcode() { 342 return opcode; 343 } 344 } 345 346 /** 347 * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate 348 * operand that needs to be patched at runtime. 349 */ 350 public static class MemoryVMConstOp extends MemoryConstOp { 351 public static final LIRInstructionClass<MemoryVMConstOp> TYPE = LIRInstructionClass.create(MemoryVMConstOp.class); 352 353 protected final VMConstant c; 354 MemoryVMConstOp(AMD64MIOp opcode, AMD64AddressValue x, VMConstant c, LIRFrameState state)355 public MemoryVMConstOp(AMD64MIOp opcode, AMD64AddressValue x, VMConstant c, LIRFrameState state) { 356 super(TYPE, opcode, DWORD, x, 0xDEADDEAD, state); 357 this.c = c; 358 } 359 360 @Override emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)361 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 362 crb.recordInlineDataInCode(c); 363 super.emitCode(crb, masm); 364 } 365 366 @Override shouldAnnotate()367 protected boolean shouldAnnotate() { 368 return true; 369 } 370 } 371 } 372