[llvm] [InstCombine] Fold minmax intrinsic using KnownBits information (PR #76242)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Fri Dec 22 11:00:36 PST 2023
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/76242
>From bd763f6ad7ba39a31e3074ed314c8ff866d3195a Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 23 Dec 2023 02:56:58 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC.
---
.../InstCombine/minmax-intrinsics.ll | 102 ++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
index f3833a420ee835..818e6a3c5baf74 100644
--- a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
@@ -2489,3 +2489,105 @@ define i1 @PR57986() {
%umin = call i1 @llvm.umin.i1(i1 ptrtoint (ptr @g to i1), i1 true)
ret i1 %umin
}
+
+define i8 @fold_umax_with_knownbits_info(i8 %a, i8 %b) {
+; CHECK-LABEL: @fold_umax_with_knownbits_info(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A1:%.*]] = or i8 [[A:%.*]], 1
+; CHECK-NEXT: [[A2:%.*]] = shl i8 [[B:%.*]], 1
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[A1]], [[A2]]
+; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[SUB]], i8 1)
+; CHECK-NEXT: ret i8 [[VAL]]
+;
+entry:
+ %a1 = or i8 %a, 1
+ %a2 = shl i8 %b, 1
+ %sub = sub i8 %a1, %a2
+ %val = call i8 @llvm.umax.i8(i8 %sub, i8 1)
+ ret i8 %val
+}
+
+define <3 x i8> @fold_umax_with_knownbits_info_undef_in_splat(<3 x i8> %a, <3 x i8> %b) {
+; CHECK-LABEL: @fold_umax_with_knownbits_info_undef_in_splat(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A1:%.*]] = or <3 x i8> [[A:%.*]], <i8 1, i8 1, i8 1>
+; CHECK-NEXT: [[A2:%.*]] = shl <3 x i8> [[B:%.*]], <i8 1, i8 1, i8 1>
+; CHECK-NEXT: [[SUB:%.*]] = sub <3 x i8> [[A1]], [[A2]]
+; CHECK-NEXT: [[VAL:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[SUB]], <3 x i8> <i8 1, i8 undef, i8 1>)
+; CHECK-NEXT: ret <3 x i8> [[VAL]]
+;
+entry:
+ %a1 = or <3 x i8> %a, <i8 1, i8 1, i8 1>
+ %a2 = shl <3 x i8> %b, <i8 1, i8 1, i8 1>
+ %sub = sub <3 x i8> %a1, %a2
+ %val = call <3 x i8> @llvm.umax.v3i8(<3 x i8> %sub, <3 x i8> <i8 1, i8 undef, i8 1>)
+ ret <3 x i8> %val
+}
+
+define i8 @fold_umin_with_knownbits_info(i8 %a, i8 %b) {
+; CHECK-LABEL: @fold_umin_with_knownbits_info(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A1:%.*]] = or i8 [[A:%.*]], 3
+; CHECK-NEXT: [[A2:%.*]] = shl i8 [[B:%.*]], 2
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[A1]], [[A2]]
+; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[SUB]], i8 3)
+; CHECK-NEXT: ret i8 [[VAL]]
+;
+entry:
+ %a1 = or i8 %a, 3
+ %a2 = shl i8 %b, 2
+ %sub = sub i8 %a1, %a2
+ %val = call i8 @llvm.umin.i8(i8 %sub, i8 3)
+ ret i8 %val
+}
+
+define <3 x i8> @fold_umin_with_knownbits_info_undef_in_splat(<3 x i8> %a, <3 x i8> %b) {
+; CHECK-LABEL: @fold_umin_with_knownbits_info_undef_in_splat(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A1:%.*]] = or <3 x i8> [[A:%.*]], <i8 3, i8 3, i8 3>
+; CHECK-NEXT: [[A2:%.*]] = shl <3 x i8> [[B:%.*]], <i8 2, i8 2, i8 2>
+; CHECK-NEXT: [[SUB:%.*]] = sub <3 x i8> [[A1]], [[A2]]
+; CHECK-NEXT: [[VAL:%.*]] = call <3 x i8> @llvm.umin.v3i8(<3 x i8> [[SUB]], <3 x i8> <i8 3, i8 undef, i8 3>)
+; CHECK-NEXT: ret <3 x i8> [[VAL]]
+;
+entry:
+ %a1 = or <3 x i8> %a, <i8 3, i8 3, i8 3>
+ %a2 = shl <3 x i8> %b, <i8 2, i8 2, i8 2>
+ %sub = sub <3 x i8> %a1, %a2
+ %val = call <3 x i8> @llvm.umin.v3i8(<3 x i8> %sub, <3 x i8> <i8 3, i8 undef, i8 3>)
+ ret <3 x i8> %val
+}
+
+define i8 @fold_umax_with_knownbits_info_fail(i8 %a, i8 %b) {
+; CHECK-LABEL: @fold_umax_with_knownbits_info_fail(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A1:%.*]] = or i8 [[A:%.*]], 2
+; CHECK-NEXT: [[A2:%.*]] = shl i8 [[B:%.*]], 1
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[A1]], [[A2]]
+; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[SUB]], i8 1)
+; CHECK-NEXT: ret i8 [[VAL]]
+;
+entry:
+ %a1 = or i8 %a, 2
+ %a2 = shl i8 %b, 1
+ %sub = sub i8 %a1, %a2
+ %val = call i8 @llvm.umax.i8(i8 %sub, i8 1)
+ ret i8 %val
+}
+
+define i8 @fold_umin_with_knownbits_info_fail(i8 %a, i8 %b) {
+; CHECK-LABEL: @fold_umin_with_knownbits_info_fail(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A1:%.*]] = or i8 [[A:%.*]], 1
+; CHECK-NEXT: [[A2:%.*]] = shl i8 [[B:%.*]], 2
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[A1]], [[A2]]
+; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[SUB]], i8 3)
+; CHECK-NEXT: ret i8 [[VAL]]
+;
+entry:
+ %a1 = or i8 %a, 1
+ %a2 = shl i8 %b, 2
+ %sub = sub i8 %a1, %a2
+ %val = call i8 @llvm.umin.i8(i8 %sub, i8 3)
+ ret i8 %val
+}
>From 17005732870d47b8ee8281342767b29a1d15aff5 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 23 Dec 2023 02:58:37 +0800
Subject: [PATCH 2/2] [InstCombine] Fold minmax intrinsic using KnownBits
information
---
llvm/include/llvm/Analysis/ValueTracking.h | 5 +++++
llvm/lib/Analysis/ValueTracking.cpp | 8 ++++----
.../InstCombine/InstCombineCalls.cpp | 17 +++++++++++++++++
.../InstCombine/minmax-intrinsics.ll | 18 ++++--------------
4 files changed, 30 insertions(+), 18 deletions(-)
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index a3186e61b94adf..baa16306ebf5df 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -863,6 +863,11 @@ ConstantRange computeConstantRange(const Value *V, bool ForSigned,
const DominatorTree *DT = nullptr,
unsigned Depth = 0);
+/// Combine constant ranges from computeConstantRange() and computeKnownBits().
+ConstantRange
+computeConstantRangeIncludingKnownBits(const WithCache<const Value *> &V,
+ bool ForSigned, const SimplifyQuery &SQ);
+
/// Return true if this function can prove that the instruction I will
/// always transfer execution to one of its successors (including the next
/// instruction that follows within a basic block). E.g. this is not
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 769d921eb1e8d1..cac2602d455f9d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -6289,10 +6289,10 @@ static OverflowResult mapOverflowResult(ConstantRange::OverflowResult OR) {
}
/// Combine constant ranges from computeConstantRange() and computeKnownBits().
-static ConstantRange
-computeConstantRangeIncludingKnownBits(const WithCache<const Value *> &V,
- bool ForSigned,
- const SimplifyQuery &SQ) {
+ConstantRange
+llvm::computeConstantRangeIncludingKnownBits(const WithCache<const Value *> &V,
+ bool ForSigned,
+ const SimplifyQuery &SQ) {
ConstantRange CR1 =
ConstantRange::fromKnownBits(V.getKnownBits(SQ), ForSigned);
ConstantRange CR2 = computeConstantRange(V, ForSigned, SQ.IIQ.UseInstrInfo);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index a272357fa04a41..202c87123746ba 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -1796,6 +1796,23 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (Instruction *NewMinMax = factorizeMinMaxTree(II))
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));
+ bool IsSigned = MinMaxIntrinsic::isSigned(IID);
+ const auto LHS_CR = llvm::computeConstantRangeIncludingKnownBits(
+ I0, IsSigned, SQ.getWithInstruction(II));
+ if (!LHS_CR.isFullSet()) {
+ if (LHS_CR.icmp(Pred, *RHSC))
+ return replaceInstUsesWith(*II, I0);
+ if (LHS_CR.icmp(ICmpInst::getSwappedPredicate(Pred), *RHSC))
+ return replaceInstUsesWith(*II,
+ ConstantInt::get(II->getType(), *RHSC));
+ }
+ }
+
break;
}
case Intrinsic::bitreverse: {
diff --git a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
index 818e6a3c5baf74..ae2e115b1dd9a2 100644
--- a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
@@ -2496,8 +2496,7 @@ define i8 @fold_umax_with_knownbits_info(i8 %a, i8 %b) {
; CHECK-NEXT: [[A1:%.*]] = or i8 [[A:%.*]], 1
; CHECK-NEXT: [[A2:%.*]] = shl i8 [[B:%.*]], 1
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[A1]], [[A2]]
-; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umax.i8(i8 [[SUB]], i8 1)
-; CHECK-NEXT: ret i8 [[VAL]]
+; CHECK-NEXT: ret i8 [[SUB]]
;
entry:
%a1 = or i8 %a, 1
@@ -2513,8 +2512,7 @@ define <3 x i8> @fold_umax_with_knownbits_info_undef_in_splat(<3 x i8> %a, <3 x
; CHECK-NEXT: [[A1:%.*]] = or <3 x i8> [[A:%.*]], <i8 1, i8 1, i8 1>
; CHECK-NEXT: [[A2:%.*]] = shl <3 x i8> [[B:%.*]], <i8 1, i8 1, i8 1>
; CHECK-NEXT: [[SUB:%.*]] = sub <3 x i8> [[A1]], [[A2]]
-; CHECK-NEXT: [[VAL:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[SUB]], <3 x i8> <i8 1, i8 undef, i8 1>)
-; CHECK-NEXT: ret <3 x i8> [[VAL]]
+; CHECK-NEXT: ret <3 x i8> [[SUB]]
;
entry:
%a1 = or <3 x i8> %a, <i8 1, i8 1, i8 1>
@@ -2527,11 +2525,7 @@ entry:
define i8 @fold_umin_with_knownbits_info(i8 %a, i8 %b) {
; CHECK-LABEL: @fold_umin_with_knownbits_info(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[A1:%.*]] = or i8 [[A:%.*]], 3
-; CHECK-NEXT: [[A2:%.*]] = shl i8 [[B:%.*]], 2
-; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[A1]], [[A2]]
-; CHECK-NEXT: [[VAL:%.*]] = call i8 @llvm.umin.i8(i8 [[SUB]], i8 3)
-; CHECK-NEXT: ret i8 [[VAL]]
+; CHECK-NEXT: ret i8 3
;
entry:
%a1 = or i8 %a, 3
@@ -2544,11 +2538,7 @@ entry:
define <3 x i8> @fold_umin_with_knownbits_info_undef_in_splat(<3 x i8> %a, <3 x i8> %b) {
; CHECK-LABEL: @fold_umin_with_knownbits_info_undef_in_splat(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[A1:%.*]] = or <3 x i8> [[A:%.*]], <i8 3, i8 3, i8 3>
-; CHECK-NEXT: [[A2:%.*]] = shl <3 x i8> [[B:%.*]], <i8 2, i8 2, i8 2>
-; CHECK-NEXT: [[SUB:%.*]] = sub <3 x i8> [[A1]], [[A2]]
-; CHECK-NEXT: [[VAL:%.*]] = call <3 x i8> @llvm.umin.v3i8(<3 x i8> [[SUB]], <3 x i8> <i8 3, i8 undef, i8 3>)
-; CHECK-NEXT: ret <3 x i8> [[VAL]]
+; CHECK-NEXT: ret <3 x i8> <i8 3, i8 3, i8 3>
;
entry:
%a1 = or <3 x i8> %a, <i8 3, i8 3, i8 3>
More information about the llvm-commits
mailing list