llvm.org GIT mirror llvm / 17bb71c
[InstCombine] matchThreeWayIntCompare(): commutativity awareness Summary: `matchThreeWayIntCompare()` looks for ``` select i1 (a == b), i32 Equal, i32 (select i1 (a < b), i32 Less, i32 Greater) ``` but both of these selects/compares can be in it's commuted form, so out of 8 variants, only the two most basic ones is handled. This fixes regression being introduced in D66232. Reviewers: spatel, nikic, efriedma, xbolva00 Reviewed By: spatel Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D66607 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369841 91177308-0d34-0410-b5e6-96231b3b80d8 Roman Lebedev 28 days ago
2 changed file(s) with 75 addition(s) and 74 deletion(s). Raw diff Collapse all Expand all
25612561 // TODO: Generalize this to work with other comparison idioms or ensure
25622562 // they get canonicalized into this form.
25632563
2564 // select i1 (a == b), i32 Equal, i32 (select i1 (a < b), i32 Less, i32
2565 // Greater), where Equal, Less and Greater are placeholders for any three
2566 // constants.
2567 ICmpInst::Predicate PredA, PredB;
2568 if (match(SI->getTrueValue(), m_ConstantInt(Equal)) &&
2569 match(SI->getCondition(), m_ICmp(PredA, m_Value(LHS), m_Value(RHS))) &&
2570 PredA == ICmpInst::ICMP_EQ &&
2571 match(SI->getFalseValue(),
2572 m_Select(m_ICmp(PredB, m_Specific(LHS), m_Specific(RHS)),
2573 m_ConstantInt(Less), m_ConstantInt(Greater))) &&
2574 PredB == ICmpInst::ICMP_SLT) {
2575 return true;
2576 }
2577 return false;
2564 // select i1 (a == b),
2565 // i32 Equal,
2566 // i32 (select i1 (a < b), i32 Less, i32 Greater)
2567 // where Equal, Less and Greater are placeholders for any three constants.
2568 ICmpInst::Predicate PredA;
2569 if (!match(SI->getCondition(), m_ICmp(PredA, m_Value(LHS), m_Value(RHS))) ||
2570 !ICmpInst::isEquality(PredA))
2571 return false;
2572 Value *EqualVal = SI->getTrueValue();
2573 Value *UnequalVal = SI->getFalseValue();
2574 // We still can get non-canonical predicate here, so canonicalize.
2575 if (PredA == ICmpInst::ICMP_NE)
2576 std::swap(EqualVal, UnequalVal);
2577 if (!match(EqualVal, m_ConstantInt(Equal)))
2578 return false;
2579 ICmpInst::Predicate PredB;
2580 Value *LHS2, *RHS2;
2581 if (!match(UnequalVal, m_Select(m_ICmp(PredB, m_Value(LHS2), m_Value(RHS2)),
2582 m_ConstantInt(Less), m_ConstantInt(Greater))))
2583 return false;
2584 // We can get predicate mismatch here, so canonicalize if possible:
2585 // First, ensure that 'LHS' match.
2586 if (LHS2 != LHS) {
2587 // x sgt y <--> y slt x
2588 std::swap(LHS2, RHS2);
2589 PredB = ICmpInst::getSwappedPredicate(PredB);
2590 }
2591 if (LHS2 != LHS)
2592 return false;
2593 // We also need to canonicalize 'RHS'.
2594 if (PredB == ICmpInst::ICMP_SGT && isa(RHS2)) {
2595 // x sgt C-1 <--> x sge C <--> not(x slt C)
2596 auto FlippedStrictness =
2597 getFlippedStrictnessPredicateAndConstant(PredB, cast(RHS2));
2598 if (!FlippedStrictness)
2599 return false;
2600 assert(FlippedStrictness->first == ICmpInst::ICMP_SGE && "Sanity check");
2601 RHS2 = FlippedStrictness->second;
2602 // And kind-of perform the result swap.
2603 std::swap(Less, Greater);
2604 PredB = ICmpInst::ICMP_SLT;
2605 }
2606 return PredB == ICmpInst::ICMP_SLT && RHS == RHS2;
25782607 }
25792608
25802609 Instruction *InstCombiner::foldICmpSelectConstant(ICmpInst &Cmp,
3535 define i32 @compare_against_zero(i32 %x) {
3636 ; CHECK-LABEL: @compare_against_zero(
3737 ; CHECK-NEXT: entry:
38 ; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[X:%.*]], 0
39 ; CHECK-NEXT: [[CMP2_INV:%.*]] = icmp sgt i32 [[X]], -1
40 ; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[CMP2_INV]], i32 1, i32 -1
41 ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP1]], i32 0, i32 [[SELECT1]]
42 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SELECT2]], 0
43 ; CHECK-NEXT: br i1 [[COND]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
44 ; CHECK: callfoo:
45 ; CHECK-NEXT: call void @foo(i32 [[SELECT2]])
38 ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 0
39 ; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
40 ; CHECK: callfoo:
41 ; CHECK-NEXT: call void @foo(i32 1)
4642 ; CHECK-NEXT: br label [[EXIT]]
4743 ; CHECK: exit:
4844 ; CHECK-NEXT: ret i32 42
9591 define i32 @compare_against_two(i32 %x) {
9692 ; CHECK-LABEL: @compare_against_two(
9793 ; CHECK-NEXT: entry:
98 ; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[X:%.*]], 2
99 ; CHECK-NEXT: [[CMP2_INV:%.*]] = icmp sgt i32 [[X]], 1
100 ; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[CMP2_INV]], i32 1, i32 -1
101 ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP1]], i32 0, i32 [[SELECT1]]
102 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SELECT2]], 0
103 ; CHECK-NEXT: br i1 [[COND]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
104 ; CHECK: callfoo:
105 ; CHECK-NEXT: call void @foo(i32 [[SELECT2]])
94 ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 2
95 ; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
96 ; CHECK: callfoo:
97 ; CHECK-NEXT: call void @foo(i32 1)
10698 ; CHECK-NEXT: br label [[EXIT]]
10799 ; CHECK: exit:
108100 ; CHECK-NEXT: ret i32 42
496488 ; CHECK-NEXT: entry:
497489 ; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X:%.*]], 42
498490 ; CHECK-NEXT: call void @use1(i1 [[CMP1]])
499 ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], 42
500 ; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[CMP2]], i32 -1, i32 1
501 ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP1]], i32 [[SELECT1]], i32 0
502 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SELECT2]], 0
503 ; CHECK-NEXT: br i1 [[COND]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
504 ; CHECK: callfoo:
505 ; CHECK-NEXT: call void @foo(i32 [[SELECT2]])
491 ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X]], 42
492 ; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
493 ; CHECK: callfoo:
494 ; CHECK-NEXT: call void @foo(i32 1)
506495 ; CHECK-NEXT: br label [[EXIT]]
507496 ; CHECK: exit:
508497 ; CHECK-NEXT: ret i32 84
526515 define i32 @compare_against_fortytwo_commutatibility_2(i32 %x) {
527516 ; CHECK-LABEL: @compare_against_fortytwo_commutatibility_2(
528517 ; CHECK-NEXT: entry:
529 ; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[X:%.*]], 42
530 ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], 41
531 ; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[CMP2]], i32 1, i32 -1
532 ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP1]], i32 0, i32 [[SELECT1]]
533 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SELECT2]], 0
534 ; CHECK-NEXT: br i1 [[COND]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
535 ; CHECK: callfoo:
536 ; CHECK-NEXT: call void @foo(i32 [[SELECT2]])
518 ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], 42
519 ; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
520 ; CHECK: callfoo:
521 ; CHECK-NEXT: call void @foo(i32 1)
537522 ; CHECK-NEXT: br label [[EXIT]]
538523 ; CHECK: exit:
539524 ; CHECK-NEXT: ret i32 84
558543 ; CHECK-NEXT: entry:
559544 ; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X:%.*]], 42
560545 ; CHECK-NEXT: call void @use1(i1 [[CMP1]])
561 ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], 41
562 ; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[CMP2]], i32 1, i32 -1
563 ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP1]], i32 [[SELECT1]], i32 0
564 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SELECT2]], 0
565 ; CHECK-NEXT: br i1 [[COND]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
566 ; CHECK: callfoo:
567 ; CHECK-NEXT: call void @foo(i32 [[SELECT2]])
546 ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X]], 42
547 ; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
548 ; CHECK: callfoo:
549 ; CHECK-NEXT: call void @foo(i32 1)
568550 ; CHECK-NEXT: br label [[EXIT]]
569551 ; CHECK: exit:
570552 ; CHECK-NEXT: ret i32 84
615597 define i32 @compare_against_arbitrary_value_commutativity1(i32 %x, i32 %c) {
616598 ; CHECK-LABEL: @compare_against_arbitrary_value_commutativity1(
617599 ; CHECK-NEXT: entry:
618 ; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[X:%.*]], [[C:%.*]]
619 ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[C]], [[X]]
620 ; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[CMP2]], i32 -1, i32 1
621 ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP1]], i32 0, i32 [[SELECT1]]
622 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SELECT2]], 0
623 ; CHECK-NEXT: br i1 [[COND]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
624 ; CHECK: callfoo:
625 ; CHECK-NEXT: call void @foo(i32 [[SELECT2]])
600 ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X:%.*]], [[C:%.*]]
601 ; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
602 ; CHECK: callfoo:
603 ; CHECK-NEXT: call void @foo(i32 1)
626604 ; CHECK-NEXT: br label [[EXIT]]
627605 ; CHECK: exit:
628606 ; CHECK-NEXT: ret i32 42
647625 ; CHECK-NEXT: entry:
648626 ; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X:%.*]], [[C:%.*]]
649627 ; CHECK-NEXT: call void @use1(i1 [[CMP1]])
650 ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], [[C]]
651 ; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[CMP2]], i32 -1, i32 1
652 ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP1]], i32 [[SELECT1]], i32 0
653 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SELECT2]], 0
654 ; CHECK-NEXT: br i1 [[COND]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
655 ; CHECK: callfoo:
656 ; CHECK-NEXT: call void @foo(i32 [[SELECT2]])
628 ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X]], [[C]]
629 ; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
630 ; CHECK: callfoo:
631 ; CHECK-NEXT: call void @foo(i32 1)
657632 ; CHECK-NEXT: br label [[EXIT]]
658633 ; CHECK: exit:
659634 ; CHECK-NEXT: ret i32 42
679654 ; CHECK-NEXT: entry:
680655 ; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[X:%.*]], [[C:%.*]]
681656 ; CHECK-NEXT: call void @use1(i1 [[CMP1]])
682 ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[C]], [[X]]
683 ; CHECK-NEXT: [[SELECT1:%.*]] = select i1 [[CMP2]], i32 -1, i32 1
684 ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP1]], i32 [[SELECT1]], i32 0
685 ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SELECT2]], 0
686 ; CHECK-NEXT: br i1 [[COND]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
687 ; CHECK: callfoo:
688 ; CHECK-NEXT: call void @foo(i32 [[SELECT2]])
657 ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[X]], [[C]]
658 ; CHECK-NEXT: br i1 [[TMP0]], label [[CALLFOO:%.*]], label [[EXIT:%.*]]
659 ; CHECK: callfoo:
660 ; CHECK-NEXT: call void @foo(i32 1)
689661 ; CHECK-NEXT: br label [[EXIT]]
690662 ; CHECK: exit:
691663 ; CHECK-NEXT: ret i32 42