[llvm] [X86][MC][CodeGen] Support encoding/decoding and pattern match for APX variant ADD instructions (PR #76319)
Shengchen Kan via llvm-commits
llvm-commits at lists.llvm.org
Sat Dec 23 22:44:43 PST 2023
https://github.com/KanRobert created https://github.com/llvm/llvm-project/pull/76319
Four variants: promoted, ND, NF and NF_ND.
>From a2c5cb3ea4a8a12f416186e84336cf963eaba133 Mon Sep 17 00:00:00 2001
From: Shengchen Kan <shengchen.kan at intel.com>
Date: Fri, 22 Dec 2023 22:16:45 +0800
Subject: [PATCH] [X86][MC][CodeGen] Support encoding/decoding and pattern
match for APX variant ADD instructions
Four variants: promoted, ND, NF and NF_ND.
---
.../Support/X86DisassemblerDecoderCommon.h | 9 +-
.../lib/Target/X86/AsmParser/X86AsmParser.cpp | 7 ++
.../X86/Disassembler/X86Disassembler.cpp | 6 +-
.../X86/Disassembler/X86DisassemblerDecoder.h | 1 +
.../lib/Target/X86/MCTargetDesc/X86BaseInfo.h | 5 +-
.../X86/MCTargetDesc/X86InstPrinterCommon.cpp | 3 +
.../X86/MCTargetDesc/X86MCCodeEmitter.cpp | 24 ++++-
llvm/lib/Target/X86/X86InstrArithmetic.td | 96 ++++++++++++++-----
llvm/lib/Target/X86/X86InstrFormats.td | 2 +
llvm/lib/Target/X86/X86InstrPredicates.td | 2 +
llvm/lib/Target/X86/X86InstrUtils.td | 14 +++
llvm/test/CodeGen/X86/apx/add.ll | 50 ++++++++++
llvm/test/MC/Disassembler/X86/apx/add.txt | 66 +++++++++++++
llvm/test/MC/X86/apx/add-att.s | 53 ++++++++++
llvm/test/MC/X86/apx/add-intel.s | 50 ++++++++++
llvm/utils/TableGen/X86DisassemblerTables.cpp | 19 ++++
llvm/utils/TableGen/X86FoldTablesEmitter.cpp | 6 +-
llvm/utils/TableGen/X86RecognizableInstr.cpp | 28 +++++-
llvm/utils/TableGen/X86RecognizableInstr.h | 2 +
19 files changed, 409 insertions(+), 34 deletions(-)
create mode 100644 llvm/test/CodeGen/X86/apx/add.ll
create mode 100644 llvm/test/MC/Disassembler/X86/apx/add.txt
create mode 100644 llvm/test/MC/X86/apx/add-att.s
create mode 100644 llvm/test/MC/X86/apx/add-intel.s
diff --git a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
index b0683ac2e32c05..3aceb247a26c21 100644
--- a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
+++ b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
@@ -70,7 +70,8 @@ enum attributeBits {
ATTR_EVEXKZ = 0x1 << 11,
ATTR_EVEXB = 0x1 << 12,
ATTR_REX2 = 0x1 << 13,
- ATTR_max = 0x1 << 14,
+ ATTR_EVEXNF = 0x1 << 14,
+ ATTR_max = 0x1 << 15,
};
// Combinations of the above attributes that are relevant to instruction
@@ -137,12 +138,15 @@ enum attributeBits {
ENUM_ENTRY(IC_VEX_L_W_XD, 5, "requires VEX, L, W and XD prefix") \
ENUM_ENTRY(IC_VEX_L_W_OPSIZE, 5, "requires VEX, L, W and OpSize") \
ENUM_ENTRY(IC_EVEX, 1, "requires an EVEX prefix") \
+ ENUM_ENTRY(IC_EVEX_NF, 2, "requires EVEX and NF prefix") \
ENUM_ENTRY(IC_EVEX_XS, 2, "requires EVEX and the XS prefix") \
ENUM_ENTRY(IC_EVEX_XD, 2, "requires EVEX and the XD prefix") \
ENUM_ENTRY(IC_EVEX_OPSIZE, 2, "requires EVEX and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_NF, 3, "requires EVEX, NF and the OpSize prefix") \
ENUM_ENTRY(IC_EVEX_OPSIZE_ADSIZE, 3, \
"requires EVEX, OPSIZE and the ADSIZE prefix") \
ENUM_ENTRY(IC_EVEX_W, 3, "requires EVEX and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_NF, 4, "requires EVEX, W and NF prefix") \
ENUM_ENTRY(IC_EVEX_W_XS, 4, "requires EVEX, W, and XS prefix") \
ENUM_ENTRY(IC_EVEX_W_XD, 4, "requires EVEX, W, and XD prefix") \
ENUM_ENTRY(IC_EVEX_W_OPSIZE, 4, "requires EVEX, W, and OpSize") \
@@ -187,10 +191,13 @@ enum attributeBits {
ENUM_ENTRY(IC_EVEX_L2_W_XD_K, 4, "requires EVEX_K, L2, W and XD prefix") \
ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_K, 4, "requires EVEX_K, L2, W and OpSize") \
ENUM_ENTRY(IC_EVEX_B, 1, "requires an EVEX_B prefix") \
+ ENUM_ENTRY(IC_EVEX_B_NF, 2, "requires EVEX_NF and EVEX_B prefix") \
ENUM_ENTRY(IC_EVEX_XS_B, 2, "requires EVEX_B and the XS prefix") \
ENUM_ENTRY(IC_EVEX_XD_B, 2, "requires EVEX_B and the XD prefix") \
ENUM_ENTRY(IC_EVEX_OPSIZE_B, 2, "requires EVEX_B and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_B_NF, 3, "requires EVEX_B, NF and Opsize prefix") \
ENUM_ENTRY(IC_EVEX_W_B, 3, "requires EVEX_B and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_B_NF, 4, "requires EVEX_NF, EVEX_B and the W prefix") \
ENUM_ENTRY(IC_EVEX_W_XS_B, 4, "requires EVEX_B, W, and XS prefix") \
ENUM_ENTRY(IC_EVEX_W_XD_B, 4, "requires EVEX_B, W, and XD prefix") \
ENUM_ENTRY(IC_EVEX_W_OPSIZE_B, 4, "requires EVEX_B, W, and OpSize") \
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index 1d40ce35c1b416..143da9c5e285c9 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -108,6 +108,8 @@ class X86AsmParser : public MCTargetAsmParser {
// Does this instruction use apx extended register?
bool UseApxExtendedReg = false;
+ // Is this instruction explicitly required not to update flags?
+ bool ForcedNoFlag = false;
private:
SMLoc consumeToken() {
@@ -3127,6 +3129,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
ForcedVEXEncoding = VEXEncoding_Default;
ForcedDispEncoding = DispEncoding_Default;
UseApxExtendedReg = false;
+ ForcedNoFlag = false;
// Parse pseudo prefixes.
while (true) {
@@ -3151,6 +3154,8 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
ForcedDispEncoding = DispEncoding_Disp8;
else if (Prefix == "disp32")
ForcedDispEncoding = DispEncoding_Disp32;
+ else if (Prefix == "nf")
+ ForcedNoFlag = true;
else
return Error(NameLoc, "unknown prefix");
@@ -3998,6 +4003,8 @@ unsigned X86AsmParser::checkTargetMatchPredicate(MCInst &Inst) {
if (UseApxExtendedReg && !X86II::canUseApxExtendedReg(MCID))
return Match_Unsupported;
+ if (ForcedNoFlag != static_cast<bool>(MCID.TSFlags & X86II::EVEX_NF))
+ return Match_Unsupported;
if (ForcedVEXEncoding == VEXEncoding_EVEX &&
(MCID.TSFlags & X86II::EncodingMask) != X86II::EVEX)
diff --git a/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp b/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
index 59e2008f56321b..347dc0d4ed43a7 100644
--- a/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
+++ b/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
@@ -1169,7 +1169,11 @@ static int getInstructionID(struct InternalInstruction *insn,
attrMask |= ATTR_EVEXKZ;
if (bFromEVEX4of4(insn->vectorExtensionPrefix[3]))
attrMask |= ATTR_EVEXB;
- if (aaaFromEVEX4of4(insn->vectorExtensionPrefix[3]))
+ // nf bit is the MSB of aaa
+ if (nfFromEVEX4of4(insn->vectorExtensionPrefix[3]) &&
+ insn->opcodeType == MAP4)
+ attrMask |= ATTR_EVEXNF;
+ else if (aaaFromEVEX4of4(insn->vectorExtensionPrefix[3]))
attrMask |= ATTR_EVEXK;
if (lFromEVEX4of4(insn->vectorExtensionPrefix[3]))
attrMask |= ATTR_VEXL;
diff --git a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
index decc45091941d7..4c7b1c094522eb 100644
--- a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
+++ b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
@@ -103,6 +103,7 @@ namespace X86Disassembler {
#define bFromEVEX4of4(evex) bitFromOffset4(evex)
#define v2FromEVEX4of4(evex) invertedBitFromOffset3(evex)
#define aaaFromEVEX4of4(evex) threeBitsFromOffset0(evex)
+#define nfFromEVEX4of4(evex) bitFromOffset2(evex)
// These enums represent Intel registers for use by the decoder.
#define REGS_8BIT \
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
index b0fcaef5f4b064..7c85697a021176 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
@@ -870,7 +870,10 @@ enum : uint64_t {
ExplicitVEXPrefix = 2ULL << ExplicitOpPrefixShift,
/// For instructions that are promoted to EVEX space for EGPR.
ExplicitEVEXPrefix = 3ULL << ExplicitOpPrefixShift,
- ExplicitOpPrefixMask = 3ULL << ExplicitOpPrefixShift
+ ExplicitOpPrefixMask = 3ULL << ExplicitOpPrefixShift,
+ /// EVEX_NF - Set if this instruction has EVEX.NF field set.
+ EVEX_NFShift = ExplicitOpPrefixShift + 2,
+ EVEX_NF = 1ULL << EVEX_NFShift
};
/// \returns true if the instruction with given opcode is a prefix.
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp
index cab2f0a2e1c1a2..1947313a9dfb0b 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp
@@ -369,6 +369,9 @@ void X86InstPrinterCommon::printInstFlags(const MCInst *MI, raw_ostream &O,
else if (Flags & X86::IP_HAS_REPEAT)
O << "\trep\t";
+ if (TSFlags & X86II::EVEX_NF)
+ O << "\t{nf}";
+
// These all require a pseudo prefix
if ((Flags & X86::IP_USE_VEX) ||
(TSFlags & X86II::ExplicitOpPrefixMask) == X86II::ExplicitVEXPrefix)
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index 9e1f1eb97e7032..deb029d4a4074f 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -251,6 +251,7 @@ class X86OpcodePrefixHelper {
void setAAA(const MCInst &MI, unsigned OpNum) {
EVEX_aaa = getRegEncoding(MI, OpNum);
}
+ void setNF(bool V) { EVEX_aaa |= V << 2; }
X86OpcodePrefixHelper(const MCRegisterInfo &MRI)
: W(0), R(0), X(0), B(0), M(0), R2(0), X2(0), B2(0), VEX_4V(0), VEX_L(0),
@@ -987,6 +988,7 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
}
Prefix.setW(TSFlags & X86II::REX_W);
+ Prefix.setNF(TSFlags & X86II::EVEX_NF);
bool HasEVEX_K = TSFlags & X86II::EVEX_K;
bool HasVEX_4V = TSFlags & X86II::VEX_4V;
@@ -1049,6 +1051,9 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
bool EncodeRC = false;
uint8_t EVEX_rc = 0;
+ bool IsND = (TSFlags & X86II::OpMapMask) == X86II::T_MAP4 &&
+ (TSFlags & X86II::EVEX_B) && HasVEX_4V;
+
unsigned CurOp = X86II::getOperandBias(Desc);
switch (TSFlags & X86II::FormMask) {
@@ -1160,12 +1165,17 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
//
// FMA4:
// dst(ModR/M.reg), src1(VEX_4V), src2(Imm[7:4]), src3(ModR/M),
+ //
+ // NDD:
+ // dst(VEX_4V), src1(ModR/M.reg), src2(ModR/M)
+ if (IsND)
+ Prefix.set4VV2(MI, CurOp++);
Prefix.setRR2(MI, CurOp++);
if (HasEVEX_K)
Prefix.setAAA(MI, CurOp++);
- if (HasVEX_4V)
+ if (!IsND && HasVEX_4V)
Prefix.set4VV2(MI, CurOp++);
Prefix.setBB2(MI, CurOp);
@@ -1209,6 +1219,11 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
// dst(ModR/M), src(ModR/M)
// dst(ModR/M), src(ModR/M), imm8
// dst(ModR/M), src1(VEX_4V), src2(ModR/M)
+ //
+ // NDD:
+ // dst(VEX_4V), src1(ModR/M), src2(ModR/M)
+ if (IsND)
+ Prefix.set4VV2(MI, CurOp++);
Prefix.setBB2(MI, CurOp);
Prefix.setX(MI, CurOp, 4);
++CurOp;
@@ -1216,7 +1231,7 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
if (HasEVEX_K)
Prefix.setAAA(MI, CurOp++);
- if (HasVEX_4V)
+ if (!IsND && HasVEX_4V)
Prefix.set4VV2(MI, CurOp++);
Prefix.setRR2(MI, CurOp++);
@@ -1508,6 +1523,9 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
unsigned OpcodeOffset = 0;
+ bool IsND = (TSFlags & X86II::OpMapMask) == X86II::T_MAP4 &&
+ (TSFlags & X86II::EVEX_B) && HasVEX_4V;
+
uint64_t Form = TSFlags & X86II::FormMask;
switch (Form) {
default:
@@ -1576,6 +1594,8 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
if (HasVEX_4V) // Skip 1st src (which is encoded in VEX_VVVV)
++SrcRegNum;
+ if (IsND) // Skip the NDD operand encoded in EVEX_VVVV
+ ++CurOp;
emitRegModRMByte(MI.getOperand(CurOp),
getX86RegNum(MI.getOperand(SrcRegNum)), CB);
diff --git a/llvm/lib/Target/X86/X86InstrArithmetic.td b/llvm/lib/Target/X86/X86InstrArithmetic.td
index 22394545a7fa2b..9d2bc1da68d176 100644
--- a/llvm/lib/Target/X86/X86InstrArithmetic.td
+++ b/llvm/lib/Target/X86/X86InstrArithmetic.td
@@ -45,12 +45,12 @@ def PLEA64r : PseudoI<(outs GR64:$dst), (ins anymem:$src), []>;
}
// BinOpRR - Instructions that read "reg, reg".
-class BinOpRR<bits<8> o, string m, X86TypeInfo t, dag out, list<dag> p>
+class BinOpRR<bits<8> o, string m, string args, X86TypeInfo t, dag out, list<dag> p>
: ITy<o, MRMDestReg, t, out, (ins t.RegClass:$src1, t.RegClass:$src2), m,
- "{$src2, $src1|$src1, $src2}", p>, Sched<[WriteALU]>;
+ args, p>, Sched<[WriteALU]>;
// BinOpRR_F - Instructions that read "reg, reg" and write EFLAGS only.
class BinOpRR_F<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node>
- : BinOpRR<o, m, t, (outs),
+ : BinOpRR<o, m, binop_args, t, (outs),
[(set EFLAGS, (node t.RegClass:$src1, t.RegClass:$src2))]>,
DefEFLAGS;
// BinOpRR_F_Rev - Reversed encoding of BinOpRR_F
@@ -58,28 +58,38 @@ class BinOpRR_F_Rev<bits<8> o, string m, X86TypeInfo t>
: BinOpRR_F<o, m, t, null_frag>, DisassembleOnly {
let Form = MRMSrcReg;
}
+// BinOpRR_R - Instructions that read "reg, reg" and write "reg".
+class BinOpRR_R<bits<8> o, string m, X86TypeInfo t, bit ndd = 0>
+ : BinOpRR<o, m, !if(!eq(ndd, 0), binop_args, binop_ndd_args), t,
+ (outs t.RegClass:$dst), []>, NDD<ndd>;
+// BinOpRR_R_Rev - Reversed encoding of BinOpRR_R
+class BinOpRR_R_Rev<bits<8> o, string m, X86TypeInfo t, bit ndd = 0>
+ : BinOpRR_R<o, m, t, ndd>, DisassembleOnly {
+ let Form = MRMSrcReg;
+}
// BinOpRR_RF - Instructions that read "reg, reg", and write "reg", EFLAGS.
-class BinOpRR_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node>
- : BinOpRR<o, m, t, (outs t.RegClass:$dst),
+class BinOpRR_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node, bit ndd = 0>
+ : BinOpRR<o, m, !if(!eq(ndd, 0), binop_args, binop_ndd_args), t,
+ (outs t.RegClass:$dst),
[(set t.RegClass:$dst, EFLAGS,
- (node t.RegClass:$src1, t.RegClass:$src2))]>, DefEFLAGS;
+ (node t.RegClass:$src1, t.RegClass:$src2))]>, DefEFLAGS, NDD<ndd>;
// BinOpRR_RF_Rev - Reversed encoding of BinOpRR_RF.
-class BinOpRR_RF_Rev<bits<8> o, string m, X86TypeInfo t>
- : BinOpRR_RF<o, m, t, null_frag>, DisassembleOnly {
+class BinOpRR_RF_Rev<bits<8> o, string m, X86TypeInfo t, bit ndd = 0>
+ : BinOpRR_RF<o, m, t, null_frag, ndd>, DisassembleOnly {
let Form = MRMSrcReg;
}
// BinOpRRF_RF - Instructions that read "reg, reg", write "reg" and read/write
// EFLAGS.
-class BinOpRRF_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node>
- : BinOpRR<o, m, t, (outs t.RegClass:$dst),
+class BinOpRRF_RF<bits<8> o, string m, X86TypeInfo t, SDPatternOperator node, bit ndd = 0>
+ : BinOpRR<o, m, !if(!eq(ndd, 0), binop_args, binop_ndd_args), t, (outs t.RegClass:$dst),
[(set t.RegClass:$dst, EFLAGS,
(node t.RegClass:$src1, t.RegClass:$src2,
- EFLAGS))]>, DefEFLAGS, UseEFLAGS {
+ EFLAGS))]>, DefEFLAGS, UseEFLAGS, NDD<ndd> {
let SchedRW = [WriteADC];
}
// BinOpRRF_RF_Rev - Reversed encoding of BinOpRRF_RF
-class BinOpRRF_RF_Rev<bits<8> o, string m, X86TypeInfo t>
- : BinOpRRF_RF<o, m, t, null_frag>, DisassembleOnly {
+class BinOpRRF_RF_Rev<bits<8> o, string m, X86TypeInfo t, bit ndd = 0>
+ : BinOpRRF_RF<o, m, t, null_frag, ndd>, DisassembleOnly {
let Form = MRMSrcReg;
}
@@ -640,20 +650,60 @@ multiclass ArithBinOp_RF<bits<8> BaseOpc, bits<8> BaseOpc2, bits<8> BaseOpc4,
SDNode opnodeflag, SDNode opnode,
bit CommutableRR, bit ConvertibleToThreeAddress,
bit ConvertibleToThreeAddressRR> {
- let Constraints = "$src1 = $dst" in {
- let isCommutable = CommutableRR,
- isConvertibleToThreeAddress = ConvertibleToThreeAddressRR in {
+ let isCommutable = CommutableRR,
+ isConvertibleToThreeAddress = ConvertibleToThreeAddressRR in {
+ let Predicates = [NoNDD] in {
def NAME#8rr : BinOpRR_RF<BaseOpc, mnemonic, Xi8 , opnodeflag>;
def NAME#16rr : BinOpRR_RF<BaseOpc, mnemonic, Xi16, opnodeflag>, OpSize16;
def NAME#32rr : BinOpRR_RF<BaseOpc, mnemonic, Xi32, opnodeflag>, OpSize32;
def NAME#64rr : BinOpRR_RF<BaseOpc, mnemonic, Xi64, opnodeflag>;
}
+ let Predicates = [HasNDD, In64BitMode] in {
+ def NAME#8rr_ND : BinOpRR_RF<BaseOpc, mnemonic, Xi8 , opnodeflag, 1>;
+ def NAME#16rr_ND : BinOpRR_RF<BaseOpc, mnemonic, Xi16, opnodeflag, 1>, PD;
+ def NAME#32rr_ND : BinOpRR_RF<BaseOpc, mnemonic, Xi32, opnodeflag, 1>;
+ def NAME#64rr_ND : BinOpRR_RF<BaseOpc, mnemonic, Xi64, opnodeflag, 1>;
+ def NAME#8rr_NF_ND : BinOpRR_R<BaseOpc, mnemonic, Xi8, 1>, EVEX_NF;
+ def NAME#16rr_NF_ND : BinOpRR_R<BaseOpc, mnemonic, Xi16, 1>, EVEX_NF, PD;
+ def NAME#32rr_NF_ND : BinOpRR_R<BaseOpc, mnemonic, Xi32, 1>, EVEX_NF;
+ def NAME#64rr_NF_ND : BinOpRR_R<BaseOpc, mnemonic, Xi64, 1>, EVEX_NF;
+ }
+ let Predicates = [In64BitMode] in {
+ def NAME#8rr_NF : BinOpRR_R<BaseOpc, mnemonic, Xi8>, T_MAP4, EVEX, EVEX_NF;
+ def NAME#16rr_NF : BinOpRR_R<BaseOpc, mnemonic, Xi16>, T_MAP4, EVEX, EVEX_NF, PD;
+ def NAME#32rr_NF : BinOpRR_R<BaseOpc, mnemonic, Xi32>, T_MAP4, EVEX, EVEX_NF;
+ def NAME#64rr_NF : BinOpRR_R<BaseOpc, mnemonic, Xi64>, T_MAP4, EVEX, EVEX_NF;
+ def NAME#8rr_EVEX : BinOpRR_RF<BaseOpc, mnemonic, Xi8 , null_frag>, T_MAP4, EVEX, ExplicitEVEXPrefix;
+ def NAME#16rr_EVEX : BinOpRR_RF<BaseOpc, mnemonic, Xi16, null_frag>, T_MAP4, EVEX, PD, ExplicitEVEXPrefix;
+ def NAME#32rr_EVEX : BinOpRR_RF<BaseOpc, mnemonic, Xi32, null_frag>, T_MAP4, EVEX, ExplicitEVEXPrefix;
+ def NAME#64rr_EVEX : BinOpRR_RF<BaseOpc, mnemonic, Xi64, null_frag>, T_MAP4, EVEX, ExplicitEVEXPrefix;
+ }
+ }
def NAME#8rr_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi8>;
def NAME#16rr_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi16>, OpSize16;
def NAME#32rr_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi32>, OpSize32;
def NAME#64rr_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi64>;
+ let Predicates = [In64BitMode] in {
+ def NAME#8rr_EVEX_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi8>, T_MAP4, EVEX, ExplicitEVEXPrefix;
+ def NAME#16rr_EVEX_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi16>, T_MAP4, EVEX, PD, ExplicitEVEXPrefix;
+ def NAME#32rr_EVEX_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi32>, T_MAP4, EVEX, ExplicitEVEXPrefix;
+ def NAME#64rr_EVEX_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi64>, T_MAP4, EVEX, ExplicitEVEXPrefix;
+ def NAME#8rr_ND_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi8, 1>;
+ def NAME#16rr_ND_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi16, 1>, PD;
+ def NAME#32rr_ND_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi32, 1>;
+ def NAME#64rr_ND_REV : BinOpRR_RF_Rev<BaseOpc2, mnemonic, Xi64, 1>;
+ def NAME#8rr_NF_REV : BinOpRR_R_Rev<BaseOpc2, mnemonic, Xi8>, T_MAP4, EVEX, EVEX_NF;
+ def NAME#16rr_NF_REV : BinOpRR_R_Rev<BaseOpc2, mnemonic, Xi16>, T_MAP4, EVEX, EVEX_NF, PD;
+ def NAME#32rr_NF_REV : BinOpRR_R_Rev<BaseOpc2, mnemonic, Xi32>, T_MAP4, EVEX, EVEX_NF;
+ def NAME#64rr_NF_REV : BinOpRR_R_Rev<BaseOpc2, mnemonic, Xi64>, T_MAP4, EVEX, EVEX_NF;
+ def NAME#8rr_NF_ND_REV : BinOpRR_R_Rev<BaseOpc2, mnemonic, Xi8, 1>, EVEX_NF;
+ def NAME#16rr_NF_ND_REV : BinOpRR_R_Rev<BaseOpc2, mnemonic, Xi16, 1>, EVEX_NF, PD;
+ def NAME#32rr_NF_ND_REV : BinOpRR_R_Rev<BaseOpc2, mnemonic, Xi32, 1>, EVEX_NF;
+ def NAME#64rr_NF_ND_REV : BinOpRR_R_Rev<BaseOpc2, mnemonic, Xi64, 1>, EVEX_NF;
+ }
+ let Constraints = "$src1 = $dst" in {
def NAME#8rm : BinOpRM_RF<BaseOpc2, mnemonic, Xi8 , opnodeflag>;
def NAME#16rm : BinOpRM_RF<BaseOpc2, mnemonic, Xi16, opnodeflag>, OpSize16;
def NAME#32rm : BinOpRM_RF<BaseOpc2, mnemonic, Xi32, opnodeflag>, OpSize32;
@@ -719,16 +769,16 @@ multiclass ArithBinOp_RFF<bits<8> BaseOpc, bits<8> BaseOpc2, bits<8> BaseOpc4,
string mnemonic, Format RegMRM, Format MemMRM,
SDNode opnode, bit CommutableRR,
bit ConvertibleToThreeAddress> {
- let Constraints = "$src1 = $dst" in {
- let isCommutable = CommutableRR in {
- def NAME#8rr : BinOpRRF_RF<BaseOpc, mnemonic, Xi8 , opnode>;
- let isConvertibleToThreeAddress = ConvertibleToThreeAddress in {
- def NAME#16rr : BinOpRRF_RF<BaseOpc, mnemonic, Xi16, opnode>, OpSize16;
- def NAME#32rr : BinOpRRF_RF<BaseOpc, mnemonic, Xi32, opnode>, OpSize32;
- def NAME#64rr : BinOpRRF_RF<BaseOpc, mnemonic, Xi64, opnode>;
+ let isCommutable = CommutableRR in {
+ def NAME#8rr : BinOpRRF_RF<BaseOpc, mnemonic, Xi8 , opnode>;
+ let isConvertibleToThreeAddress = ConvertibleToThreeAddress in {
+ def NAME#16rr : BinOpRRF_RF<BaseOpc, mnemonic, Xi16, opnode>, OpSize16;
+ def NAME#32rr : BinOpRRF_RF<BaseOpc, mnemonic, Xi32, opnode>, OpSize32;
+ def NAME#64rr : BinOpRRF_RF<BaseOpc, mnemonic, Xi64, opnode>;
} // isConvertibleToThreeAddress
} // isCommutable
+ let Constraints = "$src1 = $dst" in {
def NAME#8rr_REV : BinOpRRF_RF_Rev<BaseOpc2, mnemonic, Xi8>;
def NAME#16rr_REV : BinOpRRF_RF_Rev<BaseOpc2, mnemonic, Xi16>, OpSize16;
def NAME#32rr_REV : BinOpRRF_RF_Rev<BaseOpc2, mnemonic, Xi32>, OpSize32;
diff --git a/llvm/lib/Target/X86/X86InstrFormats.td b/llvm/lib/Target/X86/X86InstrFormats.td
index 07e5576960d65c..6e76b44b66a307 100644
--- a/llvm/lib/Target/X86/X86InstrFormats.td
+++ b/llvm/lib/Target/X86/X86InstrFormats.td
@@ -256,6 +256,7 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
bit hasEVEX_Z = 0; // Does this inst set the EVEX_Z field?
bit hasEVEX_L2 = 0; // Does this inst set the EVEX_L2 field?
bit hasEVEX_B = 0; // Does this inst set the EVEX_B field?
+ bit hasEVEX_NF = 0; // Does this inst set the EVEX_NF field?
bits<3> CD8_Form = 0; // Compressed disp8 form - vector-width.
// Declare it int rather than bits<4> so that all bits are defined when
// assigning to bits<7>.
@@ -309,4 +310,5 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
let TSFlags{48} = hasEVEX_RC;
let TSFlags{49} = hasNoTrackPrefix;
let TSFlags{51-50} = explicitOpPrefixBits;
+ let TSFlags{52} = hasEVEX_NF;
}
diff --git a/llvm/lib/Target/X86/X86InstrPredicates.td b/llvm/lib/Target/X86/X86InstrPredicates.td
index 8653f15d860281..1b6d09e5668020 100644
--- a/llvm/lib/Target/X86/X86InstrPredicates.td
+++ b/llvm/lib/Target/X86/X86InstrPredicates.td
@@ -10,6 +10,8 @@ def TruePredicate : Predicate<"true">;
def HasEGPR : Predicate<"Subtarget->hasEGPR()">;
def NoEGPR : Predicate<"!Subtarget->hasEGPR()">;
+def HasNDD : Predicate<"Subtarget->hasNDD()">;
+def NoNDD : Predicate<"!Subtarget->hasNDD()">;
def HasCMOV : Predicate<"Subtarget->canUseCMOV()">;
def NoCMOV : Predicate<"!Subtarget->canUseCMOV()">;
def HasNOPL : Predicate<"Subtarget->hasNOPL()">;
diff --git a/llvm/lib/Target/X86/X86InstrUtils.td b/llvm/lib/Target/X86/X86InstrUtils.td
index ac0507fce94fb4..111f61e5f63f48 100644
--- a/llvm/lib/Target/X86/X86InstrUtils.td
+++ b/llvm/lib/Target/X86/X86InstrUtils.td
@@ -50,6 +50,7 @@ class EVEX { Encoding OpEnc = EncEVEX; }
class EVEX_K { bit hasEVEX_K = 1; }
class EVEX_KZ : EVEX_K { bit hasEVEX_Z = 1; }
class EVEX_B { bit hasEVEX_B = 1; }
+class EVEX_NF { bit hasEVEX_NF = 1; }
class EVEX_RC { bit hasEVEX_RC = 1; }
class EVEX_V512 { bit hasEVEX_L2 = 1; bit hasVEX_L = 0; }
class EVEX_V256 { bit hasEVEX_L2 = 0; bit hasVEX_L = 1; }
@@ -967,3 +968,16 @@ class ITy<bits<8> opcode, Format f, X86TypeInfo typeinfo, dag outs, dag ins,
let hasSideEffects = 0;
let hasREX_W = typeinfo.HasREX_W;
}
+
+defvar binop_args = "{$src2, $src1|$src1, $src2}";
+defvar binop_ndd_args = "{$src2, $src1, $dst|$dst, $src1, $src2}";
+defvar binop_constraint = "$src1 = $dst";
+
+// NDD - Helper for new data destination instructions
+class NDD<bit ndd> {
+ string Constraints = !if(!eq(ndd, 0), binop_constraint, "");
+ Encoding OpEnc = !if(!eq(ndd, 0), EncNormal, EncEVEX);
+ bit hasEVEX_B = ndd;
+ bit hasVEX_4V = ndd;
+ Map OpMap = !if(!eq(ndd, 0), OB, T_MAP4);
+}
diff --git a/llvm/test/CodeGen/X86/apx/add.ll b/llvm/test/CodeGen/X86/apx/add.ll
new file mode 100644
index 00000000000000..38fce5328814b2
--- /dev/null
+++ b/llvm/test/CodeGen/X86/apx/add.ll
@@ -0,0 +1,50 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-unknown -mattr=+ndd -verify-machineinstrs | FileCheck %s
+
+define i8 @add8rr(i8 noundef %a, i8 noundef %b) {
+; CHECK-LABEL: add8rr:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: # kill: def $esi killed $esi def $rsi
+; CHECK-NEXT: # kill: def $edi killed $edi def $rdi
+; CHECK-NEXT: leal (%rdi,%rsi), %eax
+; CHECK-NEXT: # kill: def $al killed $al killed $eax
+; CHECK-NEXT: retq
+entry:
+ %add = add i8 %a, %b
+ ret i8 %add
+}
+
+define i16 @add16rr(i16 noundef %a, i16 noundef %b) {
+; CHECK-LABEL: add16rr:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: # kill: def $esi killed $esi def $rsi
+; CHECK-NEXT: # kill: def $edi killed $edi def $rdi
+; CHECK-NEXT: leal (%rdi,%rsi), %eax
+; CHECK-NEXT: # kill: def $ax killed $ax killed $eax
+; CHECK-NEXT: retq
+entry:
+ %add = add i16 %a, %b
+ ret i16 %add
+}
+
+define i32 @add32rr(i32 noundef %a, i32 noundef %b) {
+; CHECK-LABEL: add32rr:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: # kill: def $esi killed $esi def $rsi
+; CHECK-NEXT: # kill: def $edi killed $edi def $rdi
+; CHECK-NEXT: leal (%rdi,%rsi), %eax
+; CHECK-NEXT: retq
+entry:
+ %add = add i32 %a, %b
+ ret i32 %add
+}
+
+define i64 @add64rr(i64 noundef %a, i64 noundef %b) {
+; CHECK-LABEL: add64rr:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: leaq (%rdi,%rsi), %rax
+; CHECK-NEXT: retq
+entry:
+ %add = add i64 %a, %b
+ ret i64 %add
+}
diff --git a/llvm/test/MC/Disassembler/X86/apx/add.txt b/llvm/test/MC/Disassembler/X86/apx/add.txt
new file mode 100644
index 00000000000000..d49b7b5c61f6bd
--- /dev/null
+++ b/llvm/test/MC/Disassembler/X86/apx/add.txt
@@ -0,0 +1,66 @@
+# RUN: llvm-mc -triple x86_64 -disassemble %s | FileCheck %s --check-prefix=ATT
+# RUN: llvm-mc -triple x86_64 -disassemble -output-asm-variant=1 %s | FileCheck %s --check-prefix=INTEL
+
+# ATT: addb %bl, %cl
+# INTEL: add cl, bl
+0x62,0xf4,0x7c,0x08,0x00,0xd9
+
+# ATT: {nf} addb %bl, %cl
+# INTEL: {nf} add cl, bl
+0x62,0xf4,0x7c,0x0c,0x00,0xd9
+
+# ATT: addb %bl, %cl, %r8b
+# INTEL: add r8b, cl, bl
+0x62,0xf4,0x3c,0x18,0x00,0xd9
+
+# ATT: {nf} addb %bl, %cl, %r8b
+# INTEL: {nf} add r8b, cl, bl
+0x62,0xf4,0x3c,0x1c,0x00,0xd9
+
+# ATT: addw %dx, %ax
+# INTEL: add ax, dx
+0x62,0xf4,0x7d,0x08,0x01,0xd0
+
+# ATT: {nf} addw %dx, %ax
+# INTEL: {nf} add ax, dx
+0x62,0xf4,0x7d,0x0c,0x01,0xd0
+
+# ATT: addw %dx, %ax, %r9w
+# INTEL: add r9w, ax, dx
+0x62,0xf4,0x35,0x18,0x01,0xd0
+
+# ATT: {nf} addw %dx, %ax, %r9w
+# INTEL: {nf} add r9w, ax, dx
+0x62,0xf4,0x35,0x1c,0x01,0xd0
+
+# ATT: addl %ecx, %edx
+# INTEL: add edx, ecx
+0x62,0xf4,0x7c,0x08,0x01,0xca
+
+# ATT: {nf} addl %ecx, %edx
+# INTEL: {nf} add edx, ecx
+0x62,0xf4,0x7c,0x0c,0x01,0xca
+
+# ATT: addl %ecx, %edx, %r10d
+# INTEL: add r10d, edx, ecx
+0x62,0xf4,0x2c,0x18,0x01,0xca
+
+# ATT: {nf} addl %ecx, %edx, %r10d
+# INTEL: {nf} add r10d, edx, ecx
+0x62,0xf4,0x2c,0x1c,0x01,0xca
+
+# ATT: addq %r9, %r15
+# INTEL: add r15, r9
+0x62,0x54,0xfc,0x08,0x01,0xcf
+
+# ATT: {nf} addq %r9, %r15
+# INTEL: {nf} add r15, r9
+0x62,0x54,0xfc,0x0c,0x01,0xcf
+
+# ATT: addq %r9, %r15, %r11
+# INTEL: add r11, r15, r9
+0x62,0x54,0xa4,0x18,0x01,0xcf
+
+# ATT: {nf} addq %r9, %r15, %r11
+# INTEL: {nf} add r11, r15, r9
+0x62,0x54,0xa4,0x1c,0x01,0xcf
diff --git a/llvm/test/MC/X86/apx/add-att.s b/llvm/test/MC/X86/apx/add-att.s
new file mode 100644
index 00000000000000..020dd515379af8
--- /dev/null
+++ b/llvm/test/MC/X86/apx/add-att.s
@@ -0,0 +1,53 @@
+# RUN: llvm-mc -triple x86_64 -show-encoding %s | FileCheck %s
+# R;UN: not llvm-mc -triple i386 -show-encoding %s 2>&1 | FileCheck %s --check-prefix=ERROR
+
+# ERROR-COUNT-16: error:
+# ERROR-NOT: error:
+# CHECK: {evex} addb %bl, %cl
+# CHECK: encoding: [0x62,0xf4,0x7c,0x08,0x00,0xd9]
+ {evex} addb %bl, %cl
+# CHECK: {nf} addb %bl, %cl
+# CHECK: encoding: [0x62,0xf4,0x7c,0x0c,0x00,0xd9]
+ {nf} addb %bl, %cl
+# CHECK: addb %bl, %cl, %r8b
+# CHECK: encoding: [0x62,0xf4,0x3c,0x18,0x00,0xd9]
+ addb %bl, %cl, %r8b
+# CHECK: {nf} addb %bl, %cl, %r8b
+# CHECK: encoding: [0x62,0xf4,0x3c,0x1c,0x00,0xd9]
+ {nf} addb %bl, %cl, %r8b
+# CHECK: {evex} addw %dx, %ax
+# CHECK: encoding: [0x62,0xf4,0x7d,0x08,0x01,0xd0]
+ {evex} addw %dx, %ax
+# CHECK: {nf} addw %dx, %ax
+# CHECK: encoding: [0x62,0xf4,0x7d,0x0c,0x01,0xd0]
+ {nf} addw %dx, %ax
+# CHECK: addw %dx, %ax, %r9w
+# CHECK: encoding: [0x62,0xf4,0x35,0x18,0x01,0xd0]
+ addw %dx, %ax, %r9w
+# CHECK: {nf} addw %dx, %ax, %r9w
+# CHECK: encoding: [0x62,0xf4,0x35,0x1c,0x01,0xd0]
+ {nf} addw %dx, %ax, %r9w
+# CHECK: {evex} addl %ecx, %edx
+# CHECK: encoding: [0x62,0xf4,0x7c,0x08,0x01,0xca]
+ {evex} addl %ecx, %edx
+# CHECK: {nf} addl %ecx, %edx
+# CHECK: encoding: [0x62,0xf4,0x7c,0x0c,0x01,0xca]
+ {nf} addl %ecx, %edx
+# CHECK: addl %ecx, %edx, %r10d
+# CHECK: encoding: [0x62,0xf4,0x2c,0x18,0x01,0xca]
+ addl %ecx, %edx, %r10d
+# CHECK: {nf} addl %ecx, %edx, %r10d
+# CHECK: encoding: [0x62,0xf4,0x2c,0x1c,0x01,0xca]
+ {nf} addl %ecx, %edx, %r10d
+# CHECK: {evex} addq %r9, %r15
+# CHECK: encoding: [0x62,0x54,0xfc,0x08,0x01,0xcf]
+ {evex} addq %r9, %r15
+# CHECK: {nf} addq %r9, %r15
+# CHECK: encoding: [0x62,0x54,0xfc,0x0c,0x01,0xcf]
+ {nf} addq %r9, %r15
+# CHECK: addq %r9, %r15, %r11
+# CHECK: encoding: [0x62,0x54,0xa4,0x18,0x01,0xcf]
+ addq %r9, %r15, %r11
+# CHECK: {nf} addq %r9, %r15, %r11
+# CHECK: encoding: [0x62,0x54,0xa4,0x1c,0x01,0xcf]
+ {nf} addq %r9, %r15, %r11
diff --git a/llvm/test/MC/X86/apx/add-intel.s b/llvm/test/MC/X86/apx/add-intel.s
new file mode 100644
index 00000000000000..08b5881cb30271
--- /dev/null
+++ b/llvm/test/MC/X86/apx/add-intel.s
@@ -0,0 +1,50 @@
+# RUN: llvm-mc -triple x86_64 -show-encoding -x86-asm-syntax=intel -output-asm-variant=1 %s | FileCheck %s
+
+# CHECK: {evex} add cl, bl
+# CHECK: encoding: [0x62,0xf4,0x7c,0x08,0x00,0xd9]
+ {evex} add cl, bl
+# CHECK: {nf} add cl, bl
+# CHECK: encoding: [0x62,0xf4,0x7c,0x0c,0x00,0xd9]
+ {nf} add cl, bl
+# CHECK: add r8b, cl, bl
+# CHECK: encoding: [0x62,0xf4,0x3c,0x18,0x00,0xd9]
+ add r8b, cl, bl
+# CHECK: {nf} add r8b, cl, bl
+# CHECK: encoding: [0x62,0xf4,0x3c,0x1c,0x00,0xd9]
+ {nf} add r8b, cl, bl
+# CHECK: {evex} add ax, dx
+# CHECK: encoding: [0x62,0xf4,0x7d,0x08,0x01,0xd0]
+ {evex} add ax, dx
+# CHECK: {nf} add ax, dx
+# CHECK: encoding: [0x62,0xf4,0x7d,0x0c,0x01,0xd0]
+ {nf} add ax, dx
+# CHECK: add r9w, ax, dx
+# CHECK: encoding: [0x62,0xf4,0x35,0x18,0x01,0xd0]
+ add r9w, ax, dx
+# CHECK: {nf} add r9w, ax, dx
+# CHECK: encoding: [0x62,0xf4,0x35,0x1c,0x01,0xd0]
+ {nf} add r9w, ax, dx
+# CHECK: {evex} add edx, ecx
+# CHECK: encoding: [0x62,0xf4,0x7c,0x08,0x01,0xca]
+ {evex} add edx, ecx
+# CHECK: {nf} add edx, ecx
+# CHECK: encoding: [0x62,0xf4,0x7c,0x0c,0x01,0xca]
+ {nf} add edx, ecx
+# CHECK: add r10d, edx, ecx
+# CHECK: encoding: [0x62,0xf4,0x2c,0x18,0x01,0xca]
+ add r10d, edx, ecx
+# CHECK: {nf} add r10d, edx, ecx
+# CHECK: encoding: [0x62,0xf4,0x2c,0x1c,0x01,0xca]
+ {nf} add r10d, edx, ecx
+# CHECK: {evex} add r15, r9
+# CHECK: encoding: [0x62,0x54,0xfc,0x08,0x01,0xcf]
+ {evex} add r15, r9
+# CHECK: {nf} add r15, r9
+# CHECK: encoding: [0x62,0x54,0xfc,0x0c,0x01,0xcf]
+ {nf} add r15, r9
+# CHECK: add r11, r15, r9
+# CHECK: encoding: [0x62,0x54,0xa4,0x18,0x01,0xcf]
+ add r11, r15, r9
+# CHECK: {nf} add r11, r15, r9
+# CHECK: encoding: [0x62,0x54,0xa4,0x1c,0x01,0xcf]
+ {nf} add r11, r15, r9
diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp
index 06e7ec3b923075..cc84e2ccca49d5 100644
--- a/llvm/utils/TableGen/X86DisassemblerTables.cpp
+++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp
@@ -563,6 +563,13 @@ static inline bool inheritsFrom(InstructionContext child,
case IC_EVEX_L2_W_XD_KZ_B:
case IC_EVEX_L2_W_OPSIZE_KZ_B:
return false;
+ case IC_EVEX_NF:
+ case IC_EVEX_B_NF:
+ case IC_EVEX_OPSIZE_NF:
+ case IC_EVEX_OPSIZE_B_NF:
+ case IC_EVEX_W_NF:
+ case IC_EVEX_W_B_NF:
+ return false;
default:
errs() << "Unknown instruction class: "
<< stringForContext((InstructionContext)parent) << "\n";
@@ -889,6 +896,18 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
if ((index & ATTR_EVEX) && (index & ATTR_OPSIZE) && (index & ATTR_ADSIZE))
o << "IC_EVEX_OPSIZE_ADSIZE";
+ else if (index & ATTR_EVEXNF) {
+ o << "IC_EVEX";
+ if (index & ATTR_REXW)
+ o << "_W";
+ else if (index & ATTR_OPSIZE)
+ o << "_OPSIZE";
+
+ if (index & ATTR_EVEXB)
+ o << "_B";
+
+ o << "_NF";
+ }
else if ((index & ATTR_EVEX) || (index & ATTR_VEX) || (index & ATTR_VEXL)) {
if (index & ATTR_EVEX)
o << "IC_EVEX";
diff --git a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
index d3299e28103166..edb1e5a88a0fde 100644
--- a/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
+++ b/llvm/utils/TableGen/X86FoldTablesEmitter.cpp
@@ -369,7 +369,8 @@ class IsMatch {
RegRI.OpMap, RegRI.OpSize, RegRI.AdSize, RegRI.HasREX_W,
RegRI.HasVEX_4V, RegRI.HasVEX_L, RegRI.IgnoresVEX_L,
RegRI.IgnoresW, RegRI.HasEVEX_K, RegRI.HasEVEX_KZ,
- RegRI.HasEVEX_L2, RegRec->getValueAsBit("hasEVEX_RC"),
+ RegRI.HasEVEX_L2, RegRI.HasEVEX_NF,
+ RegRec->getValueAsBit("hasEVEX_RC"),
RegRec->getValueAsBit("hasLockPrefix"),
RegRec->getValueAsBit("hasNoTrackPrefix"),
RegRec->getValueAsBit("EVEX_W1_VEX_W0")) !=
@@ -377,7 +378,8 @@ class IsMatch {
MemRI.OpMap, MemRI.OpSize, MemRI.AdSize, MemRI.HasREX_W,
MemRI.HasVEX_4V, MemRI.HasVEX_L, MemRI.IgnoresVEX_L,
MemRI.IgnoresW, MemRI.HasEVEX_K, MemRI.HasEVEX_KZ,
- MemRI.HasEVEX_L2, MemRec->getValueAsBit("hasEVEX_RC"),
+ MemRI.HasEVEX_L2, MemRI.HasEVEX_NF,
+ MemRec->getValueAsBit("hasEVEX_RC"),
MemRec->getValueAsBit("hasLockPrefix"),
MemRec->getValueAsBit("hasNoTrackPrefix"),
MemRec->getValueAsBit("EVEX_W1_VEX_W0")))
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index 47ee9544f32337..04724c81b8cd56 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -125,6 +125,7 @@ RecognizableInstrBase::RecognizableInstrBase(const CodeGenInstruction &insn) {
HasEVEX_K = Rec->getValueAsBit("hasEVEX_K");
HasEVEX_KZ = Rec->getValueAsBit("hasEVEX_Z");
HasEVEX_B = Rec->getValueAsBit("hasEVEX_B");
+ HasEVEX_NF = Rec->getValueAsBit("hasEVEX_NF");
IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly");
IsAsmParserOnly = Rec->getValueAsBit("isAsmParserOnly");
ForceDisassemble = Rec->getValueAsBit("ForceDisassemble");
@@ -185,6 +186,9 @@ void RecognizableInstr::processInstr(DisassemblerTables &tables,
: (HasEVEX_KZ ? n##_KZ \
: (HasEVEX_K ? n##_K : (HasEVEX_B ? n##_B : n)))))
+#define EVEX_NF(n) (HasEVEX_NF ? n##_NF: n)
+#define EVEX_B_NF(n) (HasEVEX_B ? EVEX_NF(n##_B): EVEX_NF(n))
+
InstructionContext RecognizableInstr::insnContext() const {
InstructionContext insnContext;
@@ -193,8 +197,15 @@ InstructionContext RecognizableInstr::insnContext() const {
errs() << "Don't support VEX.L if EVEX_L2 is enabled: " << Name << "\n";
llvm_unreachable("Don't support VEX.L if EVEX_L2 is enabled");
}
- // VEX_L & VEX_W
- if (!EncodeRC && HasVEX_L && HasREX_W) {
+ if (HasEVEX_NF) {
+ if (OpPrefix == X86Local::PD)
+ insnContext = EVEX_B_NF(IC_EVEX_OPSIZE);
+ else if (HasREX_W)
+ insnContext = EVEX_B_NF(IC_EVEX_W);
+ else
+ insnContext = EVEX_B_NF(IC_EVEX);
+ } else if (!EncodeRC && HasVEX_L && HasREX_W) {
+ // VEX_L & VEX_W
if (OpPrefix == X86Local::PD)
insnContext = EVEX_KB(IC_EVEX_L_W_OPSIZE);
else if (OpPrefix == X86Local::XS)
@@ -486,6 +497,7 @@ void RecognizableInstr::emitInstructionSpecifier() {
++additionalOperands;
#endif
+ bool IsND = OpMap == X86Local::T_MAP4 && HasEVEX_B && HasVEX_4V;
switch (Form) {
default:
llvm_unreachable("Unhandled form");
@@ -536,11 +548,14 @@ void RecognizableInstr::emitInstructionSpecifier() {
numPhysicalOperands <= 3 + additionalOperands &&
"Unexpected number of operands for MRMDestReg");
+ if (IsND)
+ HANDLE_OPERAND(vvvvRegister)
+
HANDLE_OPERAND(rmRegister)
if (HasEVEX_K)
HANDLE_OPERAND(writemaskRegister)
- if (HasVEX_4V)
+ if (!IsND && HasVEX_4V)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
HANDLE_OPERAND(vvvvRegister)
@@ -594,12 +609,15 @@ void RecognizableInstr::emitInstructionSpecifier() {
numPhysicalOperands <= 4 + additionalOperands &&
"Unexpected number of operands for MRMSrcRegFrm");
+ if (IsND)
+ HANDLE_OPERAND(vvvvRegister)
+
HANDLE_OPERAND(roRegister)
if (HasEVEX_K)
HANDLE_OPERAND(writemaskRegister)
- if (HasVEX_4V)
+ if (!IsND && HasVEX_4V)
// FIXME: In AVX, the register below becomes the one encoded
// in ModRMVEX and the one above the one in the VEX.VVVV field
HANDLE_OPERAND(vvvvRegister)
@@ -1216,6 +1234,8 @@ RecognizableInstr::roRegisterEncodingFromString(const std::string &s,
OperandEncoding
RecognizableInstr::vvvvRegisterEncodingFromString(const std::string &s,
uint8_t OpSize) {
+ ENCODING("GR8", ENCODING_VVVV)
+ ENCODING("GR16", ENCODING_VVVV)
ENCODING("GR32", ENCODING_VVVV)
ENCODING("GR64", ENCODING_VVVV)
ENCODING("FR32", ENCODING_VVVV)
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.h b/llvm/utils/TableGen/X86RecognizableInstr.h
index 61ad5e32b3fb0a..493cd92d2ae576 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.h
+++ b/llvm/utils/TableGen/X86RecognizableInstr.h
@@ -212,6 +212,8 @@ struct RecognizableInstrBase {
bool HasEVEX_KZ;
/// The hasEVEX_B field from the record
bool HasEVEX_B;
+ /// The hasEVEX_NF field from the record
+ bool HasEVEX_NF;
/// Indicates that the instruction uses the L and L' fields for RC.
bool EncodeRC;
/// The isCodeGenOnly field from the record
More information about the llvm-commits
mailing list