[llvm] [GlobalISel] Fold Add Shift combine from SelectionDAG (PR #177371)
Osman Yasar via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 22 06:33:47 PST 2026
https://github.com/osmanyasar05 created https://github.com/llvm/llvm-project/pull/177371
This PR adds the combine rule `fold (add x, shl(0 - y, n)) -> sub(x, shl(y, n))` to GlobalISel, corresponding to an existing SelectionDAG combine in [DAGCombiner::visitADDLikeCommutative](https://github.com/llvm/llvm-project/blame/fcba3040107944604904aeb146c26ec0628160f4/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp#L3367).
Co-authored-by: Sarah Kuhn <sarahlinhkuhn at gmail.com>
>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] [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
More information about the llvm-commits
mailing list