| ; RUN: opt < %s -jump-threading -print-lvi-after-jump-threading -disable-output 2>&1 | FileCheck %s |
| |
| ; Testing LVI cache after jump-threading |
| |
| ; Jump-threading transforms the IR below to one where |
| ; loop and backedge basic blocks are merged into one. |
| ; basic block (named backedge) with the branch being: |
| ; %cont = icmp slt i32 %iv.next, 400 |
| ; br i1 %cont, label %backedge, label %exit |
| define i8 @test1(i32 %a, i32 %length) { |
| ; CHECK-LABEL: LVI for function 'test1': |
| entry: |
| ; CHECK-LABEL: entry: |
| ; CHECK-NEXT: ; LatticeVal for: 'i32 %a' is: overdefined |
| ; CHECK-NEXT: ; LatticeVal for: 'i32 %length' is: overdefined |
| br label %loop |
| |
| ; CHECK-LABEL: backedge: |
| ; CHECK-NEXT: ; LatticeVal for: 'i32 %a' is: overdefined |
| ; CHECK-NEXT: ; LatticeVal for: 'i32 %length' is: overdefined |
| ; CHECK-NEXT: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%backedge' is: constantrange<0, 400> |
| ; CHECK-NEXT: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%exit' is: constantrange<399, 400> |
| ; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] |
| ; CHECK-NEXT: ; LatticeVal for: ' %iv.next = add nsw i32 %iv, 1' in BB: '%backedge' is: constantrange<1, 401> |
| ; CHECK-NEXT: ; LatticeVal for: ' %iv.next = add nsw i32 %iv, 1' in BB: '%exit' is: constantrange<400, 401> |
| ; CHECK-NEXT: %iv.next = add nsw i32 %iv, 1 |
| ; CHECK-NEXT: ; LatticeVal for: ' %cont = icmp slt i32 %iv.next, 400' in BB: '%backedge' is: overdefined |
| ; CHECK-NEXT: ; LatticeVal for: ' %cont = icmp slt i32 %iv.next, 400' in BB: '%exit' is: constantrange<0, -1> |
| ; CHECK-NEXT: %cont = icmp slt i32 %iv.next, 400 |
| ; CHECK-NOT: loop |
| loop: |
| %iv = phi i32 [0, %entry], [%iv.next, %backedge] |
| %cnd = icmp sge i32 %iv, 0 |
| br i1 %cnd, label %backedge, label %exit |
| |
| backedge: |
| %iv.next = add nsw i32 %iv, 1 |
| %cont = icmp slt i32 %iv.next, 400 |
| br i1 %cont, label %loop, label %exit |
| |
| exit: |
| ret i8 0 |
| } |
| |
| ; Here JT does not transform the code, but LVICache is populated during the processing of blocks. |
| define i8 @test2(i32 %n) { |
| ; CHECK-LABEL: LVI for function 'test2': |
| ; CHECK-LABEL: entry: |
| ; CHECK-NEXT: ; LatticeVal for: 'i32 %n' is: overdefined |
| ; CHECK-NEXT: br label %loop |
| entry: |
| br label %loop |
| |
| ; CHECK-LABEL: loop: |
| ; CHECK-NEXT: ; LatticeVal for: 'i32 %n' is: overdefined |
| ; CHECK-NEXT: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%loop' is: constantrange<0, -2147483647> |
| ; CHECK-DAG: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%backedge' is: constantrange<0, -2147483648> |
| ; CHECK-DAG: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%exit' is: constantrange<0, -2147483647> |
| ; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] |
| loop: |
| %iv = phi i32 [0, %entry], [%iv.next, %backedge] |
| ; CHECK-NEXT: ; LatticeVal for: ' %iv2 = phi i32 [ %n, %entry ], [ %iv2.next, %backedge ]' in BB: '%loop' is: overdefined |
| ; CHECK-DAG: ; LatticeVal for: ' %iv2 = phi i32 [ %n, %entry ], [ %iv2.next, %backedge ]' in BB: '%backedge' is: constantrange<1, -2147483648> |
| ; CHECK-DAG: ; LatticeVal for: ' %iv2 = phi i32 [ %n, %entry ], [ %iv2.next, %backedge ]' in BB: '%exit' is: overdefined |
| ; CHECK-NEXT: %iv2 = phi i32 [ %n, %entry ], [ %iv2.next, %backedge ] |
| %iv2 = phi i32 [%n, %entry], [%iv2.next, %backedge] |
| |
| ; CHECK-NEXT: ; LatticeVal for: ' %cnd1 = icmp sge i32 %iv, 0' in BB: '%loop' is: overdefined |
| ; CHECK-DAG: ; LatticeVal for: ' %cnd1 = icmp sge i32 %iv, 0' in BB: '%backedge' is: overdefined |
| ; CHECK-DAG: ; LatticeVal for: ' %cnd1 = icmp sge i32 %iv, 0' in BB: '%exit' is: overdefined |
| ; CHECK-NEXT: %cnd1 = icmp sge i32 %iv, 0 |
| %cnd1 = icmp sge i32 %iv, 0 |
| %cnd2 = icmp sgt i32 %iv2, 0 |
| ; CHECK: %cnd2 = icmp sgt i32 %iv2, 0 |
| ; CHECK: ; LatticeVal for: ' %cnd = and i1 %cnd1, %cnd2' in BB: '%loop' is: overdefined |
| ; CHECK-DAG: ; LatticeVal for: ' %cnd = and i1 %cnd1, %cnd2' in BB: '%backedge' is: constantrange<-1, 0> |
| ; CHECK-DAG: ; LatticeVal for: ' %cnd = and i1 %cnd1, %cnd2' in BB: '%exit' is: overdefined |
| ; CHECK-NEXT: %cnd = and i1 %cnd1, %cnd2 |
| %cnd = and i1 %cnd1, %cnd2 |
| br i1 %cnd, label %backedge, label %exit |
| |
| ; CHECK-LABEL: backedge: |
| ; CHECK-NEXT: ; LatticeVal for: 'i32 %n' is: overdefined |
| ; CHECK-NEXT: ; LatticeVal for: ' %iv.next = add nsw i32 %iv, 1' in BB: '%backedge' is: constantrange<1, -2147483647> |
| ; CHECK-NEXT: %iv.next = add nsw i32 %iv, 1 |
| backedge: |
| %iv.next = add nsw i32 %iv, 1 |
| %iv2.next = sub nsw i32 %iv2, 1 |
| ; CHECK: ; LatticeVal for: ' %cont1 = icmp slt i32 %iv.next, 400' in BB: '%backedge' is: overdefined |
| ; CHECK-NEXT: %cont1 = icmp slt i32 %iv.next, 400 |
| %cont1 = icmp slt i32 %iv.next, 400 |
| ; CHECK-NEXT: ; LatticeVal for: ' %cont2 = icmp sgt i32 %iv2.next, 0' in BB: '%backedge' is: overdefined |
| ; CHECK-NEXT: %cont2 = icmp sgt i32 %iv2.next, 0 |
| %cont2 = icmp sgt i32 %iv2.next, 0 |
| ; CHECK-NEXT: ; LatticeVal for: ' %cont = and i1 %cont1, %cont2' in BB: '%backedge' is: overdefined |
| ; CHECK-NEXT: %cont = and i1 %cont1, %cont2 |
| %cont = and i1 %cont1, %cont2 |
| br i1 %cont, label %loop, label %exit |
| |
| exit: |
| ret i8 0 |
| } |
| |
| ; Merging cont block into do block. Make sure that we do not incorrectly have the cont |
| ; LVI info as LVI info for the beginning of do block. LVI info for %i is Range[0,1) |
| ; at beginning of cont Block, which is incorrect at the beginning of do block. |
| define i32 @test3(i32 %i, i1 %f, i32 %n) { |
| ; CHECK-LABEL: LVI for function 'test3': |
| ; CHECK-LABEL: entry |
| ; CHECK: ; LatticeVal for: 'i32 %i' is: overdefined |
| ; CHECK: %c = icmp ne i32 %i, -2134 |
| ; CHECK: br i1 %c, label %cont, label %exit |
| entry: |
| %c = icmp ne i32 %i, -2134 |
| br i1 %c, label %do, label %exit |
| |
| exit: |
| %c1 = icmp ne i32 %i, -42 |
| br i1 %c1, label %exit2, label %exit |
| |
| ; CHECK-LABEL: cont: |
| ; Here cont is merged to do and i is any value except -2134. |
| ; i is not the single value: zero. |
| ; CHECK-NOT: ; LatticeVal for: 'i32 %i' is: constantrange<0, 1> |
| ; CHECK: ; LatticeVal for: 'i32 %i' is: constantrange<-2133, -2134> |
| ; CHECK: ; LatticeVal for: ' %cond.0 = icmp sgt i32 %i, 0' in BB: '%cont' is: overdefined |
| ; CHECK: %cond.0 = icmp sgt i32 %i, 0 |
| ; CHECK: %consume = call i32 @consume |
| ; CHECK: %cond = icmp eq i32 %i, 0 |
| ; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 %cond) |
| ; CHECK: %cond.3 = icmp sgt i32 %i, %n |
| ; CHECK: br i1 %cond.3, label %exit2, label %exit |
| cont: |
| %cond.3 = icmp sgt i32 %i, %n |
| br i1 %cond.3, label %exit2, label %exit |
| |
| do: |
| %cond.0 = icmp sgt i32 %i, 0 |
| %consume = call i32 @consume(i1 %cond.0) |
| %cond = icmp eq i32 %i, 0 |
| call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ] |
| %cond.2 = icmp sgt i32 %i, 0 |
| br i1 %cond.2, label %exit, label %cont |
| |
| exit2: |
| ; CHECK-LABEL: exit2: |
| ; LatticeVal for: 'i32 %i' is: constantrange<-2134, 1> |
| ret i32 30 |
| } |
| |
| ; FIXME: We should be able to merge cont into do. |
| ; When we do so, LVI for cont cannot be the one for the merged do block. |
| define i32 @test4(i32 %i, i1 %f, i32 %n) { |
| ; CHECK-LABEL: LVI for function 'test4': |
| entry: |
| %c = icmp ne i32 %i, -2134 |
| br i1 %c, label %do, label %exit |
| |
| exit: ; preds = %do, %cont, %exit, %entry |
| %c1 = icmp ne i32 %i, -42 |
| br i1 %c1, label %exit2, label %exit |
| |
| cont: ; preds = %do |
| ; CHECK-LABEL: cont: |
| ; CHECK: ; LatticeVal for: 'i1 %f' is: constantrange<-1, 0> |
| ; CHECK: call void @dummy(i1 %f) |
| call void @dummy(i1 %f) |
| br label %exit2 |
| |
| do: ; preds = %entry |
| ; CHECK-LABEL: do: |
| ; CHECK: ; LatticeVal for: 'i1 %f' is: overdefined |
| ; CHECK: call void @dummy(i1 %f) |
| ; CHECK: br i1 %cond, label %exit, label %cont |
| call void @dummy(i1 %f) |
| %consume = call i32 @exit() |
| call void @llvm.assume(i1 %f) |
| %cond = icmp eq i1 %f, false |
| br i1 %cond, label %exit, label %cont |
| |
| exit2: ; preds = %cont, %exit |
| ret i32 30 |
| } |
| |
| declare i32 @exit() |
| declare i32 @consume(i1) |
| declare void @llvm.assume(i1) nounwind |
| declare void @dummy(i1) nounwind |
| declare void @llvm.experimental.guard(i1, ...) |