[NFC][ScopBuilder] Move RecordedAssumptions vector to ScopBuilder

Scope of changes:

1) Moved RecordedAssumptions vector to ScopBuilder. RecordedAssumptions are used only for Scop constructions.
2) Moved definition of RecordedAssumptionsTy to ScopHelper. It is required both by ScopBuilder and SCEVAffinator.
3) Add new function recordAssumption to ScopHelper. One of its argument is a reference to RecordedAssumption vector. This function is used by ScopBuilder and SCEVAffinator.
4) All RecordedAssumptions are created by ScopBuilder. isl::pw_aff
objects for corresponding SCEVs are created inside ScopBuilder. Scop
functions do not record any assumptions. Scop can use isl::pw_aff
objects which were created by ScopBuilder.
5) Removed functions for handling RecordedAssumptions from Scop class.
6) Removed constness from getScopArrayInfo functions.
7) Replaced SCEVVisitor struct from SCEVAffinator with taylored version, which allow to pass pointer to RecordedAssumptions as function argument.

Differential Revision: https://reviews.llvm.org/D68056
This commit is contained in:
Dominik Adamski 2020-01-19 23:50:01 +01:00
parent af3c243e99
commit 7154413567
8 changed files with 173 additions and 134 deletions

View File

@ -61,6 +61,18 @@ class ScopBuilder {
// The Scop
std::unique_ptr<Scop> scop;
/// Collection to hold taken assumptions.
///
/// There are two reasons why we want to record assumptions first before we
/// add them to the assumed/invalid context:
/// 1) If the SCoP is not profitable or otherwise invalid without the
/// assumed/invalid context we do not have to compute it.
/// 2) Information about the context are gathered rather late in the SCoP
/// construction (basically after we know all parameters), thus the user
/// might see overly complicated assumptions to be taken while they will
/// only be simplified later on.
RecordedAssumptionsTy RecordedAssumptions;
// Methods for pattern matching against Fortran code generated by dragonegg.
// @{

View File

@ -19,6 +19,7 @@
#include "polly/ScopDetection.h"
#include "polly/Support/SCEVAffinator.h"
#include "polly/Support/ScopHelper.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
@ -54,23 +55,6 @@ extern bool UseInstructionNames;
// are also unlikely to result in good code.
extern int const MaxDisjunctsInDomain;
/// Enumeration of assumptions Polly can take.
enum AssumptionKind {
ALIASING,
INBOUNDS,
WRAPPING,
UNSIGNED,
PROFITABLE,
ERRORBLOCK,
COMPLEXITY,
INFINITELOOP,
INVARIANTLOAD,
DELINEARIZATION,
};
/// Enum to distinguish between assumptions and restrictions.
enum AssumptionSign { AS_ASSUMPTION, AS_RESTRICTION };
/// The different memory kinds used in Polly.
///
/// We distinguish between arrays and various scalar memory objects. We use
@ -479,6 +463,8 @@ public:
RT_BAND, ///< Bitwise And
};
using SubscriptsTy = SmallVector<const SCEV *, 4>;
private:
/// A unique identifier for this memory access.
///
@ -590,7 +576,7 @@ private:
bool IsAffine = true;
/// Subscript expression for each dimension.
SmallVector<const SCEV *, 4> Subscripts;
SubscriptsTy Subscripts;
/// Relation from statement instances to the accessed array elements.
///
@ -633,7 +619,7 @@ private:
isl::basic_map createBasicAccessMap(ScopStmt *Statement);
void assumeNoOutOfBound();
isl::set assumeNoOutOfBound();
/// Compute bounds on an over approximated access relation.
///
@ -894,6 +880,11 @@ public:
/// Return the access instruction of this memory access.
Instruction *getAccessInstruction() const { return AccessInstruction; }
/// Return an iterator range containing the subscripts.
iterator_range<SubscriptsTy::const_iterator> subscripts() const {
return make_range(Subscripts.begin(), Subscripts.end());
}
/// Return the number of access function subscript.
unsigned getNumSubscripts() const { return Subscripts.size(); }
@ -1624,24 +1615,6 @@ public:
/// Print ScopStmt S to raw_ostream OS.
raw_ostream &operator<<(raw_ostream &OS, const ScopStmt &S);
/// Helper struct to remember assumptions.
struct Assumption {
/// The kind of the assumption (e.g., WRAPPING).
AssumptionKind Kind;
/// Flag to distinguish assumptions and restrictions.
AssumptionSign Sign;
/// The valid/invalid context if this is an assumption/restriction.
isl::set Set;
/// The location that caused this assumption.
DebugLoc Loc;
/// An optional block whose domain can simplify the assumption.
BasicBlock *BB;
};
/// Build the conditions sets for the branch condition @p Condition in
/// the @p Domain.
///
@ -1838,19 +1811,6 @@ private:
/// need to be "false". Otherwise they behave the same.
isl::set InvalidContext;
using RecordedAssumptionsTy = SmallVector<Assumption, 8>;
/// Collection to hold taken assumptions.
///
/// There are two reasons why we want to record assumptions first before we
/// add them to the assumed/invalid context:
/// 1) If the SCoP is not profitable or otherwise invalid without the
/// assumed/invalid context we do not have to compute it.
/// 2) Information about the context are gathered rather late in the SCoP
/// construction (basically after we know all parameters), thus the user
/// might see overly complicated assumptions to be taken while they will
/// only be simplified later on.
RecordedAssumptionsTy RecordedAssumptions;
/// The schedule of the SCoP
///
/// The schedule of the SCoP describes the execution order of the statements
@ -2129,12 +2089,6 @@ public:
InvariantEquivClasses.end());
}
/// Return an iterator range containing hold assumptions.
iterator_range<RecordedAssumptionsTy::const_iterator>
recorded_assumptions() const {
return make_range(RecordedAssumptions.begin(), RecordedAssumptions.end());
}
/// Return an iterator range containing all the MemoryAccess objects of the
/// Scop.
iterator_range<AccFuncVector::iterator> access_functions() {
@ -2297,9 +2251,6 @@ public:
/// @returns True if the optimized SCoP can be executed.
bool hasFeasibleRuntimeContext() const;
/// Clear assumptions which have been already processed.
void clearRecordedAssumptions() { return RecordedAssumptions.clear(); }
/// Check if the assumption in @p Set is trivial or not.
///
/// @param Set The relations between parameters that are assumed to hold.
@ -2347,24 +2298,6 @@ public:
void addAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
AssumptionSign Sign, BasicBlock *BB);
/// Record an assumption for later addition to the assumed context.
///
/// This function will add the assumption to the RecordedAssumptions. This
/// collection will be added (@see addAssumption) to the assumed context once
/// all paramaters are known and the context is fully built.
///
/// @param Kind The assumption kind describing the underlying cause.
/// @param Set The relations between parameters that are assumed to hold.
/// @param Loc The location in the source that caused this assumption.
/// @param Sign Enum to indicate if the assumptions in @p Set are positive
/// (needed/assumptions) or negative (invalid/restrictions).
/// @param BB The block in which this assumption was taken. If it is
/// set, the domain of that block will be used to simplify the
/// actual assumption in @p Set once it is added. This is useful
/// if the assumption was created prior to the domain.
void recordAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
AssumptionSign Sign, BasicBlock *BB = nullptr);
/// Mark the scop as invalid.
///
/// This method adds an assumption to the scop that is always invalid. As a
@ -2504,7 +2437,7 @@ public:
///
/// @returns The ScopArrayInfo pointer or NULL if no such pointer is
/// available.
const ScopArrayInfo *getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind);
ScopArrayInfo *getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind);
/// Return the cached ScopArrayInfo object for @p BasePtr.
///
@ -2513,7 +2446,7 @@ public:
///
/// @returns The ScopArrayInfo pointer (may assert if no such pointer is
/// available).
const ScopArrayInfo *getScopArrayInfo(Value *BasePtr, MemoryKind Kind);
ScopArrayInfo *getScopArrayInfo(Value *BasePtr, MemoryKind Kind);
/// Invalidate ScopArrayInfo object for base address.
///
@ -2589,13 +2522,16 @@ public:
/// a dummy value of appropriate dimension is returned. This allows to bail
/// for complex cases without "error handling code" needed on the users side.
PWACtx getPwAff(const SCEV *E, BasicBlock *BB = nullptr,
bool NonNegative = false);
bool NonNegative = false,
RecordedAssumptionsTy *RecordedAssumptions = nullptr);
/// Compute the isl representation for the SCEV @p E
///
/// This function is like @see Scop::getPwAff() but strips away the invalid
/// domain part associated with the piecewise affine function.
isl::pw_aff getPwAffOnly(const SCEV *E, BasicBlock *BB = nullptr);
isl::pw_aff
getPwAffOnly(const SCEV *E, BasicBlock *BB = nullptr,
RecordedAssumptionsTy *RecordedAssumptions = nullptr);
/// Check if an <nsw> AddRec for the loop L is cached.
bool hasNSWAddRecForLoop(Loop *L) { return Affinator.hasNSWAddRecForLoop(L); }

View File

@ -13,6 +13,7 @@
#ifndef POLLY_SCEV_AFFINATOR_H
#define POLLY_SCEV_AFFINATOR_H
#include "polly/Support/ScopHelper.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "isl/isl-noexceptions.h"
@ -36,10 +37,12 @@ public:
/// @param BB The block in which @p E is executed.
///
/// @returns The isl representation of the SCEV @p E in @p Domain.
PWACtx getPwAff(const llvm::SCEV *E, llvm::BasicBlock *BB = nullptr);
PWACtx getPwAff(const llvm::SCEV *E, llvm::BasicBlock *BB = nullptr,
RecordedAssumptionsTy *RecordedAssumptions = nullptr);
/// Take the assumption that @p PWAC is non-negative.
void takeNonNegativeAssumption(PWACtx &PWAC);
void takeNonNegativeAssumption(
PWACtx &PWAC, RecordedAssumptionsTy *RecordedAssumptions = nullptr);
/// Interpret the PWA in @p PWAC as an unsigned value.
void interpretAsUnsigned(PWACtx &PWAC, unsigned Width);
@ -63,6 +66,7 @@ private:
llvm::ScalarEvolution &SE;
llvm::LoopInfo &LI;
llvm::BasicBlock *BB;
RecordedAssumptionsTy *RecordedAssumptions = nullptr;
/// Target data for element size computing.
const llvm::DataLayout &TD;

View File

@ -17,6 +17,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/ValueHandle.h"
#include "isl/isl-noexceptions.h"
namespace llvm {
class LoopInfo;
@ -34,6 +35,63 @@ namespace polly {
class Scop;
class ScopStmt;
/// Enumeration of assumptions Polly can take.
enum AssumptionKind {
ALIASING,
INBOUNDS,
WRAPPING,
UNSIGNED,
PROFITABLE,
ERRORBLOCK,
COMPLEXITY,
INFINITELOOP,
INVARIANTLOAD,
DELINEARIZATION,
};
/// Enum to distinguish between assumptions and restrictions.
enum AssumptionSign { AS_ASSUMPTION, AS_RESTRICTION };
/// Helper struct to remember assumptions.
struct Assumption {
/// The kind of the assumption (e.g., WRAPPING).
AssumptionKind Kind;
/// Flag to distinguish assumptions and restrictions.
AssumptionSign Sign;
/// The valid/invalid context if this is an assumption/restriction.
isl::set Set;
/// The location that caused this assumption.
llvm::DebugLoc Loc;
/// An optional block whose domain can simplify the assumption.
llvm::BasicBlock *BB;
};
using RecordedAssumptionsTy = llvm::SmallVector<Assumption, 8>;
/// Record an assumption for later addition to the assumed context.
///
/// This function will add the assumption to the RecordedAssumptions. This
/// collection will be added (@see addAssumption) to the assumed context once
/// all paramaters are known and the context is fully built.
///
/// @param RecordedAssumption container which keeps all recorded assumptions.
/// @param Kind The assumption kind describing the underlying cause.
/// @param Set The relations between parameters that are assumed to hold.
/// @param Loc The location in the source that caused this assumption.
/// @param Sign Enum to indicate if the assumptions in @p Set are positive
/// (needed/assumptions) or negative (invalid/restrictions).
/// @param BB The block in which this assumption was taken. If it is
/// set, the domain of that block will be used to simplify the
/// actual assumption in @p Set once it is added. This is useful
/// if the assumption was created prior to the domain.
void recordAssumption(RecordedAssumptionsTy *RecordedAssumptions,
AssumptionKind Kind, isl::set Set, llvm::DebugLoc Loc,
AssumptionSign Sign, llvm::BasicBlock *BB = nullptr);
/// Type to remap values.
using ValueMapT = llvm::DenseMap<llvm::AssertingVH<llvm::Value>,
llvm::AssertingVH<llvm::Value>>;

View File

@ -96,6 +96,11 @@ static cl::opt<bool> PollyAllowDereferenceOfAllFunctionParams(
" their loads. "),
cl::Hidden, cl::init(false), cl::cat(PollyCategory));
static cl::opt<bool>
PollyIgnoreInbounds("polly-ignore-inbounds",
cl::desc("Do not take inbounds assumptions at all"),
cl::Hidden, cl::init(false), cl::cat(PollyCategory));
static cl::opt<unsigned> RunTimeChecksMaxArraysPerGroup(
"polly-rtc-max-arrays-per-group",
cl::desc("The maximal number of arrays to compare in each alias group."),
@ -344,7 +349,7 @@ __isl_give isl_pw_aff *
ScopBuilder::getPwAff(BasicBlock *BB,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
const SCEV *E, bool NonNegative) {
PWACtx PWAC = scop->getPwAff(E, BB, NonNegative);
PWACtx PWAC = scop->getPwAff(E, BB, NonNegative, &RecordedAssumptions);
InvalidDomainMap[BB] = InvalidDomainMap[BB].unite(PWAC.second);
return PWAC.first.release();
}
@ -796,9 +801,8 @@ bool ScopBuilder::addLoopBoundsToHeaderDomain(
return true;
isl::set UnboundedCtx = Parts.first.params();
scop->recordAssumption(INFINITELOOP, UnboundedCtx,
HeaderBB->getTerminator()->getDebugLoc(),
AS_RESTRICTION);
recordAssumption(&RecordedAssumptions, INFINITELOOP, UnboundedCtx,
HeaderBB->getTerminator()->getDebugLoc(), AS_RESTRICTION);
return true;
}
@ -1019,9 +1023,8 @@ bool ScopBuilder::propagateInvalidStmtDomains(
} else {
InvalidDomain = Domain;
isl::set DomPar = Domain.params();
scop->recordAssumption(ERRORBLOCK, DomPar,
BB->getTerminator()->getDebugLoc(),
AS_RESTRICTION);
recordAssumption(&RecordedAssumptions, ERRORBLOCK, DomPar,
BB->getTerminator()->getDebugLoc(), AS_RESTRICTION);
Domain = isl::set::empty(Domain.get_space());
}
@ -1488,7 +1491,7 @@ Value *ScopBuilder::findFADAllocationInvisible(MemAccInst Inst) {
}
void ScopBuilder::addRecordedAssumptions() {
for (auto &AS : llvm::reverse(scop->recorded_assumptions())) {
for (auto &AS : llvm::reverse(RecordedAssumptions)) {
if (!AS.BB) {
scop->addAssumption(AS.Kind, AS.Set, AS.Loc, AS.Sign,
@ -1518,7 +1521,6 @@ void ScopBuilder::addRecordedAssumptions() {
scop->addAssumption(AS.Kind, isl::manage(S), AS.Loc, AS_RESTRICTION, AS.BB);
}
scop->clearRecordedAssumptions();
}
void ScopBuilder::addUserAssumptions(
@ -2502,9 +2504,17 @@ void ScopBuilder::foldAccessRelations() {
}
void ScopBuilder::assumeNoOutOfBounds() {
if (PollyIgnoreInbounds)
return;
for (auto &Stmt : *scop)
for (auto &Access : Stmt)
Access->assumeNoOutOfBound();
for (auto &Access : Stmt) {
isl::set Outside = Access->assumeNoOutOfBound();
const auto &Loc = Access->getAccessInstruction()
? Access->getAccessInstruction()->getDebugLoc()
: DebugLoc();
recordAssumption(&RecordedAssumptions, INBOUNDS, Outside, Loc,
AS_ASSUMPTION);
}
}
void ScopBuilder::ensureValueWrite(Instruction *Inst) {
@ -2959,8 +2969,8 @@ bool ScopBuilder::canAlwaysBeHoisted(MemoryAccess *MA,
// Even if the statement is not modeled precisely we can hoist the load if it
// does not involve any parameters that might have been specialized by the
// statement domain.
for (unsigned u = 0, e = MA->getNumSubscripts(); u < e; u++)
if (!isa<SCEVConstant>(MA->getSubscript(u)))
for (const SCEV *Subscript : MA->subscripts())
if (!isa<SCEVConstant>(Subscript))
return false;
return true;
}
@ -3214,8 +3224,26 @@ void ScopBuilder::buildAccessRelations(ScopStmt &Stmt) {
else
Ty = MemoryKind::Array;
// Create isl::pw_aff for SCEVs which describe sizes. Collect all
// assumptions which are taken. isl::pw_aff objects are cached internally
// and they are used later by scop.
for (const SCEV *Size : Access->Sizes) {
if (!Size)
continue;
scop->getPwAff(Size, nullptr, false, &RecordedAssumptions);
}
auto *SAI = scop->getOrCreateScopArrayInfo(Access->getOriginalBaseAddr(),
ElementType, Access->Sizes, Ty);
// Create isl::pw_aff for SCEVs which describe subscripts. Collect all
// assumptions which are taken. isl::pw_aff objects are cached internally
// and they are used later by scop.
for (const SCEV *Subscript : Access->subscripts()) {
if (!Access->isAffine() || !Subscript)
continue;
scop->getPwAff(Subscript, Stmt.getEntryBlock(), false,
&RecordedAssumptions);
}
Access->buildAccessRelation(SAI);
scop->addAccessData(Access);
}
@ -3768,6 +3796,7 @@ ScopBuilder::ScopBuilder(Region *R, AssumptionCache &AC, AliasAnalysis &AA,
InfeasibleScops++;
Msg = "SCoP ends here but was dismissed.";
LLVM_DEBUG(dbgs() << "SCoP detected but dismissed\n");
RecordedAssumptions.clear();
scop.reset();
} else {
Msg = "SCoP ends here.";

View File

@ -133,11 +133,6 @@ static cl::opt<bool> PollyPreciseInbounds(
cl::desc("Take more precise inbounds assumptions (do not scale well)"),
cl::Hidden, cl::init(false), cl::cat(PollyCategory));
static cl::opt<bool>
PollyIgnoreInbounds("polly-ignore-inbounds",
cl::desc("Do not take inbounds assumptions at all"),
cl::Hidden, cl::init(false), cl::cat(PollyCategory));
static cl::opt<bool> PollyIgnoreParamBounds(
"polly-ignore-parameter-bounds",
cl::desc(
@ -662,9 +657,7 @@ isl::basic_map MemoryAccess::createBasicAccessMap(ScopStmt *Statement) {
// possibly yield out of bound memory accesses. The complement of these
// constraints is the set of constraints that needs to be assumed to ensure such
// statement instances are never executed.
void MemoryAccess::assumeNoOutOfBound() {
if (PollyIgnoreInbounds)
return;
isl::set MemoryAccess::assumeNoOutOfBound() {
auto *SAI = getScopArrayInfo();
isl::space Space = getOriginalAccessRelationSpace().range();
isl::set Outside = isl::set::empty(Space);
@ -692,13 +685,10 @@ void MemoryAccess::assumeNoOutOfBound() {
// bail out more often than strictly necessary.
Outside = Outside.remove_divs();
Outside = Outside.complement();
const auto &Loc = getAccessInstruction()
? getAccessInstruction()->getDebugLoc()
: DebugLoc();
if (!PollyPreciseInbounds)
Outside = Outside.gist_params(Statement->getDomain().params());
Statement->getParent()->recordAssumption(INBOUNDS, Outside, Loc,
AS_ASSUMPTION);
return Outside;
}
void MemoryAccess::buildMemIntrinsicAccessRelation() {
@ -1856,13 +1846,12 @@ ScopArrayInfo *Scop::createScopArrayInfo(Type *ElementType,
return SAI;
}
const ScopArrayInfo *Scop::getScopArrayInfoOrNull(Value *BasePtr,
MemoryKind Kind) {
ScopArrayInfo *Scop::getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind) {
auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)].get();
return SAI;
}
const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, MemoryKind Kind) {
ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, MemoryKind Kind) {
auto *SAI = getScopArrayInfoOrNull(BasePtr, Kind);
assert(SAI && "No ScopArrayInfo available for this base pointer");
return SAI;
@ -2117,13 +2106,6 @@ void Scop::addAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
InvalidContext = InvalidContext.unite(Set).coalesce();
}
void Scop::recordAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
AssumptionSign Sign, BasicBlock *BB) {
assert((Set.is_params() || BB) &&
"Assumptions without a basic block must be parameter sets");
RecordedAssumptions.push_back({Kind, Sign, Set, Loc, BB});
}
void Scop::invalidate(AssumptionKind Kind, DebugLoc Loc, BasicBlock *BB) {
LLVM_DEBUG(dbgs() << "Invalidate SCoP because of reason " << Kind << "\n");
addAssumption(Kind, isl::set::empty(getParamSpace()), Loc, AS_ASSUMPTION, BB);
@ -2241,13 +2223,14 @@ LLVM_DUMP_METHOD void Scop::dump() const { print(dbgs(), true); }
isl::ctx Scop::getIslCtx() const { return IslCtx.get(); }
__isl_give PWACtx Scop::getPwAff(const SCEV *E, BasicBlock *BB,
bool NonNegative) {
bool NonNegative,
RecordedAssumptionsTy *RecordedAssumptions) {
// First try to use the SCEVAffinator to generate a piecewise defined
// affine function from @p E in the context of @p BB. If that tasks becomes to
// complex the affinator might return a nullptr. In such a case we invalidate
// the SCoP and return a dummy value. This way we do not need to add error
// handling code to all users of this function.
auto PWAC = Affinator.getPwAff(E, BB);
auto PWAC = Affinator.getPwAff(E, BB, RecordedAssumptions);
if (PWAC.first) {
// TODO: We could use a heuristic and either use:
// SCEVAffinator::takeNonNegativeAssumption
@ -2255,13 +2238,13 @@ __isl_give PWACtx Scop::getPwAff(const SCEV *E, BasicBlock *BB,
// SCEVAffinator::interpretAsUnsigned
// to deal with unsigned or "NonNegative" SCEVs.
if (NonNegative)
Affinator.takeNonNegativeAssumption(PWAC);
Affinator.takeNonNegativeAssumption(PWAC, RecordedAssumptions);
return PWAC;
}
auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc();
invalidate(COMPLEXITY, DL, BB);
return Affinator.getPwAff(SE->getZero(E->getType()), BB);
return Affinator.getPwAff(SE->getZero(E->getType()), BB, RecordedAssumptions);
}
isl::union_set Scop::getDomains() const {
@ -2274,8 +2257,9 @@ isl::union_set Scop::getDomains() const {
return isl::manage(Domain);
}
isl::pw_aff Scop::getPwAffOnly(const SCEV *E, BasicBlock *BB) {
PWACtx PWAC = getPwAff(E, BB);
isl::pw_aff Scop::getPwAffOnly(const SCEV *E, BasicBlock *BB,
RecordedAssumptionsTy *RecordedAssumptions) {
PWACtx PWAC = getPwAff(E, BB, RecordedAssumptions);
return PWAC.first;
}

View File

@ -95,23 +95,28 @@ void SCEVAffinator::interpretAsUnsigned(PWACtx &PWAC, unsigned Width) {
NonNegPWA, isl_pw_aff_add(PWAC.first.release(), ExpPWA)));
}
void SCEVAffinator::takeNonNegativeAssumption(PWACtx &PWAC) {
void SCEVAffinator::takeNonNegativeAssumption(
PWACtx &PWAC, RecordedAssumptionsTy *RecordedAssumptions) {
this->RecordedAssumptions = RecordedAssumptions;
auto *NegPWA = isl_pw_aff_neg(PWAC.first.copy());
auto *NegDom = isl_pw_aff_pos_set(NegPWA);
PWAC.second =
isl::manage(isl_set_union(PWAC.second.release(), isl_set_copy(NegDom)));
auto *Restriction = BB ? NegDom : isl_set_params(NegDom);
auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc();
S->recordAssumption(UNSIGNED, isl::manage(Restriction), DL, AS_RESTRICTION,
BB);
recordAssumption(RecordedAssumptions, UNSIGNED, isl::manage(Restriction), DL,
AS_RESTRICTION, BB);
}
PWACtx SCEVAffinator::getPWACtxFromPWA(isl::pw_aff PWA) {
return std::make_pair(PWA, isl::set::empty(isl::space(Ctx, 0, NumIterators)));
}
PWACtx SCEVAffinator::getPwAff(const SCEV *Expr, BasicBlock *BB) {
PWACtx SCEVAffinator::getPwAff(const SCEV *Expr, BasicBlock *BB,
RecordedAssumptionsTy *RecordedAssumptions) {
this->BB = BB;
this->RecordedAssumptions = RecordedAssumptions;
if (BB) {
auto *DC = S->getDomainConditions(BB).release();
@ -145,7 +150,8 @@ PWACtx SCEVAffinator::checkForWrapping(const SCEV *Expr, PWACtx PWAC) const {
NotEqualSet = NotEqualSet.coalesce();
if (!NotEqualSet.is_empty())
S->recordAssumption(WRAPPING, NotEqualSet, Loc, AS_RESTRICTION, BB);
recordAssumption(RecordedAssumptions, WRAPPING, NotEqualSet, Loc,
AS_RESTRICTION, BB);
return PWAC;
}
@ -289,8 +295,8 @@ PWACtx SCEVAffinator::visitTruncateExpr(const SCEVTruncateExpr *Expr) {
OutOfBoundsDom = isl_set_params(OutOfBoundsDom);
}
S->recordAssumption(UNSIGNED, isl::manage(OutOfBoundsDom), DebugLoc(),
AS_RESTRICTION, BB);
recordAssumption(RecordedAssumptions, UNSIGNED, isl::manage(OutOfBoundsDom),
DebugLoc(), AS_RESTRICTION, BB);
return OpPWAC;
}
@ -344,7 +350,7 @@ PWACtx SCEVAffinator::visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
// If the width is to big we assume the negative part does not occur.
if (!computeModuloForExpr(Op)) {
takeNonNegativeAssumption(OpPWAC);
takeNonNegativeAssumption(OpPWAC, RecordedAssumptions);
return OpPWAC;
}
@ -485,7 +491,7 @@ PWACtx SCEVAffinator::visitUDivExpr(const SCEVUDivExpr *Expr) {
// precise but therefor a heuristic is needed.
// Assume a non-negative dividend.
takeNonNegativeAssumption(DividendPWAC);
takeNonNegativeAssumption(DividendPWAC, RecordedAssumptions);
DividendPWAC = combine(DividendPWAC, DivisorPWAC, isl_pw_aff_div);
DividendPWAC.first = DividendPWAC.first.floor();

View File

@ -221,6 +221,16 @@ void polly::splitEntryBlockForAlloca(BasicBlock *EntryBlock, Pass *P) {
polly::splitEntryBlockForAlloca(EntryBlock, DT, LI, RI);
}
void polly::recordAssumption(polly::RecordedAssumptionsTy *RecordedAssumptions,
polly::AssumptionKind Kind, isl::set Set,
DebugLoc Loc, polly::AssumptionSign Sign,
BasicBlock *BB) {
assert((Set.is_params() || BB) &&
"Assumptions without a basic block must be parameter sets");
if (RecordedAssumptions)
RecordedAssumptions->push_back({Kind, Sign, Set, Loc, BB});
}
/// The SCEVExpander will __not__ generate any code for an existing SDiv/SRem
/// instruction but just use it, if it is referenced as a SCEVUnknown. We want
/// however to generate new code if the instruction is in the analyzed region