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

via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 17 14:51:49 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-globalisel

Author: None (GrumpyPigSkin)

<details>
<summary>Changes</summary>

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

Please let me know if there is a better place for the tests to live and if you want additional checks for other sizes as I could not find any tests for these.

@<!-- -->RKSimon please could you review :)

Fixes #<!-- -->166557

---
Full diff: https://github.com/llvm/llvm-project/pull/168456.diff


2 Files Affected:

- (modified) llvm/lib/Target/X86/X86InstrInfo.cpp (+37-3) 
- (added) llvm/test/CodeGen/X86/GlobalISel/fp-bitcast.ll (+46) 


``````````diff
diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index cb0208a4a5f32..30c2e535a9a35 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -4294,10 +4294,28 @@ 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;
+
+  // SrcReg(VR128) -> DestReg(GR16)
+  // SrcReg(GR16)  -> DestReg(VR128)
+
+  if (X86::GR16RegClass.contains(DestReg) &&
+      X86::VR128XRegClass.contains(SrcReg))
+    // Copy from a VR128 register to a GR16 register.
+    return HasAVX512 ? X86::VPEXTRWZrri
+           : HasAVX  ? X86::VPEXTRWrri
+                     : X86::PEXTRWrri;
+
+  if (X86::VR128XRegClass.contains(DestReg) &&
+      X86::GR16RegClass.contains(SrcReg))
+    // Copy from a GR16 register to a VR128 register.
+    return HasAVX512 ? X86::VPINSRWZrri
+           : HasAVX  ? X86::VPINSRWrri
+                     : X86::PINSRWrri;
+
   return 0;
 }
 
@@ -4370,8 +4388,24 @@ void X86InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
     Opc = CopyToFromAsymmetricReg(DestReg, SrcReg, Subtarget);
 
   if (Opc) {
-    BuildMI(MBB, MI, DL, get(Opc), DestReg)
-        .addReg(SrcReg, getKillRegState(KillSrc));
+    auto MIB = BuildMI(MBB, MI, DL, get(Opc), DestReg);
+    switch (Opc) {
+    case X86::VPINSRWZrri:
+    case X86::VPINSRWrri:
+    case X86::PINSRWrri:
+      MIB.addReg(DestReg, RegState::Undef)
+          .addReg(SrcReg, getKillRegState(KillSrc))
+          .addImm(0);
+      break;
+    case X86::VPEXTRWZrri:
+    case X86::VPEXTRWrri:
+    case X86::PEXTRWrri:
+      MIB.addReg(SrcReg, getKillRegState(KillSrc)).addImm(0);
+      break;
+    default:
+      MIB.addReg(SrcReg, getKillRegState(KillSrc));
+      break;
+    }
     return;
   }
 
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..1d2bd50dbc368
--- /dev/null
+++ b/llvm/test/CodeGen/X86/GlobalISel/fp-bitcast.ll
@@ -0,0 +1,46 @@
+; 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=CHECK,SSE2
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -global-isel -mattr=+avx | FileCheck %s --check-prefixes=CHECK,AVX
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -global-isel -mattr=+avx512f | FileCheck %s --check-prefixes=CHECK,AVX512
+
+define dso_local noundef half @bar(i16 %0) {
+; SSE2-LABEL: bar:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    pinsrw $0, %di, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: bar:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vpinsrw $0, %di, %xmm0, %xmm0
+; AVX-NEXT:    retq
+;
+; AVX512-LABEL: bar:
+; AVX512:       # %bb.0: # %entry
+; AVX512-NEXT:    vpinsrw $0, %di, %xmm0, %xmm0
+; AVX512-NEXT:    retq
+entry:
+  %2 = bitcast i16 %0 to half
+  ret half %2
+}
+
+define dso_local noundef i16 @test_half_to_i16(half %0) {
+; SSE2-LABEL: test_half_to_i16:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    pextrw $0, %xmm0, %ax
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: test_half_to_i16:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vpextrw $0, %xmm0, %ax
+; AVX-NEXT:    retq
+;
+; AVX512-LABEL: test_half_to_i16:
+; AVX512:       # %bb.0: # %entry
+; AVX512-NEXT:    vpextrw $0, %xmm0, %ax
+; AVX512-NEXT:    retq
+entry:
+  %2 = bitcast half %0 to i16
+  ret i16 %2
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}

``````````

</details>


https://github.com/llvm/llvm-project/pull/168456


More information about the llvm-commits mailing list