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 }