[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