diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index c71870bc1b6569..35f4d7b3e53382 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,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), @@ -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; } diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll b/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll index 01dcedbdb658da..02fc4f3719167d 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll @@ -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) @@ -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) @@ -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 @@ -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 @@ -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 @@ -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 @@ -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: {{.*}}