forked from OSchip/llvm-project
ScopInfo: Split hasAffineMemoryAccesses() into multiple functions [NFC]
This makes the overall code more readable. llvm-svn: 253951
This commit is contained in:
parent
919ce23566
commit
d68ba42556
|
@ -222,6 +222,50 @@ private:
|
||||||
/// @returns True if the subregion can be over approximated, false otherwise.
|
/// @returns True if the subregion can be over approximated, false otherwise.
|
||||||
bool addOverApproximatedRegion(Region *AR, DetectionContext &Context) const;
|
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<const SCEV *, 4>
|
||||||
|
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<const SCEV *> &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<ArrayShape> 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
|
// Delinearize all non affine memory accesses and return false when there
|
||||||
// exists a non affine memory access that cannot be delinearized. Return true
|
// exists a non affine memory access that cannot be delinearized. Return true
|
||||||
// when all array accesses are affine after delinearization.
|
// when all array accesses are affine after delinearization.
|
||||||
|
|
|
@ -487,145 +487,173 @@ bool ScopDetection::isInvariant(const Value &Val, const Region &Reg) const {
|
||||||
|
|
||||||
MapInsnToMemAcc InsnToMemAcc;
|
MapInsnToMemAcc InsnToMemAcc;
|
||||||
|
|
||||||
bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const {
|
SmallVector<const SCEV *, 4>
|
||||||
Region &CurRegion = Context.CurRegion;
|
ScopDetection::getDelinearizationTerms(DetectionContext &Context,
|
||||||
|
const SCEVUnknown *BasePointer) const {
|
||||||
|
SmallVector<const SCEV *, 4> 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<SCEVAddExpr>(Pair.second)) {
|
||||||
|
for (auto Op : AF->operands()) {
|
||||||
|
if (auto *AF2 = dyn_cast<SCEVAddRecExpr>(Op))
|
||||||
|
SE->collectParametricTerms(AF2, Terms);
|
||||||
|
if (auto *AF2 = dyn_cast<SCEVMulExpr>(Op)) {
|
||||||
|
SmallVector<const SCEV *, 0> Operands;
|
||||||
|
|
||||||
for (const SCEVUnknown *BasePointer : Context.NonAffineAccesses) {
|
for (auto *MulOp : AF2->operands()) {
|
||||||
Value *BaseValue = BasePointer->getValue();
|
if (auto *Const = dyn_cast<SCEVConstant>(MulOp))
|
||||||
auto Shape = std::shared_ptr<ArrayShape>(new ArrayShape(BasePointer));
|
Operands.push_back(Const);
|
||||||
bool BasePtrHasNonAffine = false;
|
if (auto *Unknown = dyn_cast<SCEVUnknown>(MulOp)) {
|
||||||
|
if (auto *Inst = dyn_cast<Instruction>(Unknown->getValue())) {
|
||||||
// First step: collect parametric terms in all array references.
|
if (!Context.CurRegion.contains(Inst))
|
||||||
SmallVector<const SCEV *, 4> 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<SCEVAddExpr>(Pair.second)) {
|
|
||||||
for (auto Op : AF->operands()) {
|
|
||||||
if (auto *AF2 = dyn_cast<SCEVAddRecExpr>(Op))
|
|
||||||
SE->collectParametricTerms(AF2, Terms);
|
|
||||||
if (auto *AF2 = dyn_cast<SCEVMulExpr>(Op)) {
|
|
||||||
SmallVector<const SCEV *, 0> Operands;
|
|
||||||
|
|
||||||
for (auto *MulOp : AF2->operands()) {
|
|
||||||
if (auto *Const = dyn_cast<SCEVConstant>(MulOp))
|
|
||||||
Operands.push_back(Const);
|
|
||||||
if (auto *Unknown = dyn_cast<SCEVUnknown>(MulOp)) {
|
|
||||||
if (auto *Inst = dyn_cast<Instruction>(Unknown->getValue())) {
|
|
||||||
if (!Context.CurRegion.contains(Inst))
|
|
||||||
Operands.push_back(MulOp);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Operands.push_back(MulOp);
|
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.
|
bool ScopDetection::hasValidArraySizes(DetectionContext &Context,
|
||||||
SE->findArrayDimensions(Terms, Shape->DelinearizedSizes,
|
SmallVectorImpl<const SCEV *> &Sizes,
|
||||||
Context.ElementSize[BasePointer]);
|
const SCEVUnknown *BasePointer) const {
|
||||||
|
Value *BaseValue = BasePointer->getValue();
|
||||||
for (const SCEV *DelinearizedSize : Shape->DelinearizedSizes) {
|
Region &CurRegion = Context.CurRegion;
|
||||||
if (!isAffine(DelinearizedSize, Context, nullptr)) {
|
for (const SCEV *DelinearizedSize : Sizes) {
|
||||||
Shape->DelinearizedSizes.clear();
|
if (!isAffine(DelinearizedSize, Context, nullptr)) {
|
||||||
break;
|
Sizes.clear();
|
||||||
}
|
break;
|
||||||
if (auto *Unknown = dyn_cast<SCEVUnknown>(DelinearizedSize)) {
|
|
||||||
auto *V = dyn_cast<Value>(Unknown->getValue());
|
|
||||||
if (auto *Load = dyn_cast<LoadInst>(V)) {
|
|
||||||
if (Context.CurRegion.contains(Load) &&
|
|
||||||
isHoistableLoad(Load, CurRegion, *LI, *SE))
|
|
||||||
Context.RequiredILS.insert(Load);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion))
|
|
||||||
invalid<ReportNonAffineAccess>(
|
|
||||||
Context, /*Assert=*/true, DelinearizedSize,
|
|
||||||
Context.Accesses[BasePointer].front().first, BaseValue);
|
|
||||||
}
|
}
|
||||||
|
if (auto *Unknown = dyn_cast<SCEVUnknown>(DelinearizedSize)) {
|
||||||
// No array shape derived.
|
auto *V = dyn_cast<Value>(Unknown->getValue());
|
||||||
if (Shape->DelinearizedSizes.empty()) {
|
if (auto *Load = dyn_cast<LoadInst>(V)) {
|
||||||
if (AllowNonAffine)
|
if (Context.CurRegion.contains(Load) &&
|
||||||
|
isHoistableLoad(Load, CurRegion, *LI, *SE))
|
||||||
|
Context.RequiredILS.insert(Load);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (const auto &Pair : Context.Accesses[BasePointer]) {
|
|
||||||
const Instruction *Insn = Pair.first;
|
|
||||||
const SCEV *AF = Pair.second;
|
|
||||||
|
|
||||||
if (!isAffine(AF, Context, BaseValue)) {
|
|
||||||
invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Insn,
|
|
||||||
BaseValue);
|
|
||||||
if (!KeepGoing)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion))
|
||||||
|
invalid<ReportNonAffineAccess>(
|
||||||
|
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]) {
|
for (const auto &Pair : Context.Accesses[BasePointer]) {
|
||||||
const Instruction *Insn = Pair.first;
|
const Instruction *Insn = Pair.first;
|
||||||
auto *AF = Pair.second;
|
const SCEV *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(AF, Context, BaseValue)) {
|
||||||
if (isAffine(Pair.second, Context, BaseValue))
|
invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Insn,
|
||||||
Acc->DelinearizedSubscripts.push_back(Pair.second);
|
BaseValue);
|
||||||
else
|
if (!KeepGoing)
|
||||||
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<ReportNonAffineAccess>(Context, /*Assert=*/true, Pair.second,
|
|
||||||
Insn, BaseValue);
|
|
||||||
if (!KeepGoing && !AllowNonAffine)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
if (!BasePtrHasNonAffine)
|
|
||||||
InsnToMemAcc.insert(TempMemoryAccesses.begin(), TempMemoryAccesses.end());
|
|
||||||
}
|
}
|
||||||
return true;
|
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<ArrayShape> 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<ReportNonAffineAccess>(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<ArrayShape>(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,
|
bool ScopDetection::isValidMemoryAccess(Instruction &Inst,
|
||||||
DetectionContext &Context) const {
|
DetectionContext &Context) const {
|
||||||
Region &CurRegion = Context.CurRegion;
|
Region &CurRegion = Context.CurRegion;
|
||||||
|
|
Loading…
Reference in New Issue