[llvm] [X86][GlobalISel] Narrow i64 G_PHI on 32-bit targets (PR #225264)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 21 19:04:15 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: Demetrios Chiuratto Agourakis (agourakis82)

<details>
<summary>Changes</summary>

### Summary
On i386 GlobalISel, a multi-block `i64` PHI aborted selection with:

```
cannot select: G_UNMERGE_VALUES %s64
```

`G_PHI` was marked legal for `s64` even on 32-bit. IRTranslator produced an `s64` PHI plus a trailing `G_UNMERGE_VALUES`, and the selector cannot perform scalar EXTRACT/INSERT subreg lowering for an `s64` GPR on i386.

### Fix
Split `G_PHI` out of the `G_IMPLICIT_DEF`/`G_FREEZE` legality set and only allow `s64` PHIs on 64-bit targets. The legalizer then narrows them to a pair of `s32` PHIs.

### Test plan
- New: `llvm/test/CodeGen/X86/GlobalISel/phi-i64-i686.ll`
  - diamond `i64` PHI
  - loop-carried `i64` PHI with `or`/`xor`

Fixes #<!-- -->216648

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


2 Files Affected:

- (modified) llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp (+25-2) 
- (added) llvm/test/CodeGen/X86/GlobalISel/phi-i64-i686.ll (+42) 


``````````diff
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index 78ab184af6c19..27cec7ef3a43e 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
@@ -91,8 +91,10 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
   // 32/64-bits needs support for s64/s128 to handle cases:
   // s64 = EXTEND (G_IMPLICIT_DEF s32) -> s64 = G_IMPLICIT_DEF
   // s128 = EXTEND (G_IMPLICIT_DEF s32/s64) -> s128 = G_IMPLICIT_DEF
-  getActionDefinitionsBuilder(
-      {G_IMPLICIT_DEF, G_PHI, G_FREEZE, G_CONSTANT_FOLD_BARRIER})
+  // Keep G_IMPLICIT_DEF/G_FREEZE able to materialize s64 even on i386, but do
+  // not treat multi-block G_PHI of s64 as legal there: the selector cannot
+  // EXTRACT/INSERT scalar subregs of an s64 GPR on 32-bit (#216648).
+  getActionDefinitionsBuilder({G_IMPLICIT_DEF, G_FREEZE, G_CONSTANT_FOLD_BARRIER})
       .legalFor({p0, s1, s8, s16, s32, s64})
       .legalFor(UseX87, {s80})
       .legalFor(Is64Bit, {s128})
@@ -111,6 +113,27 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
                                    : s32MaxVector.getNumElements())
       .scalarizeIf(scalarOrEltWiderThan(0, 64), 0);
 
+  // On i386, keep s64 out of G_PHI: narrow to a pair of s32 PHIs instead of
+  // leaving an s64 value that later fails G_UNMERGE/G_EXTRACT selection.
+  getActionDefinitionsBuilder(G_PHI)
+      .legalFor({p0, s1, s8, s16, s32})
+      .legalFor(Is64Bit, {s64, s128})
+      .legalFor(UseX87, {s80})
+      .legalFor(HasSSE2, {v16s8, v8s16, v4s32, v2s64})
+      .legalFor(HasAVX, {v32s8, v16s16, v8s32, v4s64})
+      .legalFor(HasAVX512, {v64s8, v32s16, v16s32, v8s64})
+      .widenScalarOrEltToNextPow2(0, /*Min=*/8)
+      .clampScalarOrElt(0, s8, sMaxScalar)
+      .moreElementsToNextPow2(0)
+      .clampNumElements(0, v16s8, s8MaxVector)
+      .clampNumElements(0, v8s16, s16MaxVector)
+      .clampNumElements(0, v4s32, s32MaxVector)
+      .clampNumElements(0, v2s64, s64MaxVector)
+      .clampMaxNumElements(0, p0,
+                           Is64Bit ? s64MaxVector.getNumElements()
+                                   : s32MaxVector.getNumElements())
+      .scalarizeIf(scalarOrEltWiderThan(0, 64), 0);
+
   getActionDefinitionsBuilder(G_CONSTANT)
       .legalFor({p0, s8, s16, s32})
       .legalFor(Is64Bit, {s64})
diff --git a/llvm/test/CodeGen/X86/GlobalISel/phi-i64-i686.ll b/llvm/test/CodeGen/X86/GlobalISel/phi-i64-i686.ll
new file mode 100644
index 0000000000000..4b6b3b2998e49
--- /dev/null
+++ b/llvm/test/CodeGen/X86/GlobalISel/phi-i64-i686.ll
@@ -0,0 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=i686-unknown-linux-gnu -global-isel -O0 < %s | FileCheck %s
+
+; Multi-block i64 PHI must be narrowed to a pair of i32 PHIs on i386 GlobalISel.
+; Previously this failed selection of G_UNMERGE_VALUES from an s64 GPR (#216648).
+
+define i64 @plain_phi_i64(i64 %x, i64 %y, i1 %c) {
+; CHECK-LABEL: plain_phi_i64:
+; CHECK:       # %bb.1:
+; CHECK:         testb
+; CHECK:       # %bb.4:
+; CHECK:         movl
+; CHECK:         movl
+; CHECK:         retl
+entry:
+  br i1 %c, label %a, label %b
+a:
+  br label %tail
+b:
+  br label %tail
+tail:
+  %r = phi i64 [ %x, %a ], [ %y, %b ]
+  ret i64 %r
+}
+
+define i64 @or_xor_loop(i64 %x, i64 %y, i32 %n) {
+; CHECK-LABEL: or_xor_loop:
+; CHECK:       # %bb.
+; CHECK:         retl
+entry:
+  br label %loop
+loop:
+  %acc = phi i64 [ 0, %entry ], [ %next, %loop ]
+  %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
+  %o = or i64 %acc, %x
+  %next = xor i64 %o, %y
+  %i.next = add i32 %i, 1
+  %cond = icmp slt i32 %i.next, %n
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret i64 %next
+}

``````````

</details>


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


More information about the llvm-commits mailing list