|  | ; RUN: opt %s -S -simplifycfg | FileCheck %s | 
|  |  | 
|  | declare void @foo() | 
|  | declare void @bar() | 
|  |  | 
|  |  | 
|  | ; CHECK-LABEL: @test_and1 | 
|  | ; CHECK: taken: | 
|  | ; CHECK-NOT: cmp3 | 
|  | ; CHECK: call void @bar() | 
|  | ; CHECK-NEXT: call void @foo() | 
|  | ; CHECK: ret | 
|  | define void @test_and1(i32 %a, i32 %b) { | 
|  | entry: | 
|  | %cmp1 = icmp eq i32 %a, 0 | 
|  | %cmp2 = icmp eq i32 %b, 0 | 
|  | %and = and i1 %cmp1, %cmp2 | 
|  | br i1 %and, label %taken, label %end | 
|  |  | 
|  | taken: | 
|  | call void @bar() | 
|  | %cmp3 = icmp eq i32 %a, 0  ;; <-- implied true | 
|  | br i1 %cmp3, label %if.then, label %end | 
|  |  | 
|  | if.then: | 
|  | call void @foo() | 
|  | br label %end | 
|  |  | 
|  | end: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; We can't infer anything if the result of the 'and' is false | 
|  | ; CHECK-LABEL: @test_and2 | 
|  | ; CHECK: taken: | 
|  | ; CHECK:   call void @bar() | 
|  | ; CHECK:   %cmp3 | 
|  | ; CHECK:   br i1 %cmp3 | 
|  | ; CHECK: if.then: | 
|  | ; CHECK:   call void @foo() | 
|  | ; CHECK: ret | 
|  | define void @test_and2(i32 %a, i32 %b) { | 
|  | entry: | 
|  | %cmp1 = icmp eq i32 %a, 0 | 
|  | %cmp2 = icmp eq i32 %b, 0 | 
|  | %and = and i1 %cmp1, %cmp2 | 
|  | br i1 %and, label %end, label %taken | 
|  |  | 
|  | taken: | 
|  | call void @bar() | 
|  | %cmp3 = icmp eq i32 %a, 0 | 
|  | br i1 %cmp3, label %if.then, label %end | 
|  |  | 
|  | if.then: | 
|  | call void @foo() | 
|  | br label %end | 
|  |  | 
|  | end: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; CHECK-LABEL: @test_or1 | 
|  | ; CHECK: taken: | 
|  | ; CHECK-NOT: cmp3 | 
|  | ; CHECK: call void @bar() | 
|  | ; CHECK-NEXT: call void @foo() | 
|  | ; CHECK: ret | 
|  | define void @test_or1(i32 %a, i32 %b) { | 
|  | entry: | 
|  | %cmp1 = icmp eq i32 %a, 0 | 
|  | %cmp2 = icmp eq i32 %b, 0 | 
|  | %or = or i1 %cmp1, %cmp2 | 
|  | br i1 %or, label %end, label %taken | 
|  |  | 
|  | taken: | 
|  | call void @bar() | 
|  | %cmp3 = icmp ne i32 %a, 0   ;; <-- implied true | 
|  | br i1 %cmp3, label %if.then, label %end | 
|  |  | 
|  | if.then: | 
|  | call void @foo() | 
|  | br label %end | 
|  |  | 
|  | end: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; We can't infer anything if the result of the 'or' is true | 
|  | ; CHECK-LABEL: @test_or2 | 
|  | ; CHECK:   call void @bar() | 
|  | ; CHECK:   %cmp3 | 
|  | ; CHECK:   br i1 %cmp3 | 
|  | ; CHECK: if.then: | 
|  | ; CHECK:   call void @foo() | 
|  | ; CHECK: ret | 
|  | define void @test_or2(i32 %a, i32 %b) { | 
|  | entry: | 
|  | %cmp1 = icmp eq i32 %a, 0 | 
|  | %cmp2 = icmp eq i32 %b, 0 | 
|  | %or = or i1 %cmp1, %cmp2 | 
|  | br i1 %or, label %taken, label %end | 
|  |  | 
|  | taken: | 
|  | call void @bar() | 
|  | %cmp3 = icmp eq i32 %a, 0 | 
|  | br i1 %cmp3, label %if.then, label %end | 
|  |  | 
|  | if.then: | 
|  | call void @foo() | 
|  | br label %end | 
|  |  | 
|  | end: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; We can recurse a tree of 'and' or 'or's. | 
|  | ; CHECK-LABEL: @test_and_recurse1 | 
|  | ; CHECK: taken: | 
|  | ; CHECK-NEXT:  call void @bar() | 
|  | ; CHECK-NEXT:  call void @foo() | 
|  | ; CHECK-NEXT:  br label %end | 
|  | ; CHECK: ret | 
|  | define void @test_and_recurse1(i32 %a, i32 %b, i32 %c) { | 
|  | entry: | 
|  | %cmpa = icmp eq i32 %a, 0 | 
|  | %cmpb = icmp eq i32 %b, 0 | 
|  | %cmpc = icmp eq i32 %c, 0 | 
|  | %and1 = and i1 %cmpa, %cmpb | 
|  | %and2 = and i1 %and1, %cmpc | 
|  | br i1 %and2, label %taken, label %end | 
|  |  | 
|  | taken: | 
|  | call void @bar() | 
|  | %cmp3 = icmp eq i32 %a, 0 | 
|  | br i1 %cmp3, label %if.then, label %end | 
|  |  | 
|  | if.then: | 
|  | call void @foo() | 
|  | br label %end | 
|  |  | 
|  | end: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Check to make sure we don't recurse too deep. | 
|  | ; CHECK-LABEL: @test_and_recurse2 | 
|  | ; CHECK: taken: | 
|  | ; CHECK-NEXT:  call void @bar() | 
|  | ; CHECK-NEXT:  %cmp3 = icmp eq i32 %a, 0 | 
|  | ; CHECK-NEXT:  br i1 %cmp3, label %if.then, label %end | 
|  | ; CHECK: ret | 
|  | define void @test_and_recurse2(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, | 
|  | i32 %g, i32 %h) { | 
|  | entry: | 
|  | %cmpa = icmp eq i32 %a, 0 | 
|  | %cmpb = icmp eq i32 %b, 0 | 
|  | %cmpc = icmp eq i32 %c, 0 | 
|  | %cmpd = icmp eq i32 %d, 0 | 
|  | %cmpe = icmp eq i32 %e, 0 | 
|  | %cmpf = icmp eq i32 %f, 0 | 
|  | %cmpg = icmp eq i32 %g, 0 | 
|  | %cmph = icmp eq i32 %h, 0 | 
|  | %and1 = and i1 %cmpa, %cmpb | 
|  | %and2 = and i1 %and1, %cmpc | 
|  | %and3 = and i1 %and2, %cmpd | 
|  | %and4 = and i1 %and3, %cmpe | 
|  | %and5 = and i1 %and4, %cmpf | 
|  | %and6 = and i1 %and5, %cmpg | 
|  | %and7 = and i1 %and6, %cmph | 
|  | br i1 %and7, label %taken, label %end | 
|  |  | 
|  | taken: | 
|  | call void @bar() | 
|  | %cmp3 = icmp eq i32 %a, 0 ; <-- can be implied true | 
|  | br i1 %cmp3, label %if.then, label %end | 
|  |  | 
|  | if.then: | 
|  | call void @foo() | 
|  | br label %end | 
|  |  | 
|  | end: | 
|  | ret void | 
|  | } |