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.lir.LIRInstruction.OperandFlag.COMPOSITE; 31 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; 32 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; 33 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; 34 import static org.graalvm.compiler.lir.LIRValueUtil.differentRegisters; 35 import static org.graalvm.compiler.lir.LIRValueUtil.sameRegister; 36 37 import org.graalvm.compiler.asm.amd64.AMD64Address; 38 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; 39 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; 40 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp; 41 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; 42 import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize; 43 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; 44 import org.graalvm.compiler.core.common.NumUtil; 45 import org.graalvm.compiler.lir.LIRFrameState; 46 import org.graalvm.compiler.lir.LIRInstructionClass; 47 import org.graalvm.compiler.lir.Opcode; 48 import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck; 49 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 50 51 import jdk.vm.ci.code.site.DataSectionReference; 52 import jdk.vm.ci.meta.AllocatableValue; 53 import jdk.vm.ci.meta.JavaConstant; 54 import jdk.vm.ci.meta.Value; 55 56 /** 57 * AMD64 LIR instructions that have two inputs and one output. 58 */ 59 public class AMD64Binary { 60 61 /** 62 * Instruction that has two {@link AllocatableValue} operands. 63 */ 64 public static class TwoOp extends AMD64LIRInstruction { 65 public static final LIRInstructionClass<TwoOp> TYPE = LIRInstructionClass.create(TwoOp.class); 66 67 @Opcode private final AMD64RMOp opcode; 68 private final OperandSize size; 69 70 @Def({REG, HINT}) protected AllocatableValue result; 71 @Use({REG}) protected AllocatableValue x; 72 /** 73 * This argument must be Alive to ensure that result and y are not assigned to the same 74 * register, which would break the code generation by destroying y too early. 75 */ 76 @Alive({REG, STACK}) protected AllocatableValue y; 77 78 public TwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { 79 super(TYPE); 80 this.opcode = opcode; 81 this.size = size; 82 83 this.result = result; 84 this.x = x; 85 this.y = y; 86 } 87 88 @Override 89 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 90 AMD64Move.move(crb, masm, result, x); 91 if (isRegister(y)) { 92 opcode.emit(masm, size, asRegister(result), asRegister(y)); 93 } else { 94 assert isStackSlot(y); 95 opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y)); 96 } 97 } 98 } 99 100 /** 101 * Commutative instruction that has two {@link AllocatableValue} operands. 102 */ 103 public static class CommutativeTwoOp extends AMD64LIRInstruction { 104 public static final LIRInstructionClass<CommutativeTwoOp> TYPE = LIRInstructionClass.create(CommutativeTwoOp.class); 105 106 @Opcode private final AMD64RMOp opcode; 107 private final OperandSize size; 108 109 @Def({REG, HINT}) protected AllocatableValue result; 110 @Use({REG, STACK}) protected AllocatableValue x; 111 @Use({REG, STACK}) protected AllocatableValue y; 112 113 public CommutativeTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) { 114 super(TYPE); 115 this.opcode = opcode; 116 this.size = size; 117 118 this.result = result; 119 this.x = x; 120 this.y = y; 121 } 122 123 @Override 124 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 125 AllocatableValue input; 126 if (sameRegister(result, y)) { 127 input = x; 128 } else { 129 AMD64Move.move(crb, masm, result, x); 130 input = y; 131 } 132 133 if (isRegister(input)) { 134 opcode.emit(masm, size, asRegister(result), asRegister(input)); 135 } else { 136 assert isStackSlot(input); 137 opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input)); 138 } 139 } 140 141 public AMD64RMOp getOpcode() { 142 return opcode; 143 } 144 145 } 146 147 /** 148 * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand. 149 */ 150 public static class ConstOp extends AMD64LIRInstruction { 151 public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class); 152 153 @Opcode private final AMD64MIOp opcode; 154 private final OperandSize size; 155 156 @Def({REG, HINT}) protected AllocatableValue result; 157 @Use({REG}) protected AllocatableValue x; 158 private final int y; 159 160 public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { 161 this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, result, x, y); 162 } 163 164 public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { 165 super(TYPE); 166 this.opcode = opcode; 167 this.size = size; 168 169 this.result = result; 170 this.x = x; 171 this.y = y; 172 } 173 174 @Override 175 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 176 AMD64Move.move(crb, masm, result, x); 177 opcode.emit(masm, size, asRegister(result), y); 178 } 179 } 180 181 /** 182 * Instruction that has one {@link AllocatableValue} operand and one 183 * {@link DataSectionReference} operand. 184 */ 185 public static class DataTwoOp extends AMD64LIRInstruction { 186 public static final LIRInstructionClass<DataTwoOp> TYPE = LIRInstructionClass.create(DataTwoOp.class); 187 188 @Opcode private final AMD64RMOp opcode; 189 private final OperandSize size; 190 191 @Def({REG, HINT}) protected AllocatableValue result; 192 @Use({REG}) protected AllocatableValue x; 193 private final JavaConstant y; 194 195 private final int alignment; 196 197 public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) { 198 this(opcode, size, result, x, y, y.getJavaKind().getByteCount()); 199 } 200 201 public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) { 202 super(TYPE); 203 this.opcode = opcode; 204 this.size = size; 205 206 this.result = result; 207 this.x = x; 208 this.y = y; 209 210 this.alignment = alignment; 211 } 212 213 @Override 214 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 215 AMD64Move.move(crb, masm, result, x); 216 opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment)); 217 } 218 } 219 220 /** 221 * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue 222 * memory} operand. 223 */ 224 public static class MemoryTwoOp extends AMD64LIRInstruction implements ImplicitNullCheck { 225 public static final LIRInstructionClass<MemoryTwoOp> TYPE = LIRInstructionClass.create(MemoryTwoOp.class); 226 227 @Opcode private final AMD64RMOp opcode; 228 private final OperandSize size; 229 230 @Def({REG, HINT}) protected AllocatableValue result; 231 @Use({REG}) protected AllocatableValue x; 232 @Alive({COMPOSITE}) protected AMD64AddressValue y; 233 234 @State protected LIRFrameState state; 235 236 public MemoryTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) { 237 super(TYPE); 238 this.opcode = opcode; 239 this.size = size; 240 241 this.result = result; 242 this.x = x; 243 this.y = y; 244 245 this.state = state; 246 } 247 248 @Override 249 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 250 AMD64Move.move(crb, masm, result, x); 251 if (state != null) { 252 crb.recordImplicitException(masm.position(), state); 253 } 254 opcode.emit(masm, size, asRegister(result), y.toAddress()); 255 } 256 257 @Override 258 public void verify() { 259 super.verify(); 260 assert differentRegisters(result, y) || sameRegister(x, y); 261 } 262 263 @Override 264 public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) { 265 if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) { 266 state = nullCheckState; 267 return true; 268 } 269 return false; 270 } 271 272 public AMD64RMOp getOpcode() { 273 return opcode; 274 } 275 276 } 277 278 /** 279 * Instruction with a separate result operand, one {@link AllocatableValue} input and one 32-bit 280 * immediate input. 281 */ 282 public static class RMIOp extends AMD64LIRInstruction { 283 public static final LIRInstructionClass<RMIOp> TYPE = LIRInstructionClass.create(RMIOp.class); 284 285 @Opcode private final AMD64RMIOp opcode; 286 private final OperandSize size; 287 288 @Def({REG}) protected AllocatableValue result; 289 @Use({REG, STACK}) protected AllocatableValue x; 290 private final int y; 291 292 public RMIOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) { 293 super(TYPE); 294 this.opcode = opcode; 295 this.size = size; 296 297 this.result = result; 298 this.x = x; 299 this.y = y; 300 } 301 302 @Override 303 public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { 304 if (isRegister(x)) { 305 opcode.emit(masm, size, asRegister(result), asRegister(x), y); 306 } else { 307 assert isStackSlot(x); 308 opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), y); 309 } 310 } 311 } 312 }