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

Demetrios Chiuratto Agourakis via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 11:48:18 PDT 2026


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

>From 71cf982ec439acad1757eace6f01a6bd789cf441 Mon Sep 17 00:00:00 2001
From: Demetrios Chiuratto Agourakis <demetrios at agourakis.med.br>
Date: Tue, 22 Sep 2026 02:02:56 +0000
Subject: [PATCH 1/2] [X86][GlobalISel] Narrow i64 G_PHI on 32-bit targets

G_PHI was unconditionally legal for s64, including i386. After IRTranslator
built an s64 PHI and a trailing G_UNMERGE_VALUES, instruction selection
failed because scalar EXTRACT/INSERT subreg lowering is unimplemented for
s64 GPRs on 32-bit.

Split G_PHI from the IMPLICIT_DEF/FREEZE legality set and only allow s64
PHIs on 64-bit targets so the legalizer narrows them to a pair of s32 PHIs.

Fixes #216648
---
 .../lib/Target/X86/GISel/X86LegalizerInfo.cpp | 27 +++++++++++-
 .../CodeGen/X86/GlobalISel/phi-i64-i686.ll    | 42 +++++++++++++++++++
 2 files changed, 67 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/GlobalISel/phi-i64-i686.ll

diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index 78ab184af6c192..27cec7ef3a43e7 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 00000000000000..4b6b3b2998e495
--- /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
+}

>From 956916c78507f4b48240943f493860ee19bc680a Mon Sep 17 00:00:00 2001
From: Demetrios Chiuratto Agourakis <demetrios at agourakis.med.br>
Date: Tue, 22 Sep 2026 18:47:16 +0000
Subject: [PATCH 2/2] [X86][GlobalISel] clang-format G_PHI legality split

Assisted-by: Claude
---
 llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index 27cec7ef3a43e7..fd088fffaf22c8 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
@@ -94,7 +94,8 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
   // 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})
+  getActionDefinitionsBuilder(
+      {G_IMPLICIT_DEF, G_FREEZE, G_CONSTANT_FOLD_BARRIER})
       .legalFor({p0, s1, s8, s16, s32, s64})
       .legalFor(UseX87, {s80})
       .legalFor(Is64Bit, {s128})



More information about the llvm-commits mailing list