|  | ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | 
|  | ; RUN: opt -print-predicateinfo < %s 2>&1 | FileCheck %s | 
|  |  | 
|  | declare void @foo(i1) | 
|  | declare void @bar(i32) | 
|  | declare void @llvm.assume(i1) | 
|  |  | 
|  | define void @testor(i32 %x, i32 %y) { | 
|  | ; CHECK-LABEL: @testor( | 
|  | ; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0 | 
|  | ; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0 | 
|  | ; CHECK-NEXT:    [[Z:%.*]] = or i1 [[XZ]], [[YZ]] | 
|  | ; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]]) | 
|  | ; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]]) | 
|  | ; CHECK:         [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]]) | 
|  | ; CHECK:         [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]]) | 
|  | ; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]]) | 
|  | ; CHECK-NEXT:    br i1 [[Z]], label [[ONEOF:%.*]], label [[NEITHER:%.*]] | 
|  | ; CHECK:       oneof: | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[XZ]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[YZ]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[X]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[Y]]) | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; CHECK:       neither: | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[XZ_0]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[YZ_0]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[X_0]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[Y_0]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[Z_0]]) | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | %xz = icmp eq i32 %x, 0 | 
|  | %yz = icmp eq i32 %y, 0 | 
|  | %z = or i1 %xz, %yz | 
|  | br i1 %z, label %oneof, label %neither | 
|  | oneof: | 
|  | ;; Should not insert on the true edge for or | 
|  | call void @foo(i1 %xz) | 
|  | call void @foo(i1 %yz) | 
|  | call void @bar(i32 %x) | 
|  | call void @bar(i32 %y) | 
|  | ret void | 
|  | neither: | 
|  | call void @foo(i1 %xz) | 
|  | call void @foo(i1 %yz) | 
|  | call void @bar(i32 %x) | 
|  | call void @bar(i32 %y) | 
|  | call void @foo(i1 %z) | 
|  | ret void | 
|  | } | 
|  | define void @testand(i32 %x, i32 %y) { | 
|  | ; CHECK-LABEL: @testand( | 
|  | ; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0 | 
|  | ; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0 | 
|  | ; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XZ]], [[YZ]] | 
|  | ; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]]) | 
|  | ; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]]) | 
|  | ; CHECK:         [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]]) | 
|  | ; CHECK:         [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]]) | 
|  | ; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]]) | 
|  | ; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]] | 
|  | ; CHECK:       both: | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[XZ_0]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[YZ_0]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[X_0]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[Y_0]]) | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; CHECK:       nope: | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[XZ]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[YZ]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[X]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[Y]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[Z_0]]) | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | %xz = icmp eq i32 %x, 0 | 
|  | %yz = icmp eq i32 %y, 0 | 
|  | %z = and i1 %xz, %yz | 
|  | br i1 %z, label %both, label %nope | 
|  | both: | 
|  | call void @foo(i1 %xz) | 
|  | call void @foo(i1 %yz) | 
|  | call void @bar(i32 %x) | 
|  | call void @bar(i32 %y) | 
|  | ret void | 
|  | nope: | 
|  | ;; Should not insert on the false edge for and | 
|  | call void @foo(i1 %xz) | 
|  | call void @foo(i1 %yz) | 
|  | call void @bar(i32 %x) | 
|  | call void @bar(i32 %y) | 
|  | call void @foo(i1 %z) | 
|  | ret void | 
|  | } | 
|  | define void @testandsame(i32 %x, i32 %y) { | 
|  | ; CHECK-LABEL: @testandsame( | 
|  | ; CHECK-NEXT:    [[XGT:%.*]] = icmp sgt i32 [[X:%.*]], 0 | 
|  | ; CHECK-NEXT:    [[XLT:%.*]] = icmp slt i32 [[X]], 100 | 
|  | ; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XGT]], [[XLT]] | 
|  | ; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]]) | 
|  | ; CHECK:         [[X_0_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X_0]]) | 
|  | ; CHECK:         [[XGT_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XGT]]) | 
|  | ; CHECK:         [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XLT]]) | 
|  | ; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]]) | 
|  | ; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]] | 
|  | ; CHECK:       both: | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[XGT_0]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[XLT_0]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[X_0_1]]) | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; CHECK:       nope: | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[XGT]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[XLT]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[Z_0]]) | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | %xgt = icmp sgt i32 %x, 0 | 
|  | %xlt = icmp slt i32 %x, 100 | 
|  | %z = and i1 %xgt, %xlt | 
|  | br i1 %z, label %both, label %nope | 
|  | both: | 
|  | call void @foo(i1 %xgt) | 
|  | call void @foo(i1 %xlt) | 
|  | call void @bar(i32 %x) | 
|  | ret void | 
|  | nope: | 
|  | call void @foo(i1 %xgt) | 
|  | call void @foo(i1 %xlt) | 
|  | call void @foo(i1 %z) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @testandassume(i32 %x, i32 %y) { | 
|  | ; CHECK-LABEL: @testandassume( | 
|  | ; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0 | 
|  | ; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0 | 
|  | ; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XZ]], [[YZ]] | 
|  | ; CHECK:         [[TMP1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]]) | 
|  | ; CHECK:         [[TMP2:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]]) | 
|  | ; CHECK:         [[TMP3:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]]) | 
|  | ; CHECK:         [[TMP4:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]]) | 
|  | ; CHECK:         [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]]) | 
|  | ; CHECK-NEXT:    call void @llvm.assume(i1 [[TMP5]]) | 
|  | ; CHECK:         [[DOT0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP1]]) | 
|  | ; CHECK:         [[DOT01:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP2]]) | 
|  | ; CHECK:         [[DOT02:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP3]]) | 
|  | ; CHECK:         [[DOT03:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP4]]) | 
|  | ; CHECK:         [[DOT04:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP5]]) | 
|  | ; CHECK-NEXT:    br i1 [[TMP5]], label [[BOTH:%.*]], label [[NOPE:%.*]] | 
|  | ; CHECK:       both: | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[DOT02]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[DOT03]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[DOT0]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[DOT01]]) | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; CHECK:       nope: | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[DOT04]]) | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | %xz = icmp eq i32 %x, 0 | 
|  | %yz = icmp eq i32 %y, 0 | 
|  | %z = and i1 %xz, %yz | 
|  | call void @llvm.assume(i1 %z) | 
|  | br i1 %z, label %both, label %nope | 
|  | both: | 
|  | call void @foo(i1 %xz) | 
|  | call void @foo(i1 %yz) | 
|  | call void @bar(i32 %x) | 
|  | call void @bar(i32 %y) | 
|  | ret void | 
|  | nope: | 
|  | call void @foo(i1 %z) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ;; Unlike and/or for branches, assume is *always* true, so we only match and for it | 
|  | define void @testorassume(i32 %x, i32 %y) { | 
|  | ; | 
|  | ; CHECK-LABEL: @testorassume( | 
|  | ; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0 | 
|  | ; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0 | 
|  | ; CHECK-NEXT:    [[Z:%.*]] = or i1 [[XZ]], [[YZ]] | 
|  | ; CHECK-NEXT:    call void @llvm.assume(i1 [[Z]]) | 
|  | ; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]]) | 
|  | ; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]] | 
|  | ; CHECK:       both: | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[XZ]]) | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[YZ]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[X]]) | 
|  | ; CHECK-NEXT:    call void @bar(i32 [[Y]]) | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; CHECK:       nope: | 
|  | ; CHECK-NEXT:    call void @foo(i1 [[Z_0]]) | 
|  | ; CHECK-NEXT:    ret void | 
|  | ; | 
|  | %xz = icmp eq i32 %x, 0 | 
|  | %yz = icmp eq i32 %y, 0 | 
|  | %z = or i1 %xz, %yz | 
|  | call void @llvm.assume(i1 %z) | 
|  | br i1 %z, label %both, label %nope | 
|  | both: | 
|  | call void @foo(i1 %xz) | 
|  | call void @foo(i1 %yz) | 
|  | call void @bar(i32 %x) | 
|  | call void @bar(i32 %y) | 
|  | ret void | 
|  | nope: | 
|  | call void @foo(i1 %z) | 
|  | ret void | 
|  | } |