forked from OSchip/llvm-project
[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. llvm-svn: 229633
This commit is contained in:
parent
d7350dbb85
commit
75bc2d111f
|
@ -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;
|
||||
|
|
|
@ -110,6 +110,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.
|
||||
///
|
||||
|
@ -1266,6 +1283,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];
|
||||
|
||||
|
@ -1283,6 +1318,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<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::getAnalysisUsage(AnalysisUsage &AU) const {
|
|||
AU.addRequired<ScalarEvolution>();
|
||||
AU.addRequired<AliasAnalysis>();
|
||||
AU.addRequired<DominatorTreeWrapperPass>();
|
||||
AU.addRequired<LoopInfoWrapperPass>();
|
||||
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
@ -1310,6 +1360,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 {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue