Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[X86][MC] Support encoding of EGPR for APX #71909

Merged
merged 10 commits into from
Nov 13, 2023
Merged

Conversation

KanRobert
Copy link
Contributor

@KanRobert KanRobert commented Nov 10, 2023

#70958 adds registers R16-R31 (EGPR), this patch

  1. Introduces a new instruction prefix REX2
  2. Supports encoding of EGPR with REX2 for legacy instructions in MAP 0/1
  3. Supports encoding of EGPR with EVEX for the existing instructions in EVEX space

RFC:
https://discourse.llvm.org/t/rfc-design-for-apx-feature-egpr-and-ndd-support/73031/4

@llvmbot llvmbot added backend:X86 mc Machine (object) code labels Nov 10, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Nov 10, 2023

@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-mc

Author: Shengchen Kan (KanRobert)

Changes

Patch is 55.64 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71909.diff

9 Files Affected:

  • (modified) llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp (+10)
  • (modified) llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h (+8)
  • (modified) llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp (+155-68)
  • (added) llvm/test/MC/X86/apx/evex-format-att.s (+67)
  • (added) llvm/test/MC/X86/apx/evex-format-intel.s (+67)
  • (added) llvm/test/MC/X86/apx/rex2-bit-att.s (+240)
  • (added) llvm/test/MC/X86/apx/rex2-bit-intel.s (+237)
  • (added) llvm/test/MC/X86/apx/rex2-format-att.s (+343)
  • (added) llvm/test/MC/X86/apx/rex2-format-intel.s (+343)
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index a367fa1ff74396b..73b03723c263323 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -106,6 +106,9 @@ class X86AsmParser : public MCTargetAsmParser {
 
   DispEncoding ForcedDispEncoding = DispEncoding_Default;
 
+  // Does this instruction use apx extended register?
+  bool UseApxExtendedReg = false;
+
 private:
   SMLoc consumeToken() {
     MCAsmParser &Parser = getParser();
@@ -1410,6 +1413,9 @@ bool X86AsmParser::MatchRegisterByName(MCRegister &RegNo, StringRef RegName,
     }
   }
 
+ if (X86II::isApxExtendedReg(RegNo))
+    UseApxExtendedReg = true;
+
   // If this is "db[0-15]", match it as an alias
   // for dr[0-15].
   if (RegNo == 0 && RegName.startswith("db")) {
@@ -3084,6 +3090,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
   // Reset the forced VEX encoding.
   ForcedVEXEncoding = VEXEncoding_Default;
   ForcedDispEncoding = DispEncoding_Default;
+  UseApxExtendedReg = false;
 
   // Parse pseudo prefixes.
   while (true) {
@@ -3954,6 +3961,9 @@ unsigned X86AsmParser::checkTargetMatchPredicate(MCInst &Inst) {
   unsigned Opc = Inst.getOpcode();
   const MCInstrDesc &MCID = MII.get(Opc);
 
+  if (UseApxExtendedReg && !X86II::canUseApxExtendedReg(MCID))
+    return Match_Unsupported;
+
   if (ForcedVEXEncoding == VEXEncoding_EVEX &&
       (MCID.TSFlags & X86II::EncodingMask) != X86II::EVEX)
     return Match_Unsupported;
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
index 3ccc73398064b76..865987260b42a43 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
@@ -1208,6 +1208,11 @@ namespace X86II {
     return RegNo >= X86::ZMM0 && RegNo <= X86::ZMM31;
   }
 
+  /// \returns true if \p RegNo is an apx extended register.
+  inline bool isApxExtendedReg(unsigned RegNo) {
+    return RegNo >= X86::R16 && RegNo <= X86::R31WH;
+  }
+
   /// \returns true if the MachineOperand is a x86-64 extended (r8 or
   /// higher) register,  e.g. r8, xmm8, xmm13, etc.
   inline bool isX86_64ExtendedReg(unsigned RegNo) {
@@ -1218,6 +1223,9 @@ namespace X86II {
         (RegNo >= X86::ZMM8 && RegNo <= X86::ZMM31))
       return true;
 
+   if (isApxExtendedReg(RegNo))
+      return true;
+
     switch (RegNo) {
     default: break;
     case X86::R8:    case X86::R9:    case X86::R10:   case X86::R11:
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index b85404be3063dae..7e471f57c9c144f 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -36,7 +36,7 @@ using namespace llvm;
 
 namespace {
 
-enum PrefixKind { None, REX, XOP, VEX2, VEX3, EVEX };
+enum PrefixKind { None, REX, REX2, XOP, VEX2, VEX3, EVEX };
 
 static void emitByte(uint8_t C, SmallVectorImpl<char> &CB) { CB.push_back(C); }
 
@@ -46,6 +46,11 @@ class X86OpcodePrefixHelper {
   // | 40H | | WRXB |
   // +-----+ +------+
 
+  // REX2 (2 byte)
+  // +-----+ +-------------------+
+  // | D5H | | M | R'X'B' | WRXB |
+  // +-----+ +-------------------+
+
   // XOP (3-byte)
   // +-----+ +--------------+ +-------------------+
   // | 8Fh | | RXB | m-mmmm | | W | vvvv | L | pp |
@@ -106,9 +111,9 @@ class X86OpcodePrefixHelper {
   //  0b11: F2
 
   // EVEX (4 bytes)
-  // +-----+ +--------------+ +-------------------+ +------------------------+
-  // | 62h | | RXBR' | 0mmm | | W | vvvv | 1 | pp | | z | L'L | b | v' | aaa |
-  // +-----+ +--------------+ +-------------------+ +------------------------+
+  // +-----+ +---------------+ +--------------------+ +------------------------+
+  // | 62h | | RXBR' | B'mmm | | W | vvvv | X' | pp | | z | L'L | b | v' | aaa |
+  // +-----+ +---------------+ +--------------------+ +------------------------+
 
   // EVEX_L2/VEX_L (Vector Length):
   // L2 L
@@ -121,11 +126,14 @@ class X86OpcodePrefixHelper {
   unsigned R : 1;
   unsigned X : 1;
   unsigned B : 1;
+  unsigned M : 1;
+  unsigned R2 : 1;
+  unsigned X2 : 1;
+  unsigned B2 : 1;
   unsigned VEX_4V : 4;
   unsigned VEX_L : 1;
   unsigned VEX_PP : 2;
   unsigned VEX_5M : 5;
-  unsigned EVEX_R2 : 1;
   unsigned EVEX_z : 1;
   unsigned EVEX_L2 : 1;
   unsigned EVEX_b : 1;
@@ -139,7 +147,20 @@ class X86OpcodePrefixHelper {
   }
 
   void setR(unsigned Encoding) { R = Encoding >> 3 & 1; }
-  void setR2(unsigned Encoding) { EVEX_R2 = Encoding >> 4 & 1; }
+  void setR2(unsigned Encoding) {
+    R2 = Encoding >> 4 & 1;
+    assert((!R2 || (Kind <= REX2 || Kind == EVEX)) && "invalid setting");
+  }
+  void setX(unsigned Encoding) { X = Encoding >> 3 & 1; }
+  void setX2(unsigned Encoding) {
+    assert((Kind <= REX2 || Kind == EVEX) && "invalid setting");
+    X2 = Encoding >> 4 & 1;
+  }
+  void setB(unsigned Encoding) { B = Encoding >> 3 & 1; }
+  void setB2(unsigned Encoding) {
+    assert((Kind <= REX2 || Kind == EVEX) && "invalid setting");
+    B2 = Encoding >> 4 & 1;
+  }
   void set4V(unsigned Encoding) { VEX_4V = Encoding & 0xf; }
   void setV2(unsigned Encoding) { EVEX_V2 = Encoding >> 4 & 1; }
 
@@ -149,7 +170,12 @@ class X86OpcodePrefixHelper {
     setR(getRegEncoding(MI, OpNum));
   }
   void setX(const MCInst &MI, unsigned OpNum, unsigned Shift = 3) {
-    X = getRegEncoding(MI, OpNum) >> Shift & 1;
+    unsigned Reg = MI.getOperand(OpNum).getReg();
+    // X is used to extend vector register only when shift is not 3
+    if (Shift != 3 && X86II::isApxExtendedReg(Reg))
+      return;
+    unsigned Encoding = MRI.getEncodingValue(Reg);
+    X = Encoding >> Shift & 1;
   }
   void setB(const MCInst &MI, unsigned OpNum) {
     B = getRegEncoding(MI, OpNum) >> 3 & 1;
@@ -168,11 +194,34 @@ class X86OpcodePrefixHelper {
     setR(Encoding);
     setR2(Encoding);
   }
+  void setM(bool V) { M = V; }
+  void setXX2(const MCInst &MI, unsigned OpNum) {
+    unsigned Reg = MI.getOperand(OpNum).getReg();
+    unsigned Encoding = MRI.getEncodingValue(Reg);
+    setX(Encoding);
+    // Index can be a vector register while X2 is used to extend GPR only
+    if (Kind <= REX2 || X86II::isApxExtendedReg(Reg))
+      setX2(Encoding);
+  }
+  void setBB2(const MCInst &MI, unsigned OpNum) {
+    unsigned Reg = MI.getOperand(OpNum).getReg();
+    unsigned Encoding = MRI.getEncodingValue(Reg);
+    setB(Encoding);
+    // Base can be a vector register while B2 is used to extend GPR only
+    if (Kind <= REX2 || X86II::isApxExtendedReg(Reg))
+      setB2(Encoding);
+  }
   void setZ(bool V) { EVEX_z = V; }
   void setL2(bool V) { EVEX_L2 = V; }
   void setEVEX_b(bool V) { EVEX_b = V; }
-  void setV2(const MCInst &MI, unsigned OpNum) {
-    setV2(getRegEncoding(MI, OpNum));
+  void setV2(const MCInst &MI, unsigned OpNum, bool HasVEX_4V) {
+    // Only needed with VSIB which don't use VVVV.
+    if (HasVEX_4V)
+      return;
+    unsigned Reg = MI.getOperand(OpNum).getReg();
+    if (X86II::isApxExtendedReg(Reg))
+      return;
+    setV2(MRI.getEncodingValue(Reg));
   }
   void set4VV2(const MCInst &MI, unsigned OpNum) {
     unsigned Encoding = getRegEncoding(MI, OpNum);
@@ -184,18 +233,23 @@ class X86OpcodePrefixHelper {
   }
 
   X86OpcodePrefixHelper(const MCRegisterInfo &MRI)
-      : W(0), R(0), X(0), B(0), VEX_4V(0), VEX_L(0), VEX_PP(0), VEX_5M(0),
-        EVEX_R2(0), EVEX_z(0), EVEX_L2(0), EVEX_b(0), EVEX_V2(0), EVEX_aaa(0),
-        MRI(MRI) {}
+      : W(0), R(0), X(0), B(0), M(0), R2(0), X2(0), B2(0), VEX_4V(0), VEX_L(0),
+        VEX_PP(0), VEX_5M(0), EVEX_z(0), EVEX_L2(0), EVEX_b(0), EVEX_V2(0),
+        EVEX_aaa(0), MRI(MRI) {}
 
   void setLowerBound(PrefixKind K) { Kind = K; }
 
   PrefixKind determineOptimalKind() {
     switch (Kind) {
     case None:
-      Kind = (W | R | X | B) ? REX : None;
+      // Not M bit here by intention b/c
+      // 1. No guarantee that REX2 is supported by arch w/o explict EGPR
+      // 2. REX2 is longer than 0FH
+      Kind = (R2 | X2 | B2) ? REX2 : (W | R | X | B) ? REX : None;
       break;
     case REX:
+      Kind = (R2 | X2 | B2) ? REX2 : REX;
+    case REX2:
     case XOP:
     case VEX3:
     case EVEX:
@@ -217,6 +271,12 @@ class X86OpcodePrefixHelper {
     case REX:
       emitByte(0x40 | W << 3 | R << 2 | X << 1 | B, CB);
       return;
+    case REX2:
+      emitByte(0xD5, CB);
+      emitByte(M << 7 | R2 << 6 | X2 << 5 | B2 << 4 | W << 3 | R << 2 | X << 1 |
+                   B,
+               CB);
+      return;
     case VEX2:
       emitByte(0xC5, CB);
       emitByte(((~R) & 1) << 7 | LastPayload, CB);
@@ -230,8 +290,9 @@ class X86OpcodePrefixHelper {
     case EVEX:
       assert(VEX_5M && !(VEX_5M & 0x8) && "invalid mmm fields for EVEX!");
       emitByte(0x62, CB);
-      emitByte(FirstPayload | ((~EVEX_R2) & 0x1) << 4 | VEX_5M, CB);
-      emitByte(W << 7 | ((~VEX_4V) & 0xf) << 3 | 1 << 2 | VEX_PP, CB);
+      emitByte(FirstPayload | ((~R2) & 0x1) << 4 | B2 << 3 | VEX_5M, CB);
+      emitByte(W << 7 | ((~VEX_4V) & 0xf) << 3 | ((~X2) & 0x1) << 2 | VEX_PP,
+               CB);
       emitByte(EVEX_z << 7 | EVEX_L2 << 6 | VEX_L << 5 | EVEX_b << 4 |
                    ((~EVEX_V2) & 0x1) << 3 | EVEX_aaa,
                CB);
@@ -548,7 +609,7 @@ void X86MCCodeEmitter::emitMemModRMByte(
         // movq loads is a subset of reloc_riprel_4byte_relax_rex. It is a
         // special case because COFF and Mach-O don't support ELF's more
         // flexible R_X86_64_REX_GOTPCRELX relaxation.
-        assert(Kind == REX);
+        assert(Kind == REX || Kind == REX2);
         return X86::reloc_riprel_4byte_movq_load;
       case X86::ADC32rm:
       case X86::ADD32rm:
@@ -572,8 +633,11 @@ void X86MCCodeEmitter::emitMemModRMByte(
       case X86::SBB64rm:
       case X86::SUB64rm:
       case X86::XOR64rm:
-        return Kind == REX ? X86::reloc_riprel_4byte_relax_rex
-                           : X86::reloc_riprel_4byte_relax;
+        // We haven't support relocation for REX2 prefix, so temporarily use REX relocation
+        // TODO: Support new relocation for REX2.
+        return (Kind == REX || Kind == REX2) ? X86::reloc_riprel_4byte_relax_rex
+                                             : X86::reloc_riprel_4byte_relax;
+
       }
     }();
 
@@ -683,10 +747,11 @@ void X86MCCodeEmitter::emitMemModRMByte(
       return;
     }
 
-    // If the base is not EBP/ESP/R12/R13 and there is no displacement, use
-    // simple indirect register encoding, this handles addresses like [EAX].
-    // The encoding for [EBP] or[R13] with no displacement means [disp32] so we
-    // handle it by emitting a displacement of 0 later.
+    // If the base is not EBP/ESP/R12/R13/R20/R21/R28/R29 and there is no
+    // displacement, use simple indirect register encoding, this handles
+    // addresses like [EAX]. The encoding for [EBP], [R13], [R20], [R21], [R28]
+    // or [R29] with no displacement means [disp32] so we handle it by emitting
+    // a displacement of 0 later.
     if (BaseRegNo != N86::EBP) {
       if (Disp.isImm() && Disp.getImm() == 0 && AllowNoDisp) {
         emitByte(modRMByte(0, RegOpcodeField, BaseRegNo), CB);
@@ -708,8 +773,8 @@ void X86MCCodeEmitter::emitMemModRMByte(
 
     // Otherwise, if the displacement fits in a byte, encode as [REG+disp8].
     // Including a compressed disp8 for EVEX instructions that support it.
-    // This also handles the 0 displacement for [EBP] or [R13]. We can't use
-    // disp8 if the {disp32} pseudo prefix is present.
+    // This also handles the 0 displacement for [EBP], [R13], [R21] or [R29]. We
+    // can't use disp8 if the {disp32} pseudo prefix is present.
     if (Disp.isImm() && AllowDisp8) {
       int ImmOffset = 0;
       if (isDispOrCDisp8(TSFlags, Disp.getImm(), ImmOffset)) {
@@ -721,8 +786,8 @@ void X86MCCodeEmitter::emitMemModRMByte(
     }
 
     // Otherwise, emit the most general non-SIB encoding: [REG+disp32].
-    // Displacement may be 0 for [EBP] or [R13] case if {disp32} pseudo prefix
-    // prevented using disp8 above.
+    // Displacement may be 0 for [EBP], [R13], [R21], [R29] case if {disp32}
+    // pseudo prefix prevented using disp8 above.
     emitByte(modRMByte(2, RegOpcodeField, BaseRegNo), CB);
     unsigned Opcode = MI.getOpcode();
     unsigned FixupKind = Opcode == X86::MOV32rm ? X86::reloc_signed_4byte_relax
@@ -746,10 +811,10 @@ void X86MCCodeEmitter::emitMemModRMByte(
     emitByte(modRMByte(0, RegOpcodeField, 4), CB);
     ForceDisp32 = true;
   } else if (Disp.isImm() && Disp.getImm() == 0 && AllowNoDisp &&
-             // Base reg can't be EBP/RBP/R13 as that would end up with '5' as
-             // the base field, but that is the magic [*] nomenclature that
-             // indicates no base when mod=0. For these cases we'll emit a 0
-             // displacement instead.
+             // Base reg can't be EBP/RBP/R13/R21/R29 as that would end up with
+             // '5' as the base field, but that is the magic [*] nomenclature
+             // that indicates no base when mod=0. For these cases we'll emit a
+             // 0 displacement instead.
              BaseRegNo != N86::EBP) {
     // Emit no displacement ModR/M byte
     emitByte(modRMByte(0, RegOpcodeField, 4), CB);
@@ -869,6 +934,20 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
 
   assert(!(TSFlags & X86II::LOCK) && "Can't have LOCK VEX.");
 
+#ifndef NDEBUG
+  unsigned NumOps = MI.getNumOperands();
+  for (unsigned I = NumOps ? X86II::getOperandBias(Desc) : 0; I != NumOps;
+       ++I) {
+    const MCOperand &MO = MI.getOperand(I);
+    if (!MO.isReg())
+      continue;
+    unsigned Reg = MO.getReg();
+    if (Reg == X86::AH || Reg == X86::BH || Reg == X86::CH || Reg == X86::DH)
+      report_fatal_error(
+          "Cannot encode high byte register in VEX/EVEX-prefixed instruction");
+  }
+#endif
+
   X86OpcodePrefixHelper Prefix(*Ctx.getRegisterInfo());
   switch (TSFlags & X86II::EncodingMask) {
   default:
@@ -952,9 +1031,9 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
     llvm_unreachable("Unexpected form in emitVEXOpcodePrefix!");
   case X86II::MRMDestMem4VOp3CC: {
     //  src1(ModR/M), MemAddr, src2(VEX_4V)
-    Prefix.setR(MI, CurOp++);
-    Prefix.setB(MI, MemOperand + X86::AddrBaseReg);
-    Prefix.setX(MI, MemOperand + X86::AddrIndexReg);
+    Prefix.setRR2(MI, CurOp++);
+    Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
+    Prefix.setXX2(MI, MemOperand + X86::AddrIndexReg);
     CurOp += X86::AddrNumOperands;
     Prefix.set4V(MI, CurOp++);
     break;
@@ -969,10 +1048,9 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
     //  MemAddr, src1(VEX_4V), src2(ModR/M)
     //  MemAddr, src1(ModR/M), imm8
     //
-    Prefix.setB(MI, MemOperand + X86::AddrBaseReg);
-    Prefix.setX(MI, MemOperand + X86::AddrIndexReg);
-    if (!HasVEX_4V) // Only needed with VSIB which don't use VVVV.
-      Prefix.setV2(MI, MemOperand + X86::AddrIndexReg);
+    Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
+    Prefix.setXX2(MI, MemOperand + X86::AddrIndexReg);
+    Prefix.setV2(MI, MemOperand + X86::AddrIndexReg, HasVEX_4V);
 
     CurOp += X86::AddrNumOperands;
 
@@ -1003,10 +1081,9 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
     if (HasVEX_4V)
       Prefix.set4VV2(MI, CurOp++);
 
-    Prefix.setB(MI, MemOperand + X86::AddrBaseReg);
-    Prefix.setX(MI, MemOperand + X86::AddrIndexReg);
-    if (!HasVEX_4V) // Only needed with VSIB which don't use VVVV.
-      Prefix.setV2(MI, MemOperand + X86::AddrIndexReg);
+    Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
+    Prefix.setXX2(MI, MemOperand + X86::AddrIndexReg);
+    Prefix.setV2(MI, MemOperand + X86::AddrIndexReg, HasVEX_4V);
 
     break;
   }
@@ -1014,8 +1091,8 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
     // Instruction format for 4VOp3:
     //   src1(ModR/M), MemAddr, src3(VEX_4V)
     Prefix.setR(MI, CurOp++);
-    Prefix.setB(MI, MemOperand + X86::AddrBaseReg);
-    Prefix.setX(MI, MemOperand + X86::AddrIndexReg);
+    Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
+    Prefix.setXX2(MI, MemOperand + X86::AddrIndexReg);
     Prefix.set4V(MI, CurOp + X86::AddrNumOperands);
     break;
   }
@@ -1023,8 +1100,8 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
     //  dst(ModR/M.reg), src1(VEX_4V), src2(Imm[7:4]), src3(ModR/M),
     Prefix.setR(MI, CurOp++);
     Prefix.set4V(MI, CurOp++);
-    Prefix.setB(MI, MemOperand + X86::AddrBaseReg);
-    Prefix.setX(MI, MemOperand + X86::AddrIndexReg);
+    Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
+    Prefix.setXX2(MI, MemOperand + X86::AddrIndexReg);
     break;
   }
   case X86II::MRM0m:
@@ -1044,10 +1121,9 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
     if (HasEVEX_K)
       Prefix.setAAA(MI, CurOp++);
 
-    Prefix.setB(MI, MemOperand + X86::AddrBaseReg);
-    Prefix.setX(MI, MemOperand + X86::AddrIndexReg);
-    if (!HasVEX_4V) // Only needed with VSIB which don't use VVVV.
-      Prefix.setV2(MI, MemOperand + X86::AddrIndexReg);
+    Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
+    Prefix.setXX2(MI, MemOperand + X86::AddrIndexReg);
+    Prefix.setV2(MI, MemOperand + X86::AddrIndexReg, HasVEX_4V);
 
     break;
   }
@@ -1067,7 +1143,7 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
     if (HasVEX_4V)
       Prefix.set4VV2(MI, CurOp++);
 
-    Prefix.setB(MI, CurOp);
+    Prefix.setBB2(MI, CurOp);
     Prefix.setX(MI, CurOp, 4);
     ++CurOp;
 
@@ -1086,6 +1162,12 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
   case X86II::MRMSrcReg4VOp3: {
     // Instruction format for 4VOp3:
     //   src1(ModR/M), src2(ModR/M), src3(VEX_4V)
+    if ((TSFlags & X86II::EncodingMask) == X86II::EVEX) {
+      Prefix.setRR2(MI, CurOp++);
+      Prefix.setBB2(MI, CurOp++);
+      Prefix.set4V(MI, CurOp++);
+      break;
+    }
     Prefix.setR(MI, CurOp++);
     Prefix.setB(MI, CurOp++);
     Prefix.set4V(MI, CurOp++);
@@ -1093,12 +1175,12 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
   }
   case X86II::MRMSrcRegOp4: {
     //  dst(ModR/M.reg), src1(VEX_4V), src2(Imm[7:4]), src3(ModR/M),
-    Prefix.setR(MI, CurOp++);
+    Prefix.setRR2(MI, CurOp++);
     Prefix.set4V(MI, CurOp++);
     // Skip second register source (encoded in Imm[7:4])
     ++CurOp;
 
-    Prefix.setB(MI, CurOp);
+    Prefix.setBB2(MI, CurOp);
     Prefix.setX(MI, CurOp, 4);
     ++CurOp;
     break;
@@ -1108,7 +1190,7 @@ 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)
-    Prefix.setB(MI, CurOp);
+    Prefix.setBB2(MI, CurOp);
     Prefix.setX(MI, CurOp, 4);
     ++CurOp;
 
@@ -1146,7 +1228,7 @@ X86MCCodeEmitter::emitVEXOpcodePrefix(int MemOperand, const MCInst &MI,
     if (HasEVEX_K)
       Prefix.setAAA(MI, CurOp++);
 
-    Prefix.setB(MI, CurOp);
+    Prefix.setBB2(MI, CurOp);
     Prefix.setX(MI, CurOp, 4);
     ++CurOp;
     break;
@@ -1218,29 +1300,29 @@ PrefixKind X86MCCodeEmitter::emitREXPrefix(int MemOperand, const MCInst &MI,
   case X86II::RawFrmDstSrc:
     break;
   case X86II::AddRegFrm:
-    Prefix.setB(MI, CurOp++);
+    Prefix.setBB2(MI, CurOp++);
     break;
   case X86II::MRMSrcReg:
   case X86II::MRMSrcRegCC:
-    Prefix.setR(MI, CurOp++);
-    Prefix.setB(MI, CurOp++);
+    Prefix.setRR2(MI, CurOp++);
+    Prefix.setBB2(MI, CurOp++);
     break;
   case X86II::MRMSrcMem:
   case X86II::MRMSrcMemCC:
-    Prefix.setR(MI, CurOp++);
-    Prefix.setB(MI, MemOperand + X86::AddrBaseReg);
-    Prefix.setX(MI, MemOperand + X86::AddrIndexReg);
+    Prefix.setRR2(MI, CurOp++);
+    Prefix.setBB2(MI, MemOperand + X86::AddrBaseReg);
+    Prefix.setXX2(MI, MemOperand + X86::AddrIndexReg);
     CurOp += X86::AddrNumOperands;
     break;
   case X86II::MRMDestReg:
-    Prefix.setB(MI, CurOp++);
-    Prefix.setR(MI, CurOp++);
+    Prefix.setBB2(MI, CurOp++);
+    Prefix.setRR2(MI, CurOp++);
     break;
   case X86II::MRMDestMem:
-    Prefix.setB(MI, MemOperand + X86::AddrBaseReg);
-    Prefix.setX(MI, MemOperand + X86::AddrIndexReg);...
[truncated]

Copy link

github-actions bot commented Nov 10, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

@KanRobert KanRobert requested a review from e-kud November 10, 2023 09:16
llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp Outdated Show resolved Hide resolved
llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp Outdated Show resolved Hide resolved
llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp Outdated Show resolved Hide resolved
llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp Outdated Show resolved Hide resolved
llvm/test/MC/X86/apx/rex2-bit-att.s Show resolved Hide resolved
llvm/test/MC/X86/apx/rex2-bit-att.s Show resolved Hide resolved
Copy link
Contributor

@phoebewang phoebewang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@KanRobert KanRobert merged commit 58bb2d1 into llvm:main Nov 13, 2023
3 checks passed
zahiraam pushed a commit to zahiraam/llvm-project that referenced this pull request Nov 20, 2023
llvm#70958 adds registers R16-R31 (EGPR), this patch
1. Introduces a new instruction prefix REX2
2. Supports encoding of EGPR with REX2 for legacy instructions in MAP
0/1
3. Supports encoding of EGPR with EVEX for the existing instructions in
EVEX space

RFC:

https://discourse.llvm.org/t/rfc-design-for-apx-feature-egpr-and-ndd-support/73031/4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:X86 mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants