[llvm] [X86][MC] Support encoding/decoding for APX CCMP/CTEST (PR #83863)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 5 00:53:28 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-support
Author: Shengchen Kan (KanRobert)
<details>
<summary>Changes</summary>
APX assembly syntax recommendations:
https://cdrdv2.intel.com/v1/dl/getContent/817241
NOTE:
The change in llvm/tools/llvm-exegesis/lib/X86/Target.cpp is for test
LLVM :: tools/llvm-exegesis/X86/latency/latency-SETCCr-cond-codes-sweep.s
For `SETcc`, llvm-exegesis would randomly choose 1 other instruction to test with `SETcc`, after selecting the instruction, llvm-exegesis would check if the operand is initialized and valid, if not `randomizeTargetMCOperand` would choose a value for invalid operand, it misses support for condition code operand, which cause the flaky failure after CCMP supported.
llvm-exegesis can choose CCMP without specifying ccmp feature b/c it use `MCSubtarget` and only16/32/64 bit is considered.
llvm-exegesis doesn't choose other instructions b/c requirement in `hasAliasingRegistersThrough`: the instruction should use GPR (defined by `SETcc`) and define `EFLAGS` (used by `SETcc`).
---
Patch is 218.19 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/83863.diff
23 Files Affected:
- (modified) llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h (+1)
- (modified) llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp (+67)
- (modified) llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp (+29-4)
- (modified) llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h (+7-2)
- (modified) llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h (+4-1)
- (modified) llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp (+26-3)
- (modified) llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.h (+1)
- (modified) llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp (+46-5)
- (modified) llvm/lib/Target/X86/X86InstrAsmAlias.td (+128)
- (added) llvm/lib/Target/X86/X86InstrConditionalCompare.td (+110)
- (modified) llvm/lib/Target/X86/X86InstrFormats.td (+2)
- (modified) llvm/lib/Target/X86/X86InstrInfo.td (+1)
- (modified) llvm/lib/Target/X86/X86InstrOperands.td (+6)
- (added) llvm/test/MC/Disassembler/X86/apx/ccmp.txt (+1598)
- (modified) llvm/test/MC/Disassembler/X86/apx/reverse-encoding.txt (+18)
- (added) llvm/test/MC/X86/apx/ccmp-att-error.s (+29)
- (added) llvm/test/MC/X86/apx/ccmp-att.s (+1213)
- (added) llvm/test/MC/X86/apx/ccmp-intel-error.s (+29)
- (added) llvm/test/MC/X86/apx/ccmp-intel.s (+1210)
- (modified) llvm/test/TableGen/x86-fold-tables.inc (+23)
- (modified) llvm/tools/llvm-exegesis/lib/X86/Target.cpp (+4)
- (modified) llvm/utils/TableGen/X86RecognizableInstr.cpp (+11)
- (modified) llvm/utils/TableGen/X86RecognizableInstr.h (+2)
``````````diff
diff --git a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
index 0dc974ea9efd8d..5daae45df2f830 100644
--- a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
+++ b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
@@ -434,6 +434,7 @@ enum ModRMDecisionType { MODRMTYPES MODRM_max };
ENUM_ENTRY(ENCODING_Rv, \
"Register code of operand size added to the opcode byte") \
ENUM_ENTRY(ENCODING_CC, "Condition code encoded in opcode") \
+ ENUM_ENTRY(ENCODING_CF, "Condition flags encoded in EVEX.VVVV") \
ENUM_ENTRY(ENCODING_DUP, \
"Duplicate of another operand; ID is encoded in type") \
ENUM_ENTRY(ENCODING_SI, "Source index; encoded in OpSize/Adsize prefix") \
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index 051f6caa8c047f..e3701d69934c08 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -1122,6 +1122,7 @@ class X86AsmParser : public MCTargetAsmParser {
unsigned IdentifyMasmOperator(StringRef Name);
bool ParseMasmOperator(unsigned OpKind, int64_t &Val);
bool ParseRoundingModeOp(SMLoc Start, OperandVector &Operands);
+ bool parseCFlagsOp(OperandVector &Operands);
bool ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM,
bool &ParseError, SMLoc &End);
bool ParseMasmNamedOperator(StringRef Name, IntelExprStateMachine &SM,
@@ -2306,6 +2307,67 @@ bool X86AsmParser::ParseRoundingModeOp(SMLoc Start, OperandVector &Operands) {
return Error(Tok.getLoc(), "unknown token in expression");
}
+/// Parse condtional flags for CCMP/CTEST, e.g {dfv=of,sf,zf,cf} right after
+/// mnemonic.
+bool X86AsmParser::parseCFlagsOp(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ AsmToken Tok = Parser.getTok();
+ const SMLoc Start = Tok.getLoc();
+ if (!Tok.is(AsmToken::LCurly))
+ return Error(Tok.getLoc(), "Expected { at this point");
+ Parser.Lex(); // Eat "{"
+ Tok = Parser.getTok();
+ if (Tok.getIdentifier() != "dfv")
+ return Error(Tok.getLoc(), "Expected dfv at this point");
+ Parser.Lex(); // Eat "dfv"
+ Tok = Parser.getTok();
+ if (!Tok.is(AsmToken::Equal))
+ return Error(Tok.getLoc(), "Expected = at this point");
+ Parser.Lex(); // Eat "="
+
+ Tok = Parser.getTok();
+ SMLoc End;
+ if (Tok.is(AsmToken::RCurly)) {
+ End = Tok.getEndLoc();
+ Operands.push_back(X86Operand::CreateImm(
+ MCConstantExpr::create(0, Parser.getContext()), Start, End));
+ Parser.Lex(); // Eat "}"
+ return false;
+ }
+ unsigned CFlags = 0;
+ for (unsigned I = 0; I < 4; ++I) {
+ Tok = Parser.getTok();
+ unsigned CFlag = StringSwitch<unsigned>(Tok.getIdentifier())
+ .Case("of", 0x8)
+ .Case("sf", 0x4)
+ .Case("zf", 0x2)
+ .Case("cf", 0x1)
+ .Default(~0U);
+ if (CFlag == ~0U)
+ return Error(Tok.getLoc(), "Invalid conditional flags");
+
+ if (CFlags & CFlag)
+ return Error(Tok.getLoc(), "Duplicated conditional flag");
+ CFlags |= CFlag;
+
+ Parser.Lex(); // Eat one conditional flag
+ Tok = Parser.getTok();
+ if (Tok.is(AsmToken::RCurly)) {
+ End = Tok.getEndLoc();
+ Operands.push_back(X86Operand::CreateImm(
+ MCConstantExpr::create(CFlags, Parser.getContext()), Start, End));
+ Parser.Lex(); // Eat "}"
+ return false;
+ } else if (I == 3) {
+ return Error(Tok.getLoc(), "Expected } at this point");
+ } else if (Tok.isNot(AsmToken::Comma)) {
+ return Error(Tok.getLoc(), "Expected } or , at this point");
+ }
+ Parser.Lex(); // Eat ","
+ }
+ llvm_unreachable("Unexpected control flow");
+}
+
/// Parse the '.' operator.
bool X86AsmParser::ParseIntelDotOperator(IntelExprStateMachine &SM,
SMLoc &End) {
@@ -3461,6 +3523,11 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc));
}
+ // Parse condtional flags after mnemonic.
+ if ((Name.starts_with("ccmp") || Name.starts_with("ctest")) &&
+ parseCFlagsOp(Operands))
+ return true;
+
// This does the actual operand parsing. Don't parse any more if we have a
// prefix juxtaposed with an operation like "lock incl 4(%rax)", because we
// just want to parse the "lock" as the first instruction and the "incl" as
diff --git a/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp b/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
index dbc2cef39d8682..f8546bfc4df4ad 100644
--- a/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
+++ b/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
@@ -1141,6 +1141,15 @@ static int getInstructionIDWithAttrMask(uint16_t *instructionID,
return 0;
}
+static bool isCCMPOrCTEST(InternalInstruction *insn) {
+ return (insn->opcodeType == MAP4) &&
+ (((insn->opcode & 0xfe) == 0x38) || ((insn->opcode & 0xfe) == 0x3a) ||
+ (((insn->opcode & 0xfe) == 0x80 || insn->opcode == 0x83) &&
+ regFromModRM(insn->modRM) == 7) ||
+ (insn->opcode & 0xfe) == 0x84 ||
+ ((insn->opcode & 0xfe) == 0xf6 && regFromModRM(insn->modRM) == 0));
+}
+
static bool isNF(InternalInstruction *insn) {
if (!nfFromEVEX4of4(insn->vectorExtensionPrefix[3]))
return false;
@@ -1197,9 +1206,12 @@ static int getInstructionID(struct InternalInstruction *insn,
attrMask |= ATTR_EVEXKZ;
if (bFromEVEX4of4(insn->vectorExtensionPrefix[3]))
attrMask |= ATTR_EVEXB;
- if (isNF(insn)) // NF bit is the MSB of aaa.
+ if (isNF(insn) && !readModRM(insn) &&
+ !isCCMPOrCTEST(insn)) // NF bit is the MSB of aaa.
attrMask |= ATTR_EVEXNF;
- else if (aaaFromEVEX4of4(insn->vectorExtensionPrefix[3]))
+ // aaa is not used a opmask in MAP4
+ else if (aaaFromEVEX4of4(insn->vectorExtensionPrefix[3]) &&
+ (insn->opcodeType != MAP4))
attrMask |= ATTR_EVEXK;
if (lFromEVEX4of4(insn->vectorExtensionPrefix[3]))
attrMask |= ATTR_VEXL;
@@ -1732,8 +1744,15 @@ static int readOperands(struct InternalInstruction *insn) {
if (readOpcodeRegister(insn, 0))
return -1;
break;
+ case ENCODING_CF:
+ insn->immediates[1] = oszcFromEVEX3of4(insn->vectorExtensionPrefix[2]);
+ needVVVV = false; // oszc shares the same bits with VVVV
+ break;
case ENCODING_CC:
- insn->immediates[1] = insn->opcode & 0xf;
+ if (isCCMPOrCTEST(insn))
+ insn->immediates[2] = scFromEVEX4of4(insn->vectorExtensionPrefix[3]);
+ else
+ insn->immediates[1] = insn->opcode & 0xf;
break;
case ENCODING_FP:
break;
@@ -2371,9 +2390,15 @@ static bool translateOperand(MCInst &mcInst, const OperandSpecifier &operand,
case ENCODING_Rv:
translateRegister(mcInst, insn.opcodeRegister);
return false;
- case ENCODING_CC:
+ case ENCODING_CF:
mcInst.addOperand(MCOperand::createImm(insn.immediates[1]));
return false;
+ case ENCODING_CC:
+ if (isCCMPOrCTEST(&insn))
+ mcInst.addOperand(MCOperand::createImm(insn.immediates[2]));
+ else
+ mcInst.addOperand(MCOperand::createImm(insn.immediates[1]));
+ return false;
case ENCODING_FP:
translateFPRegister(mcInst, insn.modRM & 7);
return false;
diff --git a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
index 9cae0f02926fce..42e4de4ee682a4 100644
--- a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
+++ b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
@@ -33,6 +33,8 @@ namespace X86Disassembler {
#define twoBitsFromOffset6(val) (((val) >> 6) & 0x3)
#define threeBitsFromOffset0(val) ((val) & 0x7)
#define threeBitsFromOffset3(val) (((val) >> 3) & 0x7)
+#define fourBitsFromOffset0(val) ((val) & 0xf)
+#define fourBitsFromOffset3(val) (((val) >> 3) & 0xf)
#define fiveBitsFromOffset0(val) ((val) & 0x1f)
#define invertedBitFromOffset2(val) (((~(val)) >> 2) & 0x1)
#define invertedBitFromOffset3(val) (((~(val)) >> 3) & 0x1)
@@ -97,6 +99,7 @@ namespace X86Disassembler {
#define vvvvFromEVEX3of4(evex) invertedFourBitsFromOffset3(evex)
#define x2FromEVEX3of4(evex) invertedBitFromOffset2(evex)
#define ppFromEVEX3of4(evex) twoBitsFromOffset0(evex)
+#define oszcFromEVEX3of4(evex) fourBitsFromOffset3(evex)
#define zFromEVEX4of4(evex) bitFromOffset7(evex)
#define l2FromEVEX4of4(evex) bitFromOffset6(evex)
#define lFromEVEX4of4(evex) bitFromOffset5(evex)
@@ -104,6 +107,8 @@ namespace X86Disassembler {
#define v2FromEVEX4of4(evex) invertedBitFromOffset3(evex)
#define aaaFromEVEX4of4(evex) threeBitsFromOffset0(evex)
#define nfFromEVEX4of4(evex) bitFromOffset2(evex)
+#define oszcFromEVEX3of4(evex) fourBitsFromOffset3(evex)
+#define scFromEVEX4of4(evex) fourBitsFromOffset0(evex)
// These enums represent Intel registers for use by the decoder.
#define REGS_8BIT \
@@ -755,10 +760,10 @@ struct InternalInstruction {
// The displacement, used for memory operands
int32_t displacement;
- // Immediates. There can be two in some cases
+ // Immediates. There can be three in some cases
uint8_t numImmediatesConsumed;
uint8_t numImmediatesTranslated;
- uint64_t immediates[2];
+ uint64_t immediates[3];
// A register or immediate operand encoded into the opcode
Reg opcodeRegister;
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
index 28a067d525e010..65b8ebc0b9b994 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
@@ -875,7 +875,10 @@ enum : uint64_t {
ExplicitOpPrefixMask = 3ULL << ExplicitOpPrefixShift,
/// EVEX_NF - Set if this instruction has EVEX.NF field set.
EVEX_NFShift = ExplicitOpPrefixShift + 2,
- EVEX_NF = 1ULL << EVEX_NFShift
+ EVEX_NF = 1ULL << EVEX_NFShift,
+ // TwoConditionalOps - Set if this instruction has two conditional operands
+ TwoConditionalOps_Shift = EVEX_NFShift + 1,
+ TwoConditionalOps = 1ULL << TwoConditionalOps_Shift
};
/// \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 7422a989734653..fd46e4e1df821a 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.cpp
@@ -29,7 +29,9 @@ using namespace llvm;
void X86InstPrinterCommon::printCondCode(const MCInst *MI, unsigned Op,
raw_ostream &O) {
int64_t Imm = MI->getOperand(Op).getImm();
- bool IsCMPCCXADD = X86::isCMPCCXADD(MI->getOpcode());
+ unsigned Opc = MI->getOpcode();
+ bool IsCMPCCXADD = X86::isCMPCCXADD(Opc);
+ bool IsCCMPOrCTEST = X86::isCCMPCC(Opc) || X86::isCTESTCC(Opc);
// clang-format off
switch (Imm) {
@@ -44,8 +46,8 @@ void X86InstPrinterCommon::printCondCode(const MCInst *MI, unsigned Op,
case 7: O << (IsCMPCCXADD ? "nbe" : "a"); break;
case 8: O << "s"; break;
case 9: O << "ns"; break;
- case 0xa: O << "p"; break;
- case 0xb: O << "np"; break;
+ case 0xa: O << (IsCCMPOrCTEST ? "t" : "p"); break;
+ case 0xb: O << (IsCCMPOrCTEST ? "f" : "np"); break;
case 0xc: O << "l"; break;
case 0xd: O << (IsCMPCCXADD ? "nl" : "ge"); break;
case 0xe: O << "le"; break;
@@ -54,6 +56,27 @@ void X86InstPrinterCommon::printCondCode(const MCInst *MI, unsigned Op,
// clang-format on
}
+void X86InstPrinterCommon::printCondFlags(const MCInst *MI, unsigned Op,
+ raw_ostream &O) {
+ // +----+----+----+----+
+ // | OF | SF | ZF | CF |
+ // +----+----+----+----+
+ int64_t Imm = MI->getOperand(Op).getImm();
+ assert(Imm >= 0 && Imm < 16 && "Invalid condition flags");
+ O << "{dfv=";
+ std::string Flags;
+ if (Imm & 0x8)
+ Flags += "of,";
+ if (Imm & 0x4)
+ Flags += "sf,";
+ if (Imm & 0x2)
+ Flags += "zf,";
+ if (Imm & 0x1)
+ Flags += "cf,";
+ StringRef SimplifiedFlags = StringRef(Flags).rtrim(",");
+ O << SimplifiedFlags << "}";
+}
+
void X86InstPrinterCommon::printSSEAVXCC(const MCInst *MI, unsigned Op,
raw_ostream &O) {
int64_t Imm = MI->getOperand(Op).getImm();
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.h b/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.h
index 0cb5bf014b209e..221102e17c6538 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.h
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86InstPrinterCommon.h
@@ -24,6 +24,7 @@ class X86InstPrinterCommon : public MCInstPrinter {
virtual void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) = 0;
void printCondCode(const MCInst *MI, unsigned Op, raw_ostream &OS);
+ void printCondFlags(const MCInst *MI, unsigned Op, raw_ostream &OS);
void printSSEAVXCC(const MCInst *MI, unsigned Op, raw_ostream &OS);
void printVPCOMMnemonic(const MCInst *MI, raw_ostream &OS);
void printVPCMPMnemonic(const MCInst *MI, raw_ostream &OS);
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index 1fa676eeb79b0f..dcd0551b7b7653 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -200,8 +200,12 @@ class X86OpcodePrefixHelper {
void setB(const MCInst &MI, unsigned OpNum) {
B = getRegEncoding(MI, OpNum) >> 3 & 1;
}
- void set4V(const MCInst &MI, unsigned OpNum) {
- set4V(getRegEncoding(MI, OpNum));
+ void set4V(const MCInst &MI, unsigned OpNum, bool IsImm = false) {
+ // OF, SF, ZF and CF reuse VEX_4V bits but are not reversed
+ if (IsImm)
+ set4V(~(MI.getOperand(OpNum).getImm()));
+ else
+ set4V(getRegEncoding(MI, OpNum));
}
void setL(bool V) { VEX_L = V; }
void setPP(unsigned V) { VEX_PP = V; }
@@ -252,6 +256,11 @@ class X86OpcodePrefixHelper {
EVEX_aaa = getRegEncoding(MI, OpNum);
}
void setNF(bool V) { EVEX_aaa |= V << 2; }
+ void setSC(const MCInst &MI, unsigned OpNum) {
+ unsigned Encoding = MI.getOperand(OpNum).getImm();
+ EVEX_V2 = ~(Encoding >> 3) & 0x1;
+ EVEX_aaa = Encoding & 0x7;
+ }
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),
@@ -1045,6 +1054,7 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
uint8_t EVEX_rc = 0;
unsigned CurOp = X86II::getOperandBias(Desc);
+ bool HasTwoConditionalOps = TSFlags & X86II::TwoConditionalOps;
switch (TSFlags & X86II::FormMask) {
default:
@@ -1086,6 +1096,10 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
Prefix.set4VV2(MI, CurOp++);
Prefix.setRR2(MI, CurOp++);
+ if (HasTwoConditionalOps) {
+ Prefix.set4V(MI, CurOp++, /*IsImm=*/true);
+ Prefix.setSC(MI, CurOp++);
+ }
break;
}
case X86II::MRMSrcMemFSIB:
@@ -1115,7 +1129,11 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
Prefix.setXX2(MI, MemOperand + X86::AddrIndexReg);
Prefix.setV2(MI, MemOperand + X86::AddrIndexReg, HasVEX_4V);
-
+ CurOp += X86::AddrNumOperands;
+ if (HasTwoConditionalOps) {
+ Prefix.set4V(MI, CurOp++, /*IsImm=*/true);
+ Prefix.setSC(MI, CurOp++);
+ }
break;
}
case X86II::MRMSrcMem4VOp3: {
@@ -1155,7 +1173,11 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
Prefix.setXX2(MI, MemOperand + X86::AddrIndexReg);
Prefix.setV2(MI, MemOperand + X86::AddrIndexReg, HasVEX_4V);
-
+ CurOp += X86::AddrNumOperands + 1; // Skip first imm.
+ if (HasTwoConditionalOps) {
+ Prefix.set4V(MI, CurOp++, /*IsImm=*/true);
+ Prefix.setSC(MI, CurOp++);
+ }
break;
}
case X86II::MRMSrcReg: {
@@ -1183,6 +1205,11 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
Prefix.setX(MI, CurOp, 4);
++CurOp;
+ if (HasTwoConditionalOps) {
+ Prefix.set4V(MI, CurOp++, /*IsImm=*/true);
+ Prefix.setSC(MI, CurOp++);
+ }
+
if (TSFlags & X86II::EVEX_B) {
if (HasEVEX_RC) {
unsigned NumOps = Desc.getNumOperands();
@@ -1236,6 +1263,10 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
Prefix.set4VV2(MI, CurOp++);
Prefix.setRR2(MI, CurOp++);
+ if (HasTwoConditionalOps) {
+ Prefix.set4V(MI, CurOp++, /*IsImm=*/true);
+ Prefix.setSC(MI, CurOp++);
+ }
if (TSFlags & X86II::EVEX_B)
EncodeRC = true;
break;
@@ -1266,6 +1297,10 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
Prefix.setBB2(MI, CurOp);
Prefix.setX(MI, CurOp, 4);
++CurOp;
+ if (HasTwoConditionalOps) {
+ Prefix.set4V(MI, ++CurOp, /*IsImm=*/true);
+ Prefix.setSC(MI, ++CurOp);
+ }
break;
}
}
@@ -1525,6 +1560,7 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
unsigned OpcodeOffset = 0;
bool IsND = X86II::hasNewDataDest(TSFlags);
+ bool HasTwoConditionalOps = TSFlags & X86II::TwoConditionalOps;
uint64_t Form = TSFlags & X86II::FormMask;
switch (Form) {
@@ -1914,11 +1950,16 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
// If there is a remaining operand, it must be a trailing immediate. Emit it
// according to the right size for the instruction. Some instructions
// (SSE4a extrq and insertq) have two trailing immediates.
- while (CurOp != NumOps && NumOps - CurOp <= 2) {
+
+ // Skip two trainling conditional operands encoded in EVEX prefix
+ unsigned RemaningOps = NumOps - CurOp - 2 * HasTwoConditionalOps;
+ while (RemaningOps) {
emitImmediate(MI.getOperand(CurOp++), MI.getLoc(),
X86II::getSizeOfImm(TSFlags), getImmFixupKind(TSFlags),
StartByte, CB, Fixups);
+ --RemaningOps;
}
+ CurOp += 2 * HasTwoConditionalOps;
}
if ((TSFlags & X86II::OpMapMask) == X86II::ThreeDNow)
diff --git a/llvm/lib/Target/X86/X86InstrAsmAlias.td b/llvm/lib/Target/X86/X86InstrAsmAlias.td
index 2590be8651d517..fab058dc390bb3 100644
--- a/llvm/lib/Target/X86/X86InstrAsmAlias.td
+++ b/llvm/lib/Target/X86/X86InstrAsmAlias.td
@@ -62,6 +62,134 @@ multiclass CMPCCXADD_Aliases<string Cond, int CC> {
(CMPCCXADDmr64_EVEX GR64:$dst, i64mem:$dstsrc2, GR64:$src3, CC), 0>;
}
+// CCMP Instructions Alias
+multiclass CCMP_Aliases<string Cond, int CC> {
+let Predicates = [In64BitMode] in {
+def : InstAlias<"ccmp"#Cond#"{b} $dcf\t{$src2, $src1|$src1, $src2}",
+ (CCMP8rr GR8:$src1, GR8:$src2, cflags:$dcf, CC), 0>;
+def : InstAlias<"ccmp"#Cond#"{w} $dcf\t{$src2, $src1|$src1, $src2}",
+ (CCMP16rr GR16:$src1, GR16:$src2, cflags:$dcf, CC), 0>;
+def : InstAlias<"ccmp"#Cond#"{l} $dcf\t{$src2, $src1|$src1, $src2}",
+ (CCMP32rr GR32:$src1, GR32:$src2, cflags:$dcf, CC), 0>;
+def : InstAlias<"ccmp"#Cond#"{q} $dcf\t{$src2, $src1|$src1, $src2}",
+ (CCMP64rr GR64:$src1, GR64:$src2, cflags:$dcf, CC), 0>;
+def : InstAlias<"ccmp"#Cond#"{b} $dcf\t{$src2, $src1|$src1, $src2}",
+ (CCMP8rm GR8:$src1, i8mem:$src2, cflags:$dcf, CC), 0>;
+def : InstAlias<"ccmp"#Cond#"{w} $dcf\t{$src2, $src1|$src1, $src2}",
+ (CCMP16rm GR16:$src1, i16mem:$src2, cflags:$dcf, CC), 0>;
+def : InstAlias<"ccmp"#Cond#"{l} $dcf\t{$src2, $src1|$src1, $src2}",
+ (CCMP32rm GR32:$src1, i32mem:$src2, cflags:$dcf, CC), 0>;
+def : InstAlias<"ccmp"#Cond#"{q} $dcf\t{$src2, $src1|$src1, $src2}",
+ (CCMP64rm GR64:$src1, i64mem:$src2, cflags:$dcf, CC), 0>;
+def : InstAlias<"ccmp"#Cond#"{b} $dcf\t{$src2, $src1|$src1, $src2}",
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/83863
More information about the llvm-commits
mailing list