Skip to content

Commit cc83927

Browse files
authored
[CVP] Canonicalize signed minmax into unsigned (#82478)
This patch turns signed minmax to unsigned to match the behavior for signed icmps. Alive2: https://alive2.llvm.org/ce/z/UAAM42
1 parent 5c24c31 commit cc83927

File tree

2 files changed

+86
-12
lines changed

2 files changed

+86
-12
lines changed

llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,6 @@ using namespace llvm;
4747

4848
#define DEBUG_TYPE "correlated-value-propagation"
4949

50-
static cl::opt<bool> CanonicalizeICmpPredicatesToUnsigned(
51-
"canonicalize-icmp-predicates-to-unsigned", cl::init(true), cl::Hidden,
52-
cl::desc("Enables canonicalization of signed relational predicates to "
53-
"unsigned (e.g. sgt => ugt)"));
54-
5550
STATISTIC(NumPhis, "Number of phis propagated");
5651
STATISTIC(NumPhiCommon, "Number of phis deleted via common incoming value");
5752
STATISTIC(NumSelects, "Number of selects propagated");
@@ -90,6 +85,8 @@ STATISTIC(NumSaturating,
9085
"Number of saturating arithmetics converted to normal arithmetics");
9186
STATISTIC(NumNonNull, "Number of function pointer arguments marked non-null");
9287
STATISTIC(NumMinMax, "Number of llvm.[us]{min,max} intrinsics removed");
88+
STATISTIC(NumSMinMax,
89+
"Number of llvm.s{min,max} intrinsics simplified to unsigned");
9390
STATISTIC(NumUDivURemsNarrowedExpanded,
9491
"Number of bound udiv's/urem's expanded");
9592
STATISTIC(NumZExt, "Number of non-negative deductions");
@@ -289,9 +286,6 @@ static bool processPHI(PHINode *P, LazyValueInfo *LVI, DominatorTree *DT,
289286
}
290287

291288
static bool processICmp(ICmpInst *Cmp, LazyValueInfo *LVI) {
292-
if (!CanonicalizeICmpPredicatesToUnsigned)
293-
return false;
294-
295289
// Only for signed relational comparisons of scalar integers.
296290
if (Cmp->getType()->isVectorTy() ||
297291
!Cmp->getOperand(0)->getType()->isIntegerTy())
@@ -528,6 +522,7 @@ static bool processAbsIntrinsic(IntrinsicInst *II, LazyValueInfo *LVI) {
528522
}
529523

530524
// See if this min/max intrinsic always picks it's one specific operand.
525+
// If not, check whether we can canonicalize signed minmax into unsigned version
531526
static bool processMinMaxIntrinsic(MinMaxIntrinsic *MM, LazyValueInfo *LVI) {
532527
CmpInst::Predicate Pred = CmpInst::getNonStrictPredicate(MM->getPredicate());
533528
ConstantRange LHS_CR = LVI->getConstantRangeAtUse(MM->getOperandUse(0),
@@ -546,6 +541,20 @@ static bool processMinMaxIntrinsic(MinMaxIntrinsic *MM, LazyValueInfo *LVI) {
546541
MM->eraseFromParent();
547542
return true;
548543
}
544+
545+
if (MM->isSigned() &&
546+
ConstantRange::areInsensitiveToSignednessOfICmpPredicate(LHS_CR,
547+
RHS_CR)) {
548+
++NumSMinMax;
549+
IRBuilder<> B(MM);
550+
MM->replaceAllUsesWith(B.CreateBinaryIntrinsic(
551+
MM->getIntrinsicID() == Intrinsic::smin ? Intrinsic::umin
552+
: Intrinsic::umax,
553+
MM->getLHS(), MM->getRHS()));
554+
MM->eraseFromParent();
555+
return true;
556+
}
557+
549558
return false;
550559
}
551560

llvm/test/Transforms/CorrelatedValuePropagation/min-max.ll

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ define i8 @test15(i8 %x) {
176176
; CHECK-LABEL: @test15(
177177
; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
178178
; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]])
179-
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 42)
180-
; CHECK-NEXT: ret i8 [[R]]
179+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42)
180+
; CHECK-NEXT: ret i8 [[TMP1]]
181181
;
182182
%lim = icmp sge i8 %x, 41
183183
call void @llvm.assume(i1 %lim)
@@ -189,8 +189,8 @@ define i8 @test16(i8 %x) {
189189
; CHECK-LABEL: @test16(
190190
; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
191191
; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]])
192-
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 42)
193-
; CHECK-NEXT: ret i8 [[R]]
192+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 42)
193+
; CHECK-NEXT: ret i8 [[TMP1]]
194194
;
195195
%lim = icmp sge i8 %x, 41
196196
call void @llvm.assume(i1 %lim)
@@ -290,3 +290,68 @@ if.end:
290290
%phi = phi i64 [%val, %bb1], [0, %entry]
291291
ret i64 %phi
292292
}
293+
294+
define i8 @test_smax_to_umax_nneg(i8 %a, i8 %b) {
295+
; CHECK-LABEL: @test_smax_to_umax_nneg(
296+
; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
297+
; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
298+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
299+
; CHECK-NEXT: ret i8 [[TMP1]]
300+
;
301+
%nneg_a = and i8 %a, 127
302+
%nneg_b = and i8 %b, 127
303+
%ret = call i8 @llvm.smax.i8(i8 %nneg_a, i8 %nneg_b)
304+
ret i8 %ret
305+
}
306+
307+
define i8 @test_smax_to_umax_neg(i8 %a, i8 %b) {
308+
; CHECK-LABEL: @test_smax_to_umax_neg(
309+
; CHECK-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
310+
; CHECK-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
311+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[NEG_A]], i8 [[NEG_B]])
312+
; CHECK-NEXT: ret i8 [[TMP1]]
313+
;
314+
%neg_a = or i8 %a, 128
315+
%neg_b = or i8 %b, 128
316+
%ret = call i8 @llvm.smax.i8(i8 %neg_a, i8 %neg_b)
317+
ret i8 %ret
318+
}
319+
320+
define i8 @test_smin_to_umin_nneg(i8 %a, i8 %b) {
321+
; CHECK-LABEL: @test_smin_to_umin_nneg(
322+
; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
323+
; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
324+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
325+
; CHECK-NEXT: ret i8 [[TMP1]]
326+
;
327+
%nneg_a = and i8 %a, 127
328+
%nneg_b = and i8 %b, 127
329+
%ret = call i8 @llvm.smin.i8(i8 %nneg_a, i8 %nneg_b)
330+
ret i8 %ret
331+
}
332+
333+
define i8 @test_smin_to_umin_neg(i8 %a, i8 %b) {
334+
; CHECK-LABEL: @test_smin_to_umin_neg(
335+
; CHECK-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
336+
; CHECK-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
337+
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[NEG_A]], i8 [[NEG_B]])
338+
; CHECK-NEXT: ret i8 [[TMP1]]
339+
;
340+
%neg_a = or i8 %a, 128
341+
%neg_b = or i8 %b, 128
342+
%ret = call i8 @llvm.smin.i8(i8 %neg_a, i8 %neg_b)
343+
ret i8 %ret
344+
}
345+
346+
define i8 @test_umax_nneg(i8 %a, i8 %b) {
347+
; CHECK-LABEL: @test_umax_nneg(
348+
; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
349+
; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
350+
; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.umax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
351+
; CHECK-NEXT: ret i8 [[RET]]
352+
;
353+
%nneg_a = and i8 %a, 127
354+
%nneg_b = and i8 %b, 127
355+
%ret = call i8 @llvm.umax.i8(i8 %nneg_a, i8 %nneg_b)
356+
ret i8 %ret
357+
}

0 commit comments

Comments
 (0)