blob: 219a6cdf87eaaa4fe64b0a9c2c3012c597a60872 [file] [log] [blame]
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.asm.amd64;
import java.util.EnumSet;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.asm.amd64.AVXKind.AVXSize;
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;
/**
* This class extends the AMD64 assembler with functions that emit instructions from the AVX
* extension.
*/
public class AMD64VectorAssembler extends AMD64MacroAssembler {
public AMD64VectorAssembler(TargetDescription target) {
super(target);
assert ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX);
}
private static final int L128 = 0;
private static final int L256 = 1;
private static final int LIG = 0;
private static final int W0 = 0;
private static final int W1 = 1;
private static final int WIG = 0;
private static final int P_ = 0x0;
private static final int P_66 = 0x1;
private static final int P_F3 = 0x2;
private static final int P_F2 = 0x3;
private static final int M_0F = 0x1;
private static final int M_0F38 = 0x2;
private static final int M_0F3A = 0x3;
/**
* Low-level function to encode and emit the VEX prefix.
* <p>
* 2 byte form: [1100 0101] [R vvvv L pp]<br>
* 3 byte form: [1100 0100] [RXB m-mmmm] [W vvvv L pp]
* <p>
* The RXB and vvvv fields are stored in 1's complement in the prefix encoding. This function
* performs the 1s complement conversion, the caller is expected to pass plain unencoded
* arguments.
* <p>
* The pp field encodes an extension to the opcode:<br>
* 00: no extension<br>
* 01: 66<br>
* 10: F3<br>
* 11: F2
* <p>
* The m-mmmm field encodes the leading bytes of the opcode:<br>
* 00001: implied 0F leading opcode byte (default in 2-byte encoding)<br>
* 00010: implied 0F 38 leading opcode bytes<br>
* 00011: implied 0F 3A leading opcode bytes
* <p>
* This function automatically chooses the 2 or 3 byte encoding, based on the XBW flags and the
* m-mmmm field.
*/
private void emitVEX(int l, int pp, int mmmmm, int w, int rxb, int vvvv) {
assert ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX) : "emitting VEX prefix on a CPU without AVX support";
assert l == L128 || l == L256 || l == LIG : "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 || w == WIG : "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) {
// 2 byte encoding
int byte2 = 0;
byte2 |= (rxb1s & 0x04) << 5;
byte2 |= vvvv1s << 3;
byte2 |= l << 2;
byte2 |= pp;
emitByte(0xC5);
emitByte(byte2);
} else {
// 3 byte encoding
int byte2 = 0;
byte2 = (rxb1s & 0x07) << 5;
byte2 |= mmmmm;
int byte3 = 0;
byte3 |= w << 7;
byte3 |= vvvv1s << 3;
byte3 |= l << 2;
byte3 |= pp;
emitByte(0xC4);
emitByte(byte2);
emitByte(byte3);
}
}
private static int getLFlag(AVXSize size) {
switch (size) {
case XMM:
return L128;
case YMM:
return L256;
default:
return LIG;
}
}
/**
* Emit instruction with VEX prefix and two register operands.
* <p>
* Format: [VEX] [Opcode] [ModR/M]
*/
private void emitVexOp(int l, int pp, int mmmmm, int w, int op, Register reg, Register rm) {
emitVEX(l, pp, mmmmm, w, getRXB(reg, rm), 0);
emitByte(op);
emitModRM(reg, rm);
}
/**
* Emit instruction with VEX prefix and three register operands.
* <p>
* Format: [VEX] [Opcode] [ModR/M]
*/
private void emitVexOp(int l, int pp, int mmmmm, int w, int op, Register reg, Register vvvv, Register rm) {
emitVEX(l, pp, mmmmm, w, getRXB(reg, rm), vvvv.encoding());
emitByte(op);
emitModRM(reg, rm);
}
/**
* Emit instruction with VEX prefix and four register operands.
* <p>
* Format: [VEX] [Opcode] [ModR/M] [Imm8[7:4]]
*/
private void emitVexOp(int l, int pp, int mmmmm, int w, int op, Register reg, Register vvvv, Register rm, Register imm8) {
emitVEX(l, pp, mmmmm, w, getRXB(reg, rm), vvvv.encoding());
emitByte(op);
emitModRM(reg, rm);
emitByte(imm8.encoding() << 4);
}
/**
* Emit instruction with VEX prefix and three register operands and one memory operand.
* <p>
* Format: [VEX] [Opcode] [ModR/M] [Imm8[7:4]]
*/
private void emitVexOp(int l, int pp, int mmmmm, int w, int op, Register reg, Register vvvv, AMD64Address rm, Register imm8, int additionalInstructionSize) {
emitVEX(l, pp, mmmmm, w, getRXB(reg, rm), vvvv.encoding());
emitByte(op);
emitOperandHelper(reg, rm, additionalInstructionSize);
emitByte(imm8.encoding() << 4);
}
/**
* Emit instruction with VEX prefix and two register operands and an opcode extension in the r
* field.
* <p>
* Format: [VEX] [Opcode] [ModR/M]
*/
private void emitVexOp(int l, int pp, int mmmmm, int w, int op, int r, Register vvvv, Register rm) {
emitVEX(l, pp, mmmmm, w, getRXB(null, rm), vvvv.encoding());
emitByte(op);
emitModRM(r, rm);
}
/**
* Emit instruction with VEX prefix, one register operand and one memory operand.
* <p>
* Format: [VEX] [Opcode] [ModR/M] [SIB] [Disp]
*/
private void emitVexOp(int l, int pp, int mmmmm, int w, int op, Register reg, AMD64Address rm, int additionalInstructionSize) {
emitVEX(l, pp, mmmmm, w, getRXB(reg, rm), 0);
emitByte(op);
emitOperandHelper(reg, rm, additionalInstructionSize);
}
/**
* Emit instruction with VEX prefix, two register operands and one memory operand.
* <p>
* Format: [VEX] [Opcode] [ModR/M] [SIB] [Disp]
*/
private void emitVexOp(int l, int pp, int mmmmm, int w, int op, Register reg, Register vvvv, AMD64Address rm, int additionalInstructionSize) {
emitVEX(l, pp, mmmmm, w, getRXB(reg, rm), vvvv.encoding());
emitByte(op);
emitOperandHelper(reg, rm, additionalInstructionSize);
}
private static final OpAssertion AVX1 = new OpAssertion(CPUFeature.AVX, CPUFeature.AVX);
private static final OpAssertion AVX1_2 = new OpAssertion(CPUFeature.AVX, CPUFeature.AVX2);
private static final OpAssertion AVX2 = new OpAssertion(CPUFeature.AVX2, CPUFeature.AVX2);
private static final OpAssertion AVX1_128ONLY = new OpAssertion(CPUFeature.AVX, null);
private static final OpAssertion AVX1_256ONLY = new OpAssertion(null, CPUFeature.AVX);
private static final OpAssertion AVX2_256ONLY = new OpAssertion(null, CPUFeature.AVX2);
private static final OpAssertion XMM_CPU = new OpAssertion(CPUFeature.AVX, null, AMD64.XMM, null, AMD64.CPU, null);
private static final OpAssertion XMM_XMM_CPU = new OpAssertion(CPUFeature.AVX, null, AMD64.XMM, AMD64.XMM, AMD64.CPU, null);
private static final OpAssertion CPU_XMM = new OpAssertion(CPUFeature.AVX, null, AMD64.CPU, null, AMD64.XMM, null);
private static final class OpAssertion {
private final CPUFeature avx128feature;
private final CPUFeature avx256feature;
private final RegisterCategory rCategory;
private final RegisterCategory vCategory;
private final RegisterCategory mCategory;
private final RegisterCategory imm8Category;
private OpAssertion(CPUFeature avx128feature, CPUFeature avx256feature) {
this(avx128feature, avx256feature, AMD64.XMM, AMD64.XMM, AMD64.XMM, AMD64.XMM);
}
private OpAssertion(CPUFeature avx128feature, CPUFeature avx256feature, RegisterCategory rCategory, RegisterCategory vCategory, RegisterCategory mCategory, RegisterCategory imm8Category) {
this.avx128feature = avx128feature;
this.avx256feature = avx256feature;
this.rCategory = rCategory;
this.vCategory = vCategory;
this.mCategory = mCategory;
this.imm8Category = imm8Category;
}
public boolean check(AMD64 arch, AVXSize size, Register r, Register v, Register m) {
return check(arch, size, r, v, m, null);
}
public boolean check(AMD64 arch, AVXSize size, Register r, Register v, Register m, Register imm8) {
switch (size) {
case XMM:
assert avx128feature != null && arch.getFeatures().contains(avx128feature) : "emitting illegal 128 bit instruction";
break;
case YMM:
assert avx256feature != null && arch.getFeatures().contains(avx256feature) : "emitting illegal 256 bit instruction";
break;
}
if (r != null) {
assert r.getRegisterCategory().equals(rCategory);
}
if (v != null) {
assert v.getRegisterCategory().equals(vCategory);
}
if (m != null) {
assert m.getRegisterCategory().equals(mCategory);
}
if (imm8 != null) {
assert imm8.getRegisterCategory().equals(imm8Category);
}
return true;
}
public boolean supports(EnumSet<CPUFeature> features, AVXSize avxSize) {
switch (avxSize) {
case XMM:
return features.contains(avx128feature);
case YMM:
return features.contains(avx256feature);
default:
throw GraalError.shouldNotReachHere();
}
}
}
/**
* Base class for VEX-encoded instructions.
*/
private static class VexOp {
protected final int pp;
protected final int mmmmm;
protected final int w;
protected final int op;
private final String opcode;
protected final OpAssertion assertion;
protected VexOp(String opcode, int pp, int mmmmm, int w, int op, OpAssertion assertion) {
this.pp = pp;
this.mmmmm = mmmmm;
this.w = w;
this.op = op;
this.opcode = opcode;
this.assertion = assertion;
}
public boolean isSupported(AMD64VectorAssembler vasm, AMD64Kind kind) {
return assertion.supports(((AMD64) vasm.target.arch).getFeatures(), AVXKind.getRegisterSize(kind));
}
@Override
public String toString() {
return opcode;
}
}
/**
* VEX-encoded instructions with an operand order of RM, but the M operand must be a register.
*/
public static class VexRROp extends VexOp {
// @formatter:off
public static final VexRROp VMASKMOVDQU = new VexRROp("VMASKMOVDQU", P_66, M_0F, WIG, 0xF7, AVX1_128ONLY);
// @formatter:on
protected VexRROp(String opcode, int pp, int mmmmm, int w, int op) {
this(opcode, pp, mmmmm, w, op, AVX1);
}
protected VexRROp(String opcode, int pp, int mmmmm, int w, int op, OpAssertion assertion) {
super(opcode, pp, mmmmm, w, op, assertion);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src) {
assert assertion.check((AMD64) asm.target.arch, size, dst, null, src);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src);
}
}
/**
* VEX-encoded instructions with an operand order of RM.
*/
public static class VexRMOp extends VexRROp {
// @formatter:off
public static final VexRMOp VCVTTSS2SI = new VexRMOp("VCVTTSS2SI", P_F3, M_0F, W0, 0x2C, CPU_XMM);
public static final VexRMOp VCVTTSS2SQ = new VexRMOp("VCVTTSS2SQ", P_F3, M_0F, W1, 0x2C, CPU_XMM);
public static final VexRMOp VCVTTSD2SI = new VexRMOp("VCVTTSD2SI", P_F2, M_0F, W0, 0x2C, CPU_XMM);
public static final VexRMOp VCVTTSD2SQ = new VexRMOp("VCVTTSD2SQ", P_F2, M_0F, W1, 0x2C, CPU_XMM);
public static final VexRMOp VCVTPS2PD = new VexRMOp("VCVTPS2PD", P_, M_0F, WIG, 0x5A);
public static final VexRMOp VCVTPD2PS = new VexRMOp("VCVTPD2PS", P_66, M_0F, WIG, 0x5A);
public static final VexRMOp VCVTDQ2PS = new VexRMOp("VCVTDQ2PS", P_, M_0F, WIG, 0x5B);
public static final VexRMOp VCVTTPS2DQ = new VexRMOp("VCVTTPS2DQ", P_F3, M_0F, WIG, 0x5B);
public static final VexRMOp VCVTTPD2DQ = new VexRMOp("VCVTTPD2DQ", P_66, M_0F, WIG, 0xE6);
public static final VexRMOp VCVTDQ2PD = new VexRMOp("VCVTDQ2PD", P_F3, M_0F, WIG, 0xE6);
public static final VexRMOp VBROADCASTSS = new VexRMOp("VBROADCASTSS", P_66, M_0F38, W0, 0x18);
public static final VexRMOp VBROADCASTSD = new VexRMOp("VBROADCASTSD", P_66, M_0F38, W0, 0x19, AVX1_256ONLY);
public static final VexRMOp VBROADCASTF128 = new VexRMOp("VBROADCASTF128", P_66, M_0F38, W0, 0x1A, AVX1_256ONLY);
public static final VexRMOp VBROADCASTI128 = new VexRMOp("VBROADCASTI128", P_66, M_0F38, W0, 0x5A, AVX2_256ONLY);
public static final VexRMOp VPBROADCASTB = new VexRMOp("VPBROADCASTB", P_66, M_0F38, W0, 0x78, AVX2);
public static final VexRMOp VPBROADCASTW = new VexRMOp("VPBROADCASTW", P_66, M_0F38, W0, 0x79, AVX2);
public static final VexRMOp VPBROADCASTD = new VexRMOp("VPBROADCASTD", P_66, M_0F38, W0, 0x58, AVX2);
public static final VexRMOp VPBROADCASTQ = new VexRMOp("VPBROADCASTQ", P_66, M_0F38, W0, 0x59, AVX2);
public static final VexRMOp VPMOVSXBW = new VexRMOp("VPMOVSXBW", P_66, M_0F38, WIG, 0x20);
public static final VexRMOp VPMOVSXBD = new VexRMOp("VPMOVSXBD", P_66, M_0F38, WIG, 0x21);
public static final VexRMOp VPMOVSXBQ = new VexRMOp("VPMOVSXBQ", P_66, M_0F38, WIG, 0x22);
public static final VexRMOp VPMOVSXWD = new VexRMOp("VPMOVSXWD", P_66, M_0F38, WIG, 0x23);
public static final VexRMOp VPMOVSXWQ = new VexRMOp("VPMOVSXWQ", P_66, M_0F38, WIG, 0x24);
public static final VexRMOp VPMOVSXDQ = new VexRMOp("VPMOVSXDQ", P_66, M_0F38, WIG, 0x25);
public static final VexRMOp VPMOVZXBW = new VexRMOp("VPMOVZXBW", P_66, M_0F38, WIG, 0x30);
public static final VexRMOp VPMOVZXBD = new VexRMOp("VPMOVZXBD", P_66, M_0F38, WIG, 0x31);
public static final VexRMOp VPMOVZXBQ = new VexRMOp("VPMOVZXBQ", P_66, M_0F38, WIG, 0x32);
public static final VexRMOp VPMOVZXWD = new VexRMOp("VPMOVZXWD", P_66, M_0F38, WIG, 0x33);
public static final VexRMOp VPMOVZXWQ = new VexRMOp("VPMOVZXWQ", P_66, M_0F38, WIG, 0x34);
public static final VexRMOp VPMOVZXDQ = new VexRMOp("VPMOVZXDQ", P_66, M_0F38, WIG, 0x35);
public static final VexRMOp VSQRTPD = new VexRMOp("VSQRTPD", P_66, M_0F, WIG, 0x51);
public static final VexRMOp VSQRTPS = new VexRMOp("VSQRTPS", P_, M_0F, WIG, 0x51);
public static final VexRMOp VSQRTSD = new VexRMOp("VSQRTSD", P_F2, M_0F, WIG, 0x51);
public static final VexRMOp VSQRTSS = new VexRMOp("VSQRTSS", P_F3, M_0F, WIG, 0x51);
public static final VexRMOp VUCOMISS = new VexRMOp("VUCOMISS", P_, M_0F, WIG, 0x2E);
public static final VexRMOp VUCOMISD = new VexRMOp("VUCOMISD", P_66, M_0F, WIG, 0x2E);
// @formatter:on
protected VexRMOp(String opcode, int pp, int mmmmm, int w, int op) {
this(opcode, pp, mmmmm, w, op, AVX1);
}
protected VexRMOp(String opcode, int pp, int mmmmm, int w, int op, OpAssertion assertion) {
super(opcode, pp, mmmmm, w, op, assertion);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, AMD64Address src) {
assert assertion.check((AMD64) asm.target.arch, size, dst, null, null);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src, 0);
}
}
/**
* VEX-encoded move instructions.
* <p>
* These instructions have two opcodes: op is the forward move instruction with an operand order
* of RM, and opReverse is the reverse move instruction with an operand order of MR.
*/
public static final class VexMoveOp extends VexRMOp {
// @formatter:off
public static final VexMoveOp VMOVDQA = new VexMoveOp("VMOVDQA", P_66, M_0F, WIG, 0x6F, 0x7F);
public static final VexMoveOp VMOVDQU = new VexMoveOp("VMOVDQU", P_F3, M_0F, WIG, 0x6F, 0x7F);
public static final VexMoveOp VMOVAPS = new VexMoveOp("VMOVAPS", P_, M_0F, WIG, 0x28, 0x29);
public static final VexMoveOp VMOVAPD = new VexMoveOp("VMOVAPD", P_66, M_0F, WIG, 0x28, 0x29);
public static final VexMoveOp VMOVUPS = new VexMoveOp("VMOVUPS", P_, M_0F, WIG, 0x10, 0x11);
public static final VexMoveOp VMOVUPD = new VexMoveOp("VMOVUPD", P_66, M_0F, WIG, 0x10, 0x11);
public static final VexMoveOp VMOVSS = new VexMoveOp("VMOVSS", P_F3, M_0F, WIG, 0x10, 0x11);
public static final VexMoveOp VMOVSD = new VexMoveOp("VMOVSD", P_F2, M_0F, WIG, 0x10, 0x11);
public static final VexMoveOp VMOVD = new VexMoveOp("VMOVD", P_66, M_0F, W0, 0x6E, 0x7E, XMM_CPU);
public static final VexMoveOp VMOVQ = new VexMoveOp("VMOVQ", P_66, M_0F, W1, 0x6E, 0x7E, XMM_CPU);
// @formatter:on
private final int opReverse;
private VexMoveOp(String opcode, int pp, int mmmmm, int w, int op, int opReverse) {
this(opcode, pp, mmmmm, w, op, opReverse, AVX1);
}
private VexMoveOp(String opcode, int pp, int mmmmm, int w, int op, int opReverse, OpAssertion assertion) {
super(opcode, pp, mmmmm, w, op, assertion);
this.opReverse = opReverse;
}
public void emit(AMD64VectorAssembler asm, AVXSize size, AMD64Address dst, Register src) {
assert assertion.check((AMD64) asm.target.arch, size, src, null, null);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, opReverse, src, dst, 0);
}
public void emitReverse(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src) {
assert assertion.check((AMD64) asm.target.arch, size, src, null, dst);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, opReverse, src, dst);
}
}
public interface VexRRIOp {
void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src, int imm8);
}
/**
* VEX-encoded instructions with an operand order of RMI.
*/
public static final class VexRMIOp extends VexOp implements VexRRIOp {
// @formatter:off
public static final VexRMIOp VPERMQ = new VexRMIOp("VPERMQ", P_66, M_0F3A, W1, 0x00, AVX2_256ONLY);
public static final VexRMIOp VPSHUFLW = new VexRMIOp("VPSHUFLW", P_F2, M_0F, WIG, 0x70, AVX1_2);
public static final VexRMIOp VPSHUFHW = new VexRMIOp("VPSHUFHW", P_F3, M_0F, WIG, 0x70, AVX1_2);
public static final VexRMIOp VPSHUFD = new VexRMIOp("VPSHUFD", P_66, M_0F, WIG, 0x70, AVX1_2);
// @formatter:on
private VexRMIOp(String opcode, int pp, int mmmmm, int w, int op, OpAssertion assertion) {
super(opcode, pp, mmmmm, w, op, assertion);
}
@Override
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src, int imm8) {
assert assertion.check((AMD64) asm.target.arch, size, dst, null, src);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src);
asm.emitByte(imm8);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, AMD64Address src, int imm8) {
assert assertion.check((AMD64) asm.target.arch, size, dst, null, null);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src, 1);
asm.emitByte(imm8);
}
}
/**
* VEX-encoded instructions with an operand order of MRI.
*/
public static final class VexMRIOp extends VexOp implements VexRRIOp {
// @formatter:off
public static final VexMRIOp VEXTRACTF128 = new VexMRIOp("VEXTRACTF128", P_66, M_0F3A, W0, 0x19, AVX1_256ONLY);
public static final VexMRIOp VEXTRACTI128 = new VexMRIOp("VEXTRACTI128", P_66, M_0F3A, W0, 0x39, AVX2_256ONLY);
public static final VexMRIOp VPEXTRB = new VexMRIOp("VPEXTRB", P_66, M_0F3A, W0, 0x14, XMM_CPU);
public static final VexMRIOp VPEXTRW = new VexMRIOp("VPEXTRW", P_66, M_0F3A, W0, 0x15, XMM_CPU);
public static final VexMRIOp VPEXTRD = new VexMRIOp("VPEXTRD", P_66, M_0F3A, W0, 0x16, XMM_CPU);
public static final VexMRIOp VPEXTRQ = new VexMRIOp("VPEXTRQ", P_66, M_0F3A, W1, 0x16, XMM_CPU);
// @formatter:on
private VexMRIOp(String opcode, int pp, int mmmmm, int w, int op, OpAssertion assertion) {
super(opcode, pp, mmmmm, w, op, assertion);
}
@Override
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src, int imm8) {
assert assertion.check((AMD64) asm.target.arch, size, src, null, dst);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, src, dst);
asm.emitByte(imm8);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, AMD64Address dst, Register src, int imm8) {
assert assertion.check((AMD64) asm.target.arch, size, src, null, null);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, src, dst, 1);
asm.emitByte(imm8);
}
}
/**
* VEX-encoded instructions with an operand order of RVMR.
*/
public static class VexRVMROp extends VexOp {
// @formatter:off
public static final VexRVMROp VPBLENDVB = new VexRVMROp("VPBLENDVB", P_66, M_0F3A, W0, 0x4C, AVX1_2);
public static final VexRVMROp VPBLENDVPS = new VexRVMROp("VPBLENDVPS", P_66, M_0F3A, W0, 0x4A, AVX1);
public static final VexRVMROp VPBLENDVPD = new VexRVMROp("VPBLENDVPD", P_66, M_0F3A, W0, 0x4B, AVX1);
// @formatter:on
protected VexRVMROp(String opcode, int pp, int mmmmm, int w, int op, OpAssertion assertion) {
super(opcode, pp, mmmmm, w, op, assertion);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register mask, Register src1, Register src2) {
assert assertion.check((AMD64) asm.target.arch, size, dst, mask, src1, src2);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src1, src2, mask);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register mask, Register src1, AMD64Address src2) {
assert assertion.check((AMD64) asm.target.arch, size, dst, mask, src1, null);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src1, src2, mask, 0);
}
}
/**
* VEX-encoded instructions with an operand order of RVM.
*/
public static class VexRVMOp extends VexOp {
// @formatter:off
public static final VexRVMOp VANDPS = new VexRVMOp("VANDPS", P_, M_0F, WIG, 0x54);
public static final VexRVMOp VANDPD = new VexRVMOp("VANDPD", P_66, M_0F, WIG, 0x54);
public static final VexRVMOp VORPS = new VexRVMOp("VORPS", P_, M_0F, WIG, 0x56);
public static final VexRVMOp VORPD = new VexRVMOp("VORPD", P_66, M_0F, WIG, 0x56);
public static final VexRVMOp VADDPS = new VexRVMOp("VADDPS", P_, M_0F, WIG, 0x58);
public static final VexRVMOp VADDPD = new VexRVMOp("VADDPD", P_66, M_0F, WIG, 0x58);
public static final VexRVMOp VADDSS = new VexRVMOp("VADDSS", P_F3, M_0F, WIG, 0x58);
public static final VexRVMOp VADDSD = new VexRVMOp("VADDSD", P_F2, M_0F, WIG, 0x58);
public static final VexRVMOp VXORPS = new VexRVMOp("VXORPS", P_, M_0F, WIG, 0x57);
public static final VexRVMOp VXORPD = new VexRVMOp("VXORPD", P_66, M_0F, WIG, 0x57);
public static final VexRVMOp VMULPS = new VexRVMOp("VMULPS", P_, M_0F, WIG, 0x59);
public static final VexRVMOp VMULPD = new VexRVMOp("VMULPD", P_66, M_0F, WIG, 0x59);
public static final VexRVMOp VMULSS = new VexRVMOp("VMULSS", P_F3, M_0F, WIG, 0x59);
public static final VexRVMOp VMULSD = new VexRVMOp("VMULSD", P_F2, M_0F, WIG, 0x59);
public static final VexRVMOp VSUBPS = new VexRVMOp("VSUBPS", P_, M_0F, WIG, 0x5C);
public static final VexRVMOp VSUBPD = new VexRVMOp("VSUBPD", P_66, M_0F, WIG, 0x5C);
public static final VexRVMOp VSUBSS = new VexRVMOp("VSUBSS", P_F3, M_0F, WIG, 0x5C);
public static final VexRVMOp VSUBSD = new VexRVMOp("VSUBSD", P_F2, M_0F, WIG, 0x5C);
public static final VexRVMOp VDIVPS = new VexRVMOp("VDIVPS", P_, M_0F, WIG, 0x5E);
public static final VexRVMOp VDIVPD = new VexRVMOp("VDIVPD", P_66, M_0F, WIG, 0x5E);
public static final VexRVMOp VDIVSS = new VexRVMOp("VDIVPS", P_F3, M_0F, WIG, 0x5E);
public static final VexRVMOp VDIVSD = new VexRVMOp("VDIVPD", P_F2, M_0F, WIG, 0x5E);
public static final VexRVMOp VADDSUBPS = new VexRVMOp("VADDSUBPS", P_F2, M_0F, WIG, 0xD0);
public static final VexRVMOp VADDSUBPD = new VexRVMOp("VADDSUBPD", P_66, M_0F, WIG, 0xD0);
public static final VexRVMOp VPAND = new VexRVMOp("VPAND", P_66, M_0F, WIG, 0xDB, AVX1_2);
public static final VexRVMOp VPOR = new VexRVMOp("VPOR", P_66, M_0F, WIG, 0xEB, AVX1_2);
public static final VexRVMOp VPXOR = new VexRVMOp("VPXOR", P_66, M_0F, WIG, 0xEF, AVX1_2);
public static final VexRVMOp VPADDB = new VexRVMOp("VPADDB", P_66, M_0F, WIG, 0xFC, AVX1_2);
public static final VexRVMOp VPADDW = new VexRVMOp("VPADDW", P_66, M_0F, WIG, 0xFD, AVX1_2);
public static final VexRVMOp VPADDD = new VexRVMOp("VPADDD", P_66, M_0F, WIG, 0xFE, AVX1_2);
public static final VexRVMOp VPADDQ = new VexRVMOp("VPADDQ", P_66, M_0F, WIG, 0xD4, AVX1_2);
public static final VexRVMOp VPMULHUW = new VexRVMOp("VPMULHUW", P_66, M_0F, WIG, 0xE4, AVX1_2);
public static final VexRVMOp VPMULHW = new VexRVMOp("VPMULHW", P_66, M_0F, WIG, 0xE5, AVX1_2);
public static final VexRVMOp VPMULLW = new VexRVMOp("VPMULLW", P_66, M_0F, WIG, 0xD5, AVX1_2);
public static final VexRVMOp VPMULLD = new VexRVMOp("VPMULLD", P_66, M_0F38, WIG, 0x40, AVX1_2);
public static final VexRVMOp VPSUBB = new VexRVMOp("VPSUBB", P_66, M_0F, WIG, 0xF8, AVX1_2);
public static final VexRVMOp VPSUBW = new VexRVMOp("VPSUBW", P_66, M_0F, WIG, 0xF9, AVX1_2);
public static final VexRVMOp VPSUBD = new VexRVMOp("VPSUBD", P_66, M_0F, WIG, 0xFA, AVX1_2);
public static final VexRVMOp VPSUBQ = new VexRVMOp("VPSUBQ", P_66, M_0F, WIG, 0xFB, AVX1_2);
public static final VexRVMOp VPSHUFB = new VexRVMOp("VPSHUFB", P_66, M_0F38, WIG, 0x00, AVX1_2);
public static final VexRVMOp VCVTSD2SS = new VexRVMOp("VCVTSD2SS", P_F2, M_0F, WIG, 0x5A);
public static final VexRVMOp VCVTSS2SD = new VexRVMOp("VCVTSS2SD", P_F3, M_0F, WIG, 0x5A);
public static final VexRVMOp VCVTSI2SD = new VexRVMOp("VCVTSI2SD", P_F2, M_0F, W0, 0x2A, XMM_XMM_CPU);
public static final VexRVMOp VCVTSQ2SD = new VexRVMOp("VCVTSQ2SD", P_F2, M_0F, W1, 0x2A, XMM_XMM_CPU);
public static final VexRVMOp VCVTSI2SS = new VexRVMOp("VCVTSI2SS", P_F3, M_0F, W0, 0x2A, XMM_XMM_CPU);
public static final VexRVMOp VCVTSQ2SS = new VexRVMOp("VCVTSQ2SS", P_F3, M_0F, W1, 0x2A, XMM_XMM_CPU);
public static final VexRVMOp VPCMPEQB = new VexRVMOp("VPCMPEQB", P_66, M_0F, WIG, 0x74, AVX1_2);
public static final VexRVMOp VPCMPEQW = new VexRVMOp("VPCMPEQW", P_66, M_0F, WIG, 0x75, AVX1_2);
public static final VexRVMOp VPCMPEQD = new VexRVMOp("VPCMPEQD", P_66, M_0F, WIG, 0x76, AVX1_2);
public static final VexRVMOp VPCMPEQQ = new VexRVMOp("VPCMPEQQ", P_66, M_0F38, WIG, 0x76, AVX1_2);
public static final VexRVMOp VPCMPGTB = new VexRVMOp("VPCMPGTB", P_66, M_0F, WIG, 0x64, AVX1_2);
public static final VexRVMOp VPCMPGTW = new VexRVMOp("VPCMPGTW", P_66, M_0F, WIG, 0x65, AVX1_2);
public static final VexRVMOp VPCMPGTD = new VexRVMOp("VPCMPGTD", P_66, M_0F, WIG, 0x66, AVX1_2);
public static final VexRVMOp VPCMPGTQ = new VexRVMOp("VPCMPGTQ", P_66, M_0F38, WIG, 0x37, AVX1_2);
// @formatter:on
private VexRVMOp(String opcode, int pp, int mmmmm, int w, int op) {
this(opcode, pp, mmmmm, w, op, AVX1);
}
protected VexRVMOp(String opcode, int pp, int mmmmm, int w, int op, OpAssertion assertion) {
super(opcode, pp, mmmmm, w, op, assertion);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src1, Register src2) {
assert assertion.check((AMD64) asm.target.arch, size, dst, src1, src2);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src1, src2);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src1, AMD64Address src2) {
assert assertion.check((AMD64) asm.target.arch, size, dst, src1, null);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src1, src2, 0);
}
}
/**
* VEX-encoded shift instructions with an operand order of either RVM or VMI.
*/
public static final class VexShiftOp extends VexRVMOp implements VexRRIOp {
// @formatter:off
public static final VexShiftOp VPSRLW = new VexShiftOp("VPSRLW", P_66, M_0F, WIG, 0xD1, 0x71, 2);
public static final VexShiftOp VPSRLD = new VexShiftOp("VPSRLD", P_66, M_0F, WIG, 0xD2, 0x72, 2);
public static final VexShiftOp VPSRLQ = new VexShiftOp("VPSRLQ", P_66, M_0F, WIG, 0xD3, 0x73, 2);
public static final VexShiftOp VPSRAW = new VexShiftOp("VPSRAW", P_66, M_0F, WIG, 0xE1, 0x71, 4);
public static final VexShiftOp VPSRAD = new VexShiftOp("VPSRAD", P_66, M_0F, WIG, 0xE2, 0x72, 4);
public static final VexShiftOp VPSLLW = new VexShiftOp("VPSLLW", P_66, M_0F, WIG, 0xF1, 0x71, 6);
public static final VexShiftOp VPSLLD = new VexShiftOp("VPSLLD", P_66, M_0F, WIG, 0xF2, 0x72, 6);
public static final VexShiftOp VPSLLQ = new VexShiftOp("VPSLLQ", P_66, M_0F, WIG, 0xF3, 0x73, 6);
// @formatter:on
private final int immOp;
private final int r;
private VexShiftOp(String opcode, int pp, int mmmmm, int w, int op, int immOp, int r) {
super(opcode, pp, mmmmm, w, op, AVX1_2);
this.immOp = immOp;
this.r = r;
}
@Override
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src, int imm8) {
assert assertion.check((AMD64) asm.target.arch, size, null, dst, src);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, immOp, r, dst, src);
asm.emitByte(imm8);
}
}
public static final class VexMaskMoveOp extends VexOp {
// @formatter:off
public static final VexMaskMoveOp VMASKMOVPS = new VexMaskMoveOp("VMASKMOVPS", P_66, M_0F38, W0, 0x2C, 0x2E);
public static final VexMaskMoveOp VMASKMOVPD = new VexMaskMoveOp("VMASKMOVPD", P_66, M_0F38, W0, 0x2D, 0x2F);
public static final VexMaskMoveOp VPMASKMOVD = new VexMaskMoveOp("VPMASKMOVD", P_66, M_0F38, W0, 0x8C, 0x8E, AVX2);
public static final VexMaskMoveOp VPMASKMOVQ = new VexMaskMoveOp("VPMASKMOVQ", P_66, M_0F38, W1, 0x8C, 0x8E, AVX2);
// @formatter:on
private final int opReverse;
private VexMaskMoveOp(String opcode, int pp, int mmmmm, int w, int op, int opReverse) {
this(opcode, pp, mmmmm, w, op, opReverse, AVX1);
}
private VexMaskMoveOp(String opcode, int pp, int mmmmm, int w, int op, int opReverse, OpAssertion assertion) {
super(opcode, pp, mmmmm, w, op, assertion);
this.opReverse = opReverse;
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register mask, AMD64Address src) {
assert assertion.check((AMD64) asm.target.arch, size, dst, mask, null);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, mask, src, 0);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, AMD64Address dst, Register mask, Register src) {
assert assertion.check((AMD64) asm.target.arch, size, src, mask, null);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, opReverse, src, mask, dst, 0);
}
}
/**
* VEX-encoded instructions with an operand order of RVMI.
*/
public static final class VexRVMIOp extends VexOp {
// @formatter:off
public static final VexRVMIOp VSHUFPS = new VexRVMIOp("VSHUFPS", P_, M_0F, WIG, 0xC6);
public static final VexRVMIOp VSHUFPD = new VexRVMIOp("VSHUFPD", P_66, M_0F, WIG, 0xC6);
public static final VexRVMIOp VINSERTF128 = new VexRVMIOp("VINSERTF128", P_66, M_0F3A, W0, 0x18, AVX1_256ONLY);
public static final VexRVMIOp VINSERTI128 = new VexRVMIOp("VINSERTI128", P_66, M_0F3A, W0, 0x38, AVX2_256ONLY);
// @formatter:on
private VexRVMIOp(String opcode, int pp, int mmmmm, int w, int op) {
this(opcode, pp, mmmmm, w, op, AVX1);
}
private VexRVMIOp(String opcode, int pp, int mmmmm, int w, int op, OpAssertion assertion) {
super(opcode, pp, mmmmm, w, op, assertion);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src1, Register src2, int imm8) {
assert assertion.check((AMD64) asm.target.arch, size, dst, src1, src2);
assert (imm8 & 0xFF) == imm8;
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src1, src2);
asm.emitByte(imm8);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src1, AMD64Address src2, int imm8) {
assert assertion.check((AMD64) asm.target.arch, size, dst, src1, null);
assert (imm8 & 0xFF) == imm8;
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src1, src2, 1);
asm.emitByte(imm8);
}
}
/**
* VEX-encoded comparison operation with an operand order of RVMI. The immediate operand is a
* comparison operator.
*/
public static final class VexFloatCompareOp extends VexOp {
// @formatter:off
public static final VexFloatCompareOp VCMPPS = new VexFloatCompareOp("VCMPPS", P_, M_0F, WIG, 0xC2);
public static final VexFloatCompareOp VCMPPD = new VexFloatCompareOp("VCMPPD", P_66, M_0F, WIG, 0xC2);
public static final VexFloatCompareOp VCMPSS = new VexFloatCompareOp("VCMPSS", P_F2, M_0F, WIG, 0xC2);
public static final VexFloatCompareOp VCMPSD = new VexFloatCompareOp("VCMPSD", P_F2, M_0F, WIG, 0xC2);
// @formatter:on
public enum Predicate {
EQ_OQ(0x00),
LT_OS(0x01),
LE_OS(0x02),
UNORD_Q(0x03),
NEQ_UQ(0x04),
NLT_US(0x05),
NLE_US(0x06),
ORD_Q(0x07),
EQ_UQ(0x08),
NGE_US(0x09),
NGT_US(0x0a),
FALSE_OQ(0x0b),
NEQ_OQ(0x0c),
GE_OS(0x0d),
GT_OS(0x0e),
TRUE_UQ(0x0f),
EQ_OS(0x10),
LT_OQ(0x11),
LE_OQ(0x12),
UNORD_S(0x13),
NEQ_US(0x14),
NLT_UQ(0x15),
NLE_UQ(0x16),
ORD_S(0x17),
EQ_US(0x18),
NGE_UQ(0x19),
NGT_UQ(0x1a),
FALSE_OS(0x1b),
NEQ_OS(0x1c),
GE_OQ(0x1d),
GT_OQ(0x1e),
TRUE_US(0x1f);
private int imm8;
Predicate(int imm8) {
this.imm8 = imm8;
}
public static Predicate getPredicate(Condition condition, boolean unorderedIsTrue) {
if (unorderedIsTrue) {
switch (condition) {
case EQ:
return EQ_UQ;
case NE:
return NEQ_UQ;
case LT:
return NGE_UQ;
case LE:
return NGT_UQ;
case GT:
return NLE_UQ;
case GE:
return NLT_UQ;
default:
throw GraalError.shouldNotReachHere();
}
} else {
switch (condition) {
case EQ:
return EQ_OQ;
case NE:
return NEQ_OQ;
case LT:
return LT_OQ;
case LE:
return LE_OQ;
case GT:
return GT_OQ;
case GE:
return GE_OQ;
default:
throw GraalError.shouldNotReachHere();
}
}
}
}
private VexFloatCompareOp(String opcode, int pp, int mmmmm, int w, int op) {
super(opcode, pp, mmmmm, w, op, AVX1);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src1, Register src2, Predicate p) {
assert assertion.check((AMD64) asm.target.arch, size, dst, src1, src2);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src1, src2);
asm.emitByte(p.imm8);
}
public void emit(AMD64VectorAssembler asm, AVXSize size, Register dst, Register src1, AMD64Address src2, Predicate p) {
assert assertion.check((AMD64) asm.target.arch, size, dst, src1, null);
asm.emitVexOp(getLFlag(size), pp, mmmmm, w, op, dst, src1, src2, 1);
asm.emitByte(p.imm8);
}
}
@Override
public void movflt(Register dst, Register src) {
VexMoveOp.VMOVAPS.emit(this, AVXSize.XMM, dst, src);
}
@Override
public void movflt(Register dst, AMD64Address src) {
VexMoveOp.VMOVSS.emit(this, AVXSize.XMM, dst, src);
}
@Override
public void movflt(AMD64Address dst, Register src) {
VexMoveOp.VMOVSS.emit(this, AVXSize.XMM, dst, src);
}
@Override
public void movdbl(Register dst, Register src) {
VexMoveOp.VMOVAPD.emit(this, AVXSize.XMM, dst, src);
}
@Override
public void movdbl(Register dst, AMD64Address src) {
VexMoveOp.VMOVSD.emit(this, AVXSize.XMM, dst, src);
}
@Override
public void movdbl(AMD64Address dst, Register src) {
VexMoveOp.VMOVSD.emit(this, AVXSize.XMM, dst, src);
}
}