[llvm] [GlobalISel] Fold Add Shift combine from SelectionDAG (PR #177371)
Osman Yasar via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 23 06:48:29 PST 2026
https://github.com/osmanyasar05 updated https://github.com/llvm/llvm-project/pull/177371
>From 50992d922a9a85fd2c582cb851505eebba717598 Mon Sep 17 00:00:00 2001
From: osmanyasar05 <osmanyas05 at gmail.com>
Date: Thu, 22 Jan 2026 14:17:55 +0000
Subject: [PATCH 1/3] [GlobalISel] Fold Add Shift combine from SelectionDAG
Co-authored-by: Sarah Kuhn <sarahlinhkuhn at gmail.com>
---
.../include/llvm/Target/GlobalISel/Combine.td | 23 ++++-
.../AArch64/GlobalISel/combine-add.mir | 83 +++++++++++++++++++
2 files changed, 105 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index a9b4932b2e317..704032f3a2652 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -1926,6 +1926,27 @@ def integer_reassoc_combines: GICombineGroup<[
AMinusC1PlusC2
]>;
+// fold (A+shl(0-B, C)) -> (A-shl(B, C))
+// fold (shl(0-B, C)+A) -> (A-shl(B, C))
+def add_shl_neg_frags : GICombinePatFrag<
+ (outs root:$dst), (ins $x, $y, $n),
+ [
+ (pattern (G_CONSTANT $zero, 0),
+ (G_SUB $neg_y, $zero, $y),
+ (G_SHL $shl_neg, $neg_y, $n),
+ (G_ADD $dst, $x, $shl_neg)),
+ (pattern (G_CONSTANT $zero, 0),
+ (G_SUB $neg_y, $zero, $y),
+ (G_SHL $shl_neg, $neg_y, $n),
+ (G_ADD $dst, $shl_neg, $x))
+ ]>;
+
+def add_shift : GICombineRule<
+ (defs root:$dst),
+ (match (add_shl_neg_frags $dst, $x, $y, $n)),
+ (apply (G_SHL $new_shl, $y, $n),
+ (G_SUB $dst, $x, $new_shl))>;
+
def freeze_of_non_undef_non_poison : GICombineRule<
(defs root:$root),
(match (G_FREEZE $root, $src),
@@ -2182,7 +2203,7 @@ def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines,
simplify_neg_minmax, combine_concat_vector,
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]>;
+ truncsat_combines, lshr_of_trunc_of_lshr, ctls_combines, add_shift]>;
// 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/test/CodeGen/AArch64/GlobalISel/combine-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir
index a0142afd06777..a6941d02f85db 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir
@@ -330,3 +330,86 @@ body: |
$q1 = COPY %6(<4 x s32>)
RET_ReallyLR implicit $q0, implicit $q1
...
+
+---
+name: add_shl_neg
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0, $w1, $w2
+
+ ; CHECK-LABEL: name: add_shl_neg
+ ; CHECK: liveins: $w0, $w1, $w2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2
+ ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY1]], [[COPY2]](s32)
+ ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY]], [[SHL]]
+ ; CHECK-NEXT: $w0 = COPY [[SUB]](s32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(s32) = COPY $w0
+ %1:_(s32) = COPY $w1
+ %2:_(s32) = COPY $w2
+ %3:_(s32) = G_CONSTANT i32 0
+ %4:_(s32) = G_SUB %3, %1
+ %5:_(s32) = G_SHL %4, %2
+ %6:_(s32) = G_ADD %0, %5
+ $w0 = COPY %6
+ RET_ReallyLR implicit $w0
+...
+
+---
+name: add_shl_neg_commuted
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0, $w1, $w2
+
+ ; CHECK-LABEL: name: add_shl_neg_commuted
+ ; CHECK: liveins: $w0, $w1, $w2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $w1
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $w2
+ ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(s32) = G_SHL [[COPY1]], [[COPY2]](s32)
+ ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[COPY]], [[SHL]]
+ ; CHECK-NEXT: $w0 = COPY [[SUB]](s32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %0:_(s32) = COPY $w0
+ %1:_(s32) = COPY $w1
+ %2:_(s32) = COPY $w2
+ %3:_(s32) = G_CONSTANT i32 0
+ %4:_(s32) = G_SUB %3, %1
+ %5:_(s32) = G_SHL %4, %2
+ %6:_(s32) = G_ADD %5, %0
+ $w0 = COPY %6
+ RET_ReallyLR implicit $w0
+...
+
+---
+name: add_shl_neg_wide
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $q0, $q1, $q2
+
+ ; CHECK-LABEL: name: add_shl_neg_wide
+ ; CHECK: liveins: $q0, $q1, $q2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s128) = COPY $q0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s128) = COPY $q1
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:_(s128) = COPY $q2
+ ; CHECK-NEXT: [[SHL:%[0-9]+]]:_(s128) = G_SHL [[COPY1]], [[COPY2]](s128)
+ ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s128) = G_SUB [[COPY]], [[SHL]]
+ ; CHECK-NEXT: $q0 = COPY [[SUB]](s128)
+ ; CHECK-NEXT: RET_ReallyLR implicit $q0
+ %0:_(s128) = COPY $q0
+ %1:_(s128) = COPY $q1
+ %2:_(s128) = COPY $q2
+ %3:_(s128) = G_CONSTANT i128 0
+ %4:_(s128) = G_SUB %3, %1
+ %5:_(s128) = G_SHL %4, %2
+ %6:_(s128) = G_ADD %0, %5
+ $q0 = COPY %6
+ RET_ReallyLR implicit $q0
>From 9e2ec8ac77f2591b90ae26f27b19f2f608605f3b Mon Sep 17 00:00:00 2001
From: Osman Yasar <37121924+osmanyasar05 at users.noreply.github.com>
Date: Thu, 22 Jan 2026 15:13:21 +0000
Subject: [PATCH 2/3] Update llvm/include/llvm/Target/GlobalISel/Combine.td
Co-authored-by: Luisa Cicolini <48860705+luisacicolini at users.noreply.github.com>
---
llvm/include/llvm/Target/GlobalISel/Combine.td | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 704032f3a2652..1298011aac868 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -1926,8 +1926,8 @@ def integer_reassoc_combines: GICombineGroup<[
AMinusC1PlusC2
]>;
-// fold (A+shl(0-B, C)) -> (A-shl(B, C))
-// fold (shl(0-B, C)+A) -> (A-shl(B, C))
+// fold (A+(shl (0-B), C)) -> (A-(shl B, C))
+// fold ((shl (0-B), C)+A) -> (A-(shl B, C))
def add_shl_neg_frags : GICombinePatFrag<
(outs root:$dst), (ins $x, $y, $n),
[
>From 7124732ad813311deb57923ff2504af9beb4a9bb Mon Sep 17 00:00:00 2001
From: osmanyasar05 <osmanyas05 at gmail.com>
Date: Fri, 23 Jan 2026 14:47:19 +0000
Subject: [PATCH 3/3] Add hasOneUse checks
---
.../include/llvm/Target/GlobalISel/Combine.td | 8 +++-
.../AArch64/GlobalISel/combine-add.mir | 37 +++++++++++++++++++
2 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 1298011aac868..28b9d7c5edb5c 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -1934,11 +1934,15 @@ def add_shl_neg_frags : GICombinePatFrag<
(pattern (G_CONSTANT $zero, 0),
(G_SUB $neg_y, $zero, $y),
(G_SHL $shl_neg, $neg_y, $n),
- (G_ADD $dst, $x, $shl_neg)),
+ (G_ADD $dst, $x, $shl_neg),
+ [{ return MRI.hasOneNonDBGUse(${shl_neg}.getReg()) &&
+ MRI.hasOneNonDBGUse(${neg_y}.getReg()); }]),
(pattern (G_CONSTANT $zero, 0),
(G_SUB $neg_y, $zero, $y),
(G_SHL $shl_neg, $neg_y, $n),
- (G_ADD $dst, $shl_neg, $x))
+ (G_ADD $dst, $shl_neg, $x),
+ [{ return MRI.hasOneNonDBGUse(${shl_neg}.getReg()) &&
+ MRI.hasOneNonDBGUse(${neg_y}.getReg()); }])
]>;
def add_shift : GICombineRule<
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir
index a6941d02f85db..a5a0623354745 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir
@@ -413,3 +413,40 @@ body: |
%6:_(s128) = G_ADD %0, %5
$q0 = COPY %6
RET_ReallyLR implicit $q0
+...
+
+---
+name: add_shl_neg_multiple_uses
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $x0, $x1, $x2, $x3
+
+ ; CHECK-LABEL: name: add_shl_neg_multiple_uses
+ ; CHECK: liveins: $x0, $x1, $x2, $x3
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %x:_(s64) = COPY $x0
+ ; CHECK-NEXT: %y:_(s64) = COPY $x1
+ ; CHECK-NEXT: %n:_(s64) = COPY $x2
+ ; CHECK-NEXT: %z:_(s64) = COPY $x3
+ ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: %neg_y:_(s64) = G_SUB %zero, %y
+ ; CHECK-NEXT: %shl_neg:_(s64) = G_SHL %neg_y, %n(s64)
+ ; CHECK-NEXT: %dst:_(s64) = G_ADD %x, %shl_neg
+ ; CHECK-NEXT: %other:_(s64) = G_MUL %shl_neg, %z
+ ; CHECK-NEXT: %mul:_(s64) = G_MUL %dst, %other
+ ; CHECK-NEXT: $x0 = COPY %mul(s64)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %x:_(s64) = COPY $x0
+ %y:_(s64) = COPY $x1
+ %n:_(s64) = COPY $x2
+ %z:_(s64) = COPY $x3
+ %zero:_(s64) = G_CONSTANT i64 0
+ %neg_y:_(s64) = G_SUB %zero, %y
+ %shl_neg:_(s64) = G_SHL %neg_y, %n
+ %dst:_(s64) = G_ADD %x, %shl_neg
+ %other:_(s64) = G_MUL %shl_neg, %z
+ %mul:_(s64) = G_MUL %dst, %other
+ $x0 = COPY %mul
+ RET_ReallyLR implicit $x0
+...
More information about the llvm-commits
mailing list