From 14f36d715bee74786b2b1c673904d430daab4496 Mon Sep 17 00:00:00 2001 From: Chad Rosier Date: Fri, 22 Apr 2016 17:14:12 +0000 Subject: [PATCH] [SimplifyCFG] Add missing implications to isImpliedTrueByMatchingCmp. Summary: [u|s]gt and [u|s]lt imply [u|s]ge and [u|s]le are true, respectively. I've simplified the existing tests and added additional tests to cover the new cases mentioned above. I've also added tests for all the cases where the first compare doesn't imply anything about the second compare. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@267171 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/IR/Instructions.cpp | 13 +- .../SimplifyCFG/implied-cond-matching.ll | 1005 ++++++++++++++++++++ 2 files changed, 1013 insertions(+), 5 deletions(-) create mode 100644 test/Transforms/SimplifyCFG/implied-cond-matching.ll diff --git a/lib/IR/Instructions.cpp b/lib/IR/Instructions.cpp index e17db659c2a..13e58219baa 100644 --- a/lib/IR/Instructions.cpp +++ b/lib/IR/Instructions.cpp @@ -3562,11 +3562,14 @@ bool CmpInst::isImpliedTrueByMatchingCmp(Predicate Pred1, Predicate Pred2) { switch (Pred1) { default: break; - case ICMP_UGT: // A >u B implies A != B is true. - case ICMP_ULT: // A s B implies A != B is true. - case ICMP_SLT: // A u B implies A != B and A >=u B are true. + return Pred2 == ICMP_NE || Pred2 == ICMP_UGE; + case ICMP_ULT: // A s B implies A != B and A >=s B are true. + return Pred2 == ICMP_NE || Pred2 == ICMP_SGE; + case ICMP_SLT: // A b) { +; if (b > a) <- always false +; dead(); +; alive(); +; } +; } +; +; CHECK-LABEL: @test_swapped_ops +; CHECK-NOT: call void @dead() +; CHECK: call void @alive() +; CHECK: ret +define void @test_swapped_ops(i32 %a, i32 %b) { +entry: + %cmp = icmp ugt i32 %a, %b + br i1 %cmp, label %if.then, label %if.end3 + +if.then: + %cmp1 = icmp ugt i32 %b, %a + br i1 %cmp1, label %if.then2, label %if.end + +if.then2: + call void @dead() + br label %if.end + +if.end: + call void @alive() + br label %if.end3 + +if.end3: + ret void +} + +; void test_swapped_pred(unsigned a, unsigned b) { +; if (a > b) { +; alive(); +; if (b < a) <- always true; remove branch +; alive(); +; } +; } +; +; CHECK-LABEL: @test_swapped_pred +; CHECK: call void @alive() +; CHECK-NEXT: call void @alive() +; CHECK: ret +define void @test_swapped_pred(i32 %a, i32 %b) { +entry: + %cmp = icmp ugt i32 %a, %b + br i1 %cmp, label %if.then, label %if.end3 + +if.then: + call void @alive() + %cmp1 = icmp ult i32 %b, %a + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: + call void @alive() + br label %if.end3 + +if.end3: + ret void +} + +; A == B implies A == B is true. +; CHECK-LABEL: @test_eq_eq +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_eq_eq(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp eq i32 %a, %b + br i1 %cmp2, label %eq_eq_istrue, label %eq_eq_isfalse + +eq_eq_istrue: + call void @is(i1 true) + ret void + +eq_eq_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A != B is false. +; CHECK-LABEL: @test_eq_ne +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_ne(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ne i32 %a, %b + br i1 %cmp2, label %eq_ne_istrue, label %eq_ne_isfalse + +eq_ne_istrue: + call void @is(i1 true) + ret void + +eq_ne_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A >u B is false. +; CHECK-LABEL: @test_eq_ugt +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_ugt(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ugt i32 %a, %b + br i1 %cmp2, label %eq_ugt_istrue, label %eq_ugt_isfalse + +eq_ugt_istrue: + call void @is(i1 true) + ret void + +eq_ugt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A >=u B is unknown to be true or false. +; CHECK-LABEL: @test_eq_uge +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_uge(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp uge i32 %a, %b + br i1 %cmp2, label %eq_uge_istrue, label %eq_uge_isfalse + +eq_uge_istrue: + call void @is(i1 true) + ret void + +eq_uge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A s B is false. +; CHECK-LABEL: @test_eq_sgt +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_sgt(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sgt i32 %a, %b + br i1 %cmp2, label %eq_sgt_istrue, label %eq_sgt_isfalse + +eq_sgt_istrue: + call void @is(i1 true) + ret void + +eq_sgt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A >=s B is unknown to be true or false. +; CHECK-LABEL: @test_eq_sge +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_eq_sge(i32 %a, i32 %b) { + %cmp1 = icmp eq i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sge i32 %a, %b + br i1 %cmp2, label %eq_sge_istrue, label %eq_sge_isfalse + +eq_sge_istrue: + call void @is(i1 true) + ret void + +eq_sge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A == B implies A u B is unknown to be true or false. +; CHECK-LABEL: @test_ne_ugt +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_ugt(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ugt i32 %a, %b + br i1 %cmp2, label %ne_ugt_istrue, label %ne_ugt_isfalse + +ne_ugt_istrue: + call void @is(i1 true) + ret void + +ne_ugt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A >=u B is unknown to be true or false. +; CHECK-LABEL: @test_ne_uge +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_uge(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp uge i32 %a, %b + br i1 %cmp2, label %ne_uge_istrue, label %ne_uge_isfalse + +ne_uge_istrue: + call void @is(i1 true) + ret void + +ne_uge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A s B is unknown to be true or false. +; CHECK-LABEL: @test_ne_sgt +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_sgt(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sgt i32 %a, %b + br i1 %cmp2, label %ne_sgt_istrue, label %ne_sgt_isfalse + +ne_sgt_istrue: + call void @is(i1 true) + ret void + +ne_sgt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A >=s B is unknown to be true or false. +; CHECK-LABEL: @test_ne_sge +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ne_sge(i32 %a, i32 %b) { + %cmp1 = icmp ne i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sge i32 %a, %b + br i1 %cmp2, label %ne_sge_istrue, label %ne_sge_isfalse + +ne_sge_istrue: + call void @is(i1 true) + ret void + +ne_sge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A != B implies A u B implies A >u B is true. +; CHECK-LABEL: @test_ugt_ugt +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ugt_ugt(i32 %a, i32 %b) { + %cmp1 = icmp ugt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ugt i32 %a, %b + br i1 %cmp2, label %ugt_ugt_istrue, label %ugt_ugt_isfalse + +ugt_ugt_istrue: + call void @is(i1 true) + ret void + +ugt_ugt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >u B implies A >=u B is true. +; CHECK-LABEL: @test_ugt_uge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_ugt_uge(i32 %a, i32 %b) { + %cmp1 = icmp ugt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp uge i32 %a, %b + br i1 %cmp2, label %ugt_uge_istrue, label %ugt_uge_isfalse + +ugt_uge_istrue: + call void @is(i1 true) + ret void + +ugt_uge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >u B implies A u B implies A <=u B is false. +; CHECK-LABEL: @test_ugt_ule +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_ugt_ule(i32 %a, i32 %b) { + %cmp1 = icmp ugt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %ugt_ule_istrue, label %ugt_ule_isfalse + +ugt_ule_istrue: + call void @is(i1 true) + ret void + +ugt_ule_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=u B implies A >=u B is true. +; CHECK-LABEL: @test_uge_uge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_uge_uge(i32 %a, i32 %b) { + %cmp1 = icmp uge i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp uge i32 %a, %b + br i1 %cmp2, label %uge_uge_istrue, label %uge_uge_isfalse + +uge_uge_istrue: + call void @is(i1 true) + ret void + +uge_uge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=u B implies A =u B implies A <=u B is unknown to be true or false. +; CHECK-LABEL: @test_uge_ule +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_uge_ule(i32 %a, i32 %b) { + %cmp1 = icmp uge i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp ule i32 %a, %b + br i1 %cmp2, label %uge_ule_istrue, label %uge_ule_isfalse + +uge_ule_istrue: + call void @is(i1 true) + ret void + +uge_ule_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A s B implies A >s B is true. +; CHECK-LABEL: @test_sgt_sgt +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_sgt_sgt(i32 %a, i32 %b) { + %cmp1 = icmp sgt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sgt i32 %a, %b + br i1 %cmp2, label %sgt_sgt_istrue, label %sgt_sgt_isfalse + +sgt_sgt_istrue: + call void @is(i1 true) + ret void + +sgt_sgt_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >s B implies A >=s B is true. +; CHECK-LABEL: @test_sgt_sge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_sgt_sge(i32 %a, i32 %b) { + %cmp1 = icmp sgt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sge i32 %a, %b + br i1 %cmp2, label %sgt_sge_istrue, label %sgt_sge_isfalse + +sgt_sge_istrue: + call void @is(i1 true) + ret void + +sgt_sge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >s B implies A s B implies A <=s B is false. +; CHECK-LABEL: @test_sgt_sle +; CHECK-NOT: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_sgt_sle(i32 %a, i32 %b) { + %cmp1 = icmp sgt i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sle i32 %a, %b + br i1 %cmp2, label %sgt_sle_istrue, label %sgt_sle_isfalse + +sgt_sle_istrue: + call void @is(i1 true) + ret void + +sgt_sle_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=s B implies A >=s B is true. +; CHECK-LABEL: @test_sge_sge +; CHECK: call void @is(i1 true) +; CHECK-NOT: call void @is(i1 false) +define void @test_sge_sge(i32 %a, i32 %b) { + %cmp1 = icmp sge i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sge i32 %a, %b + br i1 %cmp2, label %sge_sge_istrue, label %sge_sge_isfalse + +sge_sge_istrue: + call void @is(i1 true) + ret void + +sge_sge_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A >=s B implies A =s B implies A <=s B is unknown to be true or false. +; CHECK-LABEL: @test_sge_sle +; CHECK: call void @is(i1 true) +; CHECK: call void @is(i1 false) +define void @test_sge_sle(i32 %a, i32 %b) { + %cmp1 = icmp sge i32 %a, %b + br i1 %cmp1, label %taken, label %untaken + +taken: + %cmp2 = icmp sle i32 %a, %b + br i1 %cmp2, label %sge_sle_istrue, label %sge_sle_isfalse + +sge_sle_istrue: + call void @is(i1 true) + ret void + +sge_sle_isfalse: + call void @is(i1 false) + ret void + +untaken: + ret void +} + +; A