[llvm] [X86][MC] Support encoding/decoding for JMPABS (PR #72835)

Shengchen Kan via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 20 18:50:14 PST 2023


https://github.com/KanRobert updated https://github.com/llvm/llvm-project/pull/72835

>From 8154951e54cf4752a7791bfae09c0946399b32db Mon Sep 17 00:00:00 2001
From: Shengchen Kan <shengchen.kan at intel.com>
Date: Mon, 20 Nov 2023 16:32:09 +0800
Subject: [PATCH 1/3] [X86][MC] Support encoding/decoding for JMPABS

---
 .../Support/X86DisassemblerDecoderCommon.h     |  4 +++-
 .../X86/Disassembler/X86Disassembler.cpp       |  5 +++++
 llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h |  9 ++++++---
 .../X86/MCTargetDesc/X86MCCodeEmitter.cpp      |  2 ++
 llvm/lib/Target/X86/X86InstrControl.td         |  3 +++
 llvm/lib/Target/X86/X86InstrFormats.td         | 18 ++++++++++++++----
 llvm/lib/Target/X86/X86InstrSSE.td             |  2 +-
 llvm/test/MC/Disassembler/X86/apx/jmpabs.txt   | 10 ++++++++++
 llvm/test/MC/X86/apx/jmpabs-att.s              | 12 ++++++++++++
 llvm/test/MC/X86/apx/jmpabs-intel.s            |  8 ++++++++
 llvm/utils/TableGen/X86DisassemblerTables.cpp  |  3 +++
 llvm/utils/TableGen/X86RecognizableInstr.cpp   |  4 ++++
 llvm/utils/TableGen/X86RecognizableInstr.h     |  4 ++++
 13 files changed, 75 insertions(+), 9 deletions(-)
 create mode 100644 llvm/test/MC/Disassembler/X86/apx/jmpabs.txt
 create mode 100644 llvm/test/MC/X86/apx/jmpabs-att.s
 create mode 100644 llvm/test/MC/X86/apx/jmpabs-intel.s

diff --git a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
index 6e08fc6a0ccb650..f9089c4755444ab 100644
--- a/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
+++ b/llvm/include/llvm/Support/X86DisassemblerDecoderCommon.h
@@ -67,7 +67,8 @@ enum attributeBits {
   ATTR_EVEXK  = 0x1 << 10,
   ATTR_EVEXKZ = 0x1 << 11,
   ATTR_EVEXB  = 0x1 << 12,
-  ATTR_max    = 0x1 << 13,
+  ATTR_REX2   = 0x1 << 13,
+  ATTR_max    = 0x1 << 14,
 };
 
 // Combinations of the above attributes that are relevant to instruction
@@ -118,6 +119,7 @@ enum attributeBits {
   ENUM_ENTRY(IC_64BIT_REXW_OPSIZE,  8,  "The Dynamic Duo!  Prefer over all "   \
                                         "else because this changes most "      \
                                         "operands' meaning")                   \
+  ENUM_ENTRY(IC_64BIT_REX2,         2,  "requires a REX2 prefix")              \
   ENUM_ENTRY(IC_VEX,                1,  "requires a VEX prefix")               \
   ENUM_ENTRY(IC_VEX_XS,             2,  "requires VEX and the XS prefix")      \
   ENUM_ENTRY(IC_VEX_XD,             2,  "requires VEX and the XD prefix")      \
diff --git a/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp b/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
index f738746ecd779bf..3e42499fe6be340 100644
--- a/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
+++ b/llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
@@ -1257,6 +1257,11 @@ static int getInstructionID(struct InternalInstruction *insn,
     attrMask &= ~ATTR_ADSIZE;
   }
 
+  // Absolute jump need special handling
+  if (insn->rex2ExtensionPrefix[0] == 0xd5 && insn->opcodeType == ONEBYTE &&
+      insn->opcode == 0xA1)
+    attrMask |= ATTR_REX2;
+
   if (insn->mode == MODE_16BIT) {
     // JCXZ/JECXZ need special handling for 16-bit mode because the meaning
     // of the AdSize prefix is inverted w.r.t. 32-bit mode.
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
index 4c57009e3bc08bf..f6ae7c6fa715d77 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
@@ -966,9 +966,12 @@ namespace X86II {
     NoTrackShift = EVEX_RCShift + 1,
     NOTRACK = 1ULL << NoTrackShift,
 
-    // Force VEX encoding
-    ExplicitVEXShift = NoTrackShift + 1,
-    ExplicitVEXPrefix = 1ULL << ExplicitVEXShift
+    // Force REX2/VEX/EVEX encoding
+    ExplicitOpPrefixShift = NoTrackShift + 1,
+    ExplicitREX2Prefix = 1ULL << ExplicitOpPrefixShift,
+    ExplicitVEXPrefix = 2ULL << ExplicitOpPrefixShift,
+    ExplicitEVEXPrefix = 3ULL << ExplicitOpPrefixShift,
+    ExplicitOpPrefix = 3ULL << ExplicitOpPrefixShift
   };
 
   /// \returns true if the instruction with given opcode is a prefix.
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index c17e7e183423804..05e33171956fb7a 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -1305,6 +1305,8 @@ PrefixKind X86MCCodeEmitter::emitREXPrefix(int MemOperand, const MCInst &MI,
       }
     }
   }
+  if (TSFlags & X86II::ExplicitREX2Prefix)
+    Prefix.setLowerBound(REX2);
   switch (TSFlags & X86II::FormMask) {
   default:
     assert(!HasRegOp && "Unexpected form in emitREXPrefix!");
diff --git a/llvm/lib/Target/X86/X86InstrControl.td b/llvm/lib/Target/X86/X86InstrControl.td
index fd996603476d780..f086191767f5fa1 100644
--- a/llvm/lib/Target/X86/X86InstrControl.td
+++ b/llvm/lib/Target/X86/X86InstrControl.td
@@ -188,6 +188,9 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in {
   }
 }
 
+def JMPABS : Ii64<0xA1, RawFrm, (outs), (ins i64imm:$dst), "jmpabs\t$dst", []>,
+             ExplicitREX2Prefix, Requires<[In64BitMode]>, Sched<[WriteJumpLd]>;
+
 // Loop instructions
 let isBranch = 1, isTerminator = 1, SchedRW = [WriteJump] in {
 def LOOP   : Ii8PCRel<0xE2, RawFrm, (outs), (ins brtarget8:$dst), "loop\t$dst", []>;
diff --git a/llvm/lib/Target/X86/X86InstrFormats.td b/llvm/lib/Target/X86/X86InstrFormats.td
index 70ffd4175e1f145..adb6aa12a0628dc 100644
--- a/llvm/lib/Target/X86/X86InstrFormats.td
+++ b/llvm/lib/Target/X86/X86InstrFormats.td
@@ -271,8 +271,17 @@ class EVEX2VEXOverride<string VEXInstrName> {
 // Prevent EVEX->VEX conversion from considering this instruction.
 class NotEVEX2VEXConvertible { bit notEVEX2VEXConvertible = 1; }
 
-// Force the instruction to use VEX encoding.
-class ExplicitVEXPrefix { bit ExplicitVEXPrefix = 1; }
+// Force the instruction to use REX2/VEX/EVEX encoding.
+class ExplicitOpPrefix<bits<2> val> {
+  bits<2> Value = val;
+}
+def NoExplicitOpPrefix : ExplicitOpPrefix<0>;
+def ExplicitREX2       : ExplicitOpPrefix<1>;
+def ExplicitVEX        : ExplicitOpPrefix<2>;
+def ExplicitEVEX       : ExplicitOpPrefix<3>;
+class ExplicitREX2Prefix { ExplicitOpPrefix explicitOpPrefix = ExplicitREX2; }
+class ExplicitVEXPrefix { ExplicitOpPrefix explicitOpPrefix = ExplicitVEX; }
+class ExplicitEVEXPrefix { ExplicitOpPrefix explicitOpPrefix = ExplicitEVEX; }
 
 class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
               string AsmStr, Domain d = GenericDomain>
@@ -354,7 +363,8 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
   string EVEX2VEXOverride = ?;
 
   bit notEVEX2VEXConvertible = 0; // Prevent EVEX->VEX conversion.
-  bit ExplicitVEXPrefix = 0; // Force the instruction to use VEX encoding.
+  ExplicitOpPrefix explicitOpPrefix = NoExplicitOpPrefix;
+  bits<2> explicitOpPrefixBits = explicitOpPrefix.Value;
   // Force to check predicate before compress EVEX to VEX encoding.
   bit checkVEXPredicate = 0;
   // TSFlags layout should be kept in sync with X86BaseInfo.h.
@@ -381,7 +391,7 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
   let TSFlags{47-45} = !if(!eq(CD8_Scale, 0), 0, !add(!logtwo(CD8_Scale), 1));
   let TSFlags{48}    = hasEVEX_RC;
   let TSFlags{49}    = hasNoTrackPrefix;
-  let TSFlags{50}    = ExplicitVEXPrefix;
+  let TSFlags{51-50} = explicitOpPrefixBits;
 }
 
 class PseudoI<dag oops, dag iops, list<dag> pattern>
diff --git a/llvm/lib/Target/X86/X86InstrSSE.td b/llvm/lib/Target/X86/X86InstrSSE.td
index 2ba1436946a286a..add24a061765014 100644
--- a/llvm/lib/Target/X86/X86InstrSSE.td
+++ b/llvm/lib/Target/X86/X86InstrSSE.td
@@ -7316,7 +7316,7 @@ defm VMASKMOVPD : avx_movmask_rm<0x2D, 0x2F, "vmaskmovpd",
 // AVX_VNNI
 //===----------------------------------------------------------------------===//
 let Predicates = [HasAVXVNNI, NoVLX_Or_NoVNNI], Constraints = "$src1 = $dst",
-    ExplicitVEXPrefix = 1, checkVEXPredicate = 1 in
+    explicitOpPrefix = ExplicitVEX, checkVEXPredicate = 1 in
 multiclass avx_vnni_rm<bits<8> opc, string OpcodeStr, SDNode OpNode,
                        bit IsCommutable> {
   let isCommutable = IsCommutable in
diff --git a/llvm/test/MC/Disassembler/X86/apx/jmpabs.txt b/llvm/test/MC/Disassembler/X86/apx/jmpabs.txt
new file mode 100644
index 000000000000000..a79dc6d5590a0eb
--- /dev/null
+++ b/llvm/test/MC/Disassembler/X86/apx/jmpabs.txt
@@ -0,0 +1,10 @@
+# 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:   jmpabs	$1
+# INTEL: jmpabs	1
+0xd5,0x00,0xa1,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+
+# ATT:   jmpabs	$72623859790382856
+# INTEL: jmpabs	72623859790382856
+0xd5,0x00,0xa1,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01
diff --git a/llvm/test/MC/X86/apx/jmpabs-att.s b/llvm/test/MC/X86/apx/jmpabs-att.s
new file mode 100644
index 000000000000000..5ce832e45857700
--- /dev/null
+++ b/llvm/test/MC/X86/apx/jmpabs-att.s
@@ -0,0 +1,12 @@
+# RUN: llvm-mc -triple x86_64 -show-encoding %s | FileCheck %s
+# RUN: not llvm-mc -triple i386 -show-encoding %s 2>&1 | FileCheck %s --check-prefix=ERROR
+
+# ERROR-COUNT-2: error:
+# ERROR-NOT: error:
+
+# CHECK: jmpabs	$1
+# CHECK: encoding: [0xd5,0x00,0xa1,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+         jmpabs	$1
+# CHECK: jmpabs	$72623859790382856
+# CHECK: encoding: [0xd5,0x00,0xa1,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01]
+         jmpabs	$72623859790382856
diff --git a/llvm/test/MC/X86/apx/jmpabs-intel.s b/llvm/test/MC/X86/apx/jmpabs-intel.s
new file mode 100644
index 000000000000000..c2b5815218a1356
--- /dev/null
+++ b/llvm/test/MC/X86/apx/jmpabs-intel.s
@@ -0,0 +1,8 @@
+# RUN: llvm-mc -triple x86_64 -show-encoding -x86-asm-syntax=intel -output-asm-variant=1 %s | FileCheck %s
+
+# CHECK: jmpabs	1
+# CHECK: encoding: [0xd5,0x00,0xa1,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+         jmpabs	1
+# CHECK: jmpabs	72623859790382856
+# CHECK: encoding: [0xd5,0x00,0xa1,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01]
+         jmpabs	72623859790382856
diff --git a/llvm/utils/TableGen/X86DisassemblerTables.cpp b/llvm/utils/TableGen/X86DisassemblerTables.cpp
index ba51bf4858e19de..e8dffaa29c2e041 100644
--- a/llvm/utils/TableGen/X86DisassemblerTables.cpp
+++ b/llvm/utils/TableGen/X86DisassemblerTables.cpp
@@ -142,6 +142,7 @@ static inline bool inheritsFrom(InstructionContext child,
   case IC_64BIT_REXW_XS:
   case IC_64BIT_REXW_OPSIZE:
   case IC_64BIT_REXW_ADSIZE:
+  case IC_64BIT_REX2:
     return false;
   case IC_VEX:
     return (VEX_LIG && WIG && inheritsFrom(child, IC_VEX_L_W)) ||
@@ -908,6 +909,8 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
           o << "_B";
       }
     }
+    else if ((index & ATTR_64BIT) && (index & ATTR_REX2))
+      o << "IC_64BIT_REX2";
     else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XS))
       o << "IC_64BIT_REXW_XS";
     else if ((index & ATTR_64BIT) && (index & ATTR_REXW) && (index & ATTR_XD))
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index 962da623b1cadc7..bcfe7a749c09533 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -129,6 +129,8 @@ RecognizableInstrBase::RecognizableInstrBase(const CodeGenInstruction &insn) {
   ForceDisassemble = Rec->getValueAsBit("ForceDisassemble");
   CD8_Scale = byteFromRec(Rec, "CD8_Scale");
   HasVEX_L = Rec->getValueAsBit("hasVEX_L");
+  ExplicitREX2Prefix =
+      byteFromRec(Rec, "explicitOpPrefixBits") == X86Local::ExplicitREX2;
 
   EncodeRC = HasEVEX_B &&
              (Form == X86Local::MRMDestReg || Form == X86Local::MRMSrcReg);
@@ -340,6 +342,8 @@ InstructionContext RecognizableInstr::insnContext() const {
       insnContext = IC_64BIT_XD;
     else if (OpPrefix == X86Local::XS)
       insnContext = IC_64BIT_XS;
+    else if (ExplicitREX2Prefix)
+      insnContext = IC_64BIT_REX2;
     else if (HasREX_W)
       insnContext = IC_64BIT_REXW;
     else
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.h b/llvm/utils/TableGen/X86RecognizableInstr.h
index 38bca87bfe614c3..d258ed21f46ab60 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.h
+++ b/llvm/utils/TableGen/X86RecognizableInstr.h
@@ -155,6 +155,8 @@ namespace X86Local {
   enum {
     AdSize16 = 1, AdSize32 = 2, AdSize64 = 3
   };
+
+  enum { ExplicitREX2 = 1 };
 }
 
 namespace X86Disassembler {
@@ -206,6 +208,8 @@ struct RecognizableInstrBase {
   bool ForceDisassemble;
   // The CD8_Scale field from the record
   uint8_t CD8_Scale;
+  /// If explicitOpPrefix field from the record equals ExplicitREX2
+  bool ExplicitREX2Prefix;
   /// \param insn The CodeGenInstruction to extract information from.
   RecognizableInstrBase(const CodeGenInstruction &insn);
   /// \returns true if this instruction should be emitted

>From b20db2f512666786375181ecad6927c540aec58d Mon Sep 17 00:00:00 2001
From: Shengchen Kan <shengchen.kan at intel.com>
Date: Tue, 21 Nov 2023 10:17:49 +0800
Subject: [PATCH 2/3] Address reivew comments: rename instructions and use mask

---
 llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h        | 2 +-
 llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp | 2 +-
 llvm/lib/Target/X86/X86InstrControl.td                | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
index f6ae7c6fa715d77..7ab215d99fc5379 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
@@ -971,7 +971,7 @@ namespace X86II {
     ExplicitREX2Prefix = 1ULL << ExplicitOpPrefixShift,
     ExplicitVEXPrefix = 2ULL << ExplicitOpPrefixShift,
     ExplicitEVEXPrefix = 3ULL << ExplicitOpPrefixShift,
-    ExplicitOpPrefix = 3ULL << ExplicitOpPrefixShift
+    ExplicitOpPrefixMask = 3ULL << ExplicitOpPrefixShift
   };
 
   /// \returns true if the instruction with given opcode is a prefix.
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index 05e33171956fb7a..f0fdd593a7fd275 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -1305,7 +1305,7 @@ PrefixKind X86MCCodeEmitter::emitREXPrefix(int MemOperand, const MCInst &MI,
       }
     }
   }
-  if (TSFlags & X86II::ExplicitREX2Prefix)
+  if ((TSFlags & X86II::ExplicitOpPrefixMask) == X86II::ExplicitREX2Prefix)
     Prefix.setLowerBound(REX2);
   switch (TSFlags & X86II::FormMask) {
   default:
diff --git a/llvm/lib/Target/X86/X86InstrControl.td b/llvm/lib/Target/X86/X86InstrControl.td
index f086191767f5fa1..5171c2249dee980 100644
--- a/llvm/lib/Target/X86/X86InstrControl.td
+++ b/llvm/lib/Target/X86/X86InstrControl.td
@@ -188,8 +188,8 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in {
   }
 }
 
-def JMPABS : Ii64<0xA1, RawFrm, (outs), (ins i64imm:$dst), "jmpabs\t$dst", []>,
-             ExplicitREX2Prefix, Requires<[In64BitMode]>, Sched<[WriteJumpLd]>;
+def JMPABS64i : Ii64<0xA1, RawFrm, (outs), (ins i64imm:$dst), "jmpabs\t$dst", []>,
+                ExplicitREX2Prefix, Requires<[In64BitMode]>, Sched<[WriteJumpLd]>;
 
 // Loop instructions
 let isBranch = 1, isTerminator = 1, SchedRW = [WriteJump] in {

>From 7d9dca7417134fea47c44a90c021bbfbbfd36f04 Mon Sep 17 00:00:00 2001
From: Shengchen Kan <shengchen.kan at intel.com>
Date: Tue, 21 Nov 2023 10:49:40 +0800
Subject: [PATCH 3/3] add comments

---
 llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index 19b4ea474f5284b..008075163b90a8d 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -3974,7 +3974,6 @@ unsigned X86AsmParser::checkTargetMatchPredicate(MCInst &Inst) {
       (MCID.TSFlags & X86II::EncodingMask) != X86II::VEX)
     return Match_Unsupported;
 
-  // These instructions are only available with {vex}, {vex2} or {vex3} prefix
   if (MCID.TSFlags & X86II::ExplicitVEXPrefix &&
       (ForcedVEXEncoding != VEXEncoding_VEX &&
        ForcedVEXEncoding != VEXEncoding_VEX2 &&



More information about the llvm-commits mailing list