[llvm] 7f8c43a - [X86][GISel] Fix crash on bitcasting i16 <-> half with gisel enabled. (#168456)

via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 25 06:31:32 PST 2025


Author: GrumpyPigSkin
Date: 2025-11-25T14:31:27Z
New Revision: 7f8c43a24949e2aa33e5f03f75ac865bb2f11ad8

URL: https://github.com/llvm/llvm-project/commit/7f8c43a24949e2aa33e5f03f75ac865bb2f11ad8
DIFF: https://github.com/llvm/llvm-project/commit/7f8c43a24949e2aa33e5f03f75ac865bb2f11ad8.diff

LOG: [X86][GISel] Fix crash on bitcasting i16 <-> half with gisel enabled. (#168456)

Added missing checks for casting half to/from i16 with global-isel
enabled.


Fixes #166557

Added: 
    llvm/test/CodeGen/X86/GlobalISel/fp-bitcast.ll

Modified: 
    llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
    llvm/lib/Target/X86/X86InstrInfo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp b/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
index 53ec7125a6490..f499e6f9d0799 100644
--- a/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
+++ b/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
@@ -312,6 +312,53 @@ bool X86InstructionSelector::selectCopy(MachineInstr &I,
       }
     }
 
+    // Special case GPR16 -> XMM
+    if (SrcSize == 16 && SrcRegBank.getID() == X86::GPRRegBankID &&
+        (DstRegBank.getID() == X86::VECRRegBankID)) {
+
+      const DebugLoc &DL = I.getDebugLoc();
+
+      // Any extend GPR16 -> GPR32
+      Register ExtReg = MRI.createVirtualRegister(&X86::GR32RegClass);
+      BuildMI(*I.getParent(), I, DL, TII.get(TargetOpcode::SUBREG_TO_REG),
+              ExtReg)
+          .addImm(0)
+          .addReg(SrcReg)
+          .addImm(X86::sub_16bit);
+
+      // Copy GR32 -> XMM
+      BuildMI(*I.getParent(), I, DL, TII.get(TargetOpcode::COPY), DstReg)
+          .addReg(ExtReg);
+
+      I.eraseFromParent();
+    }
+
+    // Special case XMM -> GR16
+    if (DstSize == 16 && DstRegBank.getID() == X86::GPRRegBankID &&
+        (SrcRegBank.getID() == X86::VECRRegBankID)) {
+
+      const DebugLoc &DL = I.getDebugLoc();
+
+      // Move XMM to GR32 register.
+      Register Temp32 = MRI.createVirtualRegister(&X86::GR32RegClass);
+      BuildMI(*I.getParent(), I, DL, TII.get(TargetOpcode::COPY), Temp32)
+          .addReg(SrcReg);
+
+      // Extract the lower 16 bits
+      if (Register Dst32 = TRI.getMatchingSuperReg(DstReg, X86::sub_16bit,
+                                                   &X86::GR32RegClass)) {
+        // Optimization for Physical Dst (e.g. AX): Copy to EAX directly.
+        BuildMI(*I.getParent(), I, DL, TII.get(TargetOpcode::COPY), Dst32)
+            .addReg(Temp32);
+      } else {
+        // Handle if there is no super.
+        BuildMI(*I.getParent(), I, DL, TII.get(TargetOpcode::COPY), DstReg)
+            .addReg(Temp32, 0, X86::sub_16bit);
+      }
+
+      I.eraseFromParent();
+    }
+
     return true;
   }
 

diff  --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index b988ae0aca912..ebed733314c6a 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -4296,10 +4296,11 @@ static unsigned CopyToFromAsymmetricReg(Register DestReg, Register SrcReg,
 
   if (X86::VR128XRegClass.contains(DestReg) &&
       X86::GR32RegClass.contains(SrcReg))
-    // Copy from a VR128 register to a VR128 register.
+    // Copy from a GR32 register to a VR128 register.
     return HasAVX512 ? X86::VMOVDI2PDIZrr
            : HasAVX  ? X86::VMOVDI2PDIrr
                      : X86::MOVDI2PDIrr;
+
   return 0;
 }
 
@@ -4368,6 +4369,7 @@ void X86InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
   else if (X86::VK16RegClass.contains(DestReg, SrcReg))
     Opc = Subtarget.hasBWI() ? (HasEGPR ? X86::KMOVQkk_EVEX : X86::KMOVQkk)
                              : (HasEGPR ? X86::KMOVQkk_EVEX : X86::KMOVWkk);
+
   if (!Opc)
     Opc = CopyToFromAsymmetricReg(DestReg, SrcReg, Subtarget);
 

diff  --git a/llvm/test/CodeGen/X86/GlobalISel/fp-bitcast.ll b/llvm/test/CodeGen/X86/GlobalISel/fp-bitcast.ll
new file mode 100644
index 0000000000000..dad33cac66dc7
--- /dev/null
+++ b/llvm/test/CodeGen/X86/GlobalISel/fp-bitcast.ll
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -global-isel | FileCheck %s --check-prefixes=SSE2
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -global-isel -mattr=+avx | FileCheck %s --check-prefixes=AVX
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -global-isel -mattr=+avx512f | FileCheck %s --check-prefixes=AVX512
+
+define half @test_i16_to_half(i16 %0) {
+; SSE2-LABEL: test_i16_to_half:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movd %edi, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: test_i16_to_half:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vmovd %edi, %xmm0
+; AVX-NEXT:    retq
+;
+; AVX512-LABEL: test_i16_to_half:
+; AVX512:       # %bb.0: # %entry
+; AVX512-NEXT:    vmovd %edi, %xmm0
+; AVX512-NEXT:    retq
+entry:
+  %2 = bitcast i16 %0 to half
+  ret half %2
+}
+
+define i16 @test_half_to_i16(half %0) {
+; SSE2-LABEL: test_half_to_i16:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movd %xmm0, %eax
+; SSE2-NEXT:    # kill: def $eax killed $eax def $ax
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: test_half_to_i16:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vmovd %xmm0, %eax
+; AVX-NEXT:    # kill: def $eax killed $eax def $ax
+; AVX-NEXT:    retq
+;
+; AVX512-LABEL: test_half_to_i16:
+; AVX512:       # %bb.0: # %entry
+; AVX512-NEXT:    vmovd %xmm0, %eax
+; AVX512-NEXT:    # kill: def $eax killed $eax def $ax
+; AVX512-NEXT:    retq
+entry:
+  %2 = bitcast half %0 to i16
+  ret i16 %2
+}


        


More information about the llvm-commits mailing list