[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