-
Notifications
You must be signed in to change notification settings - Fork 15k
[InstCombine] Fold select pattern with sub and negation to abs intrinsic #156246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-llvm-transforms Author: AZero13 (AZero13) Changes%sub = sub nsw T %x, %y
%cmp = icmp sgt T %x, %y ; or sge
%neg = sub T 0, %sub
%abs = select i1 %cmp, T %sub, T %neg becomes:| %sub = sub nsw T %x, %y
%abs = call T @<!-- -->llvm.abs.T(T %sub, i1 false) 0940842e61b4 Full diff: https://github.com/llvm/llvm-project/pull/156246.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index eb4332fbc0959..d75e34f90d469 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1153,6 +1153,15 @@ static Value *foldAbsDiff(ICmpInst *Cmp, Value *TVal, Value *FVal,
return Builder.CreateBinaryIntrinsic(Intrinsic::abs, TI, Builder.getTrue());
}
+ // Match: (A > B) ? (A - B) : (0 - (A - B)) --> abs(A - B)
+ // Recognize the pattern where we have sub, icmp, neg(sub), select
+ if (Pred == CmpInst::ICMP_SGT &&
+ match(TI, m_Sub(m_Specific(A), m_Specific(B))) &&
+ match(FI, m_Neg(m_Specific(TI))) &&
+ TI->hasNoSignedWrap()) {
+ return Builder.CreateBinaryIntrinsic(Intrinsic::abs, TI, Builder.getFalse());
+ }
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
index d32f0e4690502..b58038bbec7ad 100644
--- a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
+++ b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll
@@ -847,3 +847,74 @@ cond.end:
%r = phi i32 [ %0, %cond.true ], [ 0, %entry ]
ret i32 %r
}
+
+define i32 @abs_diff(i32 %x, i32 %y) {
+; CHECK-LABEL: @abs_diff(
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 false)
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %sub = sub nsw i32 %x, %y
+ %cmp = icmp sgt i32 %x, %y
+ %sub1 = sub i32 0, %sub
+ %cond = select i1 %cmp, i32 %sub, i32 %sub1
+ ret i32 %cond
+}
+
+define i32 @abs_diff_neg_no_nsw_neg(i32 %x, i32 %y) {
+; CHECK-LABEL: @abs_diff_neg_no_nsw_neg(
+; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], [[Y]]
+; CHECK-NEXT: [[SUB1:%.*]] = sub i32 0, [[SUB]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[SUB1]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %sub = sub i32 %x, %y
+ %cmp = icmp sgt i32 %x, %y
+ %sub1 = sub i32 0, %sub
+ %cond = select i1 %cmp, i32 %sub, i32 %sub1
+ ret i32 %cond
+}
+
+define i32 @abs_diff_neg(i32 %x, i32 %y) {
+; CHECK-LABEL: @abs_diff_neg(
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], [[Y]]
+; CHECK-NEXT: [[SUB1:%.*]] = sub i32 0, [[SUB]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[SUB1]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %sub = sub nsw i32 %y, %x
+ %cmp = icmp sgt i32 %x, %y
+ %sub1 = sub i32 0, %sub
+ %cond = select i1 %cmp, i32 %sub, i32 %sub1
+ ret i32 %cond
+}
+
+define i32 @abs_diff_neg_no_nsw(i32 %x, i32 %y) {
+; CHECK-LABEL: @abs_diff_neg_no_nsw(
+; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X]], [[Y]]
+; CHECK-NEXT: [[SUB1:%.*]] = sub i32 0, [[SUB]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[SUB1]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %sub = sub i32 %y, %x
+ %cmp = icmp sgt i32 %x, %y
+ %sub1 = sub i32 0, %sub
+ %cond = select i1 %cmp, i32 %sub, i32 %sub1
+ ret i32 %cond
+}
+
+define i32 @abs_diff_ge(i32 %x, i32 %y) {
+; CHECK-LABEL: @abs_diff_ge(
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.abs.i32(i32 [[SUB]], i1 false)
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %sub = sub nsw i32 %x, %y
+ %cmp = icmp sge i32 %x, %y
+ %sub1 = sub i32 0, %sub
+ %cond = select i1 %cmp, i32 %sub, i32 %sub1
+ ret i32 %cond
+}
|
You can test this locally with the following command:git-clang-format --diff origin/main HEAD --extensions cpp -- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
View the diff from clang-format here.diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 73a9f53bb..6d661c087 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1154,7 +1154,8 @@ static Value *foldAbsDiff(ICmpInst *Cmp, Value *TVal, Value *FVal,
}
// Match: (A > B) ? (A - B) : (0 - (A - B)) --> abs(A - B)
- // Also handles commuted cases like (B < A), (A >= B), (B <= A) after normalization
+ // Also handles commuted cases like (B < A), (A >= B), (B <= A) after
+ // normalization
if (Pred == CmpInst::ICMP_SGT &&
match(TI, m_NSWSub(m_Specific(A), m_Specific(B))) &&
match(FI, m_Neg(m_Specific(TI)))) {
@@ -1162,7 +1163,7 @@ static Value *foldAbsDiff(ICmpInst *Cmp, Value *TVal, Value *FVal,
Builder.getFalse());
}
- // Match: (A < B) ? (0 - (A - B)) : (A - B) --> abs(A - B)
+ // Match: (A < B) ? (0 - (A - B)) : (A - B) --> abs(A - B)
// This handles cases like (A <= B) after normalization
if (Pred == CmpInst::ICMP_SLT &&
match(TI, m_Neg(m_NSWSub(m_Specific(A), m_Specific(B)))) &&
|
@zyw-bot mfuzz |
This patch adds a new fold in InstCombine to recognize and optimize a common absolute value pattern. ```llvm %sub = sub nsw T %x, %y %cmp = icmp sgt T %x, %y ; or sge %neg = sub T 0, %sub %abs = select i1 %cmp, T %sub, T %neg ``` becomes:| ```llvm %sub = sub nsw T %x, %y %abs = call T @llvm.abs.T(T %sub, i1 false) ```
Missing fold for another variant: https://alive2.llvm.org/ce/z/gRTmZk |
becomes:
Alive2: https://alive2.llvm.org/ce/z/ApdJX8