1 /* 2 * Copyright (c) 2015, 2019, 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 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 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 104 public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue x, int y) { 105 this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y); 106 } 107 108 public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) { 109 this(TYPE, opcode, size, x, y); 110 } 111 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 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 131 protected boolean shouldAnnotate() { 132 return false; 133 } 134 135 public AMD64MIOp getOpcode() { 136 return opcode; 137 } 138 } 139 140 /** 141 * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand 142 * that needs to be patched at runtime. 143 */ 144 public static class VMConstOp extends ConstOp { 145 public static final LIRInstructionClass<VMConstOp> TYPE = LIRInstructionClass.create(VMConstOp.class); 146 147 protected final VMConstant c; 148 149 public VMConstOp(AMD64MIOp opcode, AllocatableValue x, VMConstant c) { 150 super(TYPE, opcode, DWORD, x, 0xDEADDEAD); 151 this.c = c; 152 } 153 154 @Override 155 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 156 crb.recordInlineDataInCode(c); 157 super.emitCode(crb, masm); 158 } 159 160 @Override 161 protected boolean shouldAnnotate() { 162 return true; 163 } 164 } 165 166 /** 167 * Instruction that has one {@link AllocatableValue} operand and one 168 * {@link DataSectionReference} operand. 169 */ 170 public static class DataOp extends AMD64LIRInstruction { 171 public static final LIRInstructionClass<DataOp> TYPE = LIRInstructionClass.create(DataOp.class); 172 173 @Opcode private final AMD64RMOp opcode; 174 private final OperandSize size; 175 176 @Use({REG}) protected AllocatableValue x; 177 private final Constant y; 178 179 private final int alignment; 180 181 public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y) { 182 this(opcode, size, x, y, size.getBytes()); 183 } 184 185 public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment) { 186 super(TYPE); 187 this.opcode = opcode; 188 this.size = size; 189 190 this.x = x; 191 this.y = y; 192 193 this.alignment = alignment; 194 } 195 196 @Override 197 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 198 opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); 199 } 200 } 201 202 /** 203 * Instruction that has an {@link AllocatableValue} as first input and a 204 * {@link AMD64AddressValue memory} operand as second input. 205 */ 206 public static class MemoryRMOp extends AMD64LIRInstruction implements ImplicitNullCheck { 207 public static final LIRInstructionClass<MemoryRMOp> TYPE = LIRInstructionClass.create(MemoryRMOp.class); 208 209 @Opcode private final AMD64RMOp opcode; 210 private final OperandSize size; 211 212 @Use({REG}) protected AllocatableValue x; 213 @Use({COMPOSITE}) protected AMD64AddressValue y; 214 215 @State protected LIRFrameState state; 216 217 public MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { 218 super(TYPE); 219 this.opcode = opcode; 220 this.size = size; 221 222 this.x = x; 223 this.y = y; 224 225 this.state = state; 226 } 227 228 @Override 229 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 230 if (state != null) { 231 crb.recordImplicitException(masm.position(), state); 232 } 233 opcode.emit(masm, size, asRegister(x), y.toAddress()); 234 } 235 236 @Override 237 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 238 if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 239 state = nullCheckState; 240 return true; 241 } 242 return false; 243 } 244 } 245 246 /** 247 * Instruction that has a {@link AMD64AddressValue memory} operand as first input and an 248 * {@link AllocatableValue} as second input. 249 */ 250 public static class MemoryMROp extends AMD64LIRInstruction implements ImplicitNullCheck { 251 public static final LIRInstructionClass<MemoryMROp> TYPE = LIRInstructionClass.create(MemoryMROp.class); 252 253 @Opcode private final AMD64MROp opcode; 254 private final OperandSize size; 255 256 @Use({COMPOSITE}) protected AMD64AddressValue x; 257 @Use({REG}) protected AllocatableValue y; 258 259 @State protected LIRFrameState state; 260 261 public MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state) { 262 super(TYPE); 263 this.opcode = opcode; 264 this.size = size; 265 266 this.x = x; 267 this.y = y; 268 269 this.state = state; 270 } 271 272 @Override 273 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 274 if (state != null) { 275 crb.recordImplicitException(masm.position(), state); 276 } 277 opcode.emit(masm, size, x.toAddress(), asRegister(y)); 278 } 279 280 @Override 281 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 282 if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 283 state = nullCheckState; 284 return true; 285 } 286 return false; 287 } 288 } 289 290 /** 291 * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate 292 * operand. 293 */ 294 public static class MemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck { 295 public static final LIRInstructionClass<MemoryConstOp> TYPE = LIRInstructionClass.create(MemoryConstOp.class); 296 297 @Opcode private final AMD64MIOp opcode; 298 private final OperandSize size; 299 300 @Use({COMPOSITE}) protected AMD64AddressValue x; 301 private final int y; 302 303 @State protected LIRFrameState state; 304 305 public MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { 306 this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y, state); 307 } 308 309 public MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { 310 this(TYPE, opcode, size, x, y, state); 311 } 312 313 protected MemoryConstOp(LIRInstructionClass<? extends MemoryConstOp> c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) { 314 super(c); 315 this.opcode = opcode; 316 this.size = size; 317 318 this.x = x; 319 this.y = y; 320 321 this.state = state; 322 } 323 324 @Override 325 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 326 if (state != null) { 327 crb.recordImplicitException(masm.position(), state); 328 } 329 opcode.emit(masm, size, x.toAddress(), y, shouldAnnotate()); 330 } 331 332 protected boolean shouldAnnotate() { 333 return false; 334 } 335 336 @Override 337 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 338 if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 339 state = nullCheckState; 340 return true; 341 } 342 return false; 343 } 344 345 public AMD64MIOp getOpcode() { 346 return opcode; 347 } 348 } 349 350 /** 351 * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate 352 * operand that needs to be patched at runtime. 353 */ 354 public static class MemoryVMConstOp extends MemoryConstOp { 355 public static final LIRInstructionClass<MemoryVMConstOp> TYPE = LIRInstructionClass.create(MemoryVMConstOp.class); 356 357 protected final VMConstant c; 358 359 public MemoryVMConstOp(AMD64MIOp opcode, AMD64AddressValue x, VMConstant c, LIRFrameState state) { 360 super(TYPE, opcode, DWORD, x, 0xDEADDEAD, state); 361 this.c = c; 362 } 363 364 @Override 365 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 366 crb.recordInlineDataInCode(c); 367 super.emitCode(crb, masm); 368 } 369 370 @Override 371 protected boolean shouldAnnotate() { 372 return true; 373 } 374 } 375 }