Index: include/llvm/Analysis/LoopAccessAnalysis.h =================================================================== --- include/llvm/Analysis/LoopAccessAnalysis.h +++ include/llvm/Analysis/LoopAccessAnalysis.h @@ -104,10 +104,16 @@ void insert(ScalarEvolution *SE, Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId, unsigned ASId, ValueToValueMap &Strides); + /// \brief No run-time memory checking is necessary. + bool empty() const { return Pointers.empty(); } + /// \brief Decide whether we need to issue a run-time check for pointer at /// index \p I and \p J to prove their independence. bool needsChecking(unsigned I, unsigned J) const; + /// \brief Print the list run-time memory checks necessary. + void print(raw_ostream &OS, unsigned Depth = 0) const; + /// This flag indicates if we need to add the runtime check. bool Need; /// Holds the pointers that we need to check. @@ -165,6 +171,9 @@ /// couldn't analyze the loop. Optional &getReport() { return Report; } + /// \brief Print the information about the memory accesses in the loop. + void print(raw_ostream &OS, unsigned Depth = 0) const; + private: /// \brief Analyze the loop. Substitute symbolic strides using Strides. void analyzeLoop(ValueToValueMap &Strides); @@ -244,6 +253,9 @@ LoopAccessInfoMap.clear(); } + /// \brief Print the result of the analysis when invoked with -analyze. + void print(raw_ostream &OS, const Module *M = nullptr) const override; + private: /// \brief The cache. DenseMap> LoopAccessInfoMap; Index: lib/Analysis/LoopAccessAnalysis.cpp =================================================================== --- lib/Analysis/LoopAccessAnalysis.cpp +++ lib/Analysis/LoopAccessAnalysis.cpp @@ -109,6 +109,23 @@ return true; } +void LoopAccessInfo::RuntimePointerCheck::print(raw_ostream &OS, + unsigned Depth) const { + unsigned NumPointers = Pointers.size(); + if (NumPointers == 0) + return; + + OS.indent(Depth) << "Run-time memory checks:\n"; + unsigned N = 0; + for (unsigned I = 0; I < NumPointers; ++I) + for (unsigned J = I + 1; J < NumPointers; ++J) + if (needsChecking(I, J)) { + OS.indent(Depth) << N++ << ":\n"; + OS.indent(Depth + 2) << *Pointers[I] << "\n"; + OS.indent(Depth + 2) << *Pointers[J] << "\n"; + } +} + namespace { /// \brief Analyses memory accesses in a loop. /// @@ -1259,6 +1276,25 @@ return std::make_pair(FirstInst, Check); } +void LoopAccessInfo::print(raw_ostream &OS, unsigned Depth) const { + if (CanVecMem) { + if (PtrRtCheck.empty()) + OS.indent(Depth) << "Memory dependences are safe\n"; + else + OS.indent(Depth) << "Memory dependences are safe with run-time checks\n"; + } + + if (Report) { + OS.indent(Depth) << "Report: " << Report->str() << "\n"; + } + + // FIXME: Print unsafe dependences + + // List the pair of accesses need run-time checks to prove independence. + PtrRtCheck.print(OS, Depth); + OS << "\n"; +} + LoopAccessInfo *LoopAccessAnalysis::getInfo(Loop *L, ValueToValueMap &Strides) { auto &LAI = LoopAccessInfoMap[L]; @@ -1278,6 +1314,19 @@ return LAI.get(); } +void LoopAccessAnalysis::print(raw_ostream &OS, const Module *M) const { + LoopAccessAnalysis &LAA = *const_cast(this); + + LoopInfo *LI = &getAnalysis().getLoopInfo(); + ValueToValueMap NoSymbolicStrides; + + for (Loop *TopLevelLoop : *LI) + for (Loop *L : depth_first(TopLevelLoop)) { + OS.indent(2) << L->getHeader()->getName() << ":\n"; + LAA.getInfo(L, NoSymbolicStrides)->print(OS, 4); + } +} + bool LoopAccessAnalysis::runOnFunction(Function &F) { SE = &getAnalysis(); DataLayoutPass *DLP = getAnalysisIfAvailable(); @@ -1294,6 +1343,7 @@ AU.addRequired(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); AU.setPreservesAll(); } @@ -1306,6 +1356,7 @@ INITIALIZE_AG_DEPENDENCY(AliasAnalysis) INITIALIZE_PASS_DEPENDENCY(ScalarEvolution) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) +INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_END(LoopAccessAnalysis, LAA_NAME, laa_name, false, true) namespace llvm { Index: test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll =================================================================== --- /dev/null +++ test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll @@ -0,0 +1,59 @@ +; RUN: opt -loop-accesses -analyze < %s | FileCheck %s +; RUN: opt -loop-accesses -analyze -debug-only=loop-accesses < %s 2>&1 | FileCheck %s --check-prefix=DEBUG + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.10.0" + +; for (i = 0; i < n; i++) +; A[i + 1] = A[i] * B[i] * C[i]; + +; CHECK: Report: unsafe dependent memory operations in loop + +; DEBUG: LAA: Distance for %loadA = load i16* %arrayidxA, align 2 to store i16 %mul1, i16* %arrayidxA_plus_2, align 2: 2 +; DEBUG-NEXT: LAA: Failure because of Positive distance 2 + +; CHECK: Run-time memory checks: +; CHECK-NEXT: 0: +; CHECK-NEXT: %arrayidxA_plus_2 = getelementptr inbounds i16* %a, i64 %add +; CHECK-NEXT: %arrayidxB = getelementptr inbounds i16* %b, i64 %storemerge3 +; CHECK-NEXT: 1: +; CHECK-NEXT: %arrayidxA_plus_2 = getelementptr inbounds i16* %a, i64 %add +; CHECK-NEXT: %arrayidxC = getelementptr inbounds i16* %c, i64 %storemerge3 + +@n = global i32 20, align 4 +@B = common global i16* null, align 8 +@A = common global i16* null, align 8 +@C = common global i16* null, align 8 + +define void @f() { +entry: + %a = load i16** @A, align 8 + %b = load i16** @B, align 8 + %c = load i16** @C, align 8 + br label %for.body + +for.body: ; preds = %for.body, %entry + %storemerge3 = phi i64 [ 0, %entry ], [ %add, %for.body ] + + %arrayidxA = getelementptr inbounds i16* %a, i64 %storemerge3 + %loadA = load i16* %arrayidxA, align 2 + + %arrayidxB = getelementptr inbounds i16* %b, i64 %storemerge3 + %loadB = load i16* %arrayidxB, align 2 + + %arrayidxC = getelementptr inbounds i16* %c, i64 %storemerge3 + %loadC = load i16* %arrayidxC, align 2 + + %mul = mul i16 %loadB, %loadA + %mul1 = mul i16 %mul, %loadC + + %add = add nuw nsw i64 %storemerge3, 1 + %arrayidxA_plus_2 = getelementptr inbounds i16* %a, i64 %add + store i16 %mul1, i16* %arrayidxA_plus_2, align 2 + + %exitcond = icmp eq i64 %add, 20 + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +}