From d68ba4255627a31196d13e6cde0568f643bd94d7 Mon Sep 17 00:00:00 2001 From: Tobias Grosser Date: Tue, 24 Nov 2015 05:00:36 +0000 Subject: [PATCH] ScopInfo: Split hasAffineMemoryAccesses() into multiple functions [NFC] This makes the overall code more readable. llvm-svn: 253951 --- polly/include/polly/ScopDetection.h | 44 +++++ polly/lib/Analysis/ScopDetection.cpp | 258 +++++++++++++++------------ 2 files changed, 187 insertions(+), 115 deletions(-) diff --git a/polly/include/polly/ScopDetection.h b/polly/include/polly/ScopDetection.h index 82f9bf66ab97..f68517fc7387 100644 --- a/polly/include/polly/ScopDetection.h +++ b/polly/include/polly/ScopDetection.h @@ -222,6 +222,50 @@ private: /// @returns True if the subregion can be over approximated, false otherwise. bool addOverApproximatedRegion(Region *AR, DetectionContext &Context) const; + /// @brief Find for a given base pointer terms that hint towards dimension + /// sizes of a multi-dimensional array. + /// + /// @param Context The current detection context. + /// @param BasePointer A base pointer indicating the virtual array we are + /// interested in. + SmallVector + getDelinearizationTerms(DetectionContext &Context, + const SCEVUnknown *BasePointer) const; + + /// @brief Check if the dimension size of a delinearized array is valid. + /// + /// @param Context The current detection context. + /// @param Sizes The sizes of the different array dimensions. + /// @param BasePointer The base pointer we are interested in. + /// @returns True if one or more array sizes could be derived - meaning: we + /// see this array as multi-dimensional. + bool hasValidArraySizes(DetectionContext &Context, + SmallVectorImpl &Sizes, + const SCEVUnknown *BasePointer) const; + + /// @brief Derive access functions for a given base pointer. + /// + /// @param Context The current detection context. + /// @param Sizes The sizes of the different array dimensions. + /// @param BasePointer The base pointer of all the array for which to compute + /// access functions. + /// @param Shape The shape that describes the derived array sizes and + /// which should be filled with newly computed access + /// functions. + /// @returns True if a set of affine access functions could be derived. + bool computeAccessFunctions(DetectionContext &Context, + const SCEVUnknown *BasePointer, + std::shared_ptr Shape) const; + + /// @brief Check if all accesses to a given BasePointer are affine. + /// + /// @param Context The current detection context. + /// @param basepointer the base pointer we are interested in. + /// @param True if consistent (multi-dimensional) array accesses could be + /// derived for this array. + bool hasBaseAffineAccesses(DetectionContext &Context, + const SCEVUnknown *BasePointer) const; + // Delinearize all non affine memory accesses and return false when there // exists a non affine memory access that cannot be delinearized. Return true // when all array accesses are affine after delinearization. diff --git a/polly/lib/Analysis/ScopDetection.cpp b/polly/lib/Analysis/ScopDetection.cpp index 5aa905928d15..c776ef778f60 100644 --- a/polly/lib/Analysis/ScopDetection.cpp +++ b/polly/lib/Analysis/ScopDetection.cpp @@ -487,145 +487,173 @@ bool ScopDetection::isInvariant(const Value &Val, const Region &Reg) const { MapInsnToMemAcc InsnToMemAcc; -bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const { - Region &CurRegion = Context.CurRegion; +SmallVector +ScopDetection::getDelinearizationTerms(DetectionContext &Context, + const SCEVUnknown *BasePointer) const { + SmallVector Terms; + for (const auto &Pair : Context.Accesses[BasePointer]) { + // In case the outermost expression is a plain add, we check if any of its + // terms has the form 4 * %inst * %param * %param ..., aka a term that + // contains a product between a parameter and an instruction that is + // inside the scop. Such instructions, if allowed at all, are instructions + // SCEV can not represent, but Polly is still looking through. As a + // result, these instructions can depend on induction variables and are + // most likely no array sizes. However, terms that are multiplied with + // them are likely candidates for array sizes. + if (auto *AF = dyn_cast(Pair.second)) { + for (auto Op : AF->operands()) { + if (auto *AF2 = dyn_cast(Op)) + SE->collectParametricTerms(AF2, Terms); + if (auto *AF2 = dyn_cast(Op)) { + SmallVector Operands; - for (const SCEVUnknown *BasePointer : Context.NonAffineAccesses) { - Value *BaseValue = BasePointer->getValue(); - auto Shape = std::shared_ptr(new ArrayShape(BasePointer)); - bool BasePtrHasNonAffine = false; - - // First step: collect parametric terms in all array references. - SmallVector Terms; - for (const auto &Pair : Context.Accesses[BasePointer]) { - // In case the outermost expression is a plain add, we check if any of its - // terms has the form 4 * %inst * %param * %param ..., aka a term that - // contains a product between a parameter and an instruction that is - // inside the scop. Such instructions, if allowed at all, are instructions - // SCEV can not represent, but Polly is still looking through. As a - // result, these instructions can depend on induction variables and are - // most likely no array sizes. However, terms that are multiplied with - // them are likely candidates for array sizes. - if (auto *AF = dyn_cast(Pair.second)) { - for (auto Op : AF->operands()) { - if (auto *AF2 = dyn_cast(Op)) - SE->collectParametricTerms(AF2, Terms); - if (auto *AF2 = dyn_cast(Op)) { - SmallVector Operands; - - for (auto *MulOp : AF2->operands()) { - if (auto *Const = dyn_cast(MulOp)) - Operands.push_back(Const); - if (auto *Unknown = dyn_cast(MulOp)) { - if (auto *Inst = dyn_cast(Unknown->getValue())) { - if (!Context.CurRegion.contains(Inst)) - Operands.push_back(MulOp); - - } else { + for (auto *MulOp : AF2->operands()) { + if (auto *Const = dyn_cast(MulOp)) + Operands.push_back(Const); + if (auto *Unknown = dyn_cast(MulOp)) { + if (auto *Inst = dyn_cast(Unknown->getValue())) { + if (!Context.CurRegion.contains(Inst)) Operands.push_back(MulOp); - } + + } else { + Operands.push_back(MulOp); } } - if (Operands.size()) - Terms.push_back(SE->getMulExpr(Operands)); } + if (Operands.size()) + Terms.push_back(SE->getMulExpr(Operands)); } } - if (Terms.empty()) - SE->collectParametricTerms(Pair.second, Terms); } + if (Terms.empty()) + SE->collectParametricTerms(Pair.second, Terms); + } + return Terms; +} - // Second step: find array shape. - SE->findArrayDimensions(Terms, Shape->DelinearizedSizes, - Context.ElementSize[BasePointer]); - - for (const SCEV *DelinearizedSize : Shape->DelinearizedSizes) { - if (!isAffine(DelinearizedSize, Context, nullptr)) { - Shape->DelinearizedSizes.clear(); - break; - } - if (auto *Unknown = dyn_cast(DelinearizedSize)) { - auto *V = dyn_cast(Unknown->getValue()); - if (auto *Load = dyn_cast(V)) { - if (Context.CurRegion.contains(Load) && - isHoistableLoad(Load, CurRegion, *LI, *SE)) - Context.RequiredILS.insert(Load); - continue; - } - } - if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion)) - invalid( - Context, /*Assert=*/true, DelinearizedSize, - Context.Accesses[BasePointer].front().first, BaseValue); +bool ScopDetection::hasValidArraySizes(DetectionContext &Context, + SmallVectorImpl &Sizes, + const SCEVUnknown *BasePointer) const { + Value *BaseValue = BasePointer->getValue(); + Region &CurRegion = Context.CurRegion; + for (const SCEV *DelinearizedSize : Sizes) { + if (!isAffine(DelinearizedSize, Context, nullptr)) { + Sizes.clear(); + break; } - - // No array shape derived. - if (Shape->DelinearizedSizes.empty()) { - if (AllowNonAffine) + if (auto *Unknown = dyn_cast(DelinearizedSize)) { + auto *V = dyn_cast(Unknown->getValue()); + if (auto *Load = dyn_cast(V)) { + if (Context.CurRegion.contains(Load) && + isHoistableLoad(Load, CurRegion, *LI, *SE)) + Context.RequiredILS.insert(Load); continue; - - for (const auto &Pair : Context.Accesses[BasePointer]) { - const Instruction *Insn = Pair.first; - const SCEV *AF = Pair.second; - - if (!isAffine(AF, Context, BaseValue)) { - invalid(Context, /*Assert=*/true, AF, Insn, - BaseValue); - if (!KeepGoing) - return false; - } } - continue; } + if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion)) + invalid( + Context, /*Assert=*/true, DelinearizedSize, + Context.Accesses[BasePointer].front().first, BaseValue); + } + + // No array shape derived. + if (Sizes.empty()) { + if (AllowNonAffine) + return true; - // Third step: compute the access functions for each subscript. - // - // We first store the resulting memory accesses in TempMemoryAccesses. Only - // if the access functions for all memory accesses have been successfully - // delinearized we continue. Otherwise, we either report a failure or, if - // non-affine accesses are allowed, we drop the information. In case the - // information is dropped the memory accesses need to be overapproximated - // when translated to a polyhedral representation. - MapInsnToMemAcc TempMemoryAccesses; for (const auto &Pair : Context.Accesses[BasePointer]) { const Instruction *Insn = Pair.first; - auto *AF = Pair.second; - bool IsNonAffine = false; - TempMemoryAccesses.insert(std::make_pair(Insn, MemAcc(Insn, Shape))); - MemAcc *Acc = &TempMemoryAccesses.find(Insn)->second; + const SCEV *AF = Pair.second; - if (!AF) { - if (isAffine(Pair.second, Context, BaseValue)) - Acc->DelinearizedSubscripts.push_back(Pair.second); - else - IsNonAffine = true; - } else { - SE->computeAccessFunctions(AF, Acc->DelinearizedSubscripts, - Shape->DelinearizedSizes); - if (Acc->DelinearizedSubscripts.size() == 0) - IsNonAffine = true; - for (const SCEV *S : Acc->DelinearizedSubscripts) - if (!isAffine(S, Context, BaseValue)) - IsNonAffine = true; - } - - // (Possibly) report non affine access - if (IsNonAffine) { - BasePtrHasNonAffine = true; - if (!AllowNonAffine) - invalid(Context, /*Assert=*/true, Pair.second, - Insn, BaseValue); - if (!KeepGoing && !AllowNonAffine) + if (!isAffine(AF, Context, BaseValue)) { + invalid(Context, /*Assert=*/true, AF, Insn, + BaseValue); + if (!KeepGoing) return false; } } - - if (!BasePtrHasNonAffine) - InsnToMemAcc.insert(TempMemoryAccesses.begin(), TempMemoryAccesses.end()); + return false; } return true; } +// We first store the resulting memory accesses in TempMemoryAccesses. Only +// if the access functions for all memory accesses have been successfully +// delinearized we continue. Otherwise, we either report a failure or, if +// non-affine accesses are allowed, we drop the information. In case the +// information is dropped the memory accesses need to be overapproximated +// when translated to a polyhedral representation. +bool ScopDetection::computeAccessFunctions( + DetectionContext &Context, const SCEVUnknown *BasePointer, + std::shared_ptr Shape) const { + Value *BaseValue = BasePointer->getValue(); + bool BasePtrHasNonAffine = false; + MapInsnToMemAcc TempMemoryAccesses; + for (const auto &Pair : Context.Accesses[BasePointer]) { + const Instruction *Insn = Pair.first; + auto *AF = Pair.second; + bool IsNonAffine = false; + TempMemoryAccesses.insert(std::make_pair(Insn, MemAcc(Insn, Shape))); + MemAcc *Acc = &TempMemoryAccesses.find(Insn)->second; + + if (!AF) { + if (isAffine(Pair.second, Context, BaseValue)) + Acc->DelinearizedSubscripts.push_back(Pair.second); + else + IsNonAffine = true; + } else { + SE->computeAccessFunctions(AF, Acc->DelinearizedSubscripts, + Shape->DelinearizedSizes); + if (Acc->DelinearizedSubscripts.size() == 0) + IsNonAffine = true; + for (const SCEV *S : Acc->DelinearizedSubscripts) + if (!isAffine(S, Context, BaseValue)) + IsNonAffine = true; + } + + // (Possibly) report non affine access + if (IsNonAffine) { + BasePtrHasNonAffine = true; + if (!AllowNonAffine) + invalid(Context, /*Assert=*/true, Pair.second, + Insn, BaseValue); + if (!KeepGoing && !AllowNonAffine) + return false; + } + } + + if (!BasePtrHasNonAffine) + InsnToMemAcc.insert(TempMemoryAccesses.begin(), TempMemoryAccesses.end()); + + return true; +} + +bool ScopDetection::hasBaseAffineAccesses( + DetectionContext &Context, const SCEVUnknown *BasePointer) const { + auto Shape = std::shared_ptr(new ArrayShape(BasePointer)); + + auto Terms = getDelinearizationTerms(Context, BasePointer); + + SE->findArrayDimensions(Terms, Shape->DelinearizedSizes, + Context.ElementSize[BasePointer]); + + if (!hasValidArraySizes(Context, Shape->DelinearizedSizes, BasePointer)) + return false; + + return computeAccessFunctions(Context, BasePointer, Shape); +} + +bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const { + for (const SCEVUnknown *BasePointer : Context.NonAffineAccesses) + if (!hasBaseAffineAccesses(Context, BasePointer)) { + if (KeepGoing) + continue; + else + return false; + } + return true; +} + bool ScopDetection::isValidMemoryAccess(Instruction &Inst, DetectionContext &Context) const { Region &CurRegion = Context.CurRegion;