
Add additional tests showing missed opportunities when using loop guards for reasoning in SCEV, depending on the order the guards appear in the IR.
439 lines
15 KiB
LLVM
439 lines
15 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5
|
|
; RUN: opt -passes='print<access-info>' -disable-output < %s 2>&1 | FileCheck %s
|
|
|
|
; Loop guard for %off guarantees the accesses in the loop do not overlap.
|
|
define void @access_after_via_loop_guard(ptr %a, i64 %off) {
|
|
; CHECK-LABEL: 'access_after_via_loop_guard'
|
|
; 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:
|
|
;
|
|
%c = icmp eq i64 %off, 100
|
|
br i1 %c, label %ph, label %exit
|
|
|
|
ph:
|
|
%gep.after = getelementptr inbounds nuw i32, ptr %a, i64 %off
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ 0, %ph ], [ %iv.next, %loop ]
|
|
%l = load i32 , ptr %gep.after, align 4
|
|
%add = add i32 %l, %l
|
|
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
|
|
store i32 %add, ptr %gep, align 4
|
|
%iv.next = add nsw nuw i64 %iv, 1
|
|
%ec = icmp eq i64 %iv.next, 100
|
|
br i1 %ec, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Loop guard for %off guarantees the accesses in the loop do not overlap.
|
|
; TODO: currently missed by LAA
|
|
define void @access_after_via_loop_guard_sge(ptr %a, i64 %off) {
|
|
; CHECK-LABEL: 'access_after_via_loop_guard_sge'
|
|
; CHECK-NEXT: loop:
|
|
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
|
|
; CHECK-NEXT: Unknown data dependence.
|
|
; CHECK-NEXT: Dependences:
|
|
; CHECK-NEXT: Unknown:
|
|
; CHECK-NEXT: %l = load i32, ptr %gep.after, align 4 ->
|
|
; CHECK-NEXT: store i32 %add, ptr %gep, align 4
|
|
; CHECK-EMPTY:
|
|
; 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:
|
|
;
|
|
%c = icmp sge i64 %off, 100
|
|
br i1 %c, label %ph, label %exit
|
|
|
|
ph:
|
|
%gep.after = getelementptr inbounds nuw i32, ptr %a, i64 %off
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ 0, %ph ], [ %iv.next, %loop ]
|
|
%l = load i32 , ptr %gep.after, align 4
|
|
%add = add i32 %l, %l
|
|
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
|
|
store i32 %add, ptr %gep, align 4
|
|
%iv.next = add nsw nuw i64 %iv, 1
|
|
%ec = icmp eq i64 %iv.next, 100
|
|
br i1 %ec, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @access_after_via_loop_guard_99(ptr %a, i64 %off) {
|
|
; CHECK-LABEL: 'access_after_via_loop_guard_99'
|
|
; CHECK-NEXT: loop:
|
|
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
|
|
; CHECK-NEXT: Unknown data dependence.
|
|
; CHECK-NEXT: Dependences:
|
|
; CHECK-NEXT: Unknown:
|
|
; CHECK-NEXT: %l = load i32, ptr %gep.after, align 4 ->
|
|
; CHECK-NEXT: store i32 %add, ptr %gep, align 4
|
|
; CHECK-EMPTY:
|
|
; 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:
|
|
;
|
|
%c = icmp eq i64 %off, 99
|
|
br i1 %c, label %ph, label %exit
|
|
|
|
ph:
|
|
%gep.after = getelementptr inbounds nuw i32, ptr %a, i64 %off
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ 0, %ph ], [ %iv.next, %loop ]
|
|
%l = load i32 , ptr %gep.after, align 4
|
|
%add = add i32 %l, %l
|
|
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
|
|
store i32 %add, ptr %gep, align 4
|
|
%iv.next = add nsw nuw i64 %iv, 1
|
|
%ec = icmp eq i64 %iv.next, 100
|
|
br i1 %ec, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Loop guard for %off guarantees the accesses in the loop do not overlap.
|
|
; TODO: currently missed by LAA
|
|
define void @access_after_via_loop_guard_sge_99(ptr %a, i64 %off) {
|
|
; CHECK-LABEL: 'access_after_via_loop_guard_sge_99'
|
|
; CHECK-NEXT: loop:
|
|
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
|
|
; CHECK-NEXT: Unknown data dependence.
|
|
; CHECK-NEXT: Dependences:
|
|
; CHECK-NEXT: Unknown:
|
|
; CHECK-NEXT: %l = load i32, ptr %gep.after, align 4 ->
|
|
; CHECK-NEXT: store i32 %add, ptr %gep, align 4
|
|
; CHECK-EMPTY:
|
|
; 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:
|
|
;
|
|
%c = icmp sge i64 %off, 99
|
|
br i1 %c, label %ph, label %exit
|
|
|
|
ph:
|
|
%gep.after = getelementptr inbounds nuw i32, ptr %a, i64 %off
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ 0, %ph ], [ %iv.next, %loop ]
|
|
%l = load i32 , ptr %gep.after, align 4
|
|
%add = add i32 %l, %l
|
|
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
|
|
store i32 %add, ptr %gep, align 4
|
|
%iv.next = add nsw nuw i64 %iv, 1
|
|
%ec = icmp eq i64 %iv.next, 100
|
|
br i1 %ec, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @access_after_via_loop_guard_uge(ptr %a, i64 %off) {
|
|
; CHECK-LABEL: 'access_after_via_loop_guard_uge'
|
|
; CHECK-NEXT: loop:
|
|
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
|
|
; CHECK-NEXT: Unknown data dependence.
|
|
; CHECK-NEXT: Dependences:
|
|
; CHECK-NEXT: Unknown:
|
|
; CHECK-NEXT: %l = load i32, ptr %gep.after, align 4 ->
|
|
; CHECK-NEXT: store i32 %add, ptr %gep, align 4
|
|
; CHECK-EMPTY:
|
|
; 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:
|
|
;
|
|
%c = icmp uge i64 %off, 100
|
|
br i1 %c, label %ph, label %exit
|
|
|
|
ph:
|
|
%gep.after = getelementptr inbounds nuw i32, ptr %a, i64 %off
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ 0, %ph ], [ %iv.next, %loop ]
|
|
%l = load i32 , ptr %gep.after, align 4
|
|
%add = add i32 %l, %l
|
|
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
|
|
store i32 %add, ptr %gep, align 4
|
|
%iv.next = add nsw nuw i64 %iv, 1
|
|
%ec = icmp eq i64 %iv.next, 100
|
|
br i1 %ec, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Loop guard for %off guarantees the accesses in the loop do not overlap.
|
|
define void @access_after_via_loop_guard_eq_loop_cond(ptr %a, i64 %off) {
|
|
; CHECK-LABEL: 'access_after_via_loop_guard_eq_loop_cond'
|
|
; 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:
|
|
;
|
|
%c = icmp eq i64 %off, 100
|
|
br i1 %c, label %ph, label %exit
|
|
|
|
ph:
|
|
%gep.after = getelementptr inbounds nuw i32, ptr %a, i64 100
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ 0, %ph ], [ %iv.next, %loop ]
|
|
%l = load i32 , ptr %gep.after, align 4
|
|
%add = add i32 %l, %l
|
|
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
|
|
store i32 %add, ptr %gep, align 4
|
|
%iv.next = add nsw nuw i64 %iv, 1
|
|
%ec = icmp eq i64 %iv.next, %off
|
|
br i1 %ec, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @access_after_via_loop_guard_eq_loop_cond_100(ptr %a, i64 %off) {
|
|
; CHECK-LABEL: 'access_after_via_loop_guard_eq_loop_cond_100'
|
|
; CHECK-NEXT: loop:
|
|
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
|
|
; CHECK-NEXT: Unknown data dependence.
|
|
; CHECK-NEXT: Dependences:
|
|
; CHECK-NEXT: Unknown:
|
|
; CHECK-NEXT: %l = load i32, ptr %gep.after, align 4 ->
|
|
; CHECK-NEXT: store i32 %add, ptr %gep, align 4
|
|
; CHECK-EMPTY:
|
|
; 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:
|
|
;
|
|
%c = icmp eq i64 %off, 101
|
|
br i1 %c, label %ph, label %exit
|
|
|
|
ph:
|
|
%gep.after = getelementptr inbounds nuw i32, ptr %a, i64 100
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ 0, %ph ], [ %iv.next, %loop ]
|
|
%l = load i32 , ptr %gep.after, align 4
|
|
%add = add i32 %l, %l
|
|
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
|
|
store i32 %add, ptr %gep, align 4
|
|
%iv.next = add nsw nuw i64 %iv, 1
|
|
%ec = icmp eq i64 %iv.next, %off
|
|
br i1 %ec, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Loop guard for %off guarantees the accesses in the loop do not overlap.
|
|
; TODO: currently missed by LAA
|
|
define void @access_after_via_loop_guard_sge_loop_cond(ptr %a, i64 %off) {
|
|
; CHECK-LABEL: 'access_after_via_loop_guard_sge_loop_cond'
|
|
; CHECK-NEXT: loop:
|
|
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
|
|
; CHECK-NEXT: Unknown data dependence.
|
|
; CHECK-NEXT: Dependences:
|
|
; CHECK-NEXT: Unknown:
|
|
; CHECK-NEXT: %l = load i32, ptr %gep.after, align 4 ->
|
|
; CHECK-NEXT: store i32 %add, ptr %gep, align 4
|
|
; CHECK-EMPTY:
|
|
; 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:
|
|
;
|
|
%c = icmp sge i64 %off, 100
|
|
br i1 %c, label %ph, label %exit
|
|
|
|
ph:
|
|
%gep.after = getelementptr inbounds nuw i32, ptr %a, i64 100
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ 0, %ph ], [ %iv.next, %loop ]
|
|
%l = load i32 , ptr %gep.after, align 4
|
|
%add = add i32 %l, %l
|
|
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
|
|
store i32 %add, ptr %gep, align 4
|
|
%iv.next = add nsw nuw i64 %iv, 1
|
|
%ec = icmp eq i64 %iv.next, %off
|
|
br i1 %ec, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @access_after_via_loop_guard_sge_loop_cond_101(ptr %a, i64 %off) {
|
|
; CHECK-LABEL: 'access_after_via_loop_guard_sge_loop_cond_101'
|
|
; CHECK-NEXT: loop:
|
|
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
|
|
; CHECK-NEXT: Unknown data dependence.
|
|
; CHECK-NEXT: Dependences:
|
|
; CHECK-NEXT: Unknown:
|
|
; CHECK-NEXT: %l = load i32, ptr %gep.after, align 4 ->
|
|
; CHECK-NEXT: store i32 %add, ptr %gep, align 4
|
|
; CHECK-EMPTY:
|
|
; 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:
|
|
;
|
|
%c = icmp sge i64 %off, 101
|
|
br i1 %c, label %ph, label %exit
|
|
|
|
ph:
|
|
%gep.after = getelementptr inbounds nuw i32, ptr %a, i64 100
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ 0, %ph ], [ %iv.next, %loop ]
|
|
%l = load i32 , ptr %gep.after, align 4
|
|
%add = add i32 %l, %l
|
|
%gep = getelementptr inbounds i32, ptr %a, i64 %iv
|
|
store i32 %add, ptr %gep, align 4
|
|
%iv.next = add nsw nuw i64 %iv, 1
|
|
%ec = icmp eq i64 %iv.next, %off
|
|
br i1 %ec, label %exit, label %loop
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; TODO Should be able to determine no-dep, same as @nodep_via_logical_and_2.
|
|
define void @nodep_via_logical_and_1(ptr %A, i32 %index, i32 %n) {
|
|
; CHECK-LABEL: 'nodep_via_logical_and_1'
|
|
; CHECK-NEXT: loop:
|
|
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
|
|
; CHECK-NEXT: Unknown data dependence.
|
|
; CHECK-NEXT: Dependences:
|
|
; CHECK-NEXT: Unknown:
|
|
; CHECK-NEXT: %0 = load double, ptr %gep.load, align 8 ->
|
|
; CHECK-NEXT: store double %0, ptr %gep.store, align 8
|
|
; CHECK-EMPTY:
|
|
; 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:
|
|
%pre.0 = icmp sgt i32 %index, 0
|
|
%pre.1 = icmp slt i32 %index, %n
|
|
%and.pre = select i1 %pre.1, i1 %pre.0, i1 false
|
|
br i1 %and.pre, label %ph, label %exit
|
|
|
|
ph:
|
|
%idx.1 = add i32 %index, 1
|
|
%start = zext i32 %idx.1 to i64
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ %start, %ph ], [ %iv.next, %loop ]
|
|
%gep.load = getelementptr double, ptr %A, i64 %iv
|
|
%1 = load double, ptr %gep.load, align 8
|
|
%index.ext = zext i32 %index to i64
|
|
%gep.store = getelementptr double, ptr %A, i64 %index.ext
|
|
store double %1, ptr %gep.store, align 8
|
|
%iv.next = add i64 %iv, 1
|
|
%t = trunc i64 %iv to i32
|
|
%ec = icmp slt i32 %t, 1
|
|
br i1 %ec, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Same as nodep_via_logical_and_1 but with different operand order of the logical and.
|
|
define void @nodep_via_logical_and_2(ptr %A, i32 %index, i32 %n) {
|
|
; CHECK-LABEL: 'nodep_via_logical_and_2'
|
|
; 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:
|
|
%pre.0 = icmp sgt i32 %index, 0
|
|
%pre.1 = icmp slt i32 %index, %n
|
|
%and.pre = select i1 %pre.0, i1 %pre.1, i1 false
|
|
br i1 %and.pre, label %ph, label %exit
|
|
|
|
ph:
|
|
%idx.1 = add i32 %index, 1
|
|
%start = zext i32 %idx.1 to i64
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i64 [ %start, %ph ], [ %iv.next, %loop ]
|
|
%gep.load = getelementptr double, ptr %A, i64 %iv
|
|
%1 = load double, ptr %gep.load, align 8
|
|
%index.ext = zext i32 %index to i64
|
|
%gep.store = getelementptr double, ptr %A, i64 %index.ext
|
|
store double %1, ptr %gep.store, align 8
|
|
%iv.next = add i64 %iv, 1
|
|
%t = trunc i64 %iv to i32
|
|
%ec = icmp slt i32 %t, 1
|
|
br i1 %ec, label %loop, label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|