| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -S -indvars < %s | FileCheck %s |
| target datalayout = "n8:16:32:64" |
| @G = external global i32 |
| |
| ; Basic case where we know the value of an induction variable along one |
| ; exit edge, but not another. |
| define i32 @test(i32 %n) { |
| ; CHECK-LABEL: @test( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], 1 |
| ; CHECK-NEXT: br label [[HEADER:%.*]] |
| ; CHECK: header: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] |
| ; CHECK-NEXT: [[V:%.*]] = load volatile i32, i32* @G |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[V]], 0 |
| ; CHECK-NEXT: br i1 [[CMP1]], label [[LATCH]], label [[EXIT1:%.*]] |
| ; CHECK: latch: |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV_NEXT]], [[TMP0]] |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label [[HEADER]], label [[EXIT2:%.*]] |
| ; CHECK: exit1: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[HEADER]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; CHECK: exit2: |
| ; CHECK-NEXT: ret i32 [[N]] |
| ; |
| entry: |
| br label %header |
| header: |
| %iv = phi i32 [0, %entry], [%iv.next, %latch] |
| %v = load volatile i32, i32* @G |
| %cmp1 = icmp eq i32 %v, 0 |
| br i1 %cmp1, label %latch, label %exit1 |
| |
| latch: |
| %iv.next = add i32 %iv, 1 |
| %cmp2 = icmp ult i32 %iv, %n |
| br i1 %cmp2, label %header, label %exit2 |
| exit1: |
| ret i32 %iv |
| exit2: |
| ret i32 %iv |
| } |
| |
| define i32 @test2(i32 %n) { |
| ; CHECK-LABEL: @test2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], 1 |
| ; CHECK-NEXT: br label [[HEADER:%.*]] |
| ; CHECK: header: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] |
| ; CHECK-NEXT: [[V:%.*]] = load volatile i32, i32* @G |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[V]], 0 |
| ; CHECK-NEXT: br i1 [[CMP1]], label [[LATCH]], label [[EXIT1:%.*]] |
| ; CHECK: latch: |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV_NEXT]], [[TMP0]] |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label [[HEADER]], label [[EXIT2:%.*]] |
| ; CHECK: exit1: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[HEADER]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; CHECK: exit2: |
| ; CHECK-NEXT: ret i32 [[TMP0]] |
| ; |
| entry: |
| br label %header |
| header: |
| %iv = phi i32 [0, %entry], [%iv.next, %latch] |
| %v = load volatile i32, i32* @G |
| %cmp1 = icmp eq i32 %v, 0 |
| br i1 %cmp1, label %latch, label %exit1 |
| |
| latch: |
| %iv.next = add i32 %iv, 1 |
| %cmp2 = icmp ult i32 %iv, %n |
| br i1 %cmp2, label %header, label %exit2 |
| exit1: |
| ret i32 %iv |
| exit2: |
| ret i32 %iv.next |
| } |
| |
| ; TODO: Generalize the code to handle other SCEV expressions |
| define i32 @test3(i32 %n) { |
| ; CHECK-LABEL: @test3( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], 1 |
| ; CHECK-NEXT: br label [[HEADER:%.*]] |
| ; CHECK: header: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] |
| ; CHECK-NEXT: [[EXPR:%.*]] = udiv i32 [[IV]], 5 |
| ; CHECK-NEXT: [[V:%.*]] = load volatile i32, i32* @G |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[V]], 0 |
| ; CHECK-NEXT: br i1 [[CMP1]], label [[LATCH]], label [[EXIT1:%.*]] |
| ; CHECK: latch: |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV_NEXT]], [[TMP0]] |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label [[HEADER]], label [[EXIT2:%.*]] |
| ; CHECK: exit1: |
| ; CHECK-NEXT: [[EXPR_LCSSA:%.*]] = phi i32 [ [[EXPR]], [[HEADER]] ] |
| ; CHECK-NEXT: ret i32 [[EXPR_LCSSA]] |
| ; CHECK: exit2: |
| ; CHECK-NEXT: [[EXPR_LCSSA1:%.*]] = phi i32 [ [[EXPR]], [[LATCH]] ] |
| ; CHECK-NEXT: ret i32 [[EXPR_LCSSA1]] |
| ; |
| entry: |
| br label %header |
| header: |
| %iv = phi i32 [0, %entry], [%iv.next, %latch] |
| %expr = udiv i32 %iv, 5 |
| %v = load volatile i32, i32* @G |
| %cmp1 = icmp eq i32 %v, 0 |
| br i1 %cmp1, label %latch, label %exit1 |
| |
| latch: |
| %iv.next = add i32 %iv, 1 |
| %cmp2 = icmp ult i32 %iv, %n |
| br i1 %cmp2, label %header, label %exit2 |
| exit1: |
| ret i32 %expr |
| exit2: |
| ret i32 %expr |
| } |
| |
| |
| ; A slightly more real example where we're searching for either a) the first |
| ; non-zero element, or b) the end of a memory region. |
| define i32 @bounded_find(i32 %n) { |
| ; CHECK-LABEL: @bounded_find( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], 1 |
| ; CHECK-NEXT: br label [[HEADER:%.*]] |
| ; CHECK: header: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ] |
| ; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, i32* @G, i32 [[IV]] |
| ; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[ADDR]] |
| ; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[V]], 0 |
| ; CHECK-NEXT: br i1 [[CMP1]], label [[LATCH]], label [[EXIT1:%.*]] |
| ; CHECK: latch: |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV_NEXT]], [[TMP0]] |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label [[HEADER]], label [[EXIT2:%.*]] |
| ; CHECK: exit1: |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[IV]], [[HEADER]] ] |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] |
| ; CHECK: exit2: |
| ; CHECK-NEXT: ret i32 [[N]] |
| ; |
| entry: |
| br label %header |
| header: |
| %iv = phi i32 [0, %entry], [%iv.next, %latch] |
| %addr = getelementptr i32, i32* @G, i32 %iv |
| %v = load i32, i32* %addr |
| %cmp1 = icmp eq i32 %v, 0 |
| br i1 %cmp1, label %latch, label %exit1 |
| |
| latch: |
| %iv.next = add i32 %iv, 1 |
| %cmp2 = icmp ult i32 %iv, %n |
| br i1 %cmp2, label %header, label %exit2 |
| exit1: |
| ret i32 %iv |
| exit2: |
| ret i32 %iv |
| } |