| ; 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 | |
| } |