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