From c182ce09e9cc3e384f5c5c322fb8b48c8dfb6b17 Mon Sep 17 00:00:00 2001 From: Adam Nemet Date: Thu, 19 Feb 2015 19:15:19 +0000 Subject: [PATCH] [LoopAccesses] Add -analyze support The LoopInfo in combination with depth_first is used to enumerate the loops. Right now -analyze is not yet complete. It only prints the result of the analysis, the report and the run-time checks. Printing the unsafe depedences will require a bit more reshuffling which I'd like to do in a follow-on to this patchset. Unsafe dependences are currently checked via -debug-only=loop-accesses in the new test. This is part of the patchset that converts LoopAccessAnalysis into an actual analysis pass. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@229898 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/LoopAccessAnalysis.h | 12 ++++ lib/Analysis/LoopAccessAnalysis.cpp | 51 ++++++++++++++++ .../unsafe-and-rt-checks-no-dbg.ll | 60 ++++++++++++++++++ .../unsafe-and-rt-checks.ll | 61 +++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks-no-dbg.ll create mode 100644 test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll diff --git a/include/llvm/Analysis/LoopAccessAnalysis.h b/include/llvm/Analysis/LoopAccessAnalysis.h index a2f938ca67c..b54279aa1b6 100644 --- a/include/llvm/Analysis/LoopAccessAnalysis.h +++ b/include/llvm/Analysis/LoopAccessAnalysis.h @@ -122,10 +122,16 @@ public: 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. @@ -176,6 +182,9 @@ public: /// 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; + /// \brief Used to ensure that if the analysis was run with speculating the /// value of symbolic strides, the client queries it with the same assumption. /// Only used in DEBUG build but we don't want NDEBUG-depedent ABI. @@ -258,6 +267,9 @@ public: 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; diff --git a/lib/Analysis/LoopAccessAnalysis.cpp b/lib/Analysis/LoopAccessAnalysis.cpp index 3e86cafd14f..e9815eb379f 100644 --- a/lib/Analysis/LoopAccessAnalysis.cpp +++ b/lib/Analysis/LoopAccessAnalysis.cpp @@ -135,6 +135,23 @@ bool LoopAccessInfo::RuntimePointerCheck::needsChecking(unsigned I, 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. /// @@ -1291,6 +1308,24 @@ LoopAccessInfo::LoopAccessInfo(Loop *L, ScalarEvolution *SE, analyzeLoop(Strides); } +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]; @@ -1308,6 +1343,20 @@ LoopAccessInfo &LoopAccessAnalysis::getInfo(Loop *L, ValueToValueMap &Strides) { 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"; + auto &LAI = LAA.getInfo(L, NoSymbolicStrides); + LAI.print(OS, 4); + } +} + bool LoopAccessAnalysis::runOnFunction(Function &F) { SE = &getAnalysis(); DL = F.getParent()->getDataLayout(); @@ -1323,6 +1372,7 @@ void LoopAccessAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); AU.setPreservesAll(); } @@ -1335,6 +1385,7 @@ INITIALIZE_PASS_BEGIN(LoopAccessAnalysis, LAA_NAME, laa_name, false, true) 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 { diff --git a/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks-no-dbg.ll b/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks-no-dbg.ll new file mode 100644 index 00000000000..62291d55b4c --- /dev/null +++ b/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks-no-dbg.ll @@ -0,0 +1,60 @@ +; RUN: opt -loop-accesses -analyze < %s | FileCheck %s + +; FIXME: This is the non-debug version of unsafe-and-rt-checks.ll not +; requiring "asserts". Once we can check memory dependences without -debug, +; we should remove this test. + +; Analyze this loop: +; for (i = 0; i < n; i++) +; A[i + 1] = A[i] * B[i] * C[i]; + +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: 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 +} diff --git a/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll b/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll new file mode 100644 index 00000000000..4769a3a47a6 --- /dev/null +++ b/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll @@ -0,0 +1,61 @@ +; 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 +; REQUIRES: asserts + +; Analyze this loop: +; for (i = 0; i < n; i++) +; A[i + 1] = A[i] * B[i] * C[i]; + +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 + +; 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 +}