[llvm] GlobalISel: neg (and x, 1) --> SIGN_EXTEND_INREG x, 1 (PR #131367)

Matthias Braun via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 17 11:12:55 PDT 2025


https://github.com/MatzeB updated https://github.com/llvm/llvm-project/pull/131367

>From d9a25546ac7aa9a7d719e584fb244de944a1fa8c Mon Sep 17 00:00:00 2001
From: Matthias Braun <matze at braunis.de>
Date: Fri, 14 Mar 2025 10:36:46 -0700
Subject: [PATCH 1/2] GlobalISel: neg (and x, 1)  -->  SIGN_EXTEND_INREG x, 1

---
 .../include/llvm/Target/GlobalISel/Combine.td | 12 ++++++++++-
 .../combine-neg-and-one-to-sext-inreg.mir     | 20 +++++++++++++++++++
 2 files changed, 31 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir

diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 3590ab221ad44..d43046ec5d282 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -747,6 +747,16 @@ def shl_ashr_to_sext_inreg : GICombineRule<
   (apply [{ Helper.applyAshShlToSextInreg(*${root}, ${info});}])
 >;
 
+// Fold sub 0, (and x, 1) -> sext_inreg x, 1
+def neg_and_one_to_sext_inreg : GICombineRule<
+  (defs root:$dst),
+  (match (G_AND $and, $x, 1),
+         (G_SUB $dst, 0, $and),
+         [{ return Helper.isLegalOrBeforeLegalizer(
+            {TargetOpcode::G_SEXT_INREG, {MRI.getType(${x}.getReg())}}); }]),
+  (apply (G_SEXT_INREG $dst, $x, 1))
+>;
+
 // Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0
 def overlapping_and: GICombineRule <
   (defs root:$root, build_fn_matchinfo:$info),
@@ -2013,7 +2023,7 @@ def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines,
     undef_combines, identity_combines, phi_combines,
     simplify_add_to_sub, hoist_logic_op_with_same_opcode_hands, shifts_too_big,
     reassocs, ptr_add_immed_chain, cmp_combines,
-    shl_ashr_to_sext_inreg, sext_inreg_of_load,
+    shl_ashr_to_sext_inreg, neg_and_one_to_sext_inreg, sext_inreg_of_load,
     width_reduction_combines, select_combines,
     known_bits_simplifications, trunc_shift,
     not_cmp_fold, opt_brcond_by_inverting_cond,
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir
new file mode 100644
index 0000000000000..aeb7ec3d9b9ee
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir
@@ -0,0 +1,20 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -o - -mtriple aarch64-- -run-pass=aarch64-prelegalizer-combiner %s | FileCheck %s
+---
+name: test_combine_neg_and_one_to_sext_inreg
+body: |
+  bb.1:
+  liveins: $w0
+    ; CHECK-LABEL: name: test_combine_neg_and_one_to_sext_inreg
+    ; CHECK: liveins: $w0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
+    ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(s32) = G_SEXT_INREG [[COPY]], 1
+    ; CHECK-NEXT: $w0 = COPY [[SEXT_INREG]](s32)
+    %0:_(s32) = COPY $w0
+    %1:_(s32) = G_CONSTANT i32 1
+    %3:_(s32) = G_CONSTANT i32 0
+    %2:_(s32) = G_AND %0:_, %1:_
+    %4:_(s32) = G_SUB %3:_, %2:_
+    $w0 = COPY %4:_(s32)
+...

>From 4ddc23d18a005b618e6d03d6b198b30e3e05f89e Mon Sep 17 00:00:00 2001
From: Matthias Braun <matze at braunis.de>
Date: Mon, 17 Mar 2025 10:59:46 -0700
Subject: [PATCH 2/2] address review comments

---
 .../include/llvm/Target/GlobalISel/Combine.td |  5 +-
 .../combine-neg-and-one-to-sext-inreg.mir     | 63 +++++++++++++++----
 .../combine-neg-and-one-to-sext-inreg.mir     | 22 +++++++
 3 files changed, 77 insertions(+), 13 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/GlobalISel/combine-neg-and-one-to-sext-inreg.mir

diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index d43046ec5d282..6d5f5f7d43703 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -752,8 +752,9 @@ def neg_and_one_to_sext_inreg : GICombineRule<
   (defs root:$dst),
   (match (G_AND $and, $x, 1),
          (G_SUB $dst, 0, $and),
-         [{ return Helper.isLegalOrBeforeLegalizer(
-            {TargetOpcode::G_SEXT_INREG, {MRI.getType(${x}.getReg())}}); }]),
+         [{ return MRI.hasOneNonDBGUse(${and}.getReg()) &&
+            Helper.isLegalOrBeforeLegalizer(
+              {TargetOpcode::G_SEXT_INREG, {MRI.getType(${x}.getReg())}}); }]),
   (apply (G_SEXT_INREG $dst, $x, 1))
 >;
 
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir
index aeb7ec3d9b9ee..b0d7de9b3f2d5 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-neg-and-one-to-sext-inreg.mir
@@ -1,20 +1,61 @@
 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
 # RUN: llc -o - -mtriple aarch64-- -run-pass=aarch64-prelegalizer-combiner %s | FileCheck %s
 ---
-name: test_combine_neg_and_one_to_sext_inreg
+name: test_combine_neg_and_one_to_sext_inreg_s32
 body: |
   bb.1:
   liveins: $w0
-    ; CHECK-LABEL: name: test_combine_neg_and_one_to_sext_inreg
+    ; CHECK-LABEL: name: test_combine_neg_and_one_to_sext_inreg_s32
     ; CHECK: liveins: $w0
     ; CHECK-NEXT: {{  $}}
-    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
-    ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(s32) = G_SEXT_INREG [[COPY]], 1
-    ; CHECK-NEXT: $w0 = COPY [[SEXT_INREG]](s32)
-    %0:_(s32) = COPY $w0
-    %1:_(s32) = G_CONSTANT i32 1
-    %3:_(s32) = G_CONSTANT i32 0
-    %2:_(s32) = G_AND %0:_, %1:_
-    %4:_(s32) = G_SUB %3:_, %2:_
-    $w0 = COPY %4:_(s32)
+    ; CHECK-NEXT: %x:_(s32) = COPY $w0
+    ; CHECK-NEXT: %res:_(s32) = G_SEXT_INREG %x, 1
+    ; CHECK-NEXT: $w0 = COPY %res(s32)
+    %x:_(s32) = COPY $w0
+    %one:_(s32) = G_CONSTANT i32 1
+    %zero:_(s32) = G_CONSTANT i32 0
+    %and:_(s32) = G_AND %x:_, %one:_
+    %res:_(s32) = G_SUB %zero:_, %and:_
+    $w0 = COPY %res:_(s32)
+...
+---
+name: test_combine_neg_and_one_to_sext_inreg_s64
+body: |
+  bb.1:
+  liveins: $x0
+    ; CHECK-LABEL: name: test_combine_neg_and_one_to_sext_inreg_s64
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s64) = COPY $x0
+    ; CHECK-NEXT: %res:_(s64) = G_SEXT_INREG %x, 1
+    ; CHECK-NEXT: $x0 = COPY %res(s64)
+    %x:_(s64) = COPY $x0
+    %one:_(s64) = G_CONSTANT i64 1
+    %zero:_(s64) = G_CONSTANT i64 0
+    %and:_(s64) = G_AND %x:_, %one:_
+    %res:_(s64) = G_SUB %zero:_, %and:_
+    $x0 = COPY %res:_(s64)
+...
+---
+name: test_combine_neg_and_one_to_sext_inreg_multiuse_should_not_transform
+body: |
+  bb.1:
+  liveins: $x0
+    ; CHECK-LABEL: name: test_combine_neg_and_one_to_sext_inreg_multiuse_should_not_transform
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(s64) = COPY $x0
+    ; CHECK-NEXT: %one:_(s64) = G_CONSTANT i64 1
+    ; CHECK-NEXT: %zero:_(s64) = G_CONSTANT i64 0
+    ; CHECK-NEXT: %and:_(s64) = G_AND %x, %one
+    ; CHECK-NEXT: %res:_(s64) = G_SUB %zero, %and
+    ; CHECK-NEXT: $x0 = COPY %res(s64)
+    ; CHECK-NEXT: $x1 = COPY %and(s64)
+    %x:_(s64) = COPY $x0
+    %one:_(s64) = G_CONSTANT i64 1
+    %zero:_(s64) = G_CONSTANT i64 0
+    %and:_(s64) = G_AND %x:_, %one:_
+    %res:_(s64) = G_SUB %zero:_, %and:_
+    $x0 = COPY %res:_(s64)
+    $x1 = COPY %and:_(s64)
 ...
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-neg-and-one-to-sext-inreg.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-neg-and-one-to-sext-inreg.mir
new file mode 100644
index 0000000000000..69c550e05591b
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/combine-neg-and-one-to-sext-inreg.mir
@@ -0,0 +1,22 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -o - -mtriple=amdgcn -run-pass=amdgpu-prelegalizer-combiner %s | FileCheck %s
+---
+name: test_combine_neg_and_one_to_sext_inreg_v2i32
+body: |
+  bb.1:
+  liveins: $vgpr0_vgpr1
+    ; CHECK-LABEL: name: test_combine_neg_and_one_to_sext_inreg_v2i32
+    ; CHECK: liveins: $vgpr0_vgpr1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %x:_(<2 x s32>) = COPY $vgpr0_vgpr1
+    ; CHECK-NEXT: %res:_(<2 x s32>) = G_SEXT_INREG %x, 1
+    ; CHECK-NEXT: $vgpr0_vgpr1 = COPY %res(<2 x s32>)
+    %x:_(<2 x s32>) = COPY $vgpr0_vgpr1
+    %one:_(s32) = G_CONSTANT i32 1
+    %ones:_(<2 x s32>) = G_BUILD_VECTOR %one, %one
+    %zero:_(s32) = G_CONSTANT i32 0
+    %zeros:_(<2 x s32>) = G_BUILD_VECTOR %zero, %zero
+    %and:_(<2 x s32>) = G_AND %x:_, %ones:_
+    %res:_(<2 x s32>) = G_SUB %zeros:_, %and:_
+    $vgpr0_vgpr1 = COPY %res:_(<2 x s32>)
+...



More information about the llvm-commits mailing list