[llvm] goldsteinn/subnuw xor simp (PR #122552)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 10 15:50:29 PST 2025
https://github.com/goldsteinn created https://github.com/llvm/llvm-project/pull/122552
- **[InstSimpify] Add tests for simplifying `(xor (sub C_Mask, X), C_Mask)`; NFC**
- **[InstSimpify] Simplifying `(xor (sub C_Mask, X), C_Mask)` -> `X`**
>From 62adb8958aa7cc54fdfe3779ad5ae9c18c262ccd Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 10 Jan 2025 17:47:12 -0600
Subject: [PATCH 1/2] [InstSimpify] Add tests for simplifying `(xor (sub
C_Mask, X), C_Mask)`; NFC
---
.../InstSimplify/subnuw-with-xor.ll | 122 ++++++++++++++++++
1 file changed, 122 insertions(+)
create mode 100644 llvm/test/Transforms/InstSimplify/subnuw-with-xor.ll
diff --git a/llvm/test/Transforms/InstSimplify/subnuw-with-xor.ll b/llvm/test/Transforms/InstSimplify/subnuw-with-xor.ll
new file mode 100644
index 00000000000000..c6175cd8dd0ce3
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/subnuw-with-xor.ll
@@ -0,0 +1,122 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+define i8 @xor_w_sub_fail_missing_nuw(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @xor_w_sub_fail_missing_nuw(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 15
+; CHECK-NEXT: [[R:%.*]] = sub nsw i8 15, [[XOR]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %xor = xor i8 %x, 15
+ %r = sub nsw i8 15, %xor
+ ret i8 %r
+}
+
+define i8 @xor_w_sub_fail_diff_values(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @xor_w_sub_fail_diff_values(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 15
+; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i8 31, [[XOR]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %xor = xor i8 %x, 15
+ %r = sub nsw nuw i8 31, %xor
+ ret i8 %r
+}
+
+define i8 @xor_w_sub_fail_diff_values2(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @xor_w_sub_fail_diff_values2(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 31
+; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i8 15, [[XOR]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %xor = xor i8 %x, 31
+ %r = sub nsw nuw i8 15, %xor
+ ret i8 %r
+}
+
+define i8 @xor_w_sub_fail_not_mask(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @xor_w_sub_fail_not_mask(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 30
+; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i8 30, [[XOR]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %xor = xor i8 %x, 30
+ %r = sub nsw nuw i8 30, %xor
+ ret i8 %r
+}
+
+define i8 @xor_w_sub_okay(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @xor_w_sub_okay(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 31
+; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i8 31, [[XOR]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %xor = xor i8 %x, 31
+ %r = sub nsw nuw i8 31, %xor
+ ret i8 %r
+}
+
+define i8 @sub_w_xor_fail_missing_nuw(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @sub_w_xor_fail_missing_nuw(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i8 15, [[X]]
+; CHECK-NEXT: [[R:%.*]] = xor i8 [[SUB]], 15
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub nsw i8 15, %x
+ %r = xor i8 %sub, 15
+ ret i8 %r
+}
+
+define i8 @sub_w_xor_fail_diff_values(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @sub_w_xor_fail_diff_values(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i8 15, [[X]]
+; CHECK-NEXT: [[R:%.*]] = xor i8 [[SUB]], 31
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub nsw nuw i8 15, %x
+ %r = xor i8 %sub, 31
+ ret i8 %r
+}
+
+define i8 @sub_w_sub_fail_diff_values2(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @sub_w_sub_fail_diff_values2(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i8 31, [[X]]
+; CHECK-NEXT: [[R:%.*]] = xor i8 [[SUB]], 15
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub nsw nuw i8 31, %x
+ %r = xor i8 %sub, 15
+ ret i8 %r
+}
+
+define i8 @sub_w_sub_fail_not_mask(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @sub_w_sub_fail_not_mask(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i8 30, [[X]]
+; CHECK-NEXT: [[R:%.*]] = xor i8 [[SUB]], 30
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub nsw nuw i8 30, %x
+ %r = xor i8 %sub, 30
+ ret i8 %r
+}
+
+define i8 @sub_w_sub_okay(i8 range(i8 0, 16) %x) {
+; CHECK-LABEL: define i8 @sub_w_sub_okay(
+; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
+; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i8 31, [[X]]
+; CHECK-NEXT: [[R:%.*]] = xor i8 [[SUB]], 31
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %sub = sub nsw nuw i8 31, %x
+ %r = xor i8 %sub, 31
+ ret i8 %r
+}
>From 59160414cef226cdb80eeb5080f9a7582f9ebee2 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 10 Jan 2025 17:47:14 -0600
Subject: [PATCH 2/2] [InstSimpify] Simplifying `(xor (sub C_Mask, X), C_Mask)`
-> `X`
Helps address regressions with folding `clz(Pow2)`.
Proof: https://alive2.llvm.org/ce/z/zGwUBp
---
llvm/lib/Analysis/InstructionSimplify.cpp | 16 ++++++++++++++++
.../Transforms/InstSimplify/subnuw-with-xor.ll | 8 ++------
2 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 999386c0a04917..ef9454fd9c9ab2 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -871,6 +871,14 @@ static Value *simplifySubInst(Value *Op0, Value *Op1, bool IsNSW, bool IsNUW,
if (Value *V = simplifyByDomEq(Instruction::Sub, Op0, Op1, Q, MaxRecurse))
return V;
+ // (sub nuw C_Mask, (xor X, C_Mask)) -> X
+ if (IsNUW) {
+ Value *X;
+ if (match(Op1, m_Xor(m_Value(X), m_Specific(Op0))) &&
+ match(Op0, m_CheckedInt([](const APInt &C) { return C.isMask(); })))
+ return X;
+ }
+
return nullptr;
}
@@ -2540,6 +2548,14 @@ static Value *simplifyXorInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
if (Value *V = simplifyByDomEq(Instruction::Xor, Op0, Op1, Q, MaxRecurse))
return V;
+ // (xor (sub nuw C_Mask, X), C_Mask) -> X
+ {
+ Value *X;
+ if (match(Op0, m_NUWSub(m_Specific(Op1), m_Value(X))) &&
+ match(Op1, m_CheckedInt([](const APInt &C) { return C.isMask(); })))
+ return X;
+ }
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstSimplify/subnuw-with-xor.ll b/llvm/test/Transforms/InstSimplify/subnuw-with-xor.ll
index c6175cd8dd0ce3..a990e2f2ae394e 100644
--- a/llvm/test/Transforms/InstSimplify/subnuw-with-xor.ll
+++ b/llvm/test/Transforms/InstSimplify/subnuw-with-xor.ll
@@ -52,9 +52,7 @@ define i8 @xor_w_sub_fail_not_mask(i8 range(i8 0, 16) %x) {
define i8 @xor_w_sub_okay(i8 range(i8 0, 16) %x) {
; CHECK-LABEL: define i8 @xor_w_sub_okay(
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
-; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X]], 31
-; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i8 31, [[XOR]]
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 [[X]]
;
%xor = xor i8 %x, 31
%r = sub nsw nuw i8 31, %xor
@@ -112,9 +110,7 @@ define i8 @sub_w_sub_fail_not_mask(i8 range(i8 0, 16) %x) {
define i8 @sub_w_sub_okay(i8 range(i8 0, 16) %x) {
; CHECK-LABEL: define i8 @sub_w_sub_okay(
; CHECK-SAME: i8 range(i8 0, 16) [[X:%.*]]) {
-; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i8 31, [[X]]
-; CHECK-NEXT: [[R:%.*]] = xor i8 [[SUB]], 31
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 [[X]]
;
%sub = sub nsw nuw i8 31, %x
%r = xor i8 %sub, 31
More information about the llvm-commits
mailing list