[llvm] r229633 - [LoopAccesses] Add -analyze support

Adam Nemet anemet at apple.com
Tue Feb 17 19:44:30 PST 2015


Author: anemet
Date: Tue Feb 17 21:44:30 2015
New Revision: 229633

URL: http://llvm.org/viewvc/llvm-project?rev=229633&view=rev
Log:
[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.

Added:
    llvm/trunk/test/Analysis/LoopAccessAnalysis/
    llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks-no-dbg.ll
    llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll
Modified:
    llvm/trunk/include/llvm/Analysis/LoopAccessAnalysis.h
    llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp

Modified: llvm/trunk/include/llvm/Analysis/LoopAccessAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/LoopAccessAnalysis.h?rev=229633&r1=229632&r2=229633&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/LoopAccessAnalysis.h (original)
+++ llvm/trunk/include/llvm/Analysis/LoopAccessAnalysis.h Tue Feb 17 21:44:30 2015
@@ -120,10 +120,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.
@@ -174,6 +180,9 @@ public:
   /// couldn't analyze the loop.
   Optional<LoopAccessReport> &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.
@@ -256,6 +265,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<Loop *, std::unique_ptr<LoopAccessInfo>> LoopAccessInfoMap;

Modified: llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp?rev=229633&r1=229632&r2=229633&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/LoopAccessAnalysis.cpp Tue Feb 17 21:44:30 2015
@@ -110,6 +110,23 @@ bool LoopAccessInfo::RuntimePointerCheck
   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.
 ///
@@ -1266,6 +1283,24 @@ LoopAccessInfo::LoopAccessInfo(Loop *L,
     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];
 
@@ -1283,6 +1318,20 @@ LoopAccessInfo &LoopAccessAnalysis::getI
   return *LAI.get();
 }
 
+void LoopAccessAnalysis::print(raw_ostream &OS, const Module *M) const {
+  LoopAccessAnalysis &LAA = *const_cast<LoopAccessAnalysis *>(this);
+
+  LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().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<ScalarEvolution>();
   DL = F.getParent()->getDataLayout();
@@ -1298,6 +1347,7 @@ void LoopAccessAnalysis::getAnalysisUsag
     AU.addRequired<ScalarEvolution>();
     AU.addRequired<AliasAnalysis>();
     AU.addRequired<DominatorTreeWrapperPass>();
+    AU.addRequired<LoopInfoWrapperPass>();
 
     AU.setPreservesAll();
 }
@@ -1310,6 +1360,7 @@ INITIALIZE_PASS_BEGIN(LoopAccessAnalysis
 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 {

Added: llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks-no-dbg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks-no-dbg.ll?rev=229633&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks-no-dbg.ll (added)
+++ llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks-no-dbg.ll Tue Feb 17 21:44:30 2015
@@ -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
+
+ at n = global i32 20, align 4
+ at B = common global i16* null, align 8
+ at A = common global i16* null, align 8
+ at 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
+}

Added: llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll?rev=229633&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll (added)
+++ llvm/trunk/test/Analysis/LoopAccessAnalysis/unsafe-and-rt-checks.ll Tue Feb 17 21:44:30 2015
@@ -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
+
+ at n = global i32 20, align 4
+ at B = common global i16* null, align 8
+ at A = common global i16* null, align 8
+ at 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
+}





More information about the llvm-commits mailing list