[llvm] [X86][NFC] Share isDispOrCDisp8 between the encoder and CompressEVEX (PR #222591)

via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 10 03:35:48 PDT 2026


https://github.com/nishant-sachdeva-amd updated https://github.com/llvm/llvm-project/pull/222591

>From 84ee1c187c538d93eb06e228bebad26c1a816849 Mon Sep 17 00:00:00 2001
From: nsachdev <nishant.sachdeva at amd.com>
Date: Thu, 10 Sep 2026 15:47:25 +0530
Subject: [PATCH] [X86][NFC] Share isDispOrCDisp8 between the encoder and
 CompressEVEX

The disp8 / compressed-disp8*N size rule was written twice: as a static
helper in X86MCCodeEmitter.cpp and re-inlined in the CompressEVEX size
veto (hasShorterEVEXViaCDisp8), kept in sync only by a comment. Hoist it
into X86II::isDispOrCDisp8 in X86BaseInfo.h (ImmOffset now optional) and
call it from both, so the size model cannot drift from what the encoder
emits. No functional change.
---
 .../lib/Target/X86/MCTargetDesc/X86BaseInfo.h | 28 ++++++++++++++++++
 .../X86/MCTargetDesc/X86MCCodeEmitter.cpp     | 29 ++-----------------
 llvm/lib/Target/X86/X86CompressEVEX.cpp       | 19 ++----------
 3 files changed, 32 insertions(+), 44 deletions(-)

diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
index 8ed4da0e223a1..49cd0703b8024 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h
@@ -1165,6 +1165,34 @@ inline int getMemoryOperandIdx(const MCInstrDesc &Desc) {
   return MemRefIdx + getOperandBias(Desc);
 }
 
+/// Return true if displacement \p Value fits one byte: a plain disp8, or a
+/// compressed disp8*N for a CDisp8-capable EVEX form (per \p TSFlags). On
+/// success, if \p ImmOffset is non-null it receives the offset to add to
+/// \p Value to leave just the encoded byte (see emitImmediate).
+inline bool isDispOrCDisp8(uint64_t TSFlags, int64_t Value,
+                           int *ImmOffset = nullptr) {
+  bool HasEVEX = (TSFlags & X86II::EncodingMask) == X86II::EVEX;
+
+  unsigned CD8_Scale =
+      (TSFlags & X86II::CD8_Scale_Mask) >> X86II::CD8_Scale_Shift;
+  CD8_Scale = CD8_Scale ? 1U << (CD8_Scale - 1) : 0U;
+  if (!HasEVEX || !CD8_Scale)
+    return isInt<8>(Value);
+
+  assert(isPowerOf2_32(CD8_Scale) && "Unexpected CD8 scale!");
+  if (Value & (CD8_Scale - 1)) // Unaligned offset
+    return false;
+
+  int64_t CDisp8 = Value / static_cast<int64_t>(CD8_Scale);
+  if (!isInt<8>(CDisp8))
+    return false;
+
+  // ImmOffset will be added to Value in emitImmediate leaving just CDisp8.
+  if (ImmOffset)
+    *ImmOffset = CDisp8 - Value;
+  return true;
+}
+
 /// \returns true if the register is a XMM.
 inline bool isXMMReg(MCRegister Reg) {
   static_assert(X86::XMM15 - X86::XMM0 == 15,
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index d4e24f52bb895..ab535c81dbf42 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -410,31 +410,6 @@ static void emitConstant(uint64_t Val, unsigned Size,
   }
 }
 
-/// Determine if this immediate can fit in a disp8 or a compressed disp8 for
-/// EVEX instructions. \p will be set to the value to pass to the ImmOffset
-/// parameter of emitImmediate.
-static bool isDispOrCDisp8(uint64_t TSFlags, int Value, int &ImmOffset) {
-  bool HasEVEX = (TSFlags & X86II::EncodingMask) == X86II::EVEX;
-
-  unsigned CD8_Scale =
-      (TSFlags & X86II::CD8_Scale_Mask) >> X86II::CD8_Scale_Shift;
-  CD8_Scale = CD8_Scale ? 1U << (CD8_Scale - 1) : 0U;
-  if (!HasEVEX || !CD8_Scale)
-    return isInt<8>(Value);
-
-  assert(isPowerOf2_32(CD8_Scale) && "Unexpected CD8 scale!");
-  if (Value & (CD8_Scale - 1)) // Unaligned offset
-    return false;
-
-  int CDisp8 = Value / static_cast<int>(CD8_Scale);
-  if (!isInt<8>(CDisp8))
-    return false;
-
-  // ImmOffset will be added to Value in emitImmediate leaving just CDisp8.
-  ImmOffset = CDisp8 - Value;
-  return true;
-}
-
 /// \returns the appropriate fixup kind to use for an immediate in an
 /// instruction with the specified TSFlags.
 static MCFixupKind getImmFixupKind(uint64_t TSFlags) {
@@ -813,7 +788,7 @@ void X86MCCodeEmitter::emitMemModRMByte(
     // can't use disp8 if the {disp32} pseudo prefix is present.
     if (Disp.isImm() && AllowDisp8) {
       int ImmOffset = 0;
-      if (isDispOrCDisp8(TSFlags, Disp.getImm(), ImmOffset)) {
+      if (X86II::isDispOrCDisp8(TSFlags, Disp.getImm(), &ImmOffset)) {
         emitByte(modRMByte(1, RegOpcodeField, BaseRegNo), CB);
         emitImmediate(Disp, MI.getLoc(), FK_Data_1, false, StartByte, CB,
                       Fixups, ImmOffset);
@@ -855,7 +830,7 @@ void X86MCCodeEmitter::emitMemModRMByte(
     // Emit no displacement ModR/M byte
     emitByte(modRMByte(0, RegOpcodeField, 4), CB);
   } else if (Disp.isImm() && AllowDisp8 &&
-             isDispOrCDisp8(TSFlags, Disp.getImm(), ImmOffset)) {
+             X86II::isDispOrCDisp8(TSFlags, Disp.getImm(), &ImmOffset)) {
     // Displacement fits in a byte or matches an EVEX compressed disp8, use
     // disp8 encoding. This also handles EBP/R13/R21/R29 base with 0
     // displacement unless {disp32} pseudo prefix was used.
diff --git a/llvm/lib/Target/X86/X86CompressEVEX.cpp b/llvm/lib/Target/X86/X86CompressEVEX.cpp
index ffd67381b5b2c..098932bcad819 100644
--- a/llvm/lib/Target/X86/X86CompressEVEX.cpp
+++ b/llvm/lib/Target/X86/X86CompressEVEX.cpp
@@ -124,16 +124,8 @@ static bool usesExtendedRegister(const MachineInstr &MI) {
 // a compressed disp8*N (1 byte) while the VEX/legacy twin would be forced to
 // spend a full disp32 (4 bytes). In that window the EVEX encoding is strictly
 // shorter overall, despite its 1-2 byte larger prefix, so compressing it to
-// VEX would grow code size. Mirrors isDispOrCDisp8 in X86MCCodeEmitter.cpp.
+// VEX would grow code size.
 static bool hasShorterEVEXViaCDisp8(const MachineInstr &MI) {
-  uint64_t TSFlags = MI.getDesc().TSFlags;
-  unsigned CD8_Scale =
-      (TSFlags & X86II::CD8_Scale_Mask) >> X86II::CD8_Scale_Shift;
-  CD8_Scale = CD8_Scale ? 1U << (CD8_Scale - 1) : 0U;
-  // Without a CD8 scale > 1 there is no displacement advantage over VEX.
-  if (CD8_Scale <= 1)
-    return false;
-
   int MemOpIdx = X86::getFirstAddrOperandIdx(MI);
   if (MemOpIdx < 0)
     return false;
@@ -145,14 +137,7 @@ static bool hasShorterEVEXViaCDisp8(const MachineInstr &MI) {
     return false;
 
   int64_t Val = Disp.getImm();
-  // VEX can already use a disp8 in this range, so EVEX offers no saving.
-  if (isInt<8>(Val))
-    return false;
-  // EVEX can use disp8*N only when the value is a multiple of N and the scaled
-  // value fits in a signed byte.
-  if (Val % static_cast<int64_t>(CD8_Scale) != 0)
-    return false;
-  return isInt<8>(Val / static_cast<int64_t>(CD8_Scale));
+  return X86II::isDispOrCDisp8(MI.getDesc().TSFlags, Val) && !isInt<8>(Val);
 }
 
 // Do any custom cleanup needed to finalize the conversion.



More information about the llvm-commits mailing list