[llvm] [GIsel] import min/max rewrites (PR #188267)
Luisa Cicolini via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 9 05:39:16 PDT 2026
https://github.com/luisacicolini updated https://github.com/llvm/llvm-project/pull/188267
>From 5209235f7b8721011452de4348e361b7e78903b5 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Tue, 24 Mar 2026 15:16:34 +0000
Subject: [PATCH 01/29] chore: smax
---
.../include/llvm/Target/GlobalISel/Combine.td | 14 ++++-
.../AArch64/GlobalISel/combine-integer.mir | 56 +++++++++++++++++++
2 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 959cd8b083d52..4c1879e82c9cf 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -2044,6 +2044,17 @@ def AMinusC1PlusC2: GICombineRule<
[{ return Helper.matchFoldAMinusC1PlusC2(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
+def SubSmaxSub: GICombineRule<
+ (defs root:$root),
+ (match (G_SUB $sub, 0, $A),
+ (G_SMAX $max, $A, $sub),
+ (G_SUB $root, 0, $max):$root,
+ [{ return MRI.hasOneNonDBGUse(${sub}.getReg())
+ && MRI.hasOneNonDBGUse(${max}.getReg()); }]),
+ (apply (G_SUB $sub1, 0, $A),
+ (G_SMIN $root, $A, $sub1))>;
+
def integer_reassoc_combines: GICombineGroup<[
APlusBMinusCMinusB,
AMinusBMinusCMinusC,
@@ -2061,7 +2072,8 @@ def integer_reassoc_combines: GICombineGroup<[
C2MinusAPlusC1,
AMinusC1MinusC2,
C1Minus2MinusC2,
- AMinusC1PlusC2
+ AMinusC1PlusC2,
+ SubSmaxSub
]>;
// fold (A+(shl (0-B), C)) -> (A-(shl B, C))
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index 1100997321a09..8afdb96a0c97a 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -7,6 +7,7 @@ name: APlusBMinusCMinusB
body: |
bb.0:
liveins: $x0, $x1, $x2
+
; CHECK-LABEL: name: APlusBMinusCMinusB
; CHECK: liveins: $x0, $x1, $x2
; CHECK-NEXT: {{ $}}
@@ -496,3 +497,58 @@ body: |
$x0 = COPY %sub2
RET_ReallyLR implicit $x0
+
+...
+---
+name: ASubMax
+body: |
+ bb.0:
+ liveins: $x0
+
+
+ ; CHECK-LABEL: name: ASubMax
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %sub2:_(s64) = G_SMIN %a, [[SUB]]
+ ; CHECK-NEXT: $x0 = COPY %sub2(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_SMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ $x0 = COPY %sub2
+ RET_ReallyLR implicit $x0
+
+...
+---
+name: ASubMaxOneUse
+body: |
+ bb.0:
+ liveins: $x0
+
+
+ ; CHECK-LABEL: name: ASubMaxOneUse
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %max:_(s64) = G_SMAX %a, %sub1
+ ; CHECK-NEXT: %sub2:_(s64) = G_SUB %zero, %max
+ ; CHECK-NEXT: %mul:_(s64) = G_MUL %max, %sub2
+ ; CHECK-NEXT: $x0 = COPY %mul(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_SMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ %mul:_(s64) = G_MUL %max, %sub2
+ $x0 = COPY %mul
+ RET_ReallyLR implicit $x0
>From 49a1378906d55b0444a75c811346e1112567b730 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Tue, 24 Mar 2026 15:31:04 +0000
Subject: [PATCH 02/29] umax conflicts with smax
---
llvm/include/llvm/Target/GlobalISel/Combine.td | 14 +++++++++++++-
.../CodeGen/AArch64/GlobalISel/combine-integer.mir | 1 +
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 4c1879e82c9cf..998828a936ef3 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -2054,6 +2054,17 @@ def SubSmaxSub: GICombineRule<
&& MRI.hasOneNonDBGUse(${max}.getReg()); }]),
(apply (G_SUB $sub1, 0, $A),
(G_SMIN $root, $A, $sub1))>;
+
+// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
+def SubUmaxSub: GICombineRule<
+ (defs root:$root),
+ (match (G_SUB $sub, 0, $A),
+ (G_UMAX $max, $A, $sub),
+ (G_SUB $root, 0, $max):$root,
+ [{ return MRI.hasOneNonDBGUse(${sub}.getReg())
+ && MRI.hasOneNonDBGUse(${max}.getReg()); }]),
+ (apply (G_SUB $sub1, 0, $A),
+ (G_UMIN $root, $A, $sub1))>;
def integer_reassoc_combines: GICombineGroup<[
APlusBMinusCMinusB,
@@ -2073,7 +2084,8 @@ def integer_reassoc_combines: GICombineGroup<[
AMinusC1MinusC2,
C1Minus2MinusC2,
AMinusC1PlusC2,
- SubSmaxSub
+ SubSmaxSub,
+ SubUmaxSub
]>;
// fold (A+(shl (0-B), C)) -> (A-(shl B, C))
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index 8afdb96a0c97a..d74c289aea4c9 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -552,3 +552,4 @@ body: |
%mul:_(s64) = G_MUL %max, %sub2
$x0 = COPY %mul
RET_ReallyLR implicit $x0
+
>From 652afe34cde3d9d21afd6f08e792109360424be8 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Thu, 9 Apr 2026 12:39:42 +0100
Subject: [PATCH 03/29] still breaks
---
llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index c63ae08456172..cdc3afc3cd7e8 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -573,7 +573,9 @@ body: |
%mul:_(s64) = G_MUL %max, %sub2
$x0 = COPY %mul
RET_ReallyLR implicit $x0
-
+
+...
+---
name: AMinusZeroMinusB_BV
body: |
bb.0:
>From aa3f57d04cc5e840457d33ddcc7308e263342e1a Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 10 Apr 2026 09:59:14 +0100
Subject: [PATCH 04/29] remove tests to figure out what is wrong
---
.../AArch64/GlobalISel/combine-integer.mir | 54 -------------------
1 file changed, 54 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index cdc3afc3cd7e8..f77ab013e20f2 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -7,7 +7,6 @@ name: APlusBMinusCMinusB
body: |
bb.0:
liveins: $x0, $x1, $x2
-
; CHECK-LABEL: name: APlusBMinusCMinusB
; CHECK: liveins: $x0, $x1, $x2
; CHECK-NEXT: {{ $}}
@@ -497,30 +496,6 @@ body: |
$x0 = COPY %sub2
RET_ReallyLR implicit $x0
-
-...
----
-name: ASubMax
-body: |
- bb.0:
- liveins: $x0
-
-
- ; CHECK-LABEL: name: ASubMax
- ; CHECK: liveins: $x0
- ; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: %a:_(s64) = COPY $x0
- ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
- ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB %zero, %a
- ; CHECK-NEXT: %sub2:_(s64) = G_SMIN %a, [[SUB]]
- ; CHECK-NEXT: $x0 = COPY %sub2(s64)
- ; CHECK-NEXT: RET_ReallyLR implicit $x0
- %a:_(s64) = COPY $x0
-
- %zero:_(s64) = G_CONSTANT i64 0
- %sub1:_(s64) = G_SUB %zero, %a
- %max:_(s64) = G_SMAX %a, %sub1
- %sub2:_(s64) = G_SUB %zero, %max
...
---
name: AMinusZeroMinusB
@@ -545,35 +520,6 @@ body: |
$x0 = COPY %sub2
RET_ReallyLR implicit $x0
-...
----
-name: ASubMaxOneUse
-body: |
- bb.0:
- liveins: $x0
-
-
- ; CHECK-LABEL: name: ASubMaxOneUse
- ; CHECK: liveins: $x0
- ; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: %a:_(s64) = COPY $x0
- ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
- ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
- ; CHECK-NEXT: %max:_(s64) = G_SMAX %a, %sub1
- ; CHECK-NEXT: %sub2:_(s64) = G_SUB %zero, %max
- ; CHECK-NEXT: %mul:_(s64) = G_MUL %max, %sub2
- ; CHECK-NEXT: $x0 = COPY %mul(s64)
- ; CHECK-NEXT: RET_ReallyLR implicit $x0
- %a:_(s64) = COPY $x0
-
- %zero:_(s64) = G_CONSTANT i64 0
- %sub1:_(s64) = G_SUB %zero, %a
- %max:_(s64) = G_SMAX %a, %sub1
- %sub2:_(s64) = G_SUB %zero, %max
- %mul:_(s64) = G_MUL %max, %sub2
- $x0 = COPY %mul
- RET_ReallyLR implicit $x0
-
...
---
name: AMinusZeroMinusB_BV
>From f9a520722652ca95d5af0bc9f23f9de66cdee1de Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 10 Apr 2026 11:29:21 +0100
Subject: [PATCH 05/29] test
---
.../llvm/CodeGen/GlobalISel/CombinerHelper.h | 3 ++
.../include/llvm/Target/GlobalISel/Combine.td | 15 ++++---
.../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 43 +++++++++++++++++++
.../AArch64/GlobalISel/combine-integer.mir | 22 ++++++++++
4 files changed, 76 insertions(+), 7 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index 365bbaacfe055..29abb162d1834 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -1021,6 +1021,9 @@ class CombinerHelper {
bool matchFoldAMinusC1PlusC2(const MachineInstr &MI,
BuildFnTy &MatchInfo) const;
+ bool matchFoldSubSmaxSub(const MachineInstr &MI,
+ BuildFnTy &MatchInfo) const;
+
bool matchExtOfExt(const MachineInstr &FirstMI, const MachineInstr &SecondMI,
BuildFnTy &MatchInfo) const;
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 9717763e30a7a..16fdc926102b7 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -2074,14 +2074,12 @@ def AMinusC1PlusC2: GICombineRule<
// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
def SubSmaxSub: GICombineRule<
- (defs root:$root),
+ (defs root:$root, build_fn_matchinfo:$matchinfo),
(match (G_SUB $sub, 0, $A),
(G_SMAX $max, $A, $sub),
(G_SUB $root, 0, $max):$root,
- [{ return MRI.hasOneNonDBGUse(${sub}.getReg())
- && MRI.hasOneNonDBGUse(${max}.getReg()); }]),
- (apply (G_SUB $sub1, 0, $A),
- (G_SMIN $root, $A, $sub1))>;
+ [{ return Helper.matchFoldSubSmaxSub(*${root}, ${matchinfo}); }]),
+ (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
def SubUmaxSub: GICombineRule<
@@ -2114,8 +2112,11 @@ def integer_reassoc_combines: GICombineGroup<[
AMinusC1MinusC2,
C1Minus2MinusC2,
AMinusC1PlusC2,
+]>;
+
+def max_min_combines: GICombineGroup<[
SubSmaxSub,
- SubUmaxSub
+ // SubUmaxSub
]>;
// fold (A+(shl (0-B), C)) -> (A-(shl B, C))
@@ -2400,7 +2401,7 @@ def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines,
sext_trunc, zext_trunc, prefer_sign_combines, shuffle_combines,
combine_use_vector_truncate, merge_combines, overflow_combines,
truncsat_combines, lshr_of_trunc_of_lshr, ctls_combines, add_shift, sub_one_from_sub,
- binop_with_neg, sub_minus_one]>;
+ binop_with_neg, sub_minus_one, max_min_combines]>;
// A combine group used to for prelegalizer combiners at -O0. The combines in
// this group have been selected based on experiments to balance code size and
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 177170575fe07..db99b972eea34 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -8374,6 +8374,49 @@ bool CombinerHelper::matchFoldAMinusC1PlusC2(const MachineInstr &MI,
return true;
}
+bool CombinerHelper::matchFoldSubSmaxSub(const MachineInstr &MI,
+ BuildFnTy &MatchInfo) const {
+ // fold (sub 0, (smax X, (sub 0, X))) --> (smin X, (sub 0, X))
+ const GSub *Sub1 = cast<GSub>(&MI);
+
+ MachineInstr *MaxMI = MRI.getVRegDef(Sub1->getRHSReg());
+ if (!MaxMI || MaxMI->getOpcode() != TargetOpcode::G_SMAX)
+ return false;
+
+ MachineInstr *Sub2MI = MRI.getVRegDef(MaxMI->getOperand(2).getReg());
+ if (!Sub2MI || Sub2MI->getOpcode() != TargetOpcode::G_SUB)
+ return false;
+
+ // Verify Sub1 LHS == 0
+ auto MaybeCst1 = getIConstantVRegValWithLookThrough(Sub1->getLHSReg(), MRI);
+ if (!MaybeCst1 || !MaybeCst1->Value.isZero())
+ return false;
+
+ // Verify Sub2 LHS == 0
+ auto MaybeCst2 = getIConstantVRegValWithLookThrough(
+ Sub2MI->getOperand(1).getReg(), MRI);
+ if (!MaybeCst2 || !MaybeCst2->Value.isZero())
+ return false;
+
+ // Verify X is the same register in both smax and the inner sub
+ Register X = MaxMI->getOperand(1).getReg();
+ if (X != Sub2MI->getOperand(2).getReg())
+ return false;
+
+ if (!MRI.hasOneNonDBGUse(Sub2MI->getOperand(0).getReg()))
+ return false;
+ if (!MRI.hasOneNonDBGUse(MaxMI->getOperand(0).getReg()))
+ return false;
+
+ Register Dst = Sub1->getReg(0);
+ Register Sub2Result = Sub2MI->getOperand(0).getReg();
+
+ MatchInfo = [=](MachineIRBuilder &B) {
+ B.buildSMin(Dst, X, Sub2Result);
+ };
+ return true;
+}
+
bool CombinerHelper::matchUnmergeValuesAnyExtBuildVector(
const MachineInstr &MI, BuildFnTy &MatchInfo) const {
const GUnmerge *Unmerge = cast<GUnmerge>(&MI);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index f77ab013e20f2..fd64e54e0773d 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -585,3 +585,25 @@ body: |
RET_ReallyLR implicit $q0
...
+---
+name: ASubMax
+body: |
+ bb.0:
+ liveins: $x0
+
+ ; CHECK-LABEL: name: ASubMax
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %sub2:_(s64) = G_SMIN %a, %sub1
+ ; CHECK-NEXT: $x0 = COPY %sub2(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_SMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ $x0 = COPY %sub2
+ RET_ReallyLR implicit $x0
>From 4be9d442df6a8ef23af037093d30aa4d7f2317df Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 10 Apr 2026 11:29:46 +0100
Subject: [PATCH 06/29] test
---
.../AArch64/GlobalISel/combine-integer.mir | 30 +++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index fd64e54e0773d..23dd6a7f3ed50 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -607,3 +607,33 @@ body: |
%sub2:_(s64) = G_SUB %zero, %max
$x0 = COPY %sub2
RET_ReallyLR implicit $x0
+
+...
+---
+name: ASubMaxOneUse
+body: |
+ bb.0:
+ liveins: $x0
+
+
+ ; CHECK-LABEL: name: ASubMaxOneUse
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %max:_(s64) = G_SMAX %a, %sub1
+ ; CHECK-NEXT: %sub2:_(s64) = G_SUB %zero, %max
+ ; CHECK-NEXT: %mul:_(s64) = G_MUL %max, %sub2
+ ; CHECK-NEXT: $x0 = COPY %mul(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_SMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ %mul:_(s64) = G_MUL %max, %sub2
+ $x0 = COPY %mul
+ RET_ReallyLR implicit $x0
+
\ No newline at end of file
>From 784f8c887ca27adb9d3d3dce84dbf94f6c029cf4 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 10 Apr 2026 11:31:00 +0100
Subject: [PATCH 07/29] wip
---
llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index 23dd6a7f3ed50..10f41853ad9c5 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -615,7 +615,6 @@ body: |
bb.0:
liveins: $x0
-
; CHECK-LABEL: name: ASubMaxOneUse
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
@@ -628,7 +627,6 @@ body: |
; CHECK-NEXT: $x0 = COPY %mul(s64)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%a:_(s64) = COPY $x0
-
%zero:_(s64) = G_CONSTANT i64 0
%sub1:_(s64) = G_SUB %zero, %a
%max:_(s64) = G_SMAX %a, %sub1
@@ -636,4 +634,4 @@ body: |
%mul:_(s64) = G_MUL %max, %sub2
$x0 = COPY %mul
RET_ReallyLR implicit $x0
-
\ No newline at end of file
+
>From b2e4a8a7b861500dc5d71fae45de3e7f9efb9f85 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 10 Apr 2026 11:31:35 +0100
Subject: [PATCH 08/29] wip
---
.../AArch64/GlobalISel/combine-integer.mir | 57 ++++++++++++++++++-
1 file changed, 54 insertions(+), 3 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index 10f41853ad9c5..91f5961160b53 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -586,12 +586,12 @@ body: |
...
---
-name: ASubMax
+name: ASubSMax
body: |
bb.0:
liveins: $x0
- ; CHECK-LABEL: name: ASubMax
+ ; CHECK-LABEL: name: ASubSMax
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %a:_(s64) = COPY $x0
@@ -610,7 +610,7 @@ body: |
...
---
-name: ASubMaxOneUse
+name: ASubSMaxOneUse
body: |
bb.0:
liveins: $x0
@@ -635,3 +635,54 @@ body: |
$x0 = COPY %mul
RET_ReallyLR implicit $x0
+...
+---
+name: ASubUMax
+body: |
+ bb.0:
+ liveins: $x0
+
+ ; CHECK-LABEL: name: ASubMax
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %sub2:_(s64) = G_SMIN %a, %sub1
+ ; CHECK-NEXT: $x0 = COPY %sub2(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_UMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ $x0 = COPY %sub2
+ RET_ReallyLR implicit $x0
+
+...
+---
+name: ASubUMaxOneUse
+body: |
+ bb.0:
+ liveins: $x0
+
+ ; CHECK-LABEL: name: ASubMaxOneUse
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %max:_(s64) = G_SMAX %a, %sub1
+ ; CHECK-NEXT: %sub2:_(s64) = G_SUB %zero, %max
+ ; CHECK-NEXT: %mul:_(s64) = G_MUL %max, %sub2
+ ; CHECK-NEXT: $x0 = COPY %mul(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_UMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ %mul:_(s64) = G_MUL %max, %sub2
+ $x0 = COPY %mul
+ RET_ReallyLR implicit $x0
+
>From 87755bdd108ea9af9c6232d5eb20ed073c332b7f Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 10 Apr 2026 11:52:57 +0100
Subject: [PATCH 09/29] no sense
---
.../include/llvm/Target/GlobalISel/Combine.td | 6 +--
.../AArch64/GlobalISel/combine-integer.mir | 37 +++----------------
2 files changed, 7 insertions(+), 36 deletions(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 16fdc926102b7..3c236c78ad6b7 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -2086,9 +2086,7 @@ def SubUmaxSub: GICombineRule<
(defs root:$root),
(match (G_SUB $sub, 0, $A),
(G_UMAX $max, $A, $sub),
- (G_SUB $root, 0, $max):$root,
- [{ return MRI.hasOneNonDBGUse(${sub}.getReg())
- && MRI.hasOneNonDBGUse(${max}.getReg()); }]),
+ (G_SUB $root, 0, $max):$root),
(apply (G_SUB $sub1, 0, $A),
(G_UMIN $root, $A, $sub1))>;
@@ -2116,7 +2114,7 @@ def integer_reassoc_combines: GICombineGroup<[
def max_min_combines: GICombineGroup<[
SubSmaxSub,
- // SubUmaxSub
+ SubUmaxSub
]>;
// fold (A+(shl (0-B), C)) -> (A-(shl B, C))
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index 91f5961160b53..8740c44ab0ec9 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -615,7 +615,7 @@ body: |
bb.0:
liveins: $x0
- ; CHECK-LABEL: name: ASubMaxOneUse
+ ; CHECK-LABEL: name: ASubSMaxOneUse
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %a:_(s64) = COPY $x0
@@ -642,13 +642,14 @@ body: |
bb.0:
liveins: $x0
- ; CHECK-LABEL: name: ASubMax
+
+ ; CHECK-LABEL: name: ASubUMax
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %a:_(s64) = COPY $x0
; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
- ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
- ; CHECK-NEXT: %sub2:_(s64) = G_SMIN %a, %sub1
+ ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %sub2:_(s64) = G_UMIN %a, [[SUB]]
; CHECK-NEXT: $x0 = COPY %sub2(s64)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%a:_(s64) = COPY $x0
@@ -658,31 +659,3 @@ body: |
%sub2:_(s64) = G_SUB %zero, %max
$x0 = COPY %sub2
RET_ReallyLR implicit $x0
-
-...
----
-name: ASubUMaxOneUse
-body: |
- bb.0:
- liveins: $x0
-
- ; CHECK-LABEL: name: ASubMaxOneUse
- ; CHECK: liveins: $x0
- ; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: %a:_(s64) = COPY $x0
- ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
- ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
- ; CHECK-NEXT: %max:_(s64) = G_SMAX %a, %sub1
- ; CHECK-NEXT: %sub2:_(s64) = G_SUB %zero, %max
- ; CHECK-NEXT: %mul:_(s64) = G_MUL %max, %sub2
- ; CHECK-NEXT: $x0 = COPY %mul(s64)
- ; CHECK-NEXT: RET_ReallyLR implicit $x0
- %a:_(s64) = COPY $x0
- %zero:_(s64) = G_CONSTANT i64 0
- %sub1:_(s64) = G_SUB %zero, %a
- %max:_(s64) = G_UMAX %a, %sub1
- %sub2:_(s64) = G_SUB %zero, %max
- %mul:_(s64) = G_MUL %max, %sub2
- $x0 = COPY %mul
- RET_ReallyLR implicit $x0
-
>From c6e602b9a042e39322f42196e841b6195d0b4e8e Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 10 Apr 2026 11:57:19 +0100
Subject: [PATCH 10/29] use;
---
.../include/llvm/Target/GlobalISel/Combine.td | 3 ++-
.../AArch64/GlobalISel/combine-integer.mir | 27 +++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 3c236c78ad6b7..336d000becd76 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -2086,7 +2086,8 @@ def SubUmaxSub: GICombineRule<
(defs root:$root),
(match (G_SUB $sub, 0, $A),
(G_UMAX $max, $A, $sub),
- (G_SUB $root, 0, $max):$root),
+ (G_SUB $root, 0, $max),
+ [{ return MRI.hasOneNonDBGUse(${sub}.getReg()) && MRI.hasOneNonDBGUse(${max}.getReg()); }]),
(apply (G_SUB $sub1, 0, $A),
(G_UMIN $root, $A, $sub1))>;
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index 8740c44ab0ec9..245633a6b3802 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -659,3 +659,30 @@ body: |
%sub2:_(s64) = G_SUB %zero, %max
$x0 = COPY %sub2
RET_ReallyLR implicit $x0
+
+...
+---
+name: ASubUMaxOneUse
+body: |
+ bb.0:
+ liveins: $x0
+
+ ; CHECK-LABEL: name: ASubUMaxOneUse
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %max:_(s64) = G_UMAX %a, %sub1
+ ; CHECK-NEXT: %sub2:_(s64) = G_SUB %zero, %max
+ ; CHECK-NEXT: %mul:_(s64) = G_MUL %max, %sub2
+ ; CHECK-NEXT: $x0 = COPY %mul(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_UMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ %mul:_(s64) = G_MUL %max, %sub2
+ $x0 = COPY %mul
+ RET_ReallyLR implicit $x0
>From 799c4b70e5d1e413c0c965cec04ed2feaf641e5f Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 10 Apr 2026 13:12:48 +0100
Subject: [PATCH 11/29] reproduce
---
.../include/llvm/Target/GlobalISel/Combine.td | 22 ++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 336d000becd76..07716c6a1a8fd 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -2072,15 +2072,27 @@ def AMinusC1PlusC2: GICombineRule<
[{ return Helper.matchFoldAMinusC1PlusC2(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+// with the manual implementation of the helper it works
+// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
+// def SubSmaxSub: GICombineRule<
+// (defs root:$root, build_fn_matchinfo:$matchinfo),
+// (match (G_SUB $sub, 0, $A),
+// (G_SMAX $max, $A, $sub),
+// (G_SUB $root, 0, $max):$root,
+// [{ return Helper.matchFoldSubSmaxSub(*${root}, ${matchinfo}); }]),
+// (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+
+// otherwise it crashes
// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
def SubSmaxSub: GICombineRule<
- (defs root:$root, build_fn_matchinfo:$matchinfo),
+ (defs root:$root),
(match (G_SUB $sub, 0, $A),
(G_SMAX $max, $A, $sub),
- (G_SUB $root, 0, $max):$root,
- [{ return Helper.matchFoldSubSmaxSub(*${root}, ${matchinfo}); }]),
- (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
-
+ (G_SUB $root, 0, $max),
+ [{ return MRI.hasOneNonDBGUse(${sub}.getReg()) && MRI.hasOneNonDBGUse(${max}.getReg()); }]),
+ (apply (G_SUB $sub1, 0, $A),
+ (G_SMIN $root, $A, $sub1))>;
+
// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
def SubUmaxSub: GICombineRule<
(defs root:$root),
>From 495a95aecc3e718d6574ed003c9ee7b92f62db53 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 10 Apr 2026 13:36:58 +0100
Subject: [PATCH 12/29] wip
---
llvm/include/llvm/Target/GlobalISel/Combine.td | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 07716c6a1a8fd..c977e38b0fd33 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -2089,7 +2089,8 @@ def SubSmaxSub: GICombineRule<
(match (G_SUB $sub, 0, $A),
(G_SMAX $max, $A, $sub),
(G_SUB $root, 0, $max),
- [{ return MRI.hasOneNonDBGUse(${sub}.getReg()) && MRI.hasOneNonDBGUse(${max}.getReg()); }]),
+ [{ return MRI.hasOneNonDBGUse(${sub}.getReg()) &&
+ MRI.hasOneNonDBGUse(${max}.getReg()); }]),
(apply (G_SUB $sub1, 0, $A),
(G_SMIN $root, $A, $sub1))>;
@@ -2099,7 +2100,8 @@ def SubUmaxSub: GICombineRule<
(match (G_SUB $sub, 0, $A),
(G_UMAX $max, $A, $sub),
(G_SUB $root, 0, $max),
- [{ return MRI.hasOneNonDBGUse(${sub}.getReg()) && MRI.hasOneNonDBGUse(${max}.getReg()); }]),
+ [{ return MRI.hasOneNonDBGUse(${sub}.getReg()) &&
+ MRI.hasOneNonDBGUse(${max}.getReg()); }]),
(apply (G_SUB $sub1, 0, $A),
(G_UMIN $root, $A, $sub1))>;
>From 06252af1870dec0c451e9d8b3066b7d6b1971e68 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Thu, 14 May 2026 14:09:11 +0100
Subject: [PATCH 13/29] format
---
.../llvm/CodeGen/GlobalISel/CombinerHelper.h | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index ebffafa308a4b..7ac0cfc9c3294 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -133,9 +133,7 @@ class CombinerHelper {
GISelValueTracking *getValueTracking() const { return VT; }
- MachineIRBuilder &getBuilder() const {
- return Builder;
- }
+ MachineIRBuilder &getBuilder() const { return Builder; }
const TargetInstrInfo &getTII() const { return *TII; }
@@ -173,8 +171,10 @@ class CombinerHelper {
/// is a legal integer constant type on the target.
bool isConstantLegalOrBeforeLegalizer(const LLT Ty) const;
- /// MachineRegisterInfo::replaceRegWith() and inform the observer of the changes
- void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const;
+ /// MachineRegisterInfo::replaceRegWith() and inform the observer of the
+ /// changes
+ void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg,
+ Register ToReg) const;
/// Replace a single register operand with a new register and inform the
/// observer of the changes.
@@ -518,12 +518,13 @@ class CombinerHelper {
bool matchEqualDefs(const MachineOperand &MOP1,
const MachineOperand &MOP2) const;
- /// Return true if \p MOP is defined by a G_CONSTANT or splat with a value equal to
+ /// Return true if \p MOP is defined by a G_CONSTANT or splat with a value
+ /// equal to
/// \p C.
bool matchConstantOp(const MachineOperand &MOP, int64_t C) const;
- /// Return true if \p MOP is defined by a G_FCONSTANT or splat with a value exactly
- /// equal to \p C.
+ /// Return true if \p MOP is defined by a G_FCONSTANT or splat with a value
+ /// exactly equal to \p C.
bool matchConstantFPOp(const MachineOperand &MOP, double C) const;
/// @brief Checks if constant at \p ConstIdx is larger than \p MI 's bitwidth
@@ -1040,9 +1041,8 @@ class CombinerHelper {
bool matchFoldAMinusC1PlusC2(const MachineInstr &MI,
BuildFnTy &MatchInfo) const;
- bool matchFoldSubSmaxSub(const MachineInstr &MI,
- BuildFnTy &MatchInfo) const;
-
+ bool matchFoldSubSmaxSub(const MachineInstr &MI, BuildFnTy &MatchInfo) const;
+
bool matchExtOfExt(const MachineInstr &FirstMI, const MachineInstr &SecondMI,
BuildFnTy &MatchInfo) const;
>From 4c0e25ed42a253312e6d75b63d86f55321b86b5b Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Thu, 14 May 2026 14:09:31 +0100
Subject: [PATCH 14/29] format
---
.../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 70 +++++++++----------
1 file changed, 34 insertions(+), 36 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 67495ec4372d7..8ffbc4093594e 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -135,7 +135,7 @@ isBigEndian(const SmallDenseMap<int64_t, int64_t, 8> &MemOffset2Idx,
if (Width < 2)
return std::nullopt;
bool BigEndian = true, LittleEndian = true;
- for (unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
+ for (unsigned MemOffset = 0; MemOffset < Width; ++MemOffset) {
auto MemOffsetAndIdx = MemOffset2Idx.find(MemOffset);
if (MemOffsetAndIdx == MemOffset2Idx.end())
return std::nullopt;
@@ -764,10 +764,9 @@ bool CombinerHelper::matchCombineExtendingLoads(
// and emit a variant of (extend (trunc X)) for the others according to the
// relative type sizes. At the same time, pick an extend to use based on the
// extend involved in the chosen type.
- unsigned PreferredOpcode =
- isa<GLoad>(&MI)
- ? TargetOpcode::G_ANYEXT
- : isa<GSExtLoad>(&MI) ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
+ unsigned PreferredOpcode = isa<GLoad>(&MI) ? TargetOpcode::G_ANYEXT
+ : isa<GSExtLoad>(&MI) ? TargetOpcode::G_SEXT
+ : TargetOpcode::G_ZEXT;
Preferred = {LLT(), PreferredOpcode, nullptr};
for (auto &UseMI : MRI.use_nodbg_instructions(LoadReg)) {
if (UseMI.getOpcode() == TargetOpcode::G_SEXT ||
@@ -1593,7 +1592,7 @@ void CombinerHelper::applyCombineDivRem(MachineInstr &MI,
Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
: TargetOpcode::G_UDIVREM,
{DestDivReg, DestRemReg},
- { FirstInst->getOperand(1), FirstInst->getOperand(2) });
+ {FirstInst->getOperand(1), FirstInst->getOperand(2)});
MI.eraseFromParent();
OtherMI->eraseFromParent();
}
@@ -2066,7 +2065,8 @@ bool CombinerHelper::matchCommuteShift(MachineInstr &MI,
auto *SrcDef = MRI.getVRegDef(SrcReg);
assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
- SrcDef->getOpcode() == TargetOpcode::G_OR) && "Unexpected op");
+ SrcDef->getOpcode() == TargetOpcode::G_OR) &&
+ "Unexpected op");
LLT SrcTy = MRI.getType(SrcReg);
MatchInfo = [=](MachineIRBuilder &B) {
auto S1 = B.buildShl(SrcTy, X, ShiftReg);
@@ -2468,7 +2468,8 @@ bool CombinerHelper::matchCombineShiftToUnmerge(MachineInstr &MI,
unsigned &ShiftVal) const {
assert((MI.getOpcode() == TargetOpcode::G_SHL ||
MI.getOpcode() == TargetOpcode::G_LSHR ||
- MI.getOpcode() == TargetOpcode::G_ASHR) && "Expected a shift");
+ MI.getOpcode() == TargetOpcode::G_ASHR) &&
+ "Expected a shift");
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
if (Ty.isVector()) // TODO:
@@ -2511,8 +2512,10 @@ void CombinerHelper::applyCombineShiftToUnmerge(
// dst = G_MERGE_VALUES (G_LSHR hi, C - 32), 0
if (NarrowShiftAmt != 0) {
- Narrowed = Builder.buildLShr(HalfTy, Narrowed,
- Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
+ Narrowed = Builder
+ .buildLShr(HalfTy, Narrowed,
+ Builder.buildConstant(HalfTy, NarrowShiftAmt))
+ .getReg(0);
}
auto Zero = Builder.buildConstant(HalfTy, 0);
@@ -2524,17 +2527,18 @@ void CombinerHelper::applyCombineShiftToUnmerge(
// lo, hi = G_UNMERGE_VALUES x
// dst = G_MERGE_VALUES 0, (G_SHL hi, C - 32)
if (NarrowShiftAmt != 0) {
- Narrowed = Builder.buildShl(HalfTy, Narrowed,
- Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
+ Narrowed = Builder
+ .buildShl(HalfTy, Narrowed,
+ Builder.buildConstant(HalfTy, NarrowShiftAmt))
+ .getReg(0);
}
auto Zero = Builder.buildConstant(HalfTy, 0);
Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
} else {
assert(MI.getOpcode() == TargetOpcode::G_ASHR);
- auto Hi = Builder.buildAShr(
- HalfTy, Unmerge.getReg(1),
- Builder.buildConstant(HalfTy, HalfSize - 1));
+ auto Hi = Builder.buildAShr(HalfTy, Unmerge.getReg(1),
+ Builder.buildConstant(HalfTy, HalfSize - 1));
if (ShiftVal == HalfSize) {
// (G_ASHR i64:x, 32) ->
@@ -2547,9 +2551,9 @@ void CombinerHelper::applyCombineShiftToUnmerge(
// G_MERGE_VALUES %narrowed, %narrowed
Builder.buildMergeLikeInstr(DstReg, {Hi, Hi});
} else {
- auto Lo = Builder.buildAShr(
- HalfTy, Unmerge.getReg(1),
- Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
+ auto Lo =
+ Builder.buildAShr(HalfTy, Unmerge.getReg(1),
+ Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
// (G_ASHR i64:x, C) ->, for C >= 32
// G_MERGE_VALUES (G_ASHR hi_32(x), C - 32), (G_ASHR hi_32(x), 31)
@@ -3423,9 +3427,7 @@ bool CombinerHelper::matchOverlappingAnd(
Register R;
int64_t C1;
int64_t C2;
- if (!mi_match(
- Dst, MRI,
- m_GAnd(m_GAnd(m_Reg(R), m_ICst(C1)), m_ICst(C2))))
+ if (!mi_match(Dst, MRI, m_GAnd(m_GAnd(m_Reg(R), m_ICst(C1)), m_ICst(C2))))
return false;
MatchInfo = [=](MachineIRBuilder &B) {
@@ -4247,8 +4249,8 @@ CombinerHelper::findLoadOffsetsForLoadOrCombine(
// pattern.
assert(Loads.size() == RegsToVisit.size() &&
"Expected to find a load for each register?");
- assert(EarliestLoad != LatestLoad && EarliestLoad &&
- LatestLoad && "Expected at least two loads?");
+ assert(EarliestLoad != LatestLoad && EarliestLoad && LatestLoad &&
+ "Expected at least two loads?");
// Check if there are any stores, calls, etc. between any of the loads. If
// there are, then we can't safely perform the combine.
@@ -4347,10 +4349,9 @@ bool CombinerHelper::matchLoadOrCombine(
// load x[i+1] -> byte 0 ---> wide_load x[i]
// load x[i+2] -> byte 1
const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
- const unsigned ZeroByteOffset =
- *IsBigEndian
- ? bigEndianByteAt(NumLoadsInTy, 0)
- : littleEndianByteAt(NumLoadsInTy, 0);
+ const unsigned ZeroByteOffset = *IsBigEndian
+ ? bigEndianByteAt(NumLoadsInTy, 0)
+ : littleEndianByteAt(NumLoadsInTy, 0);
auto ZeroOffsetIdx = MemOffset2Idx.find(ZeroByteOffset);
if (ZeroOffsetIdx == MemOffset2Idx.end() ||
ZeroOffsetIdx->second != LowestIdx)
@@ -4667,7 +4668,8 @@ bool CombinerHelper::matchFunnelShiftToRotate(MachineInstr &MI) const {
return false;
unsigned RotateOpc =
Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
- return isLegalOrBeforeLegalizer({RotateOpc, {MRI.getType(X), MRI.getType(Y)}});
+ return isLegalOrBeforeLegalizer(
+ {RotateOpc, {MRI.getType(X), MRI.getType(Y)}});
}
void CombinerHelper::applyFunnelShiftToRotate(MachineInstr &MI) const {
@@ -4980,9 +4982,7 @@ bool CombinerHelper::matchBitfieldExtractFromShrAnd(
// If the shift subsumes the mask, emit the 0 directly.
if (0 == (SMask >> ShrAmt)) {
- MatchInfo = [=](MachineIRBuilder &B) {
- B.buildConstant(Dst, 0);
- };
+ MatchInfo = [=](MachineIRBuilder &B) { B.buildConstant(Dst, 0); };
return true;
}
@@ -8440,8 +8440,8 @@ bool CombinerHelper::matchFoldSubSmaxSub(const MachineInstr &MI,
return false;
// Verify Sub2 LHS == 0
- auto MaybeCst2 = getIConstantVRegValWithLookThrough(
- Sub2MI->getOperand(1).getReg(), MRI);
+ auto MaybeCst2 =
+ getIConstantVRegValWithLookThrough(Sub2MI->getOperand(1).getReg(), MRI);
if (!MaybeCst2 || !MaybeCst2->Value.isZero())
return false;
@@ -8458,9 +8458,7 @@ bool CombinerHelper::matchFoldSubSmaxSub(const MachineInstr &MI,
Register Dst = Sub1->getReg(0);
Register Sub2Result = Sub2MI->getOperand(0).getReg();
- MatchInfo = [=](MachineIRBuilder &B) {
- B.buildSMin(Dst, X, Sub2Result);
- };
+ MatchInfo = [=](MachineIRBuilder &B) { B.buildSMin(Dst, X, Sub2Result); };
return true;
}
>From feef965faf8e13d14fe32eaeee3c8b4de0789a40 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Thu, 14 May 2026 15:04:49 +0100
Subject: [PATCH 15/29] manual impl
---
.../include/llvm/Target/GlobalISel/Combine.td | 32 +++++++++----------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 6245efbc45a11..5d1948e52dfd2 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -2106,25 +2106,25 @@ def AMinusC1PlusC2: GICombineRule<
// with the manual implementation of the helper it works
// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
-// def SubSmaxSub: GICombineRule<
-// (defs root:$root, build_fn_matchinfo:$matchinfo),
-// (match (G_SUB $sub, 0, $A),
-// (G_SMAX $max, $A, $sub),
-// (G_SUB $root, 0, $max):$root,
-// [{ return Helper.matchFoldSubSmaxSub(*${root}, ${matchinfo}); }]),
-// (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
-
-// otherwise it crashes
-// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
def SubSmaxSub: GICombineRule<
- (defs root:$root),
+ (defs root:$root, build_fn_matchinfo:$matchinfo),
(match (G_SUB $sub, 0, $A),
(G_SMAX $max, $A, $sub),
- (G_SUB $root, 0, $max),
- [{ return MRI.hasOneNonDBGUse(${sub}.getReg()) &&
- MRI.hasOneNonDBGUse(${max}.getReg()); }]),
- (apply (G_SUB $sub1, 0, $A),
- (G_SMIN $root, $A, $sub1))>;
+ (G_SUB $root, 0, $max):$root,
+ [{ return Helper.matchFoldSubSmaxSub(*${root}, ${matchinfo}); }]),
+ (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+
+// otherwise it crashes
+// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
+// def SubSmaxSub: GICombineRule<
+// (defs root:$root),
+// (match (G_SUB $sub, 0, $A),
+// (G_SMAX $max, $A, $sub),
+// (G_SUB $root, 0, $max),
+// [{ return MRI.hasOneNonDBGUse(${sub}.getReg()) &&
+// MRI.hasOneNonDBGUse(${max}.getReg()); }]),
+// (apply (G_SUB $sub1, 0, $A),
+// (G_SMIN $root, $A, $sub1))>;
// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
def SubUmaxSub: GICombineRule<
>From 553a6f3f78da9691b185958c8f70b39bb05ecedf Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 5 Jun 2026 14:36:35 +0100
Subject: [PATCH 16/29] wip
---
.../include/llvm/Target/GlobalISel/Combine.td | 23 +++++--------------
1 file changed, 6 insertions(+), 17 deletions(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 5d1948e52dfd2..6f40fba4679a5 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -2104,27 +2104,16 @@ def AMinusC1PlusC2: GICombineRule<
[{ return Helper.matchFoldAMinusC1PlusC2(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
-// with the manual implementation of the helper it works
// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
def SubSmaxSub: GICombineRule<
- (defs root:$root, build_fn_matchinfo:$matchinfo),
+ (defs root:$root),
(match (G_SUB $sub, 0, $A),
(G_SMAX $max, $A, $sub),
- (G_SUB $root, 0, $max):$root,
- [{ return Helper.matchFoldSubSmaxSub(*${root}, ${matchinfo}); }]),
- (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
-
-// otherwise it crashes
-// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
-// def SubSmaxSub: GICombineRule<
-// (defs root:$root),
-// (match (G_SUB $sub, 0, $A),
-// (G_SMAX $max, $A, $sub),
-// (G_SUB $root, 0, $max),
-// [{ return MRI.hasOneNonDBGUse(${sub}.getReg()) &&
-// MRI.hasOneNonDBGUse(${max}.getReg()); }]),
-// (apply (G_SUB $sub1, 0, $A),
-// (G_SMIN $root, $A, $sub1))>;
+ (G_SUB $root, 0, $max),
+ [{ return MRI.hasOneNonDBGUse(${sub}.getReg()) &&
+ MRI.hasOneNonDBGUse(${max}.getReg()); }]),
+ (apply (G_SUB $sub1, 0, $A),
+ (G_SMIN $root, $A, $sub1))>;
// (sub 0, (max X, (sub 0, X))) --> (min X, (sub 0, X))
def SubUmaxSub: GICombineRule<
>From 5042454b7c61852cdac3be67b0c603cdb7fa5d26 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Fri, 5 Jun 2026 14:53:15 +0100
Subject: [PATCH 17/29] IT WORKS
---
.../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 41 -------------------
.../AArch64/GlobalISel/combine-integer.mir | 6 ++-
2 files changed, 4 insertions(+), 43 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index d0ee853181fb1..fc00b2f166120 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -8485,47 +8485,6 @@ bool CombinerHelper::matchFoldAMinusC1PlusC2(const MachineInstr &MI,
return true;
}
-bool CombinerHelper::matchFoldSubSmaxSub(const MachineInstr &MI,
- BuildFnTy &MatchInfo) const {
- // fold (sub 0, (smax X, (sub 0, X))) --> (smin X, (sub 0, X))
- const GSub *Sub1 = cast<GSub>(&MI);
-
- MachineInstr *MaxMI = MRI.getVRegDef(Sub1->getRHSReg());
- if (!MaxMI || MaxMI->getOpcode() != TargetOpcode::G_SMAX)
- return false;
-
- MachineInstr *Sub2MI = MRI.getVRegDef(MaxMI->getOperand(2).getReg());
- if (!Sub2MI || Sub2MI->getOpcode() != TargetOpcode::G_SUB)
- return false;
-
- // Verify Sub1 LHS == 0
- auto MaybeCst1 = getIConstantVRegValWithLookThrough(Sub1->getLHSReg(), MRI);
- if (!MaybeCst1 || !MaybeCst1->Value.isZero())
- return false;
-
- // Verify Sub2 LHS == 0
- auto MaybeCst2 =
- getIConstantVRegValWithLookThrough(Sub2MI->getOperand(1).getReg(), MRI);
- if (!MaybeCst2 || !MaybeCst2->Value.isZero())
- return false;
-
- // Verify X is the same register in both smax and the inner sub
- Register X = MaxMI->getOperand(1).getReg();
- if (X != Sub2MI->getOperand(2).getReg())
- return false;
-
- if (!MRI.hasOneNonDBGUse(Sub2MI->getOperand(0).getReg()))
- return false;
- if (!MRI.hasOneNonDBGUse(MaxMI->getOperand(0).getReg()))
- return false;
-
- Register Dst = Sub1->getReg(0);
- Register Sub2Result = Sub2MI->getOperand(0).getReg();
-
- MatchInfo = [=](MachineIRBuilder &B) { B.buildSMin(Dst, X, Sub2Result); };
- return true;
-}
-
bool CombinerHelper::matchUnmergeValuesAnyExtBuildVector(
const MachineInstr &MI, BuildFnTy &MatchInfo) const {
const GUnmerge *Unmerge = cast<GUnmerge>(&MI);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index 245633a6b3802..9621ef21300cf 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -596,8 +596,8 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: %a:_(s64) = COPY $x0
; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
- ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
- ; CHECK-NEXT: %sub2:_(s64) = G_SMIN %a, %sub1
+ ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %sub2:_(s64) = G_SMIN %a, [[SUB]]
; CHECK-NEXT: $x0 = COPY %sub2(s64)
; CHECK-NEXT: RET_ReallyLR implicit $x0
%a:_(s64) = COPY $x0
@@ -615,6 +615,7 @@ body: |
bb.0:
liveins: $x0
+
; CHECK-LABEL: name: ASubSMaxOneUse
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
@@ -667,6 +668,7 @@ body: |
bb.0:
liveins: $x0
+
; CHECK-LABEL: name: ASubUMaxOneUse
; CHECK: liveins: $x0
; CHECK-NEXT: {{ $}}
>From 3021982f5225774df8d4ce579269468603072eb5 Mon Sep 17 00:00:00 2001
From: Luisa Cicolini <48860705+luisacicolini at users.noreply.github.com>
Date: Fri, 5 Jun 2026 14:59:54 +0100
Subject: [PATCH 18/29] Apply suggestions from code review
Co-authored-by: Luisa Cicolini <48860705+luisacicolini at users.noreply.github.com>
---
.../llvm/CodeGen/GlobalISel/CombinerHelper.h | 7 ++-
.../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 58 +++++++++----------
2 files changed, 33 insertions(+), 32 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index b0e048c0b6d9a..aa61310994a67 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -133,7 +133,9 @@ class CombinerHelper {
GISelValueTracking *getValueTracking() const { return VT; }
- MachineIRBuilder &getBuilder() const { return Builder; }
+ MachineIRBuilder &getBuilder() const {
+ return Builder;
+ }
const TargetInstrInfo &getTII() const { return *TII; }
@@ -550,8 +552,7 @@ class CombinerHelper {
LLVM_ABI bool matchEqualDefs(const MachineOperand &MOP1,
const MachineOperand &MOP2) const;
- /// Return true if \p MOP is defined by a G_CONSTANT or splat with a value
- /// equal to
+ /// Return true if \p MOP is defined by a G_CONSTANT or splat with a value equal to
/// \p C.
LLVM_ABI bool matchConstantOp(const MachineOperand &MOP, int64_t C) const;
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index fc00b2f166120..76e23906d7041 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -135,7 +135,7 @@ isBigEndian(const SmallDenseMap<int64_t, int64_t, 8> &MemOffset2Idx,
if (Width < 2)
return std::nullopt;
bool BigEndian = true, LittleEndian = true;
- for (unsigned MemOffset = 0; MemOffset < Width; ++MemOffset) {
+ for (unsigned MemOffset = 0; MemOffset < Width; ++ MemOffset) {
auto MemOffsetAndIdx = MemOffset2Idx.find(MemOffset);
if (MemOffsetAndIdx == MemOffset2Idx.end())
return std::nullopt;
@@ -819,9 +819,10 @@ bool CombinerHelper::matchCombineExtendingLoads(
// and emit a variant of (extend (trunc X)) for the others according to the
// relative type sizes. At the same time, pick an extend to use based on the
// extend involved in the chosen type.
- unsigned PreferredOpcode = isa<GLoad>(&MI) ? TargetOpcode::G_ANYEXT
- : isa<GSExtLoad>(&MI) ? TargetOpcode::G_SEXT
- : TargetOpcode::G_ZEXT;
+ unsigned PreferredOpcode =
+ isa<GLoad>(&MI)
+ ? TargetOpcode::G_ANYEXT
+ : isa<GSExtLoad>(&MI) ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
Preferred = {LLT(), PreferredOpcode, nullptr};
for (auto &UseMI : MRI.use_nodbg_instructions(LoadReg)) {
if (UseMI.getOpcode() == TargetOpcode::G_SEXT ||
@@ -1656,7 +1657,7 @@ void CombinerHelper::applyCombineDivRem(MachineInstr &MI,
Builder.buildInstr(IsSigned ? TargetOpcode::G_SDIVREM
: TargetOpcode::G_UDIVREM,
{DestDivReg, DestRemReg},
- {FirstInst->getOperand(1), FirstInst->getOperand(2)});
+ { FirstInst->getOperand(1), FirstInst->getOperand(2) });
MI.eraseFromParent();
OtherMI->eraseFromParent();
}
@@ -2129,8 +2130,7 @@ bool CombinerHelper::matchCommuteShift(MachineInstr &MI,
auto *SrcDef = MRI.getVRegDef(SrcReg);
assert((SrcDef->getOpcode() == TargetOpcode::G_ADD ||
- SrcDef->getOpcode() == TargetOpcode::G_OR) &&
- "Unexpected op");
+ SrcDef->getOpcode() == TargetOpcode::G_OR) && "Unexpected op");
LLT SrcTy = MRI.getType(SrcReg);
MatchInfo = [=](MachineIRBuilder &B) {
auto S1 = B.buildShl(SrcTy, X, ShiftReg);
@@ -2532,8 +2532,7 @@ bool CombinerHelper::matchCombineShiftToUnmerge(MachineInstr &MI,
unsigned &ShiftVal) const {
assert((MI.getOpcode() == TargetOpcode::G_SHL ||
MI.getOpcode() == TargetOpcode::G_LSHR ||
- MI.getOpcode() == TargetOpcode::G_ASHR) &&
- "Expected a shift");
+ MI.getOpcode() == TargetOpcode::G_ASHR) && "Expected a shift");
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
if (Ty.isVector()) // TODO:
@@ -2576,10 +2575,8 @@ void CombinerHelper::applyCombineShiftToUnmerge(
// dst = G_MERGE_VALUES (G_LSHR hi, C - 32), 0
if (NarrowShiftAmt != 0) {
- Narrowed = Builder
- .buildLShr(HalfTy, Narrowed,
- Builder.buildConstant(HalfTy, NarrowShiftAmt))
- .getReg(0);
+ Narrowed = Builder.buildLShr(HalfTy, Narrowed,
+ Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
}
auto Zero = Builder.buildConstant(HalfTy, 0);
@@ -2591,18 +2588,17 @@ void CombinerHelper::applyCombineShiftToUnmerge(
// lo, hi = G_UNMERGE_VALUES x
// dst = G_MERGE_VALUES 0, (G_SHL hi, C - 32)
if (NarrowShiftAmt != 0) {
- Narrowed = Builder
- .buildShl(HalfTy, Narrowed,
- Builder.buildConstant(HalfTy, NarrowShiftAmt))
- .getReg(0);
+ Narrowed = Builder.buildShl(HalfTy, Narrowed,
+ Builder.buildConstant(HalfTy, NarrowShiftAmt)).getReg(0);
}
auto Zero = Builder.buildConstant(HalfTy, 0);
Builder.buildMergeLikeInstr(DstReg, {Zero, Narrowed});
} else {
assert(MI.getOpcode() == TargetOpcode::G_ASHR);
- auto Hi = Builder.buildAShr(HalfTy, Unmerge.getReg(1),
- Builder.buildConstant(HalfTy, HalfSize - 1));
+ auto Hi = Builder.buildAShr(
+ HalfTy, Unmerge.getReg(1),
+ Builder.buildConstant(HalfTy, HalfSize - 1));
if (ShiftVal == HalfSize) {
// (G_ASHR i64:x, 32) ->
@@ -2615,9 +2611,9 @@ void CombinerHelper::applyCombineShiftToUnmerge(
// G_MERGE_VALUES %narrowed, %narrowed
Builder.buildMergeLikeInstr(DstReg, {Hi, Hi});
} else {
- auto Lo =
- Builder.buildAShr(HalfTy, Unmerge.getReg(1),
- Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
+ auto Lo = Builder.buildAShr(
+ HalfTy, Unmerge.getReg(1),
+ Builder.buildConstant(HalfTy, ShiftVal - HalfSize));
// (G_ASHR i64:x, C) ->, for C >= 32
// G_MERGE_VALUES (G_ASHR hi_32(x), C - 32), (G_ASHR hi_32(x), 31)
@@ -3491,7 +3487,9 @@ bool CombinerHelper::matchOverlappingAnd(
Register R;
int64_t C1;
int64_t C2;
- if (!mi_match(Dst, MRI, m_GAnd(m_GAnd(m_Reg(R), m_ICst(C1)), m_ICst(C2))))
+ if (!mi_match(
+ Dst, MRI,
+ m_GAnd(m_GAnd(m_Reg(R), m_ICst(C1)), m_ICst(C2))))
return false;
MatchInfo = [=](MachineIRBuilder &B) {
@@ -4413,9 +4411,10 @@ bool CombinerHelper::matchLoadOrCombine(
// load x[i+1] -> byte 0 ---> wide_load x[i]
// load x[i+2] -> byte 1
const unsigned NumLoadsInTy = WideMemSizeInBits / NarrowMemSizeInBits;
- const unsigned ZeroByteOffset = *IsBigEndian
- ? bigEndianByteAt(NumLoadsInTy, 0)
- : littleEndianByteAt(NumLoadsInTy, 0);
+ const unsigned ZeroByteOffset =
+ *IsBigEndian
+ ? bigEndianByteAt(NumLoadsInTy, 0)
+ : littleEndianByteAt(NumLoadsInTy, 0);
auto ZeroOffsetIdx = MemOffset2Idx.find(ZeroByteOffset);
if (ZeroOffsetIdx == MemOffset2Idx.end() ||
ZeroOffsetIdx->second != LowestIdx)
@@ -4732,8 +4731,7 @@ bool CombinerHelper::matchFunnelShiftToRotate(MachineInstr &MI) const {
return false;
unsigned RotateOpc =
Opc == TargetOpcode::G_FSHL ? TargetOpcode::G_ROTL : TargetOpcode::G_ROTR;
- return isLegalOrBeforeLegalizer(
- {RotateOpc, {MRI.getType(X), MRI.getType(Y)}});
+ return isLegalOrBeforeLegalizer({RotateOpc, {MRI.getType(X), MRI.getType(Y)}});
}
void CombinerHelper::applyFunnelShiftToRotate(MachineInstr &MI) const {
@@ -5046,7 +5044,9 @@ bool CombinerHelper::matchBitfieldExtractFromShrAnd(
// If the shift subsumes the mask, emit the 0 directly.
if (0 == (SMask >> ShrAmt)) {
- MatchInfo = [=](MachineIRBuilder &B) { B.buildConstant(Dst, 0); };
+ MatchInfo = [=](MachineIRBuilder &B) {
+ B.buildConstant(Dst, 0);
+ };
return true;
}
>From d833aa8369c298258f7aa512d4d6e3786ac31b8a Mon Sep 17 00:00:00 2001
From: Luisa Cicolini <48860705+luisacicolini at users.noreply.github.com>
Date: Fri, 5 Jun 2026 15:02:48 +0100
Subject: [PATCH 19/29] Apply suggestion from @luisacicolini
---
llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 76e23906d7041..88b68d7685c63 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -4311,8 +4311,8 @@ CombinerHelper::findLoadOffsetsForLoadOrCombine(
// pattern.
assert(Loads.size() == RegsToVisit.size() &&
"Expected to find a load for each register?");
- assert(EarliestLoad != LatestLoad && EarliestLoad && LatestLoad &&
- "Expected at least two loads?");
+ assert(EarliestLoad != LatestLoad && EarliestLoad &&
+ LatestLoad && "Expected at least two loads?");
// Check if there are any stores, calls, etc. between any of the loads. If
// there are, then we can't safely perform the combine.
>From 0d529afceecefda89ea23c0cb5a25664e3192974 Mon Sep 17 00:00:00 2001
From: Luisa Cicolini <48860705+luisacicolini at users.noreply.github.com>
Date: Fri, 5 Jun 2026 16:02:34 +0100
Subject: [PATCH 20/29] Update llvm/include/llvm/Target/GlobalISel/Combine.td
Co-authored-by: Osman Yasar <osmanyas05 at gmail.com>
---
llvm/include/llvm/Target/GlobalISel/Combine.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 797b4fe9c6096..0d7292f0de2fe 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -2193,7 +2193,7 @@ def integer_reassoc_combines: GICombineGroup<[
C2MinusAPlusC1,
AMinusC1MinusC2,
C1Minus2MinusC2,
- AMinusC1PlusC2,
+ AMinusC1PlusC2
]>;
def max_min_combines: GICombineGroup<[
>From ceeb7a0c1594fe623f8369f835e24cd7843a8f77 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Mon, 8 Jun 2026 18:02:15 +0100
Subject: [PATCH 21/29] test
---
.../AArch64/GlobalISel/combine-integer.mir | 104 -----------------
.../AArch64/GlobalISel/combine-smax-smin.mir | 106 ++++++++++++++++++
2 files changed, 106 insertions(+), 104 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/combine-smax-smin.mir
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index 9621ef21300cf..55c0cb2559f37 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -584,107 +584,3 @@ body: |
$q0 = COPY %sub2
RET_ReallyLR implicit $q0
-...
----
-name: ASubSMax
-body: |
- bb.0:
- liveins: $x0
-
- ; CHECK-LABEL: name: ASubSMax
- ; CHECK: liveins: $x0
- ; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: %a:_(s64) = COPY $x0
- ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
- ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB %zero, %a
- ; CHECK-NEXT: %sub2:_(s64) = G_SMIN %a, [[SUB]]
- ; CHECK-NEXT: $x0 = COPY %sub2(s64)
- ; CHECK-NEXT: RET_ReallyLR implicit $x0
- %a:_(s64) = COPY $x0
- %zero:_(s64) = G_CONSTANT i64 0
- %sub1:_(s64) = G_SUB %zero, %a
- %max:_(s64) = G_SMAX %a, %sub1
- %sub2:_(s64) = G_SUB %zero, %max
- $x0 = COPY %sub2
- RET_ReallyLR implicit $x0
-
-...
----
-name: ASubSMaxOneUse
-body: |
- bb.0:
- liveins: $x0
-
-
- ; CHECK-LABEL: name: ASubSMaxOneUse
- ; CHECK: liveins: $x0
- ; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: %a:_(s64) = COPY $x0
- ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
- ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
- ; CHECK-NEXT: %max:_(s64) = G_SMAX %a, %sub1
- ; CHECK-NEXT: %sub2:_(s64) = G_SUB %zero, %max
- ; CHECK-NEXT: %mul:_(s64) = G_MUL %max, %sub2
- ; CHECK-NEXT: $x0 = COPY %mul(s64)
- ; CHECK-NEXT: RET_ReallyLR implicit $x0
- %a:_(s64) = COPY $x0
- %zero:_(s64) = G_CONSTANT i64 0
- %sub1:_(s64) = G_SUB %zero, %a
- %max:_(s64) = G_SMAX %a, %sub1
- %sub2:_(s64) = G_SUB %zero, %max
- %mul:_(s64) = G_MUL %max, %sub2
- $x0 = COPY %mul
- RET_ReallyLR implicit $x0
-
-...
----
-name: ASubUMax
-body: |
- bb.0:
- liveins: $x0
-
-
- ; CHECK-LABEL: name: ASubUMax
- ; CHECK: liveins: $x0
- ; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: %a:_(s64) = COPY $x0
- ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
- ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB %zero, %a
- ; CHECK-NEXT: %sub2:_(s64) = G_UMIN %a, [[SUB]]
- ; CHECK-NEXT: $x0 = COPY %sub2(s64)
- ; CHECK-NEXT: RET_ReallyLR implicit $x0
- %a:_(s64) = COPY $x0
- %zero:_(s64) = G_CONSTANT i64 0
- %sub1:_(s64) = G_SUB %zero, %a
- %max:_(s64) = G_UMAX %a, %sub1
- %sub2:_(s64) = G_SUB %zero, %max
- $x0 = COPY %sub2
- RET_ReallyLR implicit $x0
-
-...
----
-name: ASubUMaxOneUse
-body: |
- bb.0:
- liveins: $x0
-
-
- ; CHECK-LABEL: name: ASubUMaxOneUse
- ; CHECK: liveins: $x0
- ; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: %a:_(s64) = COPY $x0
- ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
- ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
- ; CHECK-NEXT: %max:_(s64) = G_UMAX %a, %sub1
- ; CHECK-NEXT: %sub2:_(s64) = G_SUB %zero, %max
- ; CHECK-NEXT: %mul:_(s64) = G_MUL %max, %sub2
- ; CHECK-NEXT: $x0 = COPY %mul(s64)
- ; CHECK-NEXT: RET_ReallyLR implicit $x0
- %a:_(s64) = COPY $x0
- %zero:_(s64) = G_CONSTANT i64 0
- %sub1:_(s64) = G_SUB %zero, %a
- %max:_(s64) = G_UMAX %a, %sub1
- %sub2:_(s64) = G_SUB %zero, %max
- %mul:_(s64) = G_MUL %max, %sub2
- $x0 = COPY %mul
- RET_ReallyLR implicit $x0
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-smax-smin.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-smax-smin.mir
new file mode 100644
index 0000000000000..d91159ebdacef
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-smax-smin.mir
@@ -0,0 +1,106 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple aarch64 -run-pass=aarch64-prelegalizer-combiner %s -o - | FileCheck %s
+
+---
+name: ASubSMax
+body: |
+ bb.0:
+ liveins: $x0
+
+ ; CHECK-LABEL: name: ASubSMax
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %sub2:_(s64) = G_SMIN %a, [[SUB]]
+ ; CHECK-NEXT: $x0 = COPY %sub2(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_SMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ $x0 = COPY %sub2
+ RET_ReallyLR implicit $x0
+
+...
+---
+name: ASubSMaxOneUse
+body: |
+ bb.0:
+ liveins: $x0
+
+
+ ; CHECK-LABEL: name: ASubSMaxOneUse
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %max:_(s64) = G_SMAX %a, %sub1
+ ; CHECK-NEXT: %sub2:_(s64) = G_SUB %zero, %max
+ ; CHECK-NEXT: %mul:_(s64) = G_MUL %max, %sub2
+ ; CHECK-NEXT: $x0 = COPY %mul(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_SMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ %mul:_(s64) = G_MUL %max, %sub2
+ $x0 = COPY %mul
+ RET_ReallyLR implicit $x0
+
+...
+---
+name: ASubUMax
+body: |
+ bb.0:
+ liveins: $x0
+
+
+ ; CHECK-LABEL: name: ASubUMax
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %sub2:_(s64) = G_UMIN %a, [[SUB]]
+ ; CHECK-NEXT: $x0 = COPY %sub2(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_UMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ $x0 = COPY %sub2
+ RET_ReallyLR implicit $x0
+
+...
+---
+name: ASubUMaxOneUse
+body: |
+ bb.0:
+ liveins: $x0
+
+
+ ; CHECK-LABEL: name: ASubUMaxOneUse
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(s64) = COPY $x0
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: %sub1:_(s64) = G_SUB %zero, %a
+ ; CHECK-NEXT: %max:_(s64) = G_UMAX %a, %sub1
+ ; CHECK-NEXT: %sub2:_(s64) = G_SUB %zero, %max
+ ; CHECK-NEXT: %mul:_(s64) = G_MUL %max, %sub2
+ ; CHECK-NEXT: $x0 = COPY %mul(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %a:_(s64) = COPY $x0
+ %zero:_(s64) = G_CONSTANT i64 0
+ %sub1:_(s64) = G_SUB %zero, %a
+ %max:_(s64) = G_UMAX %a, %sub1
+ %sub2:_(s64) = G_SUB %zero, %max
+ %mul:_(s64) = G_MUL %max, %sub2
+ $x0 = COPY %mul
+ RET_ReallyLR implicit $x0
>From be8340fda444dd189e4b77defa57ad6b3e050e38 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Mon, 8 Jun 2026 18:19:29 +0100
Subject: [PATCH 22/29] test
---
.../AArch64/GlobalISel/combine-max-min.ll | 31 +++++++++++++++++++
...bine-smax-smin.mir => combine-max-min.mir} | 0
2 files changed, 31 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll
rename llvm/test/CodeGen/AArch64/GlobalISel/{combine-smax-smin.mir => combine-max-min.mir} (100%)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll b/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll
new file mode 100644
index 0000000000000..3135d3432fd41
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll
@@ -0,0 +1,31 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-SD
+; RUN: llc -mtriple=aarch64 -global-isel -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-GI
+
+declare i64 @llvm.smax.i64(i64, i64)
+declare i64 @llvm.umax.i64(i64, i64)
+
+; 0 - smax(a, 0 - a) -> smin(a, 0 - a) (i.e. -abs(a))
+define i64 @ASubSMax(i64 %a) {
+ %sub1 = sub i64 0, %a
+ %max = call i64 @llvm.smax.i64(i64 %a, i64 %sub1)
+ %sub2 = sub i64 0, %max
+ ret i64 %sub2
+}
+
+; Extra use of %max blocks the combine.
+define i64 @ASubSMaxOneUse(i64 %a) {
+ %sub1 = sub i64 0, %a
+ %max = call i64 @llvm.smax.i64(i64 %a, i64 %sub1)
+ %sub2 = sub i64 0, %max
+ %mul = mul i64 %max, %sub2
+ ret i64 %mul
+}
+
+; 0 - umax(a, 0 - a) -> umin(a, 0 - a)
+define i64 @ASubUMax(i64 %a) {
+ %sub1 = sub i64 0, %a
+ %max = call i64 @llvm.umax.i64(i64 %a, i64 %sub1)
+ %sub2 = sub i64 0, %max
+ ret i64 %sub2
+}
\ No newline at end of file
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-smax-smin.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.mir
similarity index 100%
rename from llvm/test/CodeGen/AArch64/GlobalISel/combine-smax-smin.mir
rename to llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.mir
>From 7ca991db432699d1767a5d362afc6fc290dbe775 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Mon, 8 Jun 2026 19:28:19 +0100
Subject: [PATCH 23/29] test
---
.../AArch64/GlobalISel/combine-max-min.ll | 35 ++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll b/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll
index 3135d3432fd41..8eff477d34249 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll
@@ -7,6 +7,19 @@ declare i64 @llvm.umax.i64(i64, i64)
; 0 - smax(a, 0 - a) -> smin(a, 0 - a) (i.e. -abs(a))
define i64 @ASubSMax(i64 %a) {
+; CHECK-SD-LABEL: ASubSMax:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: neg x8, x0
+; CHECK-SD-NEXT: cmp x0, x8
+; CHECK-SD-NEXT: cneg x0, x0, gt
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: ASubSMax:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: neg x8, x0
+; CHECK-GI-NEXT: cmp x0, x8
+; CHECK-GI-NEXT: cneg x0, x0, ge
+; CHECK-GI-NEXT: ret
%sub1 = sub i64 0, %a
%max = call i64 @llvm.smax.i64(i64 %a, i64 %sub1)
%sub2 = sub i64 0, %max
@@ -15,6 +28,13 @@ define i64 @ASubSMax(i64 %a) {
; Extra use of %max blocks the combine.
define i64 @ASubSMaxOneUse(i64 %a) {
+; CHECK-LABEL: ASubSMaxOneUse:
+; CHECK: // %bb.0:
+; CHECK-NEXT: neg x8, x0
+; CHECK-NEXT: cmp x0, x8
+; CHECK-NEXT: cneg x8, x0, le
+; CHECK-NEXT: mneg x0, x8, x8
+; CHECK-NEXT: ret
%sub1 = sub i64 0, %a
%max = call i64 @llvm.smax.i64(i64 %a, i64 %sub1)
%sub2 = sub i64 0, %max
@@ -24,8 +44,21 @@ define i64 @ASubSMaxOneUse(i64 %a) {
; 0 - umax(a, 0 - a) -> umin(a, 0 - a)
define i64 @ASubUMax(i64 %a) {
+; CHECK-SD-LABEL: ASubUMax:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: neg x8, x0
+; CHECK-SD-NEXT: cmp x0, x8
+; CHECK-SD-NEXT: cneg x0, x0, hi
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: ASubUMax:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: neg x8, x0
+; CHECK-GI-NEXT: cmp x0, x8
+; CHECK-GI-NEXT: cneg x0, x0, hs
+; CHECK-GI-NEXT: ret
%sub1 = sub i64 0, %a
%max = call i64 @llvm.umax.i64(i64 %a, i64 %sub1)
%sub2 = sub i64 0, %max
ret i64 %sub2
-}
\ No newline at end of file
+}
>From 99411e4aab32cd891724dd2ee2a3c44615810f2f Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Tue, 9 Jun 2026 11:52:42 +0100
Subject: [PATCH 24/29] unrelated change
---
llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index 55c0cb2559f37..a258d378ef350 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -584,3 +584,4 @@ body: |
$q0 = COPY %sub2
RET_ReallyLR implicit $q0
+
>From b1fefd177d9c37b8995606c0ce1986928358ad11 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Tue, 9 Jun 2026 11:53:34 +0100
Subject: [PATCH 25/29] unrelated change
---
llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir | 2 --
1 file changed, 2 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index a258d378ef350..fc9a683ed3df4 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -583,5 +583,3 @@ body: |
%sub2:_(<4 x s32>) = G_SUB %a, %sub1
$q0 = COPY %sub2
RET_ReallyLR implicit $q0
-
-
>From 8ae6ff372c18c4a00f6c3221133aa79a93ae7131 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Tue, 9 Jun 2026 11:54:22 +0100
Subject: [PATCH 26/29] unrelated change
---
llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir | 2 ++
1 file changed, 2 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index fc9a683ed3df4..a258d378ef350 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -583,3 +583,5 @@ body: |
%sub2:_(<4 x s32>) = G_SUB %a, %sub1
$q0 = COPY %sub2
RET_ReallyLR implicit $q0
+
+
>From 5f7db557c5bb4ff77c3c029b7b224c20d18be7bf Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Tue, 9 Jun 2026 11:54:44 +0100
Subject: [PATCH 27/29] unrelated change
---
llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
index a258d378ef350..f77ab013e20f2 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-integer.mir
@@ -584,4 +584,4 @@ body: |
$q0 = COPY %sub2
RET_ReallyLR implicit $q0
-
+...
>From a5f1f111aebe758d0b745e7378dfca0e51bc7576 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Tue, 9 Jun 2026 13:36:29 +0100
Subject: [PATCH 28/29] vec tests
---
.../AArch64/GlobalISel/combine-max-min.mir | 52 +++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.mir
index d91159ebdacef..4c505f77e1bc4 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.mir
@@ -24,6 +24,32 @@ body: |
$x0 = COPY %sub2
RET_ReallyLR implicit $x0
+...
+---
+name: ASubSMaxVec
+body: |
+ bb.0:
+ liveins: $q0
+
+ ; CHECK-LABEL: name: ASubSMaxVec
+ ; CHECK: liveins: $q0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(<4 x s32>) = COPY $q0
+ ; CHECK-NEXT: %c:_(s32) = G_CONSTANT i32 0
+ ; CHECK-NEXT: %c1:_(<4 x s32>) = G_BUILD_VECTOR %c(s32), %c(s32), %c(s32), %c(s32)
+ ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(<4 x s32>) = G_SUB %c1, %a
+ ; CHECK-NEXT: %sub2:_(<4 x s32>) = G_SMIN %a, [[SUB]]
+ ; CHECK-NEXT: $q0 = COPY %sub2(<4 x s32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %a:_(<4 x s32>) = COPY $q0
+ %c:_(s32) = G_CONSTANT i32 0
+ %c1:_(<4 x s32>) = G_BUILD_VECTOR %c(s32), %c(s32), %c(s32), %c(s32)
+ %sub1:_(<4 x s32>) = G_SUB %c1, %a
+ %max:_(<4 x s32>) = G_SMAX %a, %sub1
+ %sub2:_(<4 x s32>) = G_SUB %c1, %max
+ $q0 = COPY %sub2
+ RET_ReallyLR implicit $q0
+
...
---
name: ASubSMaxOneUse
@@ -77,6 +103,32 @@ body: |
$x0 = COPY %sub2
RET_ReallyLR implicit $x0
+...
+---
+name: ASubUMaxVec
+body: |
+ bb.0:
+ liveins: $q0
+
+ ; CHECK-LABEL: name: ASubUMaxVec
+ ; CHECK: liveins: $q0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %a:_(<4 x s32>) = COPY $q0
+ ; CHECK-NEXT: %c:_(s32) = G_CONSTANT i32 0
+ ; CHECK-NEXT: %c1:_(<4 x s32>) = G_BUILD_VECTOR %c(s32), %c(s32), %c(s32), %c(s32)
+ ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(<4 x s32>) = G_SUB %c1, %a
+ ; CHECK-NEXT: %sub2:_(<4 x s32>) = G_UMIN %a, [[SUB]]
+ ; CHECK-NEXT: $q0 = COPY %sub2(<4 x s32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %a:_(<4 x s32>) = COPY $q0
+ %c:_(s32) = G_CONSTANT i32 0
+ %c1:_(<4 x s32>) = G_BUILD_VECTOR %c(s32), %c(s32), %c(s32), %c(s32)
+ %sub1:_(<4 x s32>) = G_SUB %c1, %a
+ %max:_(<4 x s32>) = G_UMAX %a, %sub1
+ %sub2:_(<4 x s32>) = G_SUB %c1, %max
+ $q0 = COPY %sub2
+ RET_ReallyLR implicit $q0
+
...
---
name: ASubUMaxOneUse
>From 6b62057373e5230cbf48df2f510c87c239db0e83 Mon Sep 17 00:00:00 2001
From: luisacicolini <lc985 at cam.ac.uk>
Date: Tue, 9 Jun 2026 13:38:45 +0100
Subject: [PATCH 29/29] vec tests ll
---
.../AArch64/GlobalISel/combine-max-min.ll | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll b/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll
index 8eff477d34249..5c95996195f64 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-max-min.ll
@@ -4,6 +4,8 @@
declare i64 @llvm.smax.i64(i64, i64)
declare i64 @llvm.umax.i64(i64, i64)
+declare <4 x i32> @llvm.smax.v4i32(<4 x i32>, <4 x i32>)
+declare <4 x i32> @llvm.umax.v4i32(<4 x i32>, <4 x i32>)
; 0 - smax(a, 0 - a) -> smin(a, 0 - a) (i.e. -abs(a))
define i64 @ASubSMax(i64 %a) {
@@ -42,6 +44,19 @@ define i64 @ASubSMaxOneUse(i64 %a) {
ret i64 %mul
}
+; 0 - smax(a, 0 - a) -> smin(a, 0 - a) (i.e. -abs(a))
+define <4 x i32> @ASubSMaxVec(<4 x i32> %a) {
+; CHECK-LABEL: ASubSMaxVec:
+; CHECK: // %bb.0:
+; CHECK-NEXT: neg v1.4s, v0.4s
+; CHECK-NEXT: smin v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: ret
+ %sub1 = sub <4 x i32> zeroinitializer, %a
+ %max = call <4 x i32> @llvm.smax.v4i32(<4 x i32> %a, <4 x i32> %sub1)
+ %sub2 = sub <4 x i32> zeroinitializer, %max
+ ret <4 x i32> %sub2
+}
+
; 0 - umax(a, 0 - a) -> umin(a, 0 - a)
define i64 @ASubUMax(i64 %a) {
; CHECK-SD-LABEL: ASubUMax:
@@ -62,3 +77,16 @@ define i64 @ASubUMax(i64 %a) {
%sub2 = sub i64 0, %max
ret i64 %sub2
}
+
+; 0 - umax(a, 0 - a) -> umin(a, 0 - a)
+define <4 x i32> @ASubUMaxVec(<4 x i32> %a) {
+; CHECK-LABEL: ASubUMaxVec:
+; CHECK: // %bb.0:
+; CHECK-NEXT: neg v1.4s, v0.4s
+; CHECK-NEXT: umin v0.4s, v0.4s, v1.4s
+; CHECK-NEXT: ret
+ %sub1 = sub <4 x i32> zeroinitializer, %a
+ %max = call <4 x i32> @llvm.umax.v4i32(<4 x i32> %a, <4 x i32> %sub1)
+ %sub2 = sub <4 x i32> zeroinitializer, %max
+ ret <4 x i32> %sub2
+}
More information about the llvm-commits
mailing list