| ; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt -passes='print<access-info>' -disable-output %s 2>&1 | FileCheck %s |
| |
| declare noalias ptr @malloc(i64) |
| declare void @stash(ptr) |
| declare ptr @get() |
| declare ptr @passthrough(ptr) |
| |
| ; %a is only captured after the loop, so %q cannot be based on %a. |
| define void @capture_after_loop(ptr %slot, i64 %n) { |
| ; CHECK-LABEL: 'capture_after_loop' |
| ; CHECK-NEXT: loop: |
| ; CHECK-NEXT: Memory dependences are safe |
| ; CHECK-NEXT: Dependences: |
| ; CHECK-NEXT: Run-time memory checks: |
| ; CHECK-NEXT: Grouped accesses: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. |
| ; CHECK-NEXT: SCEV assumptions: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Expressions re-written: |
| ; |
| entry: |
| %a = call noalias ptr @malloc(i64 4000) |
| %q = load ptr, ptr %slot, align 8 |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %iv.1 = add nuw nsw i64 %iv, 1 |
| %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| %l = load i32, ptr %gep.q, align 4 |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| store i32 %l, ptr %gep.a, align 4 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %ec = icmp eq i64 %iv.next, %n |
| br i1 %ec, label %exit, label %loop |
| |
| exit: |
| store ptr %a, ptr %slot, align 8 |
| ret void |
| } |
| |
| ; %a is captured in the loop, but %q is loaded before the loop, so the capture |
| ; cannot reach it. |
| define void @capture_in_loop_load_before_loop(ptr %slot, i64 %n) { |
| ; CHECK-LABEL: 'capture_in_loop_load_before_loop' |
| ; CHECK-NEXT: loop: |
| ; CHECK-NEXT: Memory dependences are safe with run-time checks |
| ; CHECK-NEXT: Dependences: |
| ; CHECK-NEXT: Run-time memory checks: |
| ; CHECK-NEXT: Check 0: |
| ; CHECK-NEXT: Comparing group GRP0: |
| ; CHECK-NEXT: ptr %slot |
| ; CHECK-NEXT: Against group GRP1: |
| ; CHECK-NEXT: %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| ; CHECK-NEXT: Grouped accesses: |
| ; CHECK-NEXT: Group GRP0: |
| ; CHECK-NEXT: (Low: %slot High: (8 + %slot)) |
| ; CHECK-NEXT: Member: %slot |
| ; CHECK-NEXT: Group GRP1: |
| ; CHECK-NEXT: (Low: (4 + %q)<nuw> High: (4 + (4 * %n) + %q)) |
| ; CHECK-NEXT: Member: {(4 + %q)<nuw>,+,4}<nuw><%loop> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. |
| ; CHECK-NEXT: SCEV assumptions: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Expressions re-written: |
| ; |
| entry: |
| %a = call noalias ptr @malloc(i64 4000) |
| %q = load ptr, ptr %slot, align 8 |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %iv.1 = add nuw nsw i64 %iv, 1 |
| %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| %l = load i32, ptr %gep.q, align 4 |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| store i32 %l, ptr %gep.a, align 4 |
| store ptr %a, ptr %slot, align 8 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %ec = icmp eq i64 %iv.next, %n |
| br i1 %ec, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| ; The capture of %a later in the loop body reaches the load of %q in the next |
| ; iteration via the backedge, so %q may be based on %a. |
| define void @capture_in_loop_reaches_load_via_backedge(ptr %slot, i64 %n) { |
| ; CHECK-LABEL: 'capture_in_loop_reaches_load_via_backedge' |
| ; CHECK-NEXT: loop: |
| ; CHECK-NEXT: Report: cannot identify array bounds |
| ; CHECK-NEXT: Dependences: |
| ; CHECK-NEXT: Run-time memory checks: |
| ; CHECK-NEXT: Grouped accesses: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Non vectorizable stores to invariant address were found in loop. |
| ; CHECK-NEXT: SCEV assumptions: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Expressions re-written: |
| ; |
| entry: |
| %a = call noalias ptr @malloc(i64 4000) |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %q = load ptr, ptr %slot, align 8 |
| %iv.1 = add nuw nsw i64 %iv, 1 |
| %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| %l = load i32, ptr %gep.q, align 4 |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| store i32 %l, ptr %gep.a, align 4 |
| store ptr %a, ptr %slot, align 8 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %ec = icmp eq i64 %iv.next, %n |
| br i1 %ec, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| ; The capture of %a in the outer loop latch reaches the load of %q in later |
| ; iterations of the outer loop, so %q may be based on %a. |
| define void @capture_reaches_load_via_outer_backedge(ptr %slot, i64 %n, i64 %m) { |
| ; CHECK-LABEL: 'capture_reaches_load_via_outer_backedge' |
| ; CHECK-NEXT: inner: |
| ; CHECK-NEXT: Memory dependences are safe with run-time checks |
| ; CHECK-NEXT: Dependences: |
| ; CHECK-NEXT: Run-time memory checks: |
| ; CHECK-NEXT: Check 0: |
| ; CHECK-NEXT: Comparing group GRP0: |
| ; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| ; CHECK-NEXT: Against group GRP1: |
| ; CHECK-NEXT: %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| ; CHECK-NEXT: Grouped accesses: |
| ; CHECK-NEXT: Group GRP0: |
| ; CHECK-NEXT: (Low: %a High: ((4 * %n) + %a)) |
| ; CHECK-NEXT: Member: {%a,+,4}<nuw><%inner> |
| ; CHECK-NEXT: Group GRP1: |
| ; CHECK-NEXT: (Low: (4 + %q)<nuw> High: (4 + (4 * %n) + %q)) |
| ; CHECK-NEXT: Member: {(4 + %q)<nuw>,+,4}<nuw><%inner> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. |
| ; CHECK-NEXT: SCEV assumptions: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Expressions re-written: |
| ; CHECK-NEXT: outer.header: |
| ; CHECK-NEXT: Report: loop is not the innermost loop |
| ; CHECK-NEXT: Dependences: |
| ; CHECK-NEXT: Run-time memory checks: |
| ; CHECK-NEXT: Grouped accesses: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. |
| ; CHECK-NEXT: SCEV assumptions: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Expressions re-written: |
| ; |
| entry: |
| %a = call noalias ptr @malloc(i64 4000) |
| br label %outer.header |
| |
| outer.header: |
| %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ] |
| %q = load ptr, ptr %slot, align 8 |
| br label %inner |
| |
| inner: |
| %iv = phi i64 [ 0, %outer.header ], [ %iv.next, %inner ] |
| %iv.1 = add nuw nsw i64 %iv, 1 |
| %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| %l = load i32, ptr %gep.q, align 4 |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| store i32 %l, ptr %gep.a, align 4 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %ec = icmp eq i64 %iv.next, %n |
| br i1 %ec, label %outer.latch, label %inner |
| |
| outer.latch: |
| store ptr %a, ptr %slot, align 8 |
| %outer.iv.next = add nuw nsw i64 %outer.iv, 1 |
| %outer.ec = icmp eq i64 %outer.iv.next, %m |
| br i1 %outer.ec, label %exit, label %outer.header |
| |
| exit: |
| ret void |
| } |
| |
| ; %a is captured before %q is loaded, so %q may be based on %a. |
| define void @capture_before_loop(ptr %slot, i64 %n) { |
| ; CHECK-LABEL: 'capture_before_loop' |
| ; CHECK-NEXT: loop: |
| ; CHECK-NEXT: Memory dependences are safe with run-time checks |
| ; CHECK-NEXT: Dependences: |
| ; CHECK-NEXT: Run-time memory checks: |
| ; CHECK-NEXT: Check 0: |
| ; CHECK-NEXT: Comparing group GRP0: |
| ; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| ; CHECK-NEXT: Against group GRP1: |
| ; CHECK-NEXT: %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| ; CHECK-NEXT: Grouped accesses: |
| ; CHECK-NEXT: Group GRP0: |
| ; CHECK-NEXT: (Low: %a High: ((4 * %n) + %a)) |
| ; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop> |
| ; CHECK-NEXT: Group GRP1: |
| ; CHECK-NEXT: (Low: (4 + %q)<nuw> High: (4 + (4 * %n) + %q)) |
| ; CHECK-NEXT: Member: {(4 + %q)<nuw>,+,4}<nuw><%loop> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. |
| ; CHECK-NEXT: SCEV assumptions: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Expressions re-written: |
| ; |
| entry: |
| %a = call noalias ptr @malloc(i64 4000) |
| store ptr %a, ptr %slot, align 8 |
| %q = load ptr, ptr %slot, align 8 |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %iv.1 = add nuw nsw i64 %iv, 1 |
| %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| %l = load i32, ptr %gep.q, align 4 |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| store i32 %l, ptr %gep.a, align 4 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %ec = icmp eq i64 %iv.next, %n |
| br i1 %ec, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| ; @stash may store %a somewhere @get can return it from. |
| define void @capture_via_call_before_loop(i64 %n) { |
| ; CHECK-LABEL: 'capture_via_call_before_loop' |
| ; CHECK-NEXT: loop: |
| ; CHECK-NEXT: Memory dependences are safe with run-time checks |
| ; CHECK-NEXT: Dependences: |
| ; CHECK-NEXT: Run-time memory checks: |
| ; CHECK-NEXT: Check 0: |
| ; CHECK-NEXT: Comparing group GRP0: |
| ; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| ; CHECK-NEXT: Against group GRP1: |
| ; CHECK-NEXT: %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| ; CHECK-NEXT: Grouped accesses: |
| ; CHECK-NEXT: Group GRP0: |
| ; CHECK-NEXT: (Low: %a High: ((4 * %n) + %a)) |
| ; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop> |
| ; CHECK-NEXT: Group GRP1: |
| ; CHECK-NEXT: (Low: (4 + %q) High: (4 + (4 * %n) + %q)) |
| ; CHECK-NEXT: Member: {(4 + %q),+,4}<nuw><%loop> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. |
| ; CHECK-NEXT: SCEV assumptions: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Expressions re-written: |
| ; |
| entry: |
| %a = call noalias ptr @malloc(i64 4000) |
| call void @stash(ptr %a) |
| %q = call ptr @get() |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %iv.1 = add nuw nsw i64 %iv, 1 |
| %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| %l = load i32, ptr %gep.q, align 4 |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| store i32 %l, ptr %gep.a, align 4 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %ec = icmp eq i64 %iv.next, %n |
| br i1 %ec, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |
| |
| ; The call producing %q captures %a itself and may return it. |
| define void @capture_by_escape_source_call(i64 %n) { |
| ; CHECK-LABEL: 'capture_by_escape_source_call' |
| ; CHECK-NEXT: loop: |
| ; CHECK-NEXT: Memory dependences are safe with run-time checks |
| ; CHECK-NEXT: Dependences: |
| ; CHECK-NEXT: Run-time memory checks: |
| ; CHECK-NEXT: Check 0: |
| ; CHECK-NEXT: Comparing group GRP0: |
| ; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| ; CHECK-NEXT: Against group GRP1: |
| ; CHECK-NEXT: %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| ; CHECK-NEXT: Grouped accesses: |
| ; CHECK-NEXT: Group GRP0: |
| ; CHECK-NEXT: (Low: %a High: ((4 * %n) + %a)) |
| ; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop> |
| ; CHECK-NEXT: Group GRP1: |
| ; CHECK-NEXT: (Low: (4 + %q) High: (4 + (4 * %n) + %q)) |
| ; CHECK-NEXT: Member: {(4 + %q),+,4}<nuw><%loop> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. |
| ; CHECK-NEXT: SCEV assumptions: |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: Expressions re-written: |
| ; |
| entry: |
| %a = call noalias ptr @malloc(i64 4000) |
| %q = call ptr @passthrough(ptr %a) |
| br label %loop |
| |
| loop: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] |
| %iv.1 = add nuw nsw i64 %iv, 1 |
| %gep.q = getelementptr inbounds i32, ptr %q, i64 %iv.1 |
| %l = load i32, ptr %gep.q, align 4 |
| %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv |
| store i32 %l, ptr %gep.a, align 4 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %ec = icmp eq i64 %iv.next, %n |
| br i1 %ec, label %exit, label %loop |
| |
| exit: |
| ret void |
| } |