Skip to content

Commit 99ea2d5

Browse files
dtcxzywagozillon
authored andcommitted
[ConstraintElim] Simplify MinMaxIntrinsic (llvm#75306)
This patch replaces min/max intrinsic with one of its operands if possible. Alive2: https://alive2.llvm.org/ce/z/LoHfYf Fixes llvm#75155.
1 parent 69f98e6 commit 99ea2d5

File tree

2 files changed

+283
-0
lines changed

2 files changed

+283
-0
lines changed

llvm/lib/Transforms/Scalar/ConstraintElimination.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,9 @@ void State::addInfoFor(BasicBlock &BB) {
10651065
case Intrinsic::umax:
10661066
case Intrinsic::smin:
10671067
case Intrinsic::smax:
1068+
// TODO: handle llvm.abs as well
1069+
WorkList.push_back(
1070+
FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));
10681071
// TODO: Check if it is possible to instead only added the min/max facts
10691072
// when simplifying uses of the min/max intrinsics.
10701073
if (!isGuaranteedNotToBePoison(&I))
@@ -1395,6 +1398,26 @@ static bool checkAndReplaceCondition(
13951398
return false;
13961399
}
13971400

1401+
static bool checkAndReplaceMinMax(MinMaxIntrinsic *MinMax, ConstraintInfo &Info,
1402+
SmallVectorImpl<Instruction *> &ToRemove) {
1403+
auto ReplaceMinMaxWithOperand = [&](MinMaxIntrinsic *MinMax, bool UseLHS) {
1404+
// TODO: generate reproducer for min/max.
1405+
MinMax->replaceAllUsesWith(MinMax->getOperand(UseLHS ? 0 : 1));
1406+
ToRemove.push_back(MinMax);
1407+
return true;
1408+
};
1409+
1410+
ICmpInst::Predicate Pred =
1411+
ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
1412+
if (auto ImpliedCondition = checkCondition(
1413+
Pred, MinMax->getOperand(0), MinMax->getOperand(1), MinMax, Info))
1414+
return ReplaceMinMaxWithOperand(MinMax, *ImpliedCondition);
1415+
if (auto ImpliedCondition = checkCondition(
1416+
Pred, MinMax->getOperand(1), MinMax->getOperand(0), MinMax, Info))
1417+
return ReplaceMinMaxWithOperand(MinMax, !*ImpliedCondition);
1418+
return false;
1419+
}
1420+
13981421
static void
13991422
removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info,
14001423
Module *ReproducerModule,
@@ -1695,6 +1718,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
16951718
ReproducerCondStack, DFSInStack);
16961719
}
16971720
Changed |= Simplified;
1721+
} else if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(Inst)) {
1722+
Changed |= checkAndReplaceMinMax(MinMax, Info, ToRemove);
16981723
}
16991724
continue;
17001725
}

llvm/test/Transforms/ConstraintElimination/minmax.ll

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,264 @@ end:
343343
ret i32 0
344344
}
345345

346+
; Test from PR75155
347+
define i32 @simplify_slt_smax_val(i32 %a, i32 %b) {
348+
; CHECK-LABEL: define i32 @simplify_slt_smax_val
349+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
350+
; CHECK-NEXT: start:
351+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], [[B]]
352+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
353+
; CHECK: then:
354+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
355+
; CHECK-NEXT: ret i32 [[B]]
356+
; CHECK: else:
357+
; CHECK-NEXT: ret i32 -1
358+
;
359+
start:
360+
%cmp = icmp slt i32 %a, %b
361+
br i1 %cmp, label %then, label %else
362+
then:
363+
%add = add nsw i32 %a, 1
364+
%max = call i32 @llvm.smax.i32(i32 %b, i32 %add)
365+
ret i32 %max
366+
else:
367+
ret i32 -1
368+
}
369+
370+
define i32 @simplify_slt_smax_val_commuted(i32 %a, i32 %b) {
371+
; CHECK-LABEL: define i32 @simplify_slt_smax_val_commuted
372+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
373+
; CHECK-NEXT: start:
374+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], [[B]]
375+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
376+
; CHECK: then:
377+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
378+
; CHECK-NEXT: ret i32 [[B]]
379+
; CHECK: else:
380+
; CHECK-NEXT: ret i32 -1
381+
;
382+
start:
383+
%cmp = icmp slt i32 %a, %b
384+
br i1 %cmp, label %then, label %else
385+
then:
386+
%add = add nsw i32 %a, 1
387+
%max = call i32 @llvm.smax.i32(i32 %add, i32 %b)
388+
ret i32 %max
389+
else:
390+
ret i32 -1
391+
}
392+
393+
define i32 @simplify_slt_smax_val_at_use(i32 %a, i32 %b) {
394+
; CHECK-LABEL: define i32 @simplify_slt_smax_val_at_use
395+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
396+
; CHECK-NEXT: start:
397+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], [[B]]
398+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
399+
; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.smax.i32(i32 [[B]], i32 [[ADD]])
400+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
401+
; CHECK: then:
402+
; CHECK-NEXT: ret i32 [[MAX]]
403+
; CHECK: else:
404+
; CHECK-NEXT: ret i32 -1
405+
;
406+
start:
407+
%cmp = icmp slt i32 %a, %b
408+
%add = add nsw i32 %a, 1
409+
%max = call i32 @llvm.smax.i32(i32 %b, i32 %add)
410+
br i1 %cmp, label %then, label %else
411+
then:
412+
ret i32 %max
413+
else:
414+
ret i32 -1
415+
}
416+
417+
define i32 @simplify_sgt_smax_val(i32 %a, i32 %b) {
418+
; CHECK-LABEL: define i32 @simplify_sgt_smax_val
419+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
420+
; CHECK-NEXT: start:
421+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]]
422+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
423+
; CHECK: then:
424+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
425+
; CHECK-NEXT: ret i32 [[ADD]]
426+
; CHECK: else:
427+
; CHECK-NEXT: ret i32 -1
428+
;
429+
start:
430+
%cmp = icmp sgt i32 %a, %b
431+
br i1 %cmp, label %then, label %else
432+
then:
433+
%add = add nsw i32 %a, 1
434+
%max = call i32 @llvm.smax.i32(i32 %b, i32 %add)
435+
ret i32 %max
436+
else:
437+
ret i32 -1
438+
}
439+
440+
define i32 @simplify_sle_smax_val(i32 %a, i32 %b) {
441+
; CHECK-LABEL: define i32 @simplify_sle_smax_val
442+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
443+
; CHECK-NEXT: start:
444+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[A]], [[B]]
445+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
446+
; CHECK: then:
447+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
448+
; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.smax.i32(i32 [[B]], i32 [[ADD]])
449+
; CHECK-NEXT: ret i32 [[MAX]]
450+
; CHECK: else:
451+
; CHECK-NEXT: ret i32 -1
452+
;
453+
start:
454+
%cmp = icmp sle i32 %a, %b
455+
br i1 %cmp, label %then, label %else
456+
then:
457+
%add = add nsw i32 %a, 1
458+
%max = call i32 @llvm.smax.i32(i32 %b, i32 %add)
459+
ret i32 %max
460+
else:
461+
ret i32 -1
462+
}
463+
464+
define i32 @simplify_sge_smax_val(i32 %a, i32 %b) {
465+
; CHECK-LABEL: define i32 @simplify_sge_smax_val
466+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
467+
; CHECK-NEXT: start:
468+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[A]], [[B]]
469+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
470+
; CHECK: then:
471+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
472+
; CHECK-NEXT: ret i32 [[ADD]]
473+
; CHECK: else:
474+
; CHECK-NEXT: ret i32 -1
475+
;
476+
start:
477+
%cmp = icmp sge i32 %a, %b
478+
br i1 %cmp, label %then, label %else
479+
then:
480+
%add = add nsw i32 %a, 1
481+
%max = call i32 @llvm.smax.i32(i32 %b, i32 %add)
482+
ret i32 %max
483+
else:
484+
ret i32 -1
485+
}
486+
487+
define i32 @simplify_ult_umax_val(i32 %a, i32 %b) {
488+
; CHECK-LABEL: define i32 @simplify_ult_umax_val
489+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
490+
; CHECK-NEXT: start:
491+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A]], [[B]]
492+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
493+
; CHECK: then:
494+
; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[A]], 1
495+
; CHECK-NEXT: ret i32 [[B]]
496+
; CHECK: else:
497+
; CHECK-NEXT: ret i32 -1
498+
;
499+
start:
500+
%cmp = icmp ult i32 %a, %b
501+
br i1 %cmp, label %then, label %else
502+
then:
503+
%add = add nuw i32 %a, 1
504+
%max = call i32 @llvm.umax.i32(i32 %b, i32 %add)
505+
ret i32 %max
506+
else:
507+
ret i32 -1
508+
}
509+
510+
define i32 @simplify_slt_smin_val(i32 %a, i32 %b) {
511+
; CHECK-LABEL: define i32 @simplify_slt_smin_val
512+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
513+
; CHECK-NEXT: start:
514+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], [[B]]
515+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
516+
; CHECK: then:
517+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
518+
; CHECK-NEXT: ret i32 [[ADD]]
519+
; CHECK: else:
520+
; CHECK-NEXT: ret i32 -1
521+
;
522+
start:
523+
%cmp = icmp slt i32 %a, %b
524+
br i1 %cmp, label %then, label %else
525+
then:
526+
%add = add nsw i32 %a, 1
527+
%max = call i32 @llvm.smin.i32(i32 %b, i32 %add)
528+
ret i32 %max
529+
else:
530+
ret i32 -1
531+
}
532+
533+
define i32 @simplify_ult_umin_val(i32 %a, i32 %b) {
534+
; CHECK-LABEL: define i32 @simplify_ult_umin_val
535+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
536+
; CHECK-NEXT: start:
537+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A]], [[B]]
538+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
539+
; CHECK: then:
540+
; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[A]], 1
541+
; CHECK-NEXT: ret i32 [[ADD]]
542+
; CHECK: else:
543+
; CHECK-NEXT: ret i32 -1
544+
;
545+
start:
546+
%cmp = icmp ult i32 %a, %b
547+
br i1 %cmp, label %then, label %else
548+
then:
549+
%add = add nuw i32 %a, 1
550+
%max = call i32 @llvm.umin.i32(i32 %b, i32 %add)
551+
ret i32 %max
552+
else:
553+
ret i32 -1
554+
}
555+
556+
define i32 @simplify_slt_smax_val_fail1(i32 %a, i32 %b) {
557+
; CHECK-LABEL: define i32 @simplify_slt_smax_val_fail1
558+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
559+
; CHECK-NEXT: start:
560+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], [[B]]
561+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
562+
; CHECK: then:
563+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 2
564+
; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.smax.i32(i32 [[B]], i32 [[ADD]])
565+
; CHECK-NEXT: ret i32 [[MAX]]
566+
; CHECK: else:
567+
; CHECK-NEXT: ret i32 -1
568+
;
569+
start:
570+
%cmp = icmp slt i32 %a, %b
571+
br i1 %cmp, label %then, label %else
572+
then:
573+
%add = add nsw i32 %a, 2
574+
%max = call i32 @llvm.smax.i32(i32 %b, i32 %add)
575+
ret i32 %max
576+
else:
577+
ret i32 -1
578+
}
579+
580+
define i32 @simplify_ult_smax_val_fail2(i32 %a, i32 %b) {
581+
; CHECK-LABEL: define i32 @simplify_ult_smax_val_fail2
582+
; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
583+
; CHECK-NEXT: start:
584+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A]], [[B]]
585+
; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
586+
; CHECK: then:
587+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
588+
; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.smax.i32(i32 [[B]], i32 [[ADD]])
589+
; CHECK-NEXT: ret i32 [[MAX]]
590+
; CHECK: else:
591+
; CHECK-NEXT: ret i32 -1
592+
;
593+
start:
594+
%cmp = icmp ult i32 %a, %b
595+
br i1 %cmp, label %then, label %else
596+
then:
597+
%add = add nsw i32 %a, 1
598+
%max = call i32 @llvm.smax.i32(i32 %b, i32 %add)
599+
ret i32 %max
600+
else:
601+
ret i32 -1
602+
}
603+
346604
declare i32 @llvm.smin.i32(i32, i32)
347605
declare i32 @llvm.smax.i32(i32, i32)
348606
declare i32 @llvm.umin.i32(i32, i32)

0 commit comments

Comments
 (0)