package org.graalvm.compiler.lir.amd64;
import static jdk.vm.ci.code.ValueUtil.asRegister;
import static jdk.vm.ci.code.ValueUtil.isRegister;
import static jdk.vm.ci.code.ValueUtil.isStackSlot;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
import static org.graalvm.compiler.lir.LIRValueUtil.differentRegisters;
import static org.graalvm.compiler.lir.LIRValueUtil.sameRegister;
import org.graalvm.compiler.asm.amd64.AMD64Address;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize;
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.lir.LIRFrameState;
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.Opcode;
import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import jdk.vm.ci.code.site.DataSectionReference;
import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.Value;
public class AMD64Binary {
public static class TwoOp extends AMD64LIRInstruction {
public static final LIRInstructionClass<TwoOp> TYPE = LIRInstructionClass.create(TwoOp.class);
@Opcode private final AMD64RMOp opcode;
private final OperandSize size;
@Def({REG, HINT}) protected AllocatableValue result;
@Use({REG}) protected AllocatableValue x;
@Alive({REG, STACK}) protected AllocatableValue y;
public TwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
super(TYPE);
this.opcode = opcode;
this.size = size;
this.result = result;
this.x = x;
this.y = y;
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
AMD64Move.move(crb, masm, result, x);
if (isRegister(y)) {
opcode.emit(masm, size, asRegister(result), asRegister(y));
} else {
assert isStackSlot(y);
opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y));
}
}
}
public static class CommutativeTwoOp extends AMD64LIRInstruction {
public static final LIRInstructionClass<CommutativeTwoOp> TYPE = LIRInstructionClass.create(CommutativeTwoOp.class);
@Opcode private final AMD64RMOp opcode;
private final OperandSize size;
@Def({REG, HINT}) protected AllocatableValue result;
@Use({REG, STACK}) protected AllocatableValue x;
@Use({REG, STACK}) protected AllocatableValue y;
public CommutativeTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
super(TYPE);
this.opcode = opcode;
this.size = size;
this.result = result;
this.x = x;
this.y = y;
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
AllocatableValue input;
if (sameRegister(result, y)) {
input = x;
} else {
AMD64Move.move(crb, masm, result, x);
input = y;
}
if (isRegister(input)) {
opcode.emit(masm, size, asRegister(result), asRegister(input));
} else {
assert isStackSlot(input);
opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input));
}
}
}
public static class ConstOp extends AMD64LIRInstruction {
public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class);
@Opcode private final AMD64MIOp opcode;
private final OperandSize size;
@Def({REG, HINT}) protected AllocatableValue result;
@Use({REG}) protected AllocatableValue x;
private final int y;
public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, result, x, y);
}
public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
super(TYPE);
this.opcode = opcode;
this.size = size;
this.result = result;
this.x = x;
this.y = y;
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
AMD64Move.move(crb, masm, result, x);
opcode.emit(masm, size, asRegister(result), y);
}
}
public static class DataTwoOp extends AMD64LIRInstruction {
public static final LIRInstructionClass<DataTwoOp> TYPE = LIRInstructionClass.create(DataTwoOp.class);
@Opcode private final AMD64RMOp opcode;
private final OperandSize size;
@Def({REG, HINT}) protected AllocatableValue result;
@Use({REG}) protected AllocatableValue x;
private final JavaConstant y;
private final int alignment;
public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
this(opcode, size, result, x, y, y.getJavaKind().getByteCount());
}
public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) {
super(TYPE);
this.opcode = opcode;
this.size = size;
this.result = result;
this.x = x;
this.y = y;
this.alignment = alignment;
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
AMD64Move.move(crb, masm, result, x);
opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
}
}
public static class MemoryTwoOp extends AMD64LIRInstruction implements ImplicitNullCheck {
public static final LIRInstructionClass<MemoryTwoOp> TYPE = LIRInstructionClass.create(MemoryTwoOp.class);
@Opcode private final AMD64RMOp opcode;
private final OperandSize size;
@Def({REG, HINT}) protected AllocatableValue result;
@Use({REG}) protected AllocatableValue x;
@Alive({COMPOSITE}) protected AMD64AddressValue y;
@State protected LIRFrameState state;
public MemoryTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
super(TYPE);
this.opcode = opcode;
this.size = size;
this.result = result;
this.x = x;
this.y = y;
this.state = state;
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
AMD64Move.move(crb, masm, result, x);
if (state != null) {
crb.recordImplicitException(masm.position(), state);
}
opcode.emit(masm, size, asRegister(result), y.toAddress());
}
@Override
public void verify() {
super.verify();
assert differentRegisters(result, y) || sameRegister(x, y);
}
@Override
public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
state = nullCheckState;
return true;
}
return false;
}
}
public static class RMIOp extends AMD64LIRInstruction {
public static final LIRInstructionClass<RMIOp> TYPE = LIRInstructionClass.create(RMIOp.class);
@Opcode private final AMD64RMIOp opcode;
private final OperandSize size;
@Def({REG}) protected AllocatableValue result;
@Use({REG, STACK}) protected AllocatableValue x;
private final int y;
public RMIOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
super(TYPE);
this.opcode = opcode;
this.size = size;
this.result = result;
this.x = x;
this.y = y;
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
if (isRegister(x)) {
opcode.emit(masm, size, asRegister(result), asRegister(x), y);
} else {
assert isStackSlot(x);
opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), y);
}
}
}
}