Skip to content

Commit d3411f4

Browse files
committed
[CVP] Canonicalize signed minmax into unsigned
1 parent 66f7186 commit d3411f4

File tree

2 files changed

+87
-33
lines changed

2 files changed

+87
-33
lines changed

llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ STATISTIC(NumSaturating,
9090
"Number of saturating arithmetics converted to normal arithmetics");
9191
STATISTIC(NumNonNull, "Number of function pointer arguments marked non-null");
9292
STATISTIC(NumMinMax, "Number of llvm.[us]{min,max} intrinsics removed");
93+
STATISTIC(NumSMinMax,
94+
"Number of llvm.s{min,max} intrinsics simplified to unsigned");
9395
STATISTIC(NumUDivURemsNarrowedExpanded,
9496
"Number of bound udiv's/urem's expanded");
9597
STATISTIC(NumZExt, "Number of non-negative deductions");
@@ -528,6 +530,7 @@ static bool processAbsIntrinsic(IntrinsicInst *II, LazyValueInfo *LVI) {
528530
}
529531

530532
// See if this min/max intrinsic always picks it's one specific operand.
533+
// If not, check whether we can canonicalize signed minmax into unsigned version
531534
static bool processMinMaxIntrinsic(MinMaxIntrinsic *MM, LazyValueInfo *LVI) {
532535
CmpInst::Predicate Pred = CmpInst::getNonStrictPredicate(MM->getPredicate());
533536
ConstantRange LHS_CR = LVI->getConstantRangeAtUse(MM->getOperandUse(0),
@@ -546,6 +549,24 @@ static bool processMinMaxIntrinsic(MinMaxIntrinsic *MM, LazyValueInfo *LVI) {
546549
MM->eraseFromParent();
547550
return true;
548551
}
552+
553+
// To match the behavior of processICmp
554+
if (!CanonicalizeICmpPredicatesToUnsigned)
555+
return false;
556+
557+
if (MM->isSigned() &&
558+
ConstantRange::areInsensitiveToSignednessOfICmpPredicate(LHS_CR,
559+
RHS_CR)) {
560+
++NumSMinMax;
561+
IRBuilder<> B(MM);
562+
MM->replaceAllUsesWith(B.CreateBinaryIntrinsic(
563+
MM->getIntrinsicID() == Intrinsic::smin ? Intrinsic::umin
564+
: Intrinsic::umax,
565+
MM->getLHS(), MM->getRHS()));
566+
MM->eraseFromParent();
567+
return true;
568+
}
569+
549570
return false;
550571
}
551572

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

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,17 @@ define i8 @test14(i8 %x) {
174174
ret i8 %r
175175
}
176176
define i8 @test15(i8 %x) {
177-
; CHECK-LABEL: @test15(
178-
; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
179-
; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]])
180-
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 42)
181-
; CHECK-NEXT: ret i8 [[R]]
177+
; CHECK-CANONICALIZE-ON-LABEL: @test15(
178+
; CHECK-CANONICALIZE-ON-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
179+
; CHECK-CANONICALIZE-ON-NEXT: call void @llvm.assume(i1 [[LIM]])
180+
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42)
181+
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
182+
;
183+
; CHECK-CANONICALIZE-OFF-LABEL: @test15(
184+
; CHECK-CANONICALIZE-OFF-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
185+
; CHECK-CANONICALIZE-OFF-NEXT: call void @llvm.assume(i1 [[LIM]])
186+
; CHECK-CANONICALIZE-OFF-NEXT: [[R:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 42)
187+
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[R]]
182188
;
183189
%lim = icmp sge i8 %x, 41
184190
call void @llvm.assume(i1 %lim)
@@ -187,11 +193,17 @@ define i8 @test15(i8 %x) {
187193
}
188194

189195
define i8 @test16(i8 %x) {
190-
; CHECK-LABEL: @test16(
191-
; CHECK-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
192-
; CHECK-NEXT: call void @llvm.assume(i1 [[LIM]])
193-
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 42)
194-
; CHECK-NEXT: ret i8 [[R]]
196+
; CHECK-CANONICALIZE-ON-LABEL: @test16(
197+
; CHECK-CANONICALIZE-ON-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
198+
; CHECK-CANONICALIZE-ON-NEXT: call void @llvm.assume(i1 [[LIM]])
199+
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 42)
200+
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
201+
;
202+
; CHECK-CANONICALIZE-OFF-LABEL: @test16(
203+
; CHECK-CANONICALIZE-OFF-NEXT: [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 41
204+
; CHECK-CANONICALIZE-OFF-NEXT: call void @llvm.assume(i1 [[LIM]])
205+
; CHECK-CANONICALIZE-OFF-NEXT: [[R:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 42)
206+
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[R]]
195207
;
196208
%lim = icmp sge i8 %x, 41
197209
call void @llvm.assume(i1 %lim)
@@ -293,11 +305,17 @@ if.end:
293305
}
294306

295307
define i8 @test_smax_to_umax_nneg(i8 %a, i8 %b) {
296-
; CHECK-LABEL: @test_smax_to_umax_nneg(
297-
; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
298-
; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
299-
; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
300-
; CHECK-NEXT: ret i8 [[RET]]
308+
; CHECK-CANONICALIZE-ON-LABEL: @test_smax_to_umax_nneg(
309+
; CHECK-CANONICALIZE-ON-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
310+
; CHECK-CANONICALIZE-ON-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
311+
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
312+
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
313+
;
314+
; CHECK-CANONICALIZE-OFF-LABEL: @test_smax_to_umax_nneg(
315+
; CHECK-CANONICALIZE-OFF-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
316+
; CHECK-CANONICALIZE-OFF-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
317+
; CHECK-CANONICALIZE-OFF-NEXT: [[RET:%.*]] = call i8 @llvm.smax.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
318+
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[RET]]
301319
;
302320
%nneg_a = and i8 %a, 127
303321
%nneg_b = and i8 %b, 127
@@ -306,11 +324,17 @@ define i8 @test_smax_to_umax_nneg(i8 %a, i8 %b) {
306324
}
307325

308326
define i8 @test_smax_to_umax_neg(i8 %a, i8 %b) {
309-
; CHECK-LABEL: @test_smax_to_umax_neg(
310-
; CHECK-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
311-
; CHECK-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
312-
; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smax.i8(i8 [[NEG_A]], i8 [[NEG_B]])
313-
; CHECK-NEXT: ret i8 [[RET]]
327+
; CHECK-CANONICALIZE-ON-LABEL: @test_smax_to_umax_neg(
328+
; CHECK-CANONICALIZE-ON-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
329+
; CHECK-CANONICALIZE-ON-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
330+
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[NEG_A]], i8 [[NEG_B]])
331+
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
332+
;
333+
; CHECK-CANONICALIZE-OFF-LABEL: @test_smax_to_umax_neg(
334+
; CHECK-CANONICALIZE-OFF-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
335+
; CHECK-CANONICALIZE-OFF-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
336+
; CHECK-CANONICALIZE-OFF-NEXT: [[RET:%.*]] = call i8 @llvm.smax.i8(i8 [[NEG_A]], i8 [[NEG_B]])
337+
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[RET]]
314338
;
315339
%neg_a = or i8 %a, 128
316340
%neg_b = or i8 %b, 128
@@ -319,11 +343,17 @@ define i8 @test_smax_to_umax_neg(i8 %a, i8 %b) {
319343
}
320344

321345
define i8 @test_smin_to_umin_nneg(i8 %a, i8 %b) {
322-
; CHECK-LABEL: @test_smin_to_umin_nneg(
323-
; CHECK-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
324-
; CHECK-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
325-
; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smin.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
326-
; CHECK-NEXT: ret i8 [[RET]]
346+
; CHECK-CANONICALIZE-ON-LABEL: @test_smin_to_umin_nneg(
347+
; CHECK-CANONICALIZE-ON-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
348+
; CHECK-CANONICALIZE-ON-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
349+
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
350+
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
351+
;
352+
; CHECK-CANONICALIZE-OFF-LABEL: @test_smin_to_umin_nneg(
353+
; CHECK-CANONICALIZE-OFF-NEXT: [[NNEG_A:%.*]] = and i8 [[A:%.*]], 127
354+
; CHECK-CANONICALIZE-OFF-NEXT: [[NNEG_B:%.*]] = and i8 [[B:%.*]], 127
355+
; CHECK-CANONICALIZE-OFF-NEXT: [[RET:%.*]] = call i8 @llvm.smin.i8(i8 [[NNEG_A]], i8 [[NNEG_B]])
356+
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[RET]]
327357
;
328358
%nneg_a = and i8 %a, 127
329359
%nneg_b = and i8 %b, 127
@@ -332,11 +362,17 @@ define i8 @test_smin_to_umin_nneg(i8 %a, i8 %b) {
332362
}
333363

334364
define i8 @test_smin_to_umin_neg(i8 %a, i8 %b) {
335-
; CHECK-LABEL: @test_smin_to_umin_neg(
336-
; CHECK-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
337-
; CHECK-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
338-
; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.smin.i8(i8 [[NEG_A]], i8 [[NEG_B]])
339-
; CHECK-NEXT: ret i8 [[RET]]
365+
; CHECK-CANONICALIZE-ON-LABEL: @test_smin_to_umin_neg(
366+
; CHECK-CANONICALIZE-ON-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
367+
; CHECK-CANONICALIZE-ON-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
368+
; CHECK-CANONICALIZE-ON-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[NEG_A]], i8 [[NEG_B]])
369+
; CHECK-CANONICALIZE-ON-NEXT: ret i8 [[TMP1]]
370+
;
371+
; CHECK-CANONICALIZE-OFF-LABEL: @test_smin_to_umin_neg(
372+
; CHECK-CANONICALIZE-OFF-NEXT: [[NEG_A:%.*]] = or i8 [[A:%.*]], -128
373+
; CHECK-CANONICALIZE-OFF-NEXT: [[NEG_B:%.*]] = or i8 [[B:%.*]], -128
374+
; CHECK-CANONICALIZE-OFF-NEXT: [[RET:%.*]] = call i8 @llvm.smin.i8(i8 [[NEG_A]], i8 [[NEG_B]])
375+
; CHECK-CANONICALIZE-OFF-NEXT: ret i8 [[RET]]
340376
;
341377
%neg_a = or i8 %a, 128
342378
%neg_b = or i8 %b, 128
@@ -356,6 +392,3 @@ define i8 @test_umax_nneg(i8 %a, i8 %b) {
356392
%ret = call i8 @llvm.umax.i8(i8 %nneg_a, i8 %nneg_b)
357393
ret i8 %ret
358394
}
359-
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
360-
; CHECK-CANONICALIZE-OFF: {{.*}}
361-
; CHECK-CANONICALIZE-ON: {{.*}}

0 commit comments

Comments
 (0)