summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYingwei Zheng <dtcxzyw2333@gmail.com>2024-04-16 17:16:35 +0800
committerGitHub <noreply@github.com>2024-04-16 17:16:35 +0800
commit80fce05f2104d1c42db814276130536b014fcca2 (patch)
tree4b01ef6fe1b11b5e8ac472b1cedbf6f92b8bd7de
parent485d556d8c23b54da952e75c3cadc9db3050fd9e (diff)
[InstCombine] Fold `minmax (X & NegPow2C, Y & NegPow2C) -> minmax(X, Y) & NegPow2C` (#88859)
Alive2: https://alive2.llvm.org/ce/z/NFtkSX This optimization will be beneficial to jemalloc users.
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp8
-rw-r--r--llvm/test/Transforms/InstCombine/minmax-intrinsics.ll89
2 files changed, 96 insertions, 1 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index bae8579fc365..ba5db854647a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1774,6 +1774,13 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (Instruction *I = moveAddAfterMinMax(II, Builder))
return I;
+ // minmax (X & NegPow2C, Y & NegPow2C) --> minmax(X, Y) & NegPow2C
+ const APInt *RHSC;
+ if (match(I0, m_OneUse(m_And(m_Value(X), m_NegatedPower2(RHSC)))) &&
+ match(I1, m_OneUse(m_And(m_Value(Y), m_SpecificInt(*RHSC)))))
+ return BinaryOperator::CreateAnd(Builder.CreateBinaryIntrinsic(IID, X, Y),
+ ConstantInt::get(II->getType(), *RHSC));
+
// smax(X, -X) --> abs(X)
// smin(X, -X) --> -abs(X)
// umax(X, -X) --> -abs(X)
@@ -1815,7 +1822,6 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
return NewMinMax;
// Try to fold minmax with constant RHS based on range information
- const APInt *RHSC;
if (match(I1, m_APIntAllowUndef(RHSC))) {
ICmpInst::Predicate Pred =
ICmpInst::getNonStrictPredicate(MinMaxIntrinsic::getPredicate(IID));
diff --git a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
index ae2e115b1dd9..bd1a47bbfcc1 100644
--- a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
@@ -2581,3 +2581,92 @@ entry:
%val = call i8 @llvm.umin.i8(i8 %sub, i8 3)
ret i8 %val
}
+
+define i8 @test_umax_and(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_umax_and(
+; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.umax.i8(i8 [[X1:%.*]], i8 [[Y1:%.*]])
+; CHECK-NEXT: [[RES1:%.*]] = and i8 [[RES]], -64
+; CHECK-NEXT: ret i8 [[RES1]]
+;
+ %x1 = and i8 %x, -64
+ %y1 = and i8 %y, -64
+ %res = call i8 @llvm.umax.i8(i8 %x1, i8 %y1)
+ ret i8 %res
+}
+
+define i8 @test_umin_and(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_umin_and(
+; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.umin.i8(i8 [[X1:%.*]], i8 [[Y1:%.*]])
+; CHECK-NEXT: [[RES1:%.*]] = and i8 [[RES]], -64
+; CHECK-NEXT: ret i8 [[RES1]]
+;
+ %x1 = and i8 %x, -64
+ %y1 = and i8 %y, -64
+ %res = call i8 @llvm.umin.i8(i8 %x1, i8 %y1)
+ ret i8 %res
+}
+
+define i8 @test_smax_and(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_smax_and(
+; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.smax.i8(i8 [[X1:%.*]], i8 [[Y1:%.*]])
+; CHECK-NEXT: [[RES1:%.*]] = and i8 [[RES]], -64
+; CHECK-NEXT: ret i8 [[RES1]]
+;
+ %x1 = and i8 %x, -64
+ %y1 = and i8 %y, -64
+ %res = call i8 @llvm.smax.i8(i8 %x1, i8 %y1)
+ ret i8 %res
+}
+
+define i8 @test_smin_and(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_smin_and(
+; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.smin.i8(i8 [[X1:%.*]], i8 [[Y1:%.*]])
+; CHECK-NEXT: [[RES1:%.*]] = and i8 [[RES]], -64
+; CHECK-NEXT: ret i8 [[RES1]]
+;
+ %x1 = and i8 %x, -64
+ %y1 = and i8 %y, -64
+ %res = call i8 @llvm.smin.i8(i8 %x1, i8 %y1)
+ ret i8 %res
+}
+
+define i8 @test_smin_and_mismatch(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_smin_and_mismatch(
+; CHECK-NEXT: [[X1:%.*]] = and i8 [[X:%.*]], -64
+; CHECK-NEXT: [[Y1:%.*]] = and i8 [[Y:%.*]], -32
+; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.smin.i8(i8 [[X1]], i8 [[Y1]])
+; CHECK-NEXT: ret i8 [[RES]]
+;
+ %x1 = and i8 %x, -64
+ %y1 = and i8 %y, -32
+ %res = call i8 @llvm.smin.i8(i8 %x1, i8 %y1)
+ ret i8 %res
+}
+
+define i8 @test_smin_and_non_negated_pow2(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_smin_and_non_negated_pow2(
+; CHECK-NEXT: [[X1:%.*]] = and i8 [[X:%.*]], 31
+; CHECK-NEXT: [[Y1:%.*]] = and i8 [[Y:%.*]], 31
+; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.smin.i8(i8 [[X1]], i8 [[Y1]])
+; CHECK-NEXT: ret i8 [[RES]]
+;
+ %x1 = and i8 %x, 31
+ %y1 = and i8 %y, 31
+ %res = call i8 @llvm.smin.i8(i8 %x1, i8 %y1)
+ ret i8 %res
+}
+
+define i8 @test_smin_and_multiuse(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_smin_and_multiuse(
+; CHECK-NEXT: [[X1:%.*]] = and i8 [[X:%.*]], 31
+; CHECK-NEXT: [[Y1:%.*]] = and i8 [[Y:%.*]], 31
+; CHECK-NEXT: call void @use(i8 [[Y1]])
+; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.smin.i8(i8 [[X1]], i8 [[Y1]])
+; CHECK-NEXT: ret i8 [[RES]]
+;
+ %x1 = and i8 %x, 31
+ %y1 = and i8 %y, 31
+ call void @use(i8 %y1)
+ %res = call i8 @llvm.smin.i8(i8 %x1, i8 %y1)
+ ret i8 %res
+}