[llvm] [X86] Fix wrong ImmT in several instructions and add assertion (PR #185461)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 9 10:04:16 PDT 2026


https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/185461

Several instructions inherited ImmT=Imm8 from *Ii8Base/*Ii8 classes
without having an actual immediate operand. This made
X86MCCodeEmitter::emitMemModRMByte compute ImmSize=1 instead of 0:

  int ImmSize = !Disp.isImm() && X86II::hasImm(TSFlags)
                    ? X86II::getSizeOfImm(TSFlags)
                    : 0;

biasing RIP-relative displacements by one byte (e.g. foo-0x5 instead
of foo-0x4).

Affected instructions:
- VCVTHF82PH (via AVX512XDIi8Base): has memory forms, wrong relocations
- V[U]COMIS{S,D,H}Zrrb (via AVX512P{S,D}Ii8Base): reg-only, latent
- MMX_MOV{DQ2Q,Q2DQ}rr and variants (via MMXSDIi8/MMXS2SIi8): reg-only, latent

Fix by replacing the *Ii8Base/*Ii8 classes with their prefix-only
equivalents (TB, XD, XS, PD) and setting ExeDomain explicitly where
needed.

Add an assertion in encodeInstruction to catch future TSFlags/operand
ImmType mismatches: after consuming all operands in the Form-specific
switch, if `hasImm(TSFlags)` is true but `RemainingOps` is 0 and the Form
isn't one that handles immediates internally (RawFrm, AddCCFrm,
RawFrmImm8, RawFrmImm16, RawFrmMemOffs), the assertion fires. For
example, `VCOMISDZrrb` has `Form=MRMSrcReg` and `ImmT=Imm8` (from
AVX512PDIi8Base), but after consuming both XMM operands CurOp equals
NumOps, leaving RemainingOps=0 with no immediate to emit.


>From e11e8de0aeebb477d9e35575657ae14a4bb41a57 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 8 Mar 2026 23:36:06 -0700
Subject: [PATCH] [X86] Fix wrong ImmT in several instructions and add
 assertion

Several instructions inherited ImmT=Imm8 from *Ii8Base/*Ii8 classes
without having an actual immediate operand. This made
X86MCCodeEmitter::emitMemModRMByte compute ImmSize=1 instead of 0:

  int ImmSize = !Disp.isImm() && X86II::hasImm(TSFlags)
                    ? X86II::getSizeOfImm(TSFlags)
                    : 0;

biasing RIP-relative displacements by one byte (e.g. foo-0x5 instead
of foo-0x4).

Affected instructions:
- VCVTHF82PH (via AVX512XDIi8Base): has memory forms, wrong relocations
- V[U]COMIS{S,D,H}Zrrb (via AVX512P{S,D}Ii8Base): reg-only, latent
- MMX_MOV{DQ2Q,Q2DQ}rr and variants (via MMXSDIi8/MMXS2SIi8): reg-only, latent

Fix by replacing the *Ii8Base/*Ii8 classes with their prefix-only
equivalents (TB, XD, XS, PD) and setting ExeDomain explicitly where
needed.

Add an assertion in encodeInstruction to catch future TSFlags/operand
ImmType mismatches: after consuming all operands in the Form-specific
switch, if `hasImm(TSFlags)` is true but `RemainingOps` is 0 and the Form
isn't one that handles immediates internally (RawFrm, AddCCFrm,
RawFrmImm8, RawFrmImm16, RawFrmMemOffs), the assertion fires. For
example, `VCOMISDZrrb` has `Form=MRMSrcReg` and `ImmT=Imm8` (from
AVX512PDIi8Base), but after consuming both XMM operands CurOp equals
NumOps, leaving RemainingOps=0 with no immediate to emit.
---
 .../X86/MCTargetDesc/X86MCCodeEmitter.cpp     |  8 +++++
 llvm/lib/Target/X86/X86InstrAVX10.td          |  3 +-
 llvm/lib/Target/X86/X86InstrAVX512.td         | 12 +++----
 llvm/lib/Target/X86/X86InstrMMX.td            | 36 ++++++++++---------
 .../{avx10.2satcvt.s => evex-mem.s}           |  7 ++++
 5 files changed, 43 insertions(+), 23 deletions(-)
 rename llvm/test/MC/X86/Relocations/{avx10.2satcvt.s => evex-mem.s} (86%)

diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index cfe5b1094811a..f40e41af516fd 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -1999,6 +1999,14 @@ void X86MCCodeEmitter::encodeInstruction(const MCInst &MI,
 
     // Skip two trainling conditional operands encoded in EVEX prefix
     unsigned RemainingOps = NumOps - CurOp - 2 * HasTwoConditionalOps;
+    // Verify that hasImm(TSFlags) matches the presence of remaining operands.
+    // Exclude forms that emit immediates in the switch above (RawFrm and
+    // AddCCFrm may consume a PC-relative operand; RawFrmImm8/16 and
+    // RawFrmMemOffs always consume their immediates there).
+    assert((!X86II::hasImm(TSFlags) || RemainingOps || Form == X86II::RawFrm ||
+            Form == X86II::AddCCFrm || Form == X86II::RawFrmImm8 ||
+            Form == X86II::RawFrmImm16 || Form == X86II::RawFrmMemOffs) &&
+           "TSFlags indicates immediate but no operand provides it");
     while (RemainingOps) {
       emitImmediate(MI.getOperand(CurOp++), MI.getLoc(),
                     getImmFixupKind(Desc.TSFlags),
diff --git a/llvm/lib/Target/X86/X86InstrAVX10.td b/llvm/lib/Target/X86/X86InstrAVX10.td
index 6d388089cd5ca..586923cb6ef3f 100644
--- a/llvm/lib/Target/X86/X86InstrAVX10.td
+++ b/llvm/lib/Target/X86/X86InstrAVX10.td
@@ -970,9 +970,10 @@ multiclass avx10_convert_2op_nomb<string OpcodeStr, AVX512VLVectorVTInfo _dest,
   }
 }
 
+let ExeDomain = SSEPackedInt in
 defm VCVTHF82PH : avx10_convert_2op_nomb<"vcvthf82ph", avx512vl_f16_info,
                                          avx512vl_i8_info, 0x1e, X86vcvthf82ph>,
-                  AVX512XDIi8Base, T_MAP5, EVEX, EVEX_CD8<16, CD8VH>;
+                  TB, XD, T_MAP5, EVEX, EVEX_CD8<16, CD8VH>;
 
 //-------------------------------------------------
 // AVX10 BF16 instructions
diff --git a/llvm/lib/Target/X86/X86InstrAVX512.td b/llvm/lib/Target/X86/X86InstrAVX512.td
index 35e424a1879f3..aafc5cb3c7ee5 100644
--- a/llvm/lib/Target/X86/X86InstrAVX512.td
+++ b/llvm/lib/Target/X86/X86InstrAVX512.td
@@ -9097,13 +9097,13 @@ multiclass avx512_ord_cmp_sae<bits<8> opc, X86VectorVTInfo _,
 
 let Defs = [EFLAGS], Predicates = [HasAVX512] in {
   defm VUCOMISSZ : avx512_ord_cmp_sae<0x2E, v4f32x_info, "vucomiss", SSEPackedSingle>,
-                                   AVX512PSIi8Base, EVEX_CD8<32, CD8VT1>;
+                                   TB, EVEX_CD8<32, CD8VT1>;
   defm VUCOMISDZ : avx512_ord_cmp_sae<0x2E, v2f64x_info, "vucomisd", SSEPackedDouble>,
-                                   AVX512PDIi8Base, REX_W, EVEX_CD8<64, CD8VT1>;
+                                   TB, PD, REX_W, EVEX_CD8<64, CD8VT1>;
   defm VCOMISSZ : avx512_ord_cmp_sae<0x2F, v4f32x_info, "vcomiss", SSEPackedSingle>,
-                                   AVX512PSIi8Base, EVEX_CD8<32, CD8VT1>;
+                                   TB, EVEX_CD8<32, CD8VT1>;
   defm VCOMISDZ : avx512_ord_cmp_sae<0x2F, v2f64x_info, "vcomisd", SSEPackedDouble>,
-                                   AVX512PDIi8Base, REX_W, EVEX_CD8<64, CD8VT1>;
+                                   TB, PD, REX_W, EVEX_CD8<64, CD8VT1>;
 }
 
 let Defs = [EFLAGS], Predicates = [HasAVX512] in {
@@ -9138,10 +9138,10 @@ let Defs = [EFLAGS], Predicates = [HasAVX512] in {
 
 let Defs = [EFLAGS], Predicates = [HasFP16] in {
   defm VUCOMISHZ : avx512_ord_cmp_sae<0x2E, v8f16x_info, "vucomish",
-                                SSEPackedSingle>, AVX512PSIi8Base, T_MAP5,
+                                SSEPackedSingle>, TB, T_MAP5,
                                 EVEX_CD8<16, CD8VT1>;
   defm VCOMISHZ : avx512_ord_cmp_sae<0x2F, v8f16x_info, "vcomish",
-                                SSEPackedSingle>, AVX512PSIi8Base, T_MAP5,
+                                SSEPackedSingle>, TB, T_MAP5,
                                 EVEX_CD8<16, CD8VT1>;
   defm VUCOMISHZ : sse12_ord_cmp<0x2E, FR16X, X86any_fcmp, f16, f16mem, loadf16,
                                 "ucomish", SSEPackedSingle>, T_MAP5, EVEX,
diff --git a/llvm/lib/Target/X86/X86InstrMMX.td b/llvm/lib/Target/X86/X86InstrMMX.td
index 644d6d0b92dfc..49f10d036a972 100644
--- a/llvm/lib/Target/X86/X86InstrMMX.td
+++ b/llvm/lib/Target/X86/X86InstrMMX.td
@@ -230,24 +230,28 @@ def MMX_X86movq2dq : SDNode<"X86ISD::MOVQ2DQ", SDTypeProfile<1, 1,
                             [SDTCisVT<0, v2i64>, SDTCisVT<1, x86mmx>]>>;
 
 let SchedRW = [SchedWriteVecMoveLS.XMM.RR] in {
-def MMX_MOVDQ2Qrr : MMXSDIi8<0xD6, MRMSrcReg, (outs VR64:$dst),
-                             (ins VR128:$src), "movdq2q\t{$src, $dst|$dst, $src}",
-                             [(set VR64:$dst,
-                               (x86mmx (MMX_X86movdq2q VR128:$src)))]>;
-
-def MMX_MOVQ2DQrr : MMXS2SIi8<0xD6, MRMSrcReg, (outs VR128:$dst),
-                              (ins VR64:$src), "movq2dq\t{$src, $dst|$dst, $src}",
-                              [(set VR128:$dst,
-                                (v2i64 (MMX_X86movq2dq VR64:$src)))]>;
+def MMX_MOVDQ2Qrr : I<0xD6, MRMSrcReg, (outs VR64:$dst),
+                      (ins VR128:$src), "movdq2q\t{$src, $dst|$dst, $src}",
+                      [(set VR64:$dst,
+                        (x86mmx (MMX_X86movdq2q VR128:$src)))]>,
+                    TB, XD, Requires<[HasMMX, HasSSE2]>;
+
+def MMX_MOVQ2DQrr : I<0xD6, MRMSrcReg, (outs VR128:$dst),
+                       (ins VR64:$src), "movq2dq\t{$src, $dst|$dst, $src}",
+                       [(set VR128:$dst,
+                         (v2i64 (MMX_X86movq2dq VR64:$src)))]>,
+                    TB, XS, Requires<[HasMMX, HasSSE2]>;
 
 let isCodeGenOnly = 1, hasSideEffects = 1 in {
-def MMX_MOVQ2FR64rr: MMXS2SIi8<0xD6, MRMSrcReg, (outs FR64:$dst),
-                               (ins VR64:$src), "movq2dq\t{$src, $dst|$dst, $src}",
-                               []>;
-
-def MMX_MOVFR642Qrr: MMXSDIi8<0xD6, MRMSrcReg, (outs VR64:$dst),
-                              (ins FR64:$src), "movdq2q\t{$src, $dst|$dst, $src}",
-                              []>;
+def MMX_MOVQ2FR64rr: I<0xD6, MRMSrcReg, (outs FR64:$dst),
+                        (ins VR64:$src), "movq2dq\t{$src, $dst|$dst, $src}",
+                        []>,
+                     TB, XS, Requires<[HasMMX, HasSSE2]>;
+
+def MMX_MOVFR642Qrr: I<0xD6, MRMSrcReg, (outs VR64:$dst),
+                        (ins FR64:$src), "movdq2q\t{$src, $dst|$dst, $src}",
+                        []>,
+                     TB, XD, Requires<[HasMMX, HasSSE2]>;
 }
 } // SchedRW
 
diff --git a/llvm/test/MC/X86/Relocations/avx10.2satcvt.s b/llvm/test/MC/X86/Relocations/evex-mem.s
similarity index 86%
rename from llvm/test/MC/X86/Relocations/avx10.2satcvt.s
rename to llvm/test/MC/X86/Relocations/evex-mem.s
index 0ace05122d157..69730907b0e50 100644
--- a/llvm/test/MC/X86/Relocations/avx10.2satcvt.s
+++ b/llvm/test/MC/X86/Relocations/evex-mem.s
@@ -25,6 +25,10 @@
 # CHECK-NEXT:          R_X86_64_PC32   foo-0x4
 # CHECK-NEXT: 62 f5 7d 08 6a 05 00 00 00 00 vcvttps2iubs    (%rip), %xmm0
 # CHECK-NEXT:          R_X86_64_PC32   foo-0x4
+# CHECK-NEXT: 62 f5 7f 08 1e 05 00 00 00 00 vcvthf82ph      (%rip), %xmm0
+# CHECK-NEXT:          R_X86_64_PC32   foo-0x4
+# CHECK-NEXT: 62 f1 7c 08 2e 05 00 00 00 00 vucomiss        (%rip), %xmm0
+# CHECK-NEXT:          R_X86_64_PC32   foo-0x4
 
 vcvtbf162ibs foo(%rip), %xmm0
 vcvtbf162iubs foo(%rip), %xmm0
@@ -38,3 +42,6 @@ vcvttph2ibs foo(%rip), %xmm0
 vcvttph2iubs foo(%rip), %xmm0
 vcvttps2ibs foo(%rip), %xmm0
 vcvttps2iubs foo(%rip), %xmm0
+
+vcvthf82ph foo(%rip), %xmm0
+{evex} vucomiss foo(%rip), %xmm0



More information about the llvm-commits mailing list