[llvm] [CVP] Canonicalize signed minmax into unsigned (PR #82478)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 21 02:17:13 PST 2024
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/82478
This patch turns signed minmax to unsigned to match the behavior for signed icmps.
Alive2: https://alive2.llvm.org/ce/z/UAAM42
>From bdb0f4758791890a8085b892723f45d6573cec40 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 21 Feb 2024 17:23:29 +0800
Subject: [PATCH 1/2] [CVP] Add pre-commit tests. NFC.
---
.../CorrelatedValuePropagation/min-max.ll | 65 +++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll b/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll
index 705b6e96fe9e36..7176c0afec38c1 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll
@@ -235,3 +235,68 @@ define i8 @test19(i8 %x) {
%r = call i8 @llvm.smax(i8 %x, i8 42)
ret i8 %r
}
+
+define i8 @test_smax_to_umax_nneg(i8 %a, i8 %b) {
+; CHECK-LABEL: @test_smax_to_umax_nneg(
+; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
+; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
+; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
+; CHECK-NEXT: ret i8 [[RET]]
+;
+ %nneg_a = and i8 %a, 127
+ %nneg_b = and i8 %b, 127
+ %ret = call i8 @llvm.smax.i8(i8 %nneg_a, i8 %nneg_b)
+ ret i8 %ret
+}
+
+define i8 @test_smax_to_umax_neg(i8 %a, i8 %b) {
+; CHECK-LABEL: @test_smax_to_umax_neg(
+; CHECK-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
+; CHECK-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
+; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smax.i8(i8 [[NEG_A]], i8 [[NEG_B]])
+; CHECK-NEXT: ret i8 [[RET]]
+;
+ %neg_a = or i8 %a, 128
+ %neg_b = or i8 %b, 128
+ %ret = call i8 @llvm.smax.i8(i8 %neg_a, i8 %neg_b)
+ ret i8 %ret
+}
+
+define i8 @test_smin_to_umin_nneg(i8 %a, i8 %b) {
+; CHECK-LABEL: @test_smin_to_umin_nneg(
+; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
+; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
+; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smin.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
+; CHECK-NEXT: ret i8 [[RET]]
+;
+ %nneg_a = and i8 %a, 127
+ %nneg_b = and i8 %b, 127
+ %ret = call i8 @llvm.smin.i8(i8 %nneg_a, i8 %nneg_b)
+ ret i8 %ret
+}
+
+define i8 @test_smin_to_umin_neg(i8 %a, i8 %b) {
+; CHECK-LABEL: @test_smin_to_umin_neg(
+; CHECK-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
+; CHECK-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
+; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smin.i8(i8 [[NEG_A]], i8 [[NEG_B]])
+; CHECK-NEXT: ret i8 [[RET]]
+;
+ %neg_a = or i8 %a, 128
+ %neg_b = or i8 %b, 128
+ %ret = call i8 @llvm.smin.i8(i8 %neg_a, i8 %neg_b)
+ ret i8 %ret
+}
+
+define i8 @test_umax_nneg(i8 %a, i8 %b) {
+; CHECK-LABEL: @test_umax_nneg(
+; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
+; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
+; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.umax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
+; CHECK-NEXT: ret i8 [[RET]]
+;
+ %nneg_a = and i8 %a, 127
+ %nneg_b = and i8 %b, 127
+ %ret = call i8 @llvm.umax.i8(i8 %nneg_a, i8 %nneg_b)
+ ret i8 %ret
+}
>From fb070a0f3c5a6b19fa7b91bbbf4415c706a9e199 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 21 Feb 2024 17:41:23 +0800
Subject: [PATCH 2/2] [CVP] Canonicalize signed minmax into unsigned
---
.../Scalar/CorrelatedValuePropagation.cpp | 32 +++++++++++++++----
.../CorrelatedValuePropagation/min-max.ll | 26 +++++++--------
2 files changed, 39 insertions(+), 19 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index 9235850de92f3e..6b17d5ff050e14 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -90,6 +90,8 @@ STATISTIC(NumSaturating,
"Number of saturating arithmetics converted to normal arithmetics");
STATISTIC(NumNonNull, "Number of function pointer arguments marked non-null");
STATISTIC(NumMinMax, "Number of llvm.[us]{min,max} intrinsics removed");
+STATISTIC(NumSMinMax,
+ "Number of llvm.s{min,max} intrinsics simplified to unsigned");
STATISTIC(NumUDivURemsNarrowedExpanded,
"Number of bound udiv's/urem's expanded");
STATISTIC(NumZExt, "Number of non-negative deductions");
@@ -528,17 +530,35 @@ static bool processAbsIntrinsic(IntrinsicInst *II, LazyValueInfo *LVI) {
}
// See if this min/max intrinsic always picks it's one specific operand.
+// If not, check whether we can canonicalize signed minmax into unsigned version
static bool processMinMaxIntrinsic(MinMaxIntrinsic *MM, LazyValueInfo *LVI) {
CmpInst::Predicate Pred = CmpInst::getNonStrictPredicate(MM->getPredicate());
LazyValueInfo::Tristate Result = LVI->getPredicateAt(
Pred, MM->getLHS(), MM->getRHS(), MM, /*UseBlockValue=*/true);
- if (Result == LazyValueInfo::Unknown)
- return false;
+ if (Result != LazyValueInfo::Unknown) {
+ ++NumMinMax;
+ MM->replaceAllUsesWith(MM->getOperand(!Result));
+ MM->eraseFromParent();
+ return true;
+ }
- ++NumMinMax;
- MM->replaceAllUsesWith(MM->getOperand(!Result));
- MM->eraseFromParent();
- return true;
+ if (MM->isSigned() &&
+ ConstantRange::areInsensitiveToSignednessOfICmpPredicate(
+ LVI->getConstantRangeAtUse(MM->getOperandUse(0),
+ /*UndefAllowed*/ true),
+ LVI->getConstantRangeAtUse(MM->getOperandUse(1),
+ /*UndefAllowed*/ true))) {
+ ++NumSMinMax;
+ IRBuilder<> B(MM);
+ MM->replaceAllUsesWith(B.CreateBinaryIntrinsic(
+ MM->getIntrinsicID() == Intrinsic::smin ? Intrinsic::umin
+ : Intrinsic::umax,
+ MM->getLHS(), MM->getRHS()));
+ MM->eraseFromParent();
+ return true;
+ }
+
+ return false;
}
// Rewrite this with.overflow intrinsic as non-overflowing.
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll b/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll
index 7176c0afec38c1..fb14adcf7b61ba 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll
@@ -167,7 +167,7 @@ define i8 @test14(i8 %x) {
; CHECK-LABEL: @test14(
; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 42
; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 42)
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42)
; CHECK-NEXT: ret i8 42
;
%lim = icmp sge i8 %x, 42
@@ -179,8 +179,8 @@ define i8 @test15(i8 %x) {
; CHECK-LABEL: @test15(
; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 42)
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42)
+; CHECK-NEXT: ret i8 [[TMP1]]
;
%lim = icmp sge i8 %x, 41
call void @llvm.assume(i1 %lim)
@@ -192,8 +192,8 @@ define i8 @test16(i8 %x) {
; CHECK-LABEL: @test16(
; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]])
-; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 42)
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 42)
+; CHECK-NEXT: ret i8 [[TMP1]]
;
%lim = icmp sge i8 %x, 41
call void @llvm.assume(i1 %lim)
@@ -240,8 +240,8 @@ define i8 @test_smax_to_umax_nneg(i8 %a, i8 %b) {
; CHECK-LABEL: @test_smax_to_umax_nneg(
; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
-; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
-; CHECK-NEXT: ret i8 [[RET]]
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
+; CHECK-NEXT: ret i8 [[TMP1]]
;
%nneg_a = and i8 %a, 127
%nneg_b = and i8 %b, 127
@@ -253,8 +253,8 @@ define i8 @test_smax_to_umax_neg(i8 %a, i8 %b) {
; CHECK-LABEL: @test_smax_to_umax_neg(
; CHECK-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
; CHECK-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
-; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smax.i8(i8 [[NEG_A]], i8 [[NEG_B]])
-; CHECK-NEXT: ret i8 [[RET]]
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[NEG_A]], i8 [[NEG_B]])
+; CHECK-NEXT: ret i8 [[TMP1]]
;
%neg_a = or i8 %a, 128
%neg_b = or i8 %b, 128
@@ -266,8 +266,8 @@ define i8 @test_smin_to_umin_nneg(i8 %a, i8 %b) {
; CHECK-LABEL: @test_smin_to_umin_nneg(
; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
-; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smin.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
-; CHECK-NEXT: ret i8 [[RET]]
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
+; CHECK-NEXT: ret i8 [[TMP1]]
;
%nneg_a = and i8 %a, 127
%nneg_b = and i8 %b, 127
@@ -279,8 +279,8 @@ define i8 @test_smin_to_umin_neg(i8 %a, i8 %b) {
; CHECK-LABEL: @test_smin_to_umin_neg(
; CHECK-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
; CHECK-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
-; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smin.i8(i8 [[NEG_A]], i8 [[NEG_B]])
-; CHECK-NEXT: ret i8 [[RET]]
+; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[NEG_A]], i8 [[NEG_B]])
+; CHECK-NEXT: ret i8 [[TMP1]]
;
%neg_a = or i8 %a, 128
%neg_b = or i8 %b, 128
More information about the llvm-commits
mailing list