[polly] delinearize together all array refs
Tobias Grosser
tobias at grosser.es
Fri May 9 15:18:50 PDT 2014
On 09/05/2014 23:07, Sebastian Pop wrote:
> Hi Tobi,
>
> here is the first half of making polly delinearize all memory accesses together:
> this is only modifying the scop detection. I wanted to get your comments on this
> part before I do the next part in the translation to the polyhedral representation.
Nice. I like this small patch. I have some comments inline.
> From e772e224cb6dd24a0555fadf8d78d3309b6102b9 Mon Sep 17 00:00:00 2001
> From: Sebastian Pop<spop at codeaurora.org>
> Date: Thu, 8 May 2014 11:03:02 -0500
> Subject: [PATCH] delinearize together all accesses to the same array
>
> ---
> include/polly/ScopDetection.h | 15 ++++++++++
> lib/Analysis/ScopDetection.cpp | 58 ++++++++++++++++++++++++++++++++-------
> 2 files changed, 62 insertions(+), 11 deletions(-)
>
> diff --git a/include/polly/ScopDetection.h b/include/polly/ScopDetection.h
> index 452eb09..1fd20bd 100644
> --- a/include/polly/ScopDetection.h
> +++ b/include/polly/ScopDetection.h
> @@ -63,6 +63,7 @@ class Loop;
> class ScalarEvolution;
> class SCEV;
> class SCEVAddRecExpr;
> +class SCEVUnknown;
> class CallInst;
> class Instruction;
> class AliasAnalysis;
> @@ -96,6 +97,15 @@ class ScopDetection : public FunctionPass {
> Region &CurRegion; // The region to check.
> AliasSetTracker AST; // The AliasSetTracker to hold the alias information.
> bool Verifying; // If we are in the verification phase?
> + // The set of base pointers for non affine array accesses.
> + std::set<const SCEVUnknown *> NonAffineArrays;
This set seems redundant. Any reason you can not use
NonAffineAccesses.count() to check if a base pointer
> +
> + typedef std::vector<const SCEVAddRecExpr *> AFs;
> + typedef std::map<const SCEVUnknown *, AFs> BaseToAFs;
> +
> + // Map a base pointer to all access functions accessing it.
> + BaseToAFs NonAffineAccesses;
> +
> DetectionContext(Region &R, AliasAnalysis &AA, bool Verify)
> : CurRegion(R), AST(AA), Verifying(Verify) {}
> };
> @@ -112,6 +122,11 @@ class ScopDetection : public FunctionPass {
> FunctionSet InvalidFunctions;
> mutable std::string LastFailure;
>
> + // Delinearize all non affine memory accesses and returns true when there
Delinearize returns
Either imperative or third person singular, but not mixed.
> + // exists a non affine memory access that cannot be delinearized. Returns
>
> + // false when all array accesses are affine after delinearization.
> + bool hasNonAffineMemoryAccesses(DetectionContext &Context) const;
> +
> // Try to expand the region R. If R can be expanded return the expanded
> // region, NULL otherwise.
> Region *expandRegion(Region &R);
> diff --git a/lib/Analysis/ScopDetection.cpp b/lib/Analysis/ScopDetection.cpp
> index 62b9c2a..494189e 100644
> --- a/lib/Analysis/ScopDetection.cpp
> +++ b/lib/Analysis/ScopDetection.cpp
> @@ -337,6 +337,34 @@ bool ScopDetection::isInvariant(const Value &Val, const Region &Reg) const {
> return true;
> }
>
> +bool
> +ScopDetection::hasNonAffineMemoryAccesses(DetectionContext &Context) const {
> + for (const SCEVUnknown *BasePointer : Context.NonAffineArrays) {
> + Value *BaseValue = BasePointer->getValue();
> +
> + // First step: collect parametric terms in all array references.
> + SmallVector<const SCEV *, 4> Terms;
> + for (const SCEVAddRecExpr *AF : Context.NonAffineAccesses[BasePointer])
> + AF->collectParametricTerms(*SE, Terms);
> +
> + // Second step: find array shape.
> + SmallVector<const SCEV *, 4> Sizes;
> + SE->findArrayDimensions(Terms, Sizes);
> +
> + // Third step: compute the access functions for each subscript.
> + for (const SCEVAddRecExpr *AF : Context.NonAffineAccesses[BasePointer]) {
> + SmallVector<const SCEV *, 4> Subscripts;
> + AF->computeAccessFunctions(*SE, Subscripts, Sizes);
> +
> + // Check that the delinearized subscripts are affine.
> + for (const SCEV *S : Subscripts)
> + if (!isAffineExpr(&Context.CurRegion, S, *SE, BaseValue))
> + return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF);
> + }
> + }
> + return false;
> +}
> +
> bool ScopDetection::isValidMemoryAccess(Instruction &Inst,
> DetectionContext &Context) const {
> Value *Ptr = getPointerOperand(Inst);
> @@ -370,21 +398,22 @@ bool ScopDetection::isValidMemoryAccess(Instruction &Inst,
> } else if (!isAffineExpr(&Context.CurRegion, AccessFunction, *SE,
> BaseValue)) {
> const SCEVAddRecExpr *AF = dyn_cast<SCEVAddRecExpr>(AccessFunction);
> +
> if (!PollyDelinearize || !AF)
> return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true,
> AccessFunction);
>
> - // Try to delinearize AccessFunction only when the expression is known to
> - // not be affine: as all affine functions can be represented without
> - // problems in Polly, we do not have to delinearize them.
> - SmallVector<const SCEV *, 4> Subscripts, Sizes;
> - AF->delinearize(*SE, Subscripts, Sizes);
> - int size = Subscripts.size();
> -
> - for (int i = 0; i < size; ++i)
> - if (!isAffineExpr(&Context.CurRegion, Subscripts[i], *SE, BaseValue))
> - return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true,
> - AccessFunction);
> + // Collect all non affine memory accesses, and check whether they are linear
> + // at the end of scop detection. That way we can delinearize all the memory
> + // accesses to the same array in a unique step.
> + if (Context.NonAffineArrays.count(BasePointer) == 0) {
> + Context.NonAffineArrays.insert(BasePointer);
> +
> + typedef std::vector<const SCEVAddRecExpr *> AFs;
Instead of introducing another typedef, would it make sense to reuse the
one defined in the header?
> + Context.NonAffineAccesses[BasePointer] = AFs();
> + }
> + Context.NonAffineAccesses[BasePointer].push_back(AF);
>
> }
>
> // FIXME: Alias Analysis thinks IntToPtrInst aliases with alloca instructions
> @@ -604,11 +633,18 @@ bool ScopDetection::allBlocksValid(DetectionContext &Context) const {
> if (!isValidCFG(*BB, Context))
> return false;
>
> + // Clear before starting collecting non affine accesses in the current region.
> + Context.NonAffineArrays.clear();
> + Context.NonAffineAccesses.clear();
This should not be necessary. We allocate for each region a new
detection context. If I remove this, all tests are still passing.
> for (BasicBlock *BB : R.blocks())
> for (BasicBlock::iterator I = BB->begin(), E = --BB->end(); I != E; ++I)
> if (!isValidInstruction(*I, Context))
> return false;
>
> + if (hasNonAffineMemoryAccesses(Context))
> + return false;
> +
> return true;
> }
>
> -- 1.7.6.4
>
>
> 0001-move-findArrayDimensions-to-ScalarEvolution.patch
>
>
> From b1c13698acf130125be301e6e83780e9ec97c8b5 Mon Sep 17 00:00:00 2001
> From: Sebastian Pop<spop at codeaurora.org>
> Date: Thu, 8 May 2014 17:20:32 -0500
> Subject: [PATCH] move findArrayDimensions to ScalarEvolution
>
> we do not use the information from SCEVAddRecExpr to compute the shape of the array,
> so a better place for this function is in ScalarEvolution.
This one looks reasonable.
> 0001-fix-typo-in-debug-message.patch
>
>
> From f2694b03ab90a20ae3aad4df48d6bf3abf067d51 Mon Sep 17 00:00:00 2001
> From: Sebastian Pop<spop at codeaurora.org>
> Date: Fri, 9 May 2014 11:09:03 -0500
> Subject: [PATCH] fix typo in debug message
This patch is trivial. No need to post it for review.
Cheers,
Tobias
More information about the llvm-commits
mailing list