Skip to content

Commit

Permalink
[LAA] Add Memory dependence remarks.
Browse files Browse the repository at this point in the history
Adds new optimization remarks when vectorization fails.

More specifically, new remarks are added for following 4 cases:

- Backward dependency
- Backward dependency that prevents Store-to-load forwarding
- Forward dependency that prevents Store-to-load forwarding
- Unknown dependency

It is important to note that only one of the sources
of failures (to vectorize) is reported by the remarks.
This source of failure may not be first in program order.

A regression test has been added to test the following cases:

a) Loop can be vectorized: No optimization remark is emitted
b) Loop can not be vectorized: In this case an optimization
remark will be emitted for one source of failure.

Reviewed By: sdesmalen, david-arm

Differential Revision: https://reviews.llvm.org/D108371
  • Loading branch information
malJaj committed Feb 2, 2022
1 parent 5aa2acc commit 778b455
Show file tree
Hide file tree
Showing 12 changed files with 491 additions and 11 deletions.
5 changes: 5 additions & 0 deletions llvm/include/llvm/Analysis/LoopAccessAnalysis.h
Expand Up @@ -605,6 +605,11 @@ class LoopAccessInfo {
/// invariant.
void collectStridedAccess(Value *LoadOrStoreInst);

// Emits the first unsafe memory dependence in a loop.
// Emits nothing if there are no unsafe dependences
// or if the dependences were not recorded.
void emitUnsafeDependenceRemark();

std::unique_ptr<PredicatedScalarEvolution> PSE;

/// We need to check that all of the pointers in this list are disjoint
Expand Down
62 changes: 55 additions & 7 deletions llvm/lib/Analysis/LoopAccessAnalysis.cpp
Expand Up @@ -2129,13 +2129,61 @@ void LoopAccessInfo::analyzeLoop(AAResults *AA, LoopInfo *LI,
dbgs() << "LAA: No unsafe dependent memory operations in loop. We"
<< (PtrRtChecking->Need ? "" : " don't")
<< " need runtime memory checks.\n");
else {
recordAnalysis("UnsafeMemDep")
<< "unsafe dependent memory operations in loop. Use "
"#pragma loop distribute(enable) to allow loop distribution "
"to attempt to isolate the offending operations into a separate "
"loop";
LLVM_DEBUG(dbgs() << "LAA: unsafe dependent memory operations in loop\n");
else
emitUnsafeDependenceRemark();
}

void LoopAccessInfo::emitUnsafeDependenceRemark() {
auto Deps = getDepChecker().getDependences();
if (!Deps)
return;
auto Found = std::find_if(
Deps->begin(), Deps->end(), [](const MemoryDepChecker::Dependence &D) {
return MemoryDepChecker::Dependence::isSafeForVectorization(D.Type) !=
MemoryDepChecker::VectorizationSafetyStatus::Safe;
});
if (Found == Deps->end())
return;
MemoryDepChecker::Dependence Dep = *Found;

LLVM_DEBUG(dbgs() << "LAA: unsafe dependent memory operations in loop\n");

// Emit remark for first unsafe dependence
OptimizationRemarkAnalysis &R =
recordAnalysis("UnsafeDep", Dep.getDestination(*this))
<< "unsafe dependent memory operations in loop. Use "
"#pragma loop distribute(enable) to allow loop distribution "
"to attempt to isolate the offending operations into a separate "
"loop";

switch (Dep.Type) {
case MemoryDepChecker::Dependence::NoDep:
case MemoryDepChecker::Dependence::Forward:
case MemoryDepChecker::Dependence::BackwardVectorizable:
llvm_unreachable("Unexpected dependence");
case MemoryDepChecker::Dependence::Backward:
R << "\nBackward loop carried data dependence.";
break;
case MemoryDepChecker::Dependence::ForwardButPreventsForwarding:
R << "\nForward loop carried data dependence that prevents "
"store-to-load forwarding.";
break;
case MemoryDepChecker::Dependence::BackwardVectorizableButPreventsForwarding:
R << "\nBackward loop carried data dependence that prevents "
"store-to-load forwarding.";
break;
case MemoryDepChecker::Dependence::Unknown:
R << "\nUnknown data dependence.";
break;
}

if (Instruction *I = Dep.getSource(*this)) {
DebugLoc SourceLoc = I->getDebugLoc();
if (auto *DD = dyn_cast_or_null<Instruction>(getPointerOperand(I)))
SourceLoc = DD->getDebugLoc();
if (SourceLoc)
R << " Memory location is the same as accessed at "
<< ore::NV("Location", SourceLoc);
}
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll
Expand Up @@ -78,6 +78,7 @@ exit:
; CHECK-LABEL: function 'backdep_type_store_size_equivalence':
; CHECK-NEXT: loop:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop.
; CHECK-NEXT: Unknown data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Unknown:
; CHECK-NEXT: %ld.f32 = load float, float* %gep.iv.f32, align 8 ->
Expand Down Expand Up @@ -120,6 +121,7 @@ exit:
; CHECK-LABEL: function 'neg_dist_dep_type_size_equivalence':
; CHECK-NEXT: loop:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop.
; CHECK-NEXT: Unknown data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Unknown:
; CHECK-NEXT: %ld.i64 = load i64, i64* %gep.iv, align 8 ->
Expand Down
6 changes: 6 additions & 0 deletions llvm/test/Analysis/LoopAccessAnalysis/pointer-phis.ll
Expand Up @@ -127,6 +127,7 @@ define i32 @load_with_pointer_phi_outside_loop(double* %A, double* %B, double* %
; CHECK-LABEL: 'load_with_pointer_phi_outside_loop'
; CHECK-NEXT: loop.header:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
; CHECK-NEXT: Unknown data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Unknown:
; CHECK-NEXT: %v8 = load double, double* %ptr, align 8 ->
Expand Down Expand Up @@ -164,6 +165,7 @@ define i32 @store_with_pointer_phi_outside_loop(double* %A, double* %B, double*
; CHECK-LABEL: 'store_with_pointer_phi_outside_loop'
; CHECK-NEXT: loop.header:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop.
; CHECK-NEXT: Unknown data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Unknown:
; CHECK-NEXT: %v8 = load double, double* %arrayidx, align 8 ->
Expand Down Expand Up @@ -201,6 +203,7 @@ define i32 @store_with_pointer_phi_incoming_phi(double* %A, double* %B, double*
; CHECK-LABEL: 'store_with_pointer_phi_incoming_phi'
; CHECK-NEXT: loop.header:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma 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: %v8 = load double, double* %arrayidx, align 8 ->
Expand Down Expand Up @@ -277,6 +280,7 @@ define i32 @store_with_pointer_phi_incoming_phi_irreducible_cycle(double* %A, do
; CHECK-LABEL: 'store_with_pointer_phi_incoming_phi_irreducible_cycle'
; CHECK-NEXT: loop.header:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma 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: %v8 = load double, double* %arrayidx, align 8 ->
Expand Down Expand Up @@ -348,6 +352,7 @@ define i32 @store_with_pointer_phi_outside_loop_select(double* %A, double* %B, d
; CHECK-LABEL: 'store_with_pointer_phi_outside_loop_select'
; CHECK-NEXT: loop.header:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop.
; CHECK-NEXT: Unknown data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Unknown:
; CHECK-NEXT: %v8 = load double, double* %arrayidx, align 8 ->
Expand Down Expand Up @@ -413,6 +418,7 @@ define void @phi_load_store_memdep_check(i1 %c, i16* %A, i16* %B, i16* %C) {
; CHECK-LABEL: Loop access info in function 'phi_load_store_memdep_check':
; CHECK-NEXT: for.body:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma 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: %lv3 = load i16, i16* %c.sink, align 2 ->
Expand Down
Expand Up @@ -13,6 +13,7 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
; CHECK-NEXT: for.body:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
; CHECK-NOT: Report: cannot identify array bounds
; CHECK-NEXT: Unknown data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Unknown:
; CHECK-NEXT: %loadA = load i16, i16* %arrayidxA, align 2 ->
Expand Down
Expand Up @@ -118,6 +118,7 @@ for.body: ; preds = %entry, %for.body
; CHECK: function 'unsafe_Read_Write':
; CHECK-NEXT: for.body:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: %0 = load i32, i32* %arrayidx, align 4 ->
Expand Down Expand Up @@ -157,6 +158,7 @@ for.body: ; preds = %entry, %for.body
; CHECK: function 'unsafe_Write_Read':
; CHECK-NEXT: for.body:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: store i32 %0, i32* %arrayidx, align 4 ->
Expand Down Expand Up @@ -193,6 +195,7 @@ for.body: ; preds = %entry, %for.body
; CHECK: function 'unsafe_Write_Write':
; CHECK-NEXT: for.body:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: store i32 %0, i32* %arrayidx, align 4 ->
Expand Down Expand Up @@ -346,6 +349,7 @@ for.body: ; preds = %entry, %for.body
; CHECK: function 'vectorizable_unscaled_Read_Write':
; CHECK-NEXT: for.body:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
; CHECK-NEXT: Backward loop carried data dependence that prevents store-to-load forwarding.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizableButPreventsForwarding:
; CHECK-NEXT: %2 = load i32, i32* %arrayidx, align 4 ->
Expand Down Expand Up @@ -425,6 +429,7 @@ for.body: ; preds = %entry, %for.body
; CHECK: function 'unsafe_unscaled_Read_Write':
; CHECK-NEXT: for.body:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: %2 = load i32, i32* %arrayidx, align 4 ->
Expand Down Expand Up @@ -455,6 +460,7 @@ for.body: ; preds = %entry, %for.body
; CHECK: function 'unsafe_unscaled_Read_Write2':
; CHECK-NEXT: for.body:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: %2 = load i32, i32* %arrayidx, align 4 ->
Expand Down Expand Up @@ -505,6 +511,7 @@ for.body: ; preds = %entry, %for.body
; CHECK: function 'interleaved_stores':
; CHECK-NEXT: for.body:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: store i32 %4, i32* %arrayidx5, align 4 ->
Expand Down
3 changes: 3 additions & 0 deletions llvm/test/Analysis/LoopAccessAnalysis/symbolic-stride.ll
Expand Up @@ -8,6 +8,7 @@ define void @single_stride(i32* noalias %A, i32* noalias %B, i64 %N, i64 %stride
; CHECK-LABEL: Loop access info in function 'single_stride':
; CHECK-NEXT: loop:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop.
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: %load = load i32, i32* %gep.A, align 4 ->
Expand Down Expand Up @@ -51,6 +52,7 @@ define void @single_stride_struct({ i32, i8 }* noalias %A, { i32, i8 }* noalias
; CHECK-LABEL: Loop access info in function 'single_stride_struct':
; CHECK-NEXT: loop:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop.
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: %load = load { i32, i8 }, { i32, i8 }* %gep.A, align 4 ->
Expand Down Expand Up @@ -97,6 +99,7 @@ define void @two_strides(i32* noalias %A, i32* noalias %B, i64 %N, i64 %stride.1
; CHECK-LABEL: Loop access info in function 'two_strides':
; CHECK-NEXT: loop:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop.
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: %load = load i32, i32* %gep.A, align 4 ->
Expand Down
Expand Up @@ -39,6 +39,7 @@ target triple = "x86_64-apple-macosx10.10.0"
; CHECK-LABEL: function 'f'
; CHECK: for_j.body:
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: %loadB = load i8, i8* %gepB, align 1 ->
Expand Down
Expand Up @@ -8,6 +8,7 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.10.0"

; CHECK: Report: unsafe dependent memory operations in loop
; CHECK-NEXT: Backward loop carried data dependence.
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Backward:
; CHECK-NEXT: %loadA = load i16, i16* %arrayidxA, align 2 ->
Expand Down
Expand Up @@ -22,9 +22,12 @@
; 19 }
; 20 }

; CHECK: remark: /tmp/s.c:2:3: loop not vectorized: unsafe dependent memory operations in loop. Use #pragma loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop (hotness: 300)
; CHECK: remark: /tmp/s.c:9:3: loop not vectorized: unsafe dependent memory operations in loop. Use #pragma loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop (hotness: 5000)
; CHECK: remark: /tmp/s.c:16:3: loop not vectorized: unsafe dependent memory operations in loop. Use #pragma loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop{{$}}
; CHECK: remark: /tmp/s.c:3:14: loop not vectorized: unsafe dependent memory operations in loop. Use #pragma loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
; CHECK-NEXT: Backward loop carried data dependence. Memory location is the same as accessed at /tmp/s.c:3:16 (hotness: 300)
; CHECK: remark: /tmp/s.c:10:14: loop not vectorized: unsafe dependent memory operations in loop. Use #pragma loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
; CHECK-NEXT: Backward loop carried data dependence. Memory location is the same as accessed at /tmp/s.c:10:16 (hotness: 5000)
; CHECK: remark: /tmp/s.c:17:14: loop not vectorized: unsafe dependent memory operations in loop. Use #pragma loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
; CHECK-NEXT: Backward loop carried data dependence. Memory location is the same as accessed at /tmp/s.c:17:16{{$}}

; ModuleID = '/tmp/s.c'
source_filename = "/tmp/s.c"
Expand Down

0 comments on commit 778b455

Please sign in to comment.