Skip to content

Commit

Permalink
[CVP] Canonicalize signed minmax into unsigned
Browse files Browse the repository at this point in the history
  • Loading branch information
dtcxzyw committed Feb 22, 2024
1 parent 66f7186 commit d3411f4
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 33 deletions.
21 changes: 21 additions & 0 deletions llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -528,6 +530,7 @@ 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());
ConstantRange LHS_CR = LVI->getConstantRangeAtUse(MM->getOperandUse(0),
Expand All @@ -546,6 +549,24 @@ static bool processMinMaxIntrinsic(MinMaxIntrinsic *MM, LazyValueInfo *LVI) {
MM->eraseFromParent();
return true;
}

// To match the behavior of processICmp
if (!CanonicalizeICmpPredicatesToUnsigned)
return false;

if (MM->isSigned() &&
ConstantRange::areInsensitiveToSignednessOfICmpPredicate(LHS_CR,
RHS_CR)) {
++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;
}

Expand Down
99 changes: 66 additions & 33 deletions llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,17 @@ define i8 @test14(i8 %x) {
ret i8 %r
}
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-CANONICALIZE-ON-LABEL: @test15(
; CHECK-CANONICALIZE-ON-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
; CHECK-CANONICALIZE-ON-NEXT: call void @llvm.assume(i1 [[LIM]])
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42)
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
;
; CHECK-CANONICALIZE-OFF-LABEL: @test15(
; CHECK-CANONICALIZE-OFF-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
; CHECK-CANONICALIZE-OFF-NEXT: call void @llvm.assume(i1 [[LIM]])
; CHECK-CANONICALIZE-OFF-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 42)
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[R]]
;
%lim = icmp sge i8 %x, 41
call void @llvm.assume(i1 %lim)
Expand All @@ -187,11 +193,17 @@ define i8 @test15(i8 %x) {
}

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-CANONICALIZE-ON-LABEL: @test16(
; CHECK-CANONICALIZE-ON-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
; CHECK-CANONICALIZE-ON-NEXT: call void @llvm.assume(i1 [[LIM]])
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 42)
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
;
; CHECK-CANONICALIZE-OFF-LABEL: @test16(
; CHECK-CANONICALIZE-OFF-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
; CHECK-CANONICALIZE-OFF-NEXT: call void @llvm.assume(i1 [[LIM]])
; CHECK-CANONICALIZE-OFF-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 42)
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[R]]
;
%lim = icmp sge i8 %x, 41
call void @llvm.assume(i1 %lim)
Expand Down Expand Up @@ -293,11 +305,17 @@ if.end:
}

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-CANONICALIZE-ON-LABEL: @test_smax_to_umax_nneg(
; CHECK-CANONICALIZE-ON-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
; CHECK-CANONICALIZE-ON-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
;
; CHECK-CANONICALIZE-OFF-LABEL: @test_smax_to_umax_nneg(
; CHECK-CANONICALIZE-OFF-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
; CHECK-CANONICALIZE-OFF-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
; CHECK-CANONICALIZE-OFF-NEXT: [[RET:%.*]] = call i8 @llvm.smax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[RET]]
;
%nneg_a = and i8 %a, 127
%nneg_b = and i8 %b, 127
Expand All @@ -306,11 +324,17 @@ define i8 @test_smax_to_umax_nneg(i8 %a, i8 %b) {
}

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-CANONICALIZE-ON-LABEL: @test_smax_to_umax_neg(
; CHECK-CANONICALIZE-ON-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
; CHECK-CANONICALIZE-ON-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[NEG_A]], i8 [[NEG_B]])
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
;
; CHECK-CANONICALIZE-OFF-LABEL: @test_smax_to_umax_neg(
; CHECK-CANONICALIZE-OFF-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
; CHECK-CANONICALIZE-OFF-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
; CHECK-CANONICALIZE-OFF-NEXT: [[RET:%.*]] = call i8 @llvm.smax.i8(i8 [[NEG_A]], i8 [[NEG_B]])
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[RET]]
;
%neg_a = or i8 %a, 128
%neg_b = or i8 %b, 128
Expand All @@ -319,11 +343,17 @@ define i8 @test_smax_to_umax_neg(i8 %a, i8 %b) {
}

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-CANONICALIZE-ON-LABEL: @test_smin_to_umin_nneg(
; CHECK-CANONICALIZE-ON-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
; CHECK-CANONICALIZE-ON-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
;
; CHECK-CANONICALIZE-OFF-LABEL: @test_smin_to_umin_nneg(
; CHECK-CANONICALIZE-OFF-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
; CHECK-CANONICALIZE-OFF-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
; CHECK-CANONICALIZE-OFF-NEXT: [[RET:%.*]] = call i8 @llvm.smin.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[RET]]
;
%nneg_a = and i8 %a, 127
%nneg_b = and i8 %b, 127
Expand All @@ -332,11 +362,17 @@ define i8 @test_smin_to_umin_nneg(i8 %a, i8 %b) {
}

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-CANONICALIZE-ON-LABEL: @test_smin_to_umin_neg(
; CHECK-CANONICALIZE-ON-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
; CHECK-CANONICALIZE-ON-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[NEG_A]], i8 [[NEG_B]])
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
;
; CHECK-CANONICALIZE-OFF-LABEL: @test_smin_to_umin_neg(
; CHECK-CANONICALIZE-OFF-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
; CHECK-CANONICALIZE-OFF-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
; CHECK-CANONICALIZE-OFF-NEXT: [[RET:%.*]] = call i8 @llvm.smin.i8(i8 [[NEG_A]], i8 [[NEG_B]])
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[RET]]
;
%neg_a = or i8 %a, 128
%neg_b = or i8 %b, 128
Expand All @@ -356,6 +392,3 @@ define i8 @test_umax_nneg(i8 %a, i8 %b) {
%ret = call i8 @llvm.umax.i8(i8 %nneg_a, i8 %nneg_b)
ret i8 %ret
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK-CANONICALIZE-OFF: {{.*}}
; CHECK-CANONICALIZE-ON: {{.*}}

0 comments on commit d3411f4

Please sign in to comment.