| ; Test the the loop nest depth is correctly calculated for basic blocks. |
| |
| ; REQUIRES: allow_dump |
| |
| ; Single threaded so that the dumps used for checking happen in order. |
| ; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 --verbose=loop \ |
| ; RUN: -log=%t --threads=0 && FileCheck %s < %t |
| |
| define internal void @test_single_loop(i32 %a32) { |
| entry: |
| %a = trunc i32 %a32 to i1 |
| br label %loop0 |
| |
| loop0: ; <-+ |
| br label %loop1 ; | |
| loop1: ; | |
| br i1 %a, label %loop0, label %out ; --+ |
| |
| out: |
| ret void |
| } |
| |
| ; CHECK-LABEL: After loop analysis |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: loop0: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: loop1: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: out: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-LABEL: Before RMW |
| |
| define internal void @test_single_loop_with_continue(i32 %a32, i32 %b32) { |
| entry: |
| %a = trunc i32 %a32 to i1 |
| %b = trunc i32 %b32 to i1 |
| br label %loop0 |
| |
| loop0: ; <-+ |
| br label %loop1 ; | |
| loop1: ; | |
| br i1 %a, label %loop0, label %loop2 ; --+ |
| loop2: ; | |
| br i1 %b, label %loop0, label %out ; --+ |
| |
| out: |
| ret void |
| } |
| |
| ; CHECK-LABEL: After loop analysis |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: loop0: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: loop1: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: loop2: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: out: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-LABEL: Before RMW |
| |
| define internal void @test_multiple_exits(i32 %a32, i32 %b32) { |
| entry: |
| %a = trunc i32 %a32 to i1 |
| %b = trunc i32 %b32 to i1 |
| br label %loop0 |
| |
| loop0: ; <-+ |
| br label %loop1 ; | |
| loop1: ; | |
| br i1 %a, label %loop2, label %out ; --+-+ |
| loop2: ; | | |
| br i1 %b, label %loop0, label %out ; --+ | |
| ; | |
| out: ; <---+ |
| ret void |
| } |
| |
| ; CHECK-LABEL: After loop analysis |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: loop0: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: loop1: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: loop2: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: out: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-LABEL: Before RMW |
| |
| define internal void @test_two_nested_loops(i32 %a32, i32 %b32) { |
| entry: |
| %a = trunc i32 %a32 to i1 |
| %b = trunc i32 %b32 to i1 |
| br label %loop0_0 |
| |
| loop0_0: ; <---+ |
| br label %loop1_0 ; | |
| loop1_0: ; <-+ | |
| br label %loop1_1 ; | | |
| loop1_1: ; | | |
| br i1 %a, label %loop1_0, label %loop0_1 ; --+ | |
| loop0_1: ; | |
| br i1 %b, label %loop0_0, label %out ; ----+ |
| |
| out: |
| ret void |
| } |
| |
| ; CHECK-LABEL: After loop analysis |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: loop0_0: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: loop1_0: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop1_1: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop0_1: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: out: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-LABEL: Before RMW |
| |
| define internal void @test_two_nested_loops_with_continue(i32 %a32, i32 %b32, |
| i32 %c32) { |
| entry: |
| %a = trunc i32 %a32 to i1 |
| %b = trunc i32 %b32 to i1 |
| %c = trunc i32 %c32 to i1 |
| br label %loop0_0 |
| |
| loop0_0: ; <---+ |
| br label %loop1_0 ; | |
| loop1_0: ; <-+ | |
| br label %loop1_1 ; | | |
| loop1_1: ; | | |
| br i1 %a, label %loop1_0, label %loop1_2 ; --+ | |
| loop1_2: ; | | |
| br i1 %a, label %loop1_0, label %loop0_1 ; --+ | |
| loop0_1: ; | |
| br i1 %b, label %loop0_0, label %out ; ----+ |
| |
| out: |
| ret void |
| } |
| |
| ; CHECK-LABEL: After loop analysis |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: loop0_0: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: loop1_0: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop1_1: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop1_2: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop0_1: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: out: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-LABEL: Before RMW |
| |
| define internal void @test_multiple_nested_loops(i32 %a32, i32 %b32) { |
| entry: |
| %a = trunc i32 %a32 to i1 |
| %b = trunc i32 %b32 to i1 |
| br label %loop0_0 |
| |
| loop0_0: ; <---+ |
| br label %loop1_0 ; | |
| loop1_0: ; <-+ | |
| br label %loop1_1 ; | | |
| loop1_1: ; | | |
| br i1 %a, label %loop1_0, label %loop0_1 ; --+ | |
| loop0_1: ; | |
| br label %loop2_0 ; | |
| loop2_0: ; <-+ | |
| br label %loop2_1 ; | | |
| loop2_1: ; | | |
| br i1 %a, label %loop2_0, label %loop0_2 ; --+ | |
| loop0_2: ; | |
| br i1 %b, label %loop0_0, label %out ; ----+ |
| |
| out: |
| ret void |
| } |
| |
| ; CHECK-LABEL: After loop analysis |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: loop0_0: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: loop1_0: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop1_1: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop0_1: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: loop2_0: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop2_1: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop0_2: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: out: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-LABEL: Before RMW |
| |
| define internal void @test_three_nested_loops(i32 %a32, i32 %b32, i32 %c32) { |
| entry: |
| %a = trunc i32 %a32 to i1 |
| %b = trunc i32 %b32 to i1 |
| %c = trunc i32 %c32 to i1 |
| br label %loop0_0 |
| |
| loop0_0: ; <-----+ |
| br label %loop1_0 ; | |
| loop1_0: ; <---+ | |
| br label %loop2_0 ; | | |
| loop2_0: ; <-+ | | |
| br label %loop2_1 ; | | | |
| loop2_1: ; | | | |
| br i1 %a, label %loop2_0, label %loop1_1 ; --+ | | |
| loop1_1: ; | | |
| br i1 %b, label %loop1_0, label %loop0_1 ; ----+ | |
| loop0_1: ; | |
| br i1 %c, label %loop0_0, label %out ; ------+ |
| |
| out: |
| ret void |
| } |
| |
| ; CHECK-LABEL: After loop analysis |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: loop0_0: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: loop1_0: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop2_0: |
| ; CHECK-NEXT: LoopNestDepth = 3 |
| ; CHECK-NEXT: loop2_1: |
| ; CHECK-NEXT: LoopNestDepth = 3 |
| ; CHECK-NEXT: loop1_1: |
| ; CHECK-NEXT: LoopNestDepth = 2 |
| ; CHECK-NEXT: loop0_1: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: out: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-LABEL: Before RMW |
| |
| define internal void @test_diamond(i32 %a32) { |
| entry: |
| %a = trunc i32 %a32 to i1 |
| br i1 %a, label %left, label %right |
| |
| left: |
| br label %out |
| |
| right: |
| br label %out |
| |
| out: |
| ret void |
| } |
| |
| ; CHECK-LABEL: After loop analysis |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: left: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: right: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: out: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-LABEL: Before RMW |
| |
| define internal void @test_single_block_loop(i32 %count) { |
| entry: |
| br label %body |
| body: |
| ; %i = phi i32 [ 0, %entry ], [ %inc, %body ] |
| ; A normal loop would have a phi instruction like above for the induction |
| ; variable, but that may introduce new basic blocks due to phi edge splitting, |
| ; so we use an alternative definition for %i to make the test more clear. |
| %i = add i32 %count, 1 |
| %inc = add i32 %i, 1 |
| %cmp = icmp slt i32 %inc, %count |
| br i1 %cmp, label %body, label %exit |
| exit: |
| ret void |
| } |
| |
| ; CHECK-LABEL: After loop analysis |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-NEXT: body: |
| ; CHECK-NEXT: LoopNestDepth = 1 |
| ; CHECK-NEXT: exit: |
| ; CHECK-NEXT: LoopNestDepth = 0 |
| ; CHECK-LABEL: Before RMW |