mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-20 10:24:12 +00:00
Revert r229622: "[LoopAccesses] Make VectorizerParams global" and others. r229622 brought cyclic dependencies between Analysis and Vector.
r229622: "[LoopAccesses] Make VectorizerParams global" r229623: "[LoopAccesses] Stash the report from the analysis rather than emitting it" r229624: "[LoopAccesses] Cache the result of canVectorizeMemory" r229626: "[LoopAccesses] Create the analysis pass" r229628: "[LoopAccesses] Change debug messages from LV to LAA" r229630: "[LoopAccesses] Add canAnalyzeLoop" r229631: "[LoopAccesses] Add missing const to APIs in VectorizationReport" r229632: "[LoopAccesses] Split out LoopAccessReport from VectorizerReport" r229633: "[LoopAccesses] Add -analyze support" r229634: "[LoopAccesses] Change LAA:getInfo to return a constant reference" r229638: "Analysis: fix buildbots" git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@229650 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -23,16 +23,15 @@
|
||||
#include "llvm/Transforms/Utils/VectorUtils.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "loop-accesses"
|
||||
#define DEBUG_TYPE "loop-vectorize"
|
||||
|
||||
void LoopAccessReport::emitAnalysis(const LoopAccessReport &Message,
|
||||
const Function *TheFunction,
|
||||
const Loop *TheLoop,
|
||||
const char *PassName) {
|
||||
void VectorizationReport::emitAnalysis(VectorizationReport &Message,
|
||||
const Function *TheFunction,
|
||||
const Loop *TheLoop) {
|
||||
DebugLoc DL = TheLoop->getStartLoc();
|
||||
if (const Instruction *I = Message.getInstr())
|
||||
if (Instruction *I = Message.getInstr())
|
||||
DL = I->getDebugLoc();
|
||||
emitOptimizationRemarkAnalysis(TheFunction->getContext(), PassName,
|
||||
emitOptimizationRemarkAnalysis(TheFunction->getContext(), DEBUG_TYPE,
|
||||
*TheFunction, DL, Message.str());
|
||||
}
|
||||
|
||||
@ -65,7 +64,7 @@ const SCEV *llvm::replaceSymbolicStrideSCEV(ScalarEvolution *SE,
|
||||
|
||||
const SCEV *ByOne =
|
||||
SCEVParameterRewriter::rewrite(OrigSCEV, *SE, RewriteMap, true);
|
||||
DEBUG(dbgs() << "LAA: Replacing SCEV: " << *OrigSCEV << " by: " << *ByOne
|
||||
DEBUG(dbgs() << "LV: Replacing SCEV: " << *OrigSCEV << " by: " << *ByOne
|
||||
<< "\n");
|
||||
return ByOne;
|
||||
}
|
||||
@ -110,23 +109,6 @@ 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.
|
||||
///
|
||||
@ -282,7 +264,7 @@ bool AccessAnalysis::canCheckPtrAtRT(
|
||||
|
||||
RtCheck.insert(SE, TheLoop, Ptr, IsWrite, DepId, ASId, StridesMap);
|
||||
|
||||
DEBUG(dbgs() << "LAA: Found a runtime check ptr:" << *Ptr << '\n');
|
||||
DEBUG(dbgs() << "LV: Found a runtime check ptr:" << *Ptr << '\n');
|
||||
} else {
|
||||
CanDoRT = false;
|
||||
}
|
||||
@ -319,7 +301,7 @@ bool AccessAnalysis::canCheckPtrAtRT(
|
||||
unsigned ASi = PtrI->getType()->getPointerAddressSpace();
|
||||
unsigned ASj = PtrJ->getType()->getPointerAddressSpace();
|
||||
if (ASi != ASj) {
|
||||
DEBUG(dbgs() << "LAA: Runtime check would require comparison between"
|
||||
DEBUG(dbgs() << "LV: Runtime check would require comparison between"
|
||||
" different address spaces\n");
|
||||
return false;
|
||||
}
|
||||
@ -334,9 +316,9 @@ void AccessAnalysis::processMemAccesses() {
|
||||
// process read-only pointers. This allows us to skip dependence tests for
|
||||
// read-only pointers.
|
||||
|
||||
DEBUG(dbgs() << "LAA: Processing memory accesses...\n");
|
||||
DEBUG(dbgs() << "LV: Processing memory accesses...\n");
|
||||
DEBUG(dbgs() << " AST: "; AST.dump());
|
||||
DEBUG(dbgs() << "LAA: Accesses:\n");
|
||||
DEBUG(dbgs() << "LV: Accesses:\n");
|
||||
DEBUG({
|
||||
for (auto A : Accesses)
|
||||
dbgs() << "\t" << *A.getPointer() << " (" <<
|
||||
@ -472,9 +454,10 @@ public:
|
||||
typedef PointerIntPair<Value *, 1, bool> MemAccessInfo;
|
||||
typedef SmallPtrSet<MemAccessInfo, 8> MemAccessInfoSet;
|
||||
|
||||
MemoryDepChecker(ScalarEvolution *Se, const DataLayout *Dl, const Loop *L)
|
||||
MemoryDepChecker(ScalarEvolution *Se, const DataLayout *Dl, const Loop *L,
|
||||
const LoopAccessInfo::VectorizerParams &VectParams)
|
||||
: SE(Se), DL(Dl), InnermostLoop(L), AccessIdx(0),
|
||||
ShouldRetryWithRuntimeCheck(false) {}
|
||||
ShouldRetryWithRuntimeCheck(false), VectParams(VectParams) {}
|
||||
|
||||
/// \brief Register the location (instructions are given increasing numbers)
|
||||
/// of a write access.
|
||||
@ -529,6 +512,9 @@ private:
|
||||
/// vectorize this loop with runtime checks.
|
||||
bool ShouldRetryWithRuntimeCheck;
|
||||
|
||||
/// \brief Vectorizer parameters used by the analysis.
|
||||
LoopAccessInfo::VectorizerParams VectParams;
|
||||
|
||||
/// \brief Check whether there is a plausible dependence between the two
|
||||
/// accesses.
|
||||
///
|
||||
@ -567,8 +553,8 @@ static int isStridedPtr(ScalarEvolution *SE, const DataLayout *DL, Value *Ptr,
|
||||
// Make sure that the pointer does not point to aggregate types.
|
||||
const PointerType *PtrTy = cast<PointerType>(Ty);
|
||||
if (PtrTy->getElementType()->isAggregateType()) {
|
||||
DEBUG(dbgs() << "LAA: Bad stride - Not a pointer to a scalar type"
|
||||
<< *Ptr << "\n");
|
||||
DEBUG(dbgs() << "LV: Bad stride - Not a pointer to a scalar type" << *Ptr <<
|
||||
"\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -576,14 +562,14 @@ static int isStridedPtr(ScalarEvolution *SE, const DataLayout *DL, Value *Ptr,
|
||||
|
||||
const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(PtrScev);
|
||||
if (!AR) {
|
||||
DEBUG(dbgs() << "LAA: Bad stride - Not an AddRecExpr pointer "
|
||||
DEBUG(dbgs() << "LV: Bad stride - Not an AddRecExpr pointer "
|
||||
<< *Ptr << " SCEV: " << *PtrScev << "\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The accesss function must stride over the innermost loop.
|
||||
if (Lp != AR->getLoop()) {
|
||||
DEBUG(dbgs() << "LAA: Bad stride - Not striding over innermost loop " <<
|
||||
DEBUG(dbgs() << "LV: Bad stride - Not striding over innermost loop " <<
|
||||
*Ptr << " SCEV: " << *PtrScev << "\n");
|
||||
}
|
||||
|
||||
@ -598,7 +584,7 @@ static int isStridedPtr(ScalarEvolution *SE, const DataLayout *DL, Value *Ptr,
|
||||
bool IsNoWrapAddRec = AR->getNoWrapFlags(SCEV::NoWrapMask);
|
||||
bool IsInAddressSpaceZero = PtrTy->getAddressSpace() == 0;
|
||||
if (!IsNoWrapAddRec && !IsInBoundsGEP && !IsInAddressSpaceZero) {
|
||||
DEBUG(dbgs() << "LAA: Bad stride - Pointer may wrap in the address space "
|
||||
DEBUG(dbgs() << "LV: Bad stride - Pointer may wrap in the address space "
|
||||
<< *Ptr << " SCEV: " << *PtrScev << "\n");
|
||||
return 0;
|
||||
}
|
||||
@ -609,7 +595,7 @@ static int isStridedPtr(ScalarEvolution *SE, const DataLayout *DL, Value *Ptr,
|
||||
// Calculate the pointer stride and check if it is consecutive.
|
||||
const SCEVConstant *C = dyn_cast<SCEVConstant>(Step);
|
||||
if (!C) {
|
||||
DEBUG(dbgs() << "LAA: Bad stride - Not a constant strided " << *Ptr <<
|
||||
DEBUG(dbgs() << "LV: Bad stride - Not a constant strided " << *Ptr <<
|
||||
" SCEV: " << *PtrScev << "\n");
|
||||
return 0;
|
||||
}
|
||||
@ -652,8 +638,7 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(unsigned Distance,
|
||||
// Store-load forwarding distance.
|
||||
const unsigned NumCyclesForStoreLoadThroughMemory = 8*TypeByteSize;
|
||||
// Maximum vector factor.
|
||||
unsigned MaxVFWithoutSLForwardIssues =
|
||||
VectorizerParams::MaxVectorWidth * TypeByteSize;
|
||||
unsigned MaxVFWithoutSLForwardIssues = VectParams.MaxVectorWidth*TypeByteSize;
|
||||
if(MaxSafeDepDistBytes < MaxVFWithoutSLForwardIssues)
|
||||
MaxVFWithoutSLForwardIssues = MaxSafeDepDistBytes;
|
||||
|
||||
@ -666,14 +651,13 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(unsigned Distance,
|
||||
}
|
||||
|
||||
if (MaxVFWithoutSLForwardIssues< 2*TypeByteSize) {
|
||||
DEBUG(dbgs() << "LAA: Distance " << Distance <<
|
||||
DEBUG(dbgs() << "LV: Distance " << Distance <<
|
||||
" that could cause a store-load forwarding conflict\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (MaxVFWithoutSLForwardIssues < MaxSafeDepDistBytes &&
|
||||
MaxVFWithoutSLForwardIssues !=
|
||||
VectorizerParams::MaxVectorWidth * TypeByteSize)
|
||||
MaxVFWithoutSLForwardIssues != VectParams.MaxVectorWidth*TypeByteSize)
|
||||
MaxSafeDepDistBytes = MaxVFWithoutSLForwardIssues;
|
||||
return false;
|
||||
}
|
||||
@ -720,9 +704,9 @@ bool MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
|
||||
|
||||
const SCEV *Dist = SE->getMinusSCEV(Sink, Src);
|
||||
|
||||
DEBUG(dbgs() << "LAA: Src Scev: " << *Src << "Sink Scev: " << *Sink
|
||||
DEBUG(dbgs() << "LV: Src Scev: " << *Src << "Sink Scev: " << *Sink
|
||||
<< "(Induction step: " << StrideAPtr << ")\n");
|
||||
DEBUG(dbgs() << "LAA: Distance for " << *InstMap[AIdx] << " to "
|
||||
DEBUG(dbgs() << "LV: Distance for " << *InstMap[AIdx] << " to "
|
||||
<< *InstMap[BIdx] << ": " << *Dist << "\n");
|
||||
|
||||
// Need consecutive accesses. We don't want to vectorize
|
||||
@ -735,7 +719,7 @@ bool MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
|
||||
|
||||
const SCEVConstant *C = dyn_cast<SCEVConstant>(Dist);
|
||||
if (!C) {
|
||||
DEBUG(dbgs() << "LAA: Dependence because of non-constant distance\n");
|
||||
DEBUG(dbgs() << "LV: Dependence because of non-constant distance\n");
|
||||
ShouldRetryWithRuntimeCheck = true;
|
||||
return true;
|
||||
}
|
||||
@ -753,7 +737,7 @@ bool MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
|
||||
ATy != BTy))
|
||||
return true;
|
||||
|
||||
DEBUG(dbgs() << "LAA: Dependence is negative: NoDep\n");
|
||||
DEBUG(dbgs() << "LV: Dependence is negative: NoDep\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -762,7 +746,7 @@ bool MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
|
||||
if (Val == 0) {
|
||||
if (ATy == BTy)
|
||||
return false;
|
||||
DEBUG(dbgs() << "LAA: Zero dependence difference but different types\n");
|
||||
DEBUG(dbgs() << "LV: Zero dependence difference but different types\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -771,17 +755,17 @@ bool MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
|
||||
// Positive distance bigger than max vectorization factor.
|
||||
if (ATy != BTy) {
|
||||
DEBUG(dbgs() <<
|
||||
"LAA: ReadWrite-Write positive dependency with different types\n");
|
||||
"LV: ReadWrite-Write positive dependency with different types\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned Distance = (unsigned) Val.getZExtValue();
|
||||
|
||||
// Bail out early if passed-in parameters make vectorization not feasible.
|
||||
unsigned ForcedFactor = (VectorizerParams::VectorizationFactor ?
|
||||
VectorizerParams::VectorizationFactor : 1);
|
||||
unsigned ForcedUnroll = (VectorizerParams::VectorizationInterleave ?
|
||||
VectorizerParams::VectorizationInterleave : 1);
|
||||
unsigned ForcedFactor = (VectParams.VectorizationFactor ?
|
||||
VectParams.VectorizationFactor : 1);
|
||||
unsigned ForcedUnroll = (VectParams.VectorizationInterleave ?
|
||||
VectParams.VectorizationInterleave : 1);
|
||||
|
||||
// The distance must be bigger than the size needed for a vectorized version
|
||||
// of the operation and the size of the vectorized operation must not be
|
||||
@ -789,7 +773,7 @@ bool MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
|
||||
if (Distance < 2*TypeByteSize ||
|
||||
2*TypeByteSize > MaxSafeDepDistBytes ||
|
||||
Distance < TypeByteSize * ForcedUnroll * ForcedFactor) {
|
||||
DEBUG(dbgs() << "LAA: Failure because of Positive distance "
|
||||
DEBUG(dbgs() << "LV: Failure because of Positive distance "
|
||||
<< Val.getSExtValue() << '\n');
|
||||
return true;
|
||||
}
|
||||
@ -802,7 +786,7 @@ bool MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
|
||||
couldPreventStoreLoadForward(Distance, TypeByteSize))
|
||||
return true;
|
||||
|
||||
DEBUG(dbgs() << "LAA: Positive distance " << Val.getSExtValue() <<
|
||||
DEBUG(dbgs() << "LV: Positive distance " << Val.getSExtValue() <<
|
||||
" with max VF = " << MaxSafeDepDistBytes / TypeByteSize << '\n');
|
||||
|
||||
return false;
|
||||
@ -847,56 +831,7 @@ bool MemoryDepChecker::areDepsSafe(AccessAnalysis::DepCandidates &AccessSets,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoopAccessInfo::canAnalyzeLoop() {
|
||||
// We can only analyze innermost loops.
|
||||
if (!TheLoop->empty()) {
|
||||
emitAnalysis(LoopAccessReport() << "loop is not the innermost loop");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must have a single backedge.
|
||||
if (TheLoop->getNumBackEdges() != 1) {
|
||||
emitAnalysis(
|
||||
LoopAccessReport() <<
|
||||
"loop control flow is not understood by analyzer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must have a single exiting block.
|
||||
if (!TheLoop->getExitingBlock()) {
|
||||
emitAnalysis(
|
||||
LoopAccessReport() <<
|
||||
"loop control flow is not understood by analyzer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We only handle bottom-tested loops, i.e. loop in which the condition is
|
||||
// checked at the end of each iteration. With that we can assume that all
|
||||
// instructions in the loop are executed the same number of times.
|
||||
if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch()) {
|
||||
emitAnalysis(
|
||||
LoopAccessReport() <<
|
||||
"loop control flow is not understood by analyzer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to have a loop header.
|
||||
DEBUG(dbgs() << "LAA: Found a loop: " <<
|
||||
TheLoop->getHeader()->getName() << '\n');
|
||||
|
||||
// ScalarEvolution needs to be able to find the exit count.
|
||||
const SCEV *ExitCount = SE->getBackedgeTakenCount(TheLoop);
|
||||
if (ExitCount == SE->getCouldNotCompute()) {
|
||||
emitAnalysis(LoopAccessReport() <<
|
||||
"could not determine number of loop iterations");
|
||||
DEBUG(dbgs() << "LAA: SCEV could not compute the loop exit count.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
bool LoopAccessInfo::canVectorizeMemory(ValueToValueMap &Strides) {
|
||||
|
||||
typedef SmallVector<Value*, 16> ValueVector;
|
||||
typedef SmallPtrSet<Value*, 16> ValueSet;
|
||||
@ -913,7 +848,7 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
PtrRtCheck.Need = false;
|
||||
|
||||
const bool IsAnnotatedParallel = TheLoop->isAnnotatedParallel();
|
||||
MemoryDepChecker DepChecker(SE, DL, TheLoop);
|
||||
MemoryDepChecker DepChecker(SE, DL, TheLoop, VectParams);
|
||||
|
||||
// For each block.
|
||||
for (Loop::block_iterator bb = TheLoop->block_begin(),
|
||||
@ -936,11 +871,10 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
|
||||
LoadInst *Ld = dyn_cast<LoadInst>(it);
|
||||
if (!Ld || (!Ld->isSimple() && !IsAnnotatedParallel)) {
|
||||
emitAnalysis(LoopAccessReport(Ld)
|
||||
emitAnalysis(VectorizationReport(Ld)
|
||||
<< "read with atomic ordering or volatile read");
|
||||
DEBUG(dbgs() << "LAA: Found a non-simple load.\n");
|
||||
CanVecMem = false;
|
||||
return;
|
||||
DEBUG(dbgs() << "LV: Found a non-simple load.\n");
|
||||
return false;
|
||||
}
|
||||
NumLoads++;
|
||||
Loads.push_back(Ld);
|
||||
@ -952,17 +886,15 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
if (it->mayWriteToMemory()) {
|
||||
StoreInst *St = dyn_cast<StoreInst>(it);
|
||||
if (!St) {
|
||||
emitAnalysis(LoopAccessReport(it) <<
|
||||
emitAnalysis(VectorizationReport(it) <<
|
||||
"instruction cannot be vectorized");
|
||||
CanVecMem = false;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!St->isSimple() && !IsAnnotatedParallel) {
|
||||
emitAnalysis(LoopAccessReport(St)
|
||||
emitAnalysis(VectorizationReport(St)
|
||||
<< "write with atomic ordering or volatile write");
|
||||
DEBUG(dbgs() << "LAA: Found a non-simple store.\n");
|
||||
CanVecMem = false;
|
||||
return;
|
||||
DEBUG(dbgs() << "LV: Found a non-simple store.\n");
|
||||
return false;
|
||||
}
|
||||
NumStores++;
|
||||
Stores.push_back(St);
|
||||
@ -977,9 +909,8 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
// Check if we see any stores. If there are no stores, then we don't
|
||||
// care if the pointers are *restrict*.
|
||||
if (!Stores.size()) {
|
||||
DEBUG(dbgs() << "LAA: Found a read-only loop!\n");
|
||||
CanVecMem = true;
|
||||
return;
|
||||
DEBUG(dbgs() << "LV: Found a read-only loop!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
AccessAnalysis::DepCandidates DependentAccesses;
|
||||
@ -999,11 +930,10 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
|
||||
if (isUniform(Ptr)) {
|
||||
emitAnalysis(
|
||||
LoopAccessReport(ST)
|
||||
VectorizationReport(ST)
|
||||
<< "write to a loop invariant address could not be vectorized");
|
||||
DEBUG(dbgs() << "LAA: We don't allow storing to uniform addresses\n");
|
||||
CanVecMem = false;
|
||||
return;
|
||||
DEBUG(dbgs() << "LV: We don't allow storing to uniform addresses\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we did *not* see this pointer before, insert it to the read-write
|
||||
@ -1024,10 +954,9 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
|
||||
if (IsAnnotatedParallel) {
|
||||
DEBUG(dbgs()
|
||||
<< "LAA: A loop annotated parallel, ignore memory dependency "
|
||||
<< "LV: A loop annotated parallel, ignore memory dependency "
|
||||
<< "checks.\n");
|
||||
CanVecMem = true;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (I = Loads.begin(), IE = Loads.end(); I != IE; ++I) {
|
||||
@ -1061,9 +990,8 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
// If we write (or read-write) to a single destination and there are no
|
||||
// other reads in this loop then is it safe to vectorize.
|
||||
if (NumReadWrites == 1 && NumReads == 0) {
|
||||
DEBUG(dbgs() << "LAA: Found a write-only loop!\n");
|
||||
CanVecMem = true;
|
||||
return;
|
||||
DEBUG(dbgs() << "LV: Found a write-only loop!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build dependence sets and check whether we need a runtime pointer bounds
|
||||
@ -1079,7 +1007,7 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
CanDoRT = Accesses.canCheckPtrAtRT(PtrRtCheck, NumComparisons, SE, TheLoop,
|
||||
Strides);
|
||||
|
||||
DEBUG(dbgs() << "LAA: We need to do " << NumComparisons <<
|
||||
DEBUG(dbgs() << "LV: We need to do " << NumComparisons <<
|
||||
" pointer comparisons.\n");
|
||||
|
||||
// If we only have one set of dependences to check pointers among we don't
|
||||
@ -1089,36 +1017,34 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
|
||||
// Check that we did not collect too many pointers or found an unsizeable
|
||||
// pointer.
|
||||
if (!CanDoRT ||
|
||||
NumComparisons > VectorizerParams::RuntimeMemoryCheckThreshold) {
|
||||
if (!CanDoRT || NumComparisons > VectParams.RuntimeMemoryCheckThreshold) {
|
||||
PtrRtCheck.reset();
|
||||
CanDoRT = false;
|
||||
}
|
||||
|
||||
if (CanDoRT) {
|
||||
DEBUG(dbgs() << "LAA: We can perform a memory runtime check if needed.\n");
|
||||
DEBUG(dbgs() << "LV: We can perform a memory runtime check if needed.\n");
|
||||
}
|
||||
|
||||
if (NeedRTCheck && !CanDoRT) {
|
||||
emitAnalysis(LoopAccessReport() << "cannot identify array bounds");
|
||||
DEBUG(dbgs() << "LAA: We can't vectorize because we can't find " <<
|
||||
emitAnalysis(VectorizationReport() << "cannot identify array bounds");
|
||||
DEBUG(dbgs() << "LV: We can't vectorize because we can't find " <<
|
||||
"the array bounds.\n");
|
||||
PtrRtCheck.reset();
|
||||
CanVecMem = false;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
PtrRtCheck.Need = NeedRTCheck;
|
||||
|
||||
CanVecMem = true;
|
||||
bool CanVecMem = true;
|
||||
if (Accesses.isDependencyCheckNeeded()) {
|
||||
DEBUG(dbgs() << "LAA: Checking memory dependencies\n");
|
||||
DEBUG(dbgs() << "LV: Checking memory dependencies\n");
|
||||
CanVecMem = DepChecker.areDepsSafe(
|
||||
DependentAccesses, Accesses.getDependenciesToCheck(), Strides);
|
||||
MaxSafeDepDistBytes = DepChecker.getMaxSafeDepDistBytes();
|
||||
|
||||
if (!CanVecMem && DepChecker.shouldRetryWithRuntimeCheck()) {
|
||||
DEBUG(dbgs() << "LAA: Retrying with memory checks\n");
|
||||
DEBUG(dbgs() << "LV: Retrying with memory checks\n");
|
||||
NeedRTCheck = true;
|
||||
|
||||
// Clear the dependency checks. We assume they are not needed.
|
||||
@ -1131,20 +1057,18 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
TheLoop, Strides, true);
|
||||
// Check that we did not collect too many pointers or found an unsizeable
|
||||
// pointer.
|
||||
if (!CanDoRT ||
|
||||
NumComparisons > VectorizerParams::RuntimeMemoryCheckThreshold) {
|
||||
if (!CanDoRT || NumComparisons > VectParams.RuntimeMemoryCheckThreshold) {
|
||||
if (!CanDoRT && NumComparisons > 0)
|
||||
emitAnalysis(LoopAccessReport()
|
||||
emitAnalysis(VectorizationReport()
|
||||
<< "cannot check memory dependencies at runtime");
|
||||
else
|
||||
emitAnalysis(LoopAccessReport()
|
||||
emitAnalysis(VectorizationReport()
|
||||
<< NumComparisons << " exceeds limit of "
|
||||
<< VectorizerParams::RuntimeMemoryCheckThreshold
|
||||
<< VectParams.RuntimeMemoryCheckThreshold
|
||||
<< " dependent memory operations checked at runtime");
|
||||
DEBUG(dbgs() << "LAA: Can't vectorize with memory checks\n");
|
||||
DEBUG(dbgs() << "LV: Can't vectorize with memory checks\n");
|
||||
PtrRtCheck.reset();
|
||||
CanVecMem = false;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
CanVecMem = true;
|
||||
@ -1152,11 +1076,13 @@ void LoopAccessInfo::analyzeLoop(ValueToValueMap &Strides) {
|
||||
}
|
||||
|
||||
if (!CanVecMem)
|
||||
emitAnalysis(LoopAccessReport() <<
|
||||
emitAnalysis(VectorizationReport() <<
|
||||
"unsafe dependent memory operations in loop");
|
||||
|
||||
DEBUG(dbgs() << "LAA: We" << (NeedRTCheck ? "" : " don't") <<
|
||||
DEBUG(dbgs() << "LV: We" << (NeedRTCheck ? "" : " don't") <<
|
||||
" need a runtime memory check.\n");
|
||||
|
||||
return CanVecMem;
|
||||
}
|
||||
|
||||
bool LoopAccessInfo::blockNeedsPredication(BasicBlock *BB, Loop *TheLoop,
|
||||
@ -1168,12 +1094,11 @@ bool LoopAccessInfo::blockNeedsPredication(BasicBlock *BB, Loop *TheLoop,
|
||||
return !DT->dominates(BB, Latch);
|
||||
}
|
||||
|
||||
void LoopAccessInfo::emitAnalysis(LoopAccessReport &Message) {
|
||||
assert(!Report && "Multiple report generated");
|
||||
Report = Message;
|
||||
void LoopAccessInfo::emitAnalysis(VectorizationReport &Message) {
|
||||
VectorizationReport::emitAnalysis(Message, TheFunction, TheLoop);
|
||||
}
|
||||
|
||||
bool LoopAccessInfo::isUniform(Value *V) const {
|
||||
bool LoopAccessInfo::isUniform(Value *V) {
|
||||
return (SE->isLoopInvariant(SE->getSCEV(V), TheLoop));
|
||||
}
|
||||
|
||||
@ -1189,7 +1114,7 @@ static Instruction *getFirstInst(Instruction *FirstInst, Value *V,
|
||||
}
|
||||
|
||||
std::pair<Instruction *, Instruction *>
|
||||
LoopAccessInfo::addRuntimeCheck(Instruction *Loc) const {
|
||||
LoopAccessInfo::addRuntimeCheck(Instruction *Loc) {
|
||||
Instruction *tnullptr = nullptr;
|
||||
if (!PtrRtCheck.Need)
|
||||
return std::pair<Instruction *, Instruction *>(tnullptr, tnullptr);
|
||||
@ -1207,12 +1132,12 @@ LoopAccessInfo::addRuntimeCheck(Instruction *Loc) const {
|
||||
const SCEV *Sc = SE->getSCEV(Ptr);
|
||||
|
||||
if (SE->isLoopInvariant(Sc, TheLoop)) {
|
||||
DEBUG(dbgs() << "LAA: Adding RT check for a loop invariant ptr:" <<
|
||||
DEBUG(dbgs() << "LV: Adding RT check for a loop invariant ptr:" <<
|
||||
*Ptr <<"\n");
|
||||
Starts.push_back(Ptr);
|
||||
Ends.push_back(Ptr);
|
||||
} else {
|
||||
DEBUG(dbgs() << "LAA: Adding RT check for range:" << *Ptr << '\n');
|
||||
DEBUG(dbgs() << "LV: Adding RT check for range:" << *Ptr << '\n');
|
||||
unsigned AS = Ptr->getType()->getPointerAddressSpace();
|
||||
|
||||
// Use this type for pointer arithmetic.
|
||||
@ -1272,100 +1197,3 @@ LoopAccessInfo::addRuntimeCheck(Instruction *Loc) const {
|
||||
FirstInst = getFirstInst(FirstInst, Check, Loc);
|
||||
return std::make_pair(FirstInst, Check);
|
||||
}
|
||||
|
||||
LoopAccessInfo::LoopAccessInfo(Loop *L, ScalarEvolution *SE,
|
||||
const DataLayout *DL,
|
||||
const TargetLibraryInfo *TLI, AliasAnalysis *AA,
|
||||
DominatorTree *DT, ValueToValueMap &Strides)
|
||||
: TheLoop(L), SE(SE), DL(DL), TLI(TLI), AA(AA), DT(DT), NumLoads(0),
|
||||
NumStores(0), MaxSafeDepDistBytes(-1U), CanVecMem(false) {
|
||||
if (canAnalyzeLoop())
|
||||
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";
|
||||
}
|
||||
|
||||
const LoopAccessInfo &LoopAccessAnalysis::getInfo(Loop *L,
|
||||
ValueToValueMap &Strides) {
|
||||
auto &LAI = LoopAccessInfoMap[L];
|
||||
|
||||
#ifndef NDEBUG
|
||||
assert((!LAI || LAI->NumSymbolicStrides == Strides.size()) &&
|
||||
"Symbolic strides changed for loop");
|
||||
#endif
|
||||
|
||||
if (!LAI) {
|
||||
LAI = llvm::make_unique<LoopAccessInfo>(L, SE, DL, TLI, AA, DT, Strides);
|
||||
#ifndef NDEBUG
|
||||
LAI->NumSymbolicStrides = Strides.size();
|
||||
#endif
|
||||
}
|
||||
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();
|
||||
auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>();
|
||||
TLI = TLIP ? &TLIP->getTLI() : nullptr;
|
||||
AA = &getAnalysis<AliasAnalysis>();
|
||||
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LoopAccessAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<ScalarEvolution>();
|
||||
AU.addRequired<AliasAnalysis>();
|
||||
AU.addRequired<DominatorTreeWrapperPass>();
|
||||
AU.addRequired<LoopInfoWrapperPass>();
|
||||
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
char LoopAccessAnalysis::ID = 0;
|
||||
static const char laa_name[] = "Loop Access Analysis";
|
||||
#define LAA_NAME "loop-accesses"
|
||||
|
||||
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 {
|
||||
Pass *createLAAPass() {
|
||||
return new LoopAccessAnalysis();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user