package org.graalvm.compiler.asm.amd64;
import static jdk.vm.ci.amd64.AMD64.MASK;
import static jdk.vm.ci.amd64.AMD64.XMM;
import static jdk.vm.ci.amd64.AMD64.r12;
import static jdk.vm.ci.amd64.AMD64.r13;
import static jdk.vm.ci.amd64.AMD64.rbp;
import static jdk.vm.ci.amd64.AMD64.rsp;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.EVEXPrefixConfig.B0;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.EVEXPrefixConfig.B1;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.EVEXPrefixConfig.Z0;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.EVEXPrefixConfig.Z1;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.L128;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.L256;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.L512;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.LZ;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.M_0F;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.M_0F38;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.M_0F3A;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.P_;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.P_66;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.P_F2;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.P_F3;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.W0;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.W1;
import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.VEXPrefixConfig.WIG;
import static org.graalvm.compiler.core.common.NumUtil.isByte;
import org.graalvm.compiler.asm.Assembler;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.asm.amd64.AVXKind.AVXSize;
import org.graalvm.compiler.debug.GraalError;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64.CPUFeature;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.Register.RegisterCategory;
import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.meta.PlatformKind;
public abstract class AMD64BaseAssembler extends Assembler {
private final SIMDEncoder simdEncoder;
public AMD64BaseAssembler(TargetDescription target) {
super(target);
if (supports(CPUFeature.AVX)) {
simdEncoder = new VEXEncoderImpl();
} else {
simdEncoder = new SSEEncoderImpl();
}
}
public enum OperandSize {
BYTE(1, AMD64Kind.BYTE) {
@Override
protected void emitImmediate(AMD64BaseAssembler asm, int imm) {
assert imm == (byte) imm;
asm.emitByte(imm);
}
@Override
protected int immediateSize() {
return 1;
}
},
WORD(2, AMD64Kind.WORD, 0x66) {
@Override
protected void emitImmediate(AMD64BaseAssembler asm, int imm) {
assert imm == (short) imm;
asm.emitShort(imm);
}
@Override
protected int immediateSize() {
return 2;
}
},
DWORD(4, AMD64Kind.DWORD) {
@Override
protected void emitImmediate(AMD64BaseAssembler asm, int imm) {
asm.emitInt(imm);
}
@Override
protected int immediateSize() {
return 4;
}
},
QWORD(8, AMD64Kind.QWORD) {
@Override
protected void emitImmediate(AMD64BaseAssembler asm, int imm) {
asm.emitInt(imm);
}
@Override
protected int immediateSize() {
return 4;
}
},
SS(4, AMD64Kind.SINGLE, 0xF3, true),
SD(8, AMD64Kind.DOUBLE, 0xF2, true),
PS(16, AMD64Kind.V128_SINGLE, true),
PD(16, AMD64Kind.V128_DOUBLE, 0x66, true);
private final int sizePrefix;
private final int bytes;
private final boolean xmm;
private final AMD64Kind kind;
OperandSize(int bytes, AMD64Kind kind) {
this(bytes, kind, 0);
}
OperandSize(int bytes, AMD64Kind kind, int sizePrefix) {
this(bytes, kind, sizePrefix, false);
}
OperandSize(int bytes, AMD64Kind kind, boolean xmm) {
this(bytes, kind, 0, xmm);
}
OperandSize(int bytes, AMD64Kind kind, int sizePrefix, boolean xmm) {
this.sizePrefix = sizePrefix;
this.bytes = bytes;
this.kind = kind;
this.xmm = xmm;
}
public int getSizePrefix() {
return sizePrefix;
}
public int getBytes() {
return bytes;
}
public boolean isXmmType() {
return xmm;
}
public AMD64Kind getKind() {
return kind;
}
public static OperandSize get(PlatformKind kind) {
for (OperandSize operandSize : OperandSize.values()) {
if (operandSize.kind.equals(kind)) {
return operandSize;
}
}
throw GraalError.shouldNotReachHere("Unexpected kind: " + kind.toString());
}
protected void emitImmediate(AMD64BaseAssembler asm, int imm) {
throw new UnsupportedOperationException();
}
protected int immediateSize() {
throw new UnsupportedOperationException();
}
}
public static class OperandDataAnnotation extends CodeAnnotation {
public final int operandPosition;
public final int operandSize;
public final int nextInstructionPosition;
OperandDataAnnotation(int instructionPosition, int operandPosition, int operandSize, int nextInstructionPosition) {
super(instructionPosition);
this.operandPosition = operandPosition;
this.operandSize = operandSize;
this.nextInstructionPosition = nextInstructionPosition;
}
@Override
public String toString() {
return getClass().getSimpleName() + " instruction [" + instructionPosition + ", " + nextInstructionPosition + "[ operand at " + operandPosition + " size " + operandSize;
}
}
protected void annotatePatchingImmediate(int operandOffset, int operandSize) {
if (codePatchingAnnotationConsumer != null) {
int pos = position();
codePatchingAnnotationConsumer.accept(new OperandDataAnnotation(pos, pos + operandOffset, operandSize, pos + operandOffset + operandSize));
}
}
public final boolean supports(CPUFeature feature) {
return ((AMD64) target.arch).getFeatures().contains(feature);
}
protected static boolean inRC(RegisterCategory rc, Register r) {
return r.getRegisterCategory().equals(rc);
}
protected static int encode(Register r) {
assert r.encoding >= 0 && (inRC(XMM, r) ? r.encoding < 32 : r.encoding < 16) : "encoding out of range: " + r.encoding;
return r.encoding & 0x7;
}
private static final int MinEncodingNeedsRex = 8;
private static class Prefix {
private static final int REX = 0x40;
private static final int REXB = 0x41;
private static final int REXX = 0x42;
private static final int REXXB = 0x43;
private static final int REXR = 0x44;
private static final int REXRB = 0x45;
private static final int REXRX = 0x46;
private static final int REXRXB = 0x47;
private static final int REXW = 0x48;
private static final int REXWB = 0x49;
private static final int REXWX = 0x4A;
private static final int REXWXB = 0x4B;
private static final int REXWR = 0x4C;
private static final int REXWRB = 0x4D;
private static final int REXWRX = 0x4E;
private static final int REXWRXB = 0x4F;
private static final int VEX2 = 0xC5;
private static final int VEX3 = 0xC4;
private static final int EVEX = 0x62;
}
protected final void rexw() {
emitByte(Prefix.REXW);
}
protected final void prefix(Register reg) {
prefix(reg, false);
}
protected final void prefix(Register reg, boolean byteinst) {
int regEnc = reg.encoding;
if (regEnc >= 8) {
emitByte(Prefix.REXB);
} else if (byteinst && regEnc >= 4) {
emitByte(Prefix.REX);
}
}
protected final void prefixq(Register reg) {
if (reg.encoding < 8) {
emitByte(Prefix.REXW);
} else {
emitByte(Prefix.REXWB);
}
}
protected final void prefix(Register dst, Register src) {
prefix(dst, false, src, false);
}
protected final void prefix(Register dst, boolean dstIsByte, Register src, boolean srcIsByte) {
int dstEnc = dst.encoding;
int srcEnc = src.encoding;
if (dstEnc < 8) {
if (srcEnc >= 8) {
emitByte(Prefix.REXB);
} else if ((srcIsByte && srcEnc >= 4) || (dstIsByte && dstEnc >= 4)) {
emitByte(Prefix.REX);
}
} else {
if (srcEnc < 8) {
emitByte(Prefix.REXR);
} else {
emitByte(Prefix.REXRB);
}
}
}
protected final void prefixq(Register reg, Register rm) {
int regEnc = reg.encoding;
int rmEnc = rm.encoding;
if (regEnc < 8) {
if (rmEnc < 8) {
emitByte(Prefix.REXW);
} else {
emitByte(Prefix.REXWB);
}
} else {
if (rmEnc < 8) {
emitByte(Prefix.REXWR);
} else {
emitByte(Prefix.REXWRB);
}
}
}
private static boolean needsRex(Register reg) {
return reg.encoding >= MinEncodingNeedsRex;
}
protected final void prefix(AMD64Address adr) {
if (needsRex(adr.getBase())) {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXXB);
} else {
emitByte(Prefix.REXB);
}
} else {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXX);
}
}
}
protected final void prefixq(AMD64Address adr) {
if (needsRex(adr.getBase())) {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXWXB);
} else {
emitByte(Prefix.REXWB);
}
} else {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXWX);
} else {
emitByte(Prefix.REXW);
}
}
}
protected void prefixb(AMD64Address adr, Register reg) {
prefix(adr, reg, true);
}
protected void prefix(AMD64Address adr, Register reg) {
prefix(adr, reg, false);
}
protected void prefix(AMD64Address adr, Register reg, boolean byteinst) {
if (reg.encoding < 8) {
if (needsRex(adr.getBase())) {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXXB);
} else {
emitByte(Prefix.REXB);
}
} else {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXX);
} else if (byteinst && reg.encoding >= 4) {
emitByte(Prefix.REX);
}
}
} else {
if (needsRex(adr.getBase())) {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXRXB);
} else {
emitByte(Prefix.REXRB);
}
} else {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXRX);
} else {
emitByte(Prefix.REXR);
}
}
}
}
protected void prefixq(AMD64Address adr, Register src) {
if (src.encoding < 8) {
if (needsRex(adr.getBase())) {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXWXB);
} else {
emitByte(Prefix.REXWB);
}
} else {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXWX);
} else {
emitByte(Prefix.REXW);
}
}
} else {
if (needsRex(adr.getBase())) {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXWRXB);
} else {
emitByte(Prefix.REXWRB);
}
} else {
if (needsRex(adr.getIndex())) {
emitByte(Prefix.REXWRX);
} else {
emitByte(Prefix.REXWR);
}
}
}
}
protected static int getRXB(Register reg, Register rm) {
int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1;
rxb |= (rm == null ? 0 : rm.encoding & 0x08) >> 3;
return rxb;
}
protected static int getRXB(Register reg, AMD64Address rm) {
int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1;
if (!rm.getIndex().equals(Register.None)) {
rxb |= (rm.getIndex().encoding & 0x08) >> 2;
}
if (!rm.getBase().equals(Register.None)) {
rxb |= (rm.getBase().encoding & 0x08) >> 3;
}
return rxb;
}
protected final void emitModRM(int reg, Register rm) {
assert (reg & 0x07) == reg;
emitByte(0xC0 | (reg << 3) | (rm.encoding & 0x07));
}
protected final void emitModRM(Register reg, Register rm) {
emitModRM(reg.encoding & 0x07, rm);
}
public static final int DEFAULT_DISP8_SCALE = 1;
protected final void emitOperandHelper(Register reg, AMD64Address addr, boolean force4Byte, int additionalInstructionSize) {
assert !reg.equals(Register.None);
emitOperandHelper(encode(reg), addr, force4Byte, additionalInstructionSize, DEFAULT_DISP8_SCALE);
}
protected final void emitOperandHelper(int reg, AMD64Address addr, int additionalInstructionSize) {
emitOperandHelper(reg, addr, false, additionalInstructionSize, DEFAULT_DISP8_SCALE);
}
protected final void emitOperandHelper(Register reg, AMD64Address addr, int additionalInstructionSize) {
assert !reg.equals(Register.None);
emitOperandHelper(encode(reg), addr, false, additionalInstructionSize, DEFAULT_DISP8_SCALE);
}
protected final void emitOperandHelper(Register reg, AMD64Address addr, int additionalInstructionSize, int evexDisp8Scale) {
assert !reg.equals(Register.None);
emitOperandHelper(encode(reg), addr, false, additionalInstructionSize, evexDisp8Scale);
}
private void emitOperandHelper(int reg, AMD64Address addr, boolean force4Byte, int additionalInstructionSize, int evexDisp8Scale) {
assert (reg & 0x07) == reg;
int regenc = reg << 3;
Register base = addr.getBase();
Register index = addr.getIndex();
Scale scale = addr.getScale();
int disp = addr.getDisplacement();
if (base.equals(AMD64.rip)) {
assert index.equals(Register.None) : "cannot use RIP relative addressing with index register";
emitByte(0x05 | regenc);
if (codePatchingAnnotationConsumer != null && addr.instructionStartPosition >= 0) {
codePatchingAnnotationConsumer.accept(new OperandDataAnnotation(addr.instructionStartPosition, position(), 4, position() + 4 + additionalInstructionSize));
}
emitInt(disp);
} else if (base.isValid()) {
boolean overriddenForce4Byte = force4Byte;
int baseenc = base.isValid() ? encode(base) : 0;
if (index.isValid()) {
int indexenc = encode(index) << 3;
if (disp == 0 && !base.equals(rbp) && !base.equals(r13)) {
assert !index.equals(rsp) : "illegal addressing mode";
emitByte(0x04 | regenc);
emitByte(scale.log2 << 6 | indexenc | baseenc);
} else {
if (evexDisp8Scale > 1 && !overriddenForce4Byte) {
if (disp % evexDisp8Scale == 0) {
int newDisp = disp / evexDisp8Scale;
if (isByte(newDisp)) {
disp = newDisp;
assert isByte(disp) && !overriddenForce4Byte;
}
} else {
overriddenForce4Byte = true;
}
}
if (isByte(disp) && !overriddenForce4Byte) {
assert !index.equals(rsp) : "illegal addressing mode";
emitByte(0x44 | regenc);
emitByte(scale.log2 << 6 | indexenc | baseenc);
emitByte(disp & 0xFF);
} else {
assert !index.equals(rsp) : "illegal addressing mode";
emitByte(0x84 | regenc);
emitByte(scale.log2 << 6 | indexenc | baseenc);
emitInt(disp);
}
}
} else if (base.equals(rsp) || base.equals(r12)) {
if (disp == 0) {
emitByte(0x04 | regenc);
emitByte(0x24);
} else {
if (evexDisp8Scale > 1 && !overriddenForce4Byte) {
if (disp % evexDisp8Scale == 0) {
int newDisp = disp / evexDisp8Scale;
if (isByte(newDisp)) {
disp = newDisp;
assert isByte(disp) && !overriddenForce4Byte;
}
} else {
overriddenForce4Byte = true;
}
}
if (isByte(disp) && !overriddenForce4Byte) {
emitByte(0x44 | regenc);
emitByte(0x24);
emitByte(disp & 0xFF);
} else {
emitByte(0x84 | regenc);
emitByte(0x24);
emitInt(disp);
}
}
} else {
assert !base.equals(rsp) && !base.equals(r12) : "illegal addressing mode";
if (disp == 0 && !base.equals(rbp) && !base.equals(r13)) {
emitByte(0x00 | regenc | baseenc);
} else {
if (evexDisp8Scale > 1 && !overriddenForce4Byte) {
if (disp % evexDisp8Scale == 0) {
int newDisp = disp / evexDisp8Scale;
if (isByte(newDisp)) {
disp = newDisp;
assert isByte(disp) && !overriddenForce4Byte;
}
} else {
overriddenForce4Byte = true;
}
}
if (isByte(disp) && !overriddenForce4Byte) {
emitByte(0x40 | regenc | baseenc);
emitByte(disp & 0xFF);
} else {
emitByte(0x80 | regenc | baseenc);
emitInt(disp);
}
}
}
} else {
if (index.isValid()) {
int indexenc = encode(index) << 3;
assert !index.equals(rsp) : "illegal addressing mode";
emitByte(0x04 | regenc);
emitByte(scale.log2 << 6 | indexenc | 0x05);
emitInt(disp);
} else {
emitByte(0x04 | regenc);
emitByte(0x25);
emitInt(disp);
}
}
}
private interface SIMDEncoder {
void simdPrefix(Register xreg, Register nds, AMD64Address adr, int sizePrefix, int opcodeEscapePrefix, boolean isRexW);
void simdPrefix(Register dst, Register nds, Register src, int sizePrefix, int opcodeEscapePrefix, boolean isRexW);
}
private class SSEEncoderImpl implements SIMDEncoder {
@Override
public void simdPrefix(Register xreg, Register nds, AMD64Address adr, int sizePrefix, int opcodeEscapePrefix, boolean isRexW) {
assert (!nds.isValid()) || nds.equals(xreg);
if (sizePrefix > 0) {
emitByte(sizePrefix);
}
if (isRexW) {
prefixq(adr, xreg);
} else {
prefix(adr, xreg);
}
if (opcodeEscapePrefix > 0xFF) {
emitShort(opcodeEscapePrefix);
} else if (opcodeEscapePrefix > 0) {
emitByte(opcodeEscapePrefix);
}
}
@Override
public void simdPrefix(Register dst, Register nds, Register src, int sizePrefix, int opcodeEscapePrefix, boolean isRexW) {
assert (!nds.isValid()) || nds.equals(dst) || nds.equals(src);
if (sizePrefix > 0) {
emitByte(sizePrefix);
}
if (isRexW) {
prefixq(dst, src);
} else {
prefix(dst, src);
}
if (opcodeEscapePrefix > 0xFF) {
emitShort(opcodeEscapePrefix);
} else if (opcodeEscapePrefix > 0) {
emitByte(opcodeEscapePrefix);
}
}
}
public static final class VEXPrefixConfig {
public static final int L128 = 0;
public static final int L256 = 1;
public static final int L512 = 2;
public static final int LZ = 0;
public static final int W0 = 0;
public static final int W1 = 1;
public static final int WIG = 0;
public static final int P_ = 0x0;
public static final int P_66 = 0x1;
public static final int P_F3 = 0x2;
public static final int P_F2 = 0x3;
public static final int M_0F = 0x1;
public static final int M_0F38 = 0x2;
public static final int M_0F3A = 0x3;
private VEXPrefixConfig() {
}
}
private class VEXEncoderImpl implements SIMDEncoder {
private int sizePrefixToPP(int sizePrefix) {
switch (sizePrefix) {
case 0x66:
return P_66;
case 0xF2:
return P_F2;
case 0xF3:
return P_F3;
default:
return P_;
}
}
private int opcodeEscapePrefixToMMMMM(int opcodeEscapePrefix) {
switch (opcodeEscapePrefix) {
case 0x0F:
return M_0F;
case 0x380F:
return M_0F38;
case 0x3A0F:
return M_0F3A;
default:
return 0;
}
}
@Override
public void simdPrefix(Register reg, Register nds, AMD64Address rm, int sizePrefix, int opcodeEscapePrefix, boolean isRexW) {
assert reg.encoding < 16 : "encoding out of range: " + reg.encoding;
assert nds.encoding < 16 : "encoding out of range: " + nds.encoding;
emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(reg, rm), nds.isValid() ? nds.encoding : 0, true);
}
@Override
public void simdPrefix(Register dst, Register nds, Register src, int sizePrefix, int opcodeEscapePrefix, boolean isRexW) {
assert dst.encoding < 16 : "encoding out of range: " + dst.encoding;
assert src.encoding < 16 : "encoding out of range: " + src.encoding;
assert nds.encoding < 16 : "encoding out of range: " + nds.encoding;
emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(dst, src), nds.isValid() ? nds.encoding : 0, true);
}
}
protected final void simdPrefix(Register xreg, Register nds, AMD64Address adr, OperandSize size, int overriddenSizePrefix, int opcodeEscapePrefix, boolean isRexW) {
simdEncoder.simdPrefix(xreg, nds, adr, overriddenSizePrefix != 0 ? overriddenSizePrefix : size.sizePrefix, opcodeEscapePrefix, isRexW);
}
protected final void simdPrefix(Register xreg, Register nds, AMD64Address adr, OperandSize size, int opcodeEscapePrefix, boolean isRexW) {
simdEncoder.simdPrefix(xreg, nds, adr, size.sizePrefix, opcodeEscapePrefix, isRexW);
}
protected final void simdPrefix(Register dst, Register nds, Register src, OperandSize size, int overriddenSizePrefix, int opcodeEscapePrefix, boolean isRexW) {
simdEncoder.simdPrefix(dst, nds, src, overriddenSizePrefix != 0 ? overriddenSizePrefix : size.sizePrefix, opcodeEscapePrefix, isRexW);
}
protected final void simdPrefix(Register dst, Register nds, Register src, OperandSize size, int opcodeEscapePrefix, boolean isRexW) {
simdEncoder.simdPrefix(dst, nds, src, size.sizePrefix, opcodeEscapePrefix, isRexW);
}
protected final void emitVEX(int l, int pp, int mmmmm, int w, int rxb, int vvvv, boolean checkAVX) {
assert !checkAVX || ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX) : "emitting VEX prefix on a CPU without AVX support";
assert l == L128 || l == L256 : "invalid value for VEX.L";
assert pp == P_ || pp == P_66 || pp == P_F3 || pp == P_F2 : "invalid value for VEX.pp";
assert mmmmm == M_0F || mmmmm == M_0F38 || mmmmm == M_0F3A : "invalid value for VEX.m-mmmm";
assert w == W0 || w == W1 : "invalid value for VEX.W";
assert (rxb & 0x07) == rxb : "invalid value for VEX.RXB";
assert (vvvv & 0x0F) == vvvv : "invalid value for VEX.vvvv";
int rxb1s = rxb ^ 0x07;
int vvvv1s = vvvv ^ 0x0F;
if ((rxb & 0x03) == 0 && w == WIG && mmmmm == M_0F) {
int byte2 = 0;
byte2 |= (rxb1s & 0x04) << 5;
byte2 |= vvvv1s << 3;
byte2 |= l << 2;
byte2 |= pp;
emitByte(Prefix.VEX2);
emitByte(byte2);
} else {
int byte2 = 0;
byte2 = (rxb1s & 0x07) << 5;
byte2 |= mmmmm;
int byte3 = 0;
byte3 |= w << 7;
byte3 |= vvvv1s << 3;
byte3 |= l << 2;
byte3 |= pp;
emitByte(Prefix.VEX3);
emitByte(byte2);
emitByte(byte3);
}
}
public static int getLFlag(AVXSize size) {
switch (size) {
case XMM:
return L128;
case YMM:
return L256;
case ZMM:
return L512;
default:
return LZ;
}
}
public static boolean isAVX512Register(Register reg) {
return reg != null && reg.isValid() && AMD64.XMM.equals(reg.getRegisterCategory()) && reg.encoding > 15;
}
public final boolean vexPrefix(Register dst, Register nds, Register src, AVXSize size, int pp, int mmmmm, int w, int wEvex, boolean checkAVX) {
if (isAVX512Register(dst) || isAVX512Register(nds) || isAVX512Register(src) || size == AVXSize.ZMM) {
evexPrefix(dst, Register.None, nds, src, size, pp, mmmmm, wEvex, Z0, B0);
return true;
}
emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0, checkAVX);
return false;
}
public final boolean vexPrefix(Register dst, Register nds, AMD64Address src, AVXSize size, int pp, int mmmmm, int w, int wEvex, boolean checkAVX) {
if (isAVX512Register(dst) || isAVX512Register(nds) || size == AVXSize.ZMM) {
evexPrefix(dst, Register.None, nds, src, size, pp, mmmmm, wEvex, Z0, B0);
return true;
}
emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0, checkAVX);
return false;
}
protected static final class EVEXPrefixConfig {
public static final int Z0 = 0x0;
public static final int Z1 = 0x1;
public static final int B0 = 0x0;
public static final int B1 = 0x1;
private EVEXPrefixConfig() {
}
}
private static final int NOT_SUPPORTED_VECTOR_LENGTH = -1;
protected enum EVEXTuple {
INVALID(NOT_SUPPORTED_VECTOR_LENGTH, NOT_SUPPORTED_VECTOR_LENGTH, NOT_SUPPORTED_VECTOR_LENGTH),
FV_NO_BROADCAST_32BIT(16, 32, 64),
FV_BROADCAST_32BIT(4, 4, 4),
FV_NO_BROADCAST_64BIT(16, 32, 64),
FV_BROADCAST_64BIT(8, 8, 8),
HV_NO_BROADCAST_32BIT(8, 16, 32),
HV_BROADCAST_32BIT(4, 4, 4),
FVM(16, 32, 64),
T1S_8BIT(1, 1, 1),
T1S_16BIT(2, 2, 2),
T1S_32BIT(4, 4, 4),
T1S_64BIT(8, 8, 8),
T1F_32BIT(4, 4, 4),
T1F_64BIT(8, 8, 8),
T2_32BIT(8, 8, 8),
T2_64BIT(NOT_SUPPORTED_VECTOR_LENGTH, 16, 16),
T4_32BIT(NOT_SUPPORTED_VECTOR_LENGTH, 16, 16),
T4_64BIT(NOT_SUPPORTED_VECTOR_LENGTH, NOT_SUPPORTED_VECTOR_LENGTH, 32),
T8_32BIT(NOT_SUPPORTED_VECTOR_LENGTH, NOT_SUPPORTED_VECTOR_LENGTH, 32),
HVM(8, 16, 32),
QVM(4, 8, 16),
OVM(2, 4, 8),
M128(16, 16, 16),
DUP(8, 32, 64);
private final int scalingFactorVL128;
private final int scalingFactorVL256;
private final int scalingFactorVL512;
EVEXTuple(int scalingFactorVL128, int scalingFactorVL256, int scalingFactorVL512) {
this.scalingFactorVL128 = scalingFactorVL128;
this.scalingFactorVL256 = scalingFactorVL256;
this.scalingFactorVL512 = scalingFactorVL512;
}
private static int verifyScalingFactor(int scalingFactor) {
if (scalingFactor == NOT_SUPPORTED_VECTOR_LENGTH) {
throw GraalError.shouldNotReachHere("Invalid scaling factor.");
}
return scalingFactor;
}
public int getDisp8ScalingFactor(AVXSize size) {
switch (size) {
case XMM:
return verifyScalingFactor(scalingFactorVL128);
case YMM:
return verifyScalingFactor(scalingFactorVL256);
case ZMM:
return verifyScalingFactor(scalingFactorVL512);
default:
throw GraalError.shouldNotReachHere("Unsupported vector size.");
}
}
}