#include "polly/ScopPass.h"
-#include <map>
#include "isl/ctx.h"
struct isl_pw_aff;
class ScopStmt;
class MemoryAccess;
-class DependenceInfo : public ScopPass {
-public:
- static char ID;
+/// @brief The accumulated dependence information for a SCoP.
+///
+/// The dependences struct holds all dependence information we collect and
+/// compute for one SCoP. It also offers an interface that allows users to
+/// query only specific parts.
+struct Dependences {
+
+ /// @brief Map type for reduction dependences.
+ using ReductionDependencesMapTy = DenseMap<MemoryAccess *, isl_map *>;
+
+ /// @brief Map type to associate statements with schedules.
+ using StatementToIslMapTy = DenseMap<ScopStmt *, isl_map *>;
/// @brief The type of the dependences.
///
TYPE_TC_RED = 1 << 4,
};
- typedef std::map<ScopStmt *, isl_map *> StatementToIslMapTy;
+ /// @brief Get the dependences of type @p Kinds.
+ ///
+ /// @param Kinds This integer defines the different kinds of dependences
+ /// that will be returned. To return more than one kind, the
+ /// different kinds are 'ored' together.
+ __isl_give isl_union_map *getDependences(int Kinds) const;
- DependenceInfo();
+ /// @brief Report if valid dependences are available.
+ bool hasValidDependences() const;
- /// @brief Check if a new scattering is valid.
- ///
- /// @param NewScattering The new scatterings
+ /// @brief Return the reduction dependences caused by @p MA.
///
- /// @return bool True if the new scattering is valid, false it it reverses
- /// dependences.
- bool isValidScattering(StatementToIslMapTy *NewScatterings);
+ /// @return The reduction dependences caused by @p MA or nullptr if none.
+ __isl_give isl_map *getReductionDependences(MemoryAccess *MA) const;
+
+ /// @brief Return all reduction dependences.
+ const ReductionDependencesMapTy &getReductionDependences() const {
+ return ReductionDependences;
+ }
/// @brief Check if a partial schedule is parallel wrt to @p Deps.
///
/// @p Schedule is valid according to the dependences @p Deps.
bool isParallel(__isl_keep isl_union_map *Schedule,
__isl_take isl_union_map *Deps,
- __isl_give isl_pw_aff **MinDistancePtr = nullptr);
+ __isl_give isl_pw_aff **MinDistancePtr = nullptr) const;
- /// @brief Get the dependences in this Scop.
+ /// @brief Check if a new scattering is valid.
///
- /// @param Kinds This integer defines the different kinds of dependences
- /// that will be returned. To return more than one kind, the
- /// different kinds are 'ored' together.
- isl_union_map *getDependences(int Kinds);
+ /// @param S The current SCoP.
+ /// @param NewScattering The new scatterings
+ ///
+ /// @return bool True if the new scattering is valid, false it it reverses
+ /// dependences.
+ bool isValidScattering(Scop &S, StatementToIslMapTy *NewScatterings) const;
- /// @brief Report if valid dependences are available.
- bool hasValidDependences();
+ /// @brief Print the dependence information stored.
+ void print(llvm::raw_ostream &OS) const;
- /// @brief Return the reduction dependences caused by @p MA.
+ /// @brief Dump the dependence information stored to the dbgs stream.
+ void dump() const;
+
+ /// @brief Allow the DependenceInfo access to private members and methods.
///
- /// @return The reduction dependences caused by @p MA or nullptr if None.
- __isl_give isl_map *getReductionDependences(MemoryAccess *MA);
+ /// To restict access to the internal state only the DependenceInfo class
+ /// is able to call or modify a dependences struct.
+ friend class DependenceInfo;
- /// @brief Return the reduction dependences mapped by the causing @p MA.
- const DenseMap<MemoryAccess *, isl_map *> &getReductionDependences() const {
- return ReductionDependences;
- }
+private:
+ /// @brief Create an empty dependences struct.
+ Dependences()
+ : RAW(nullptr), WAR(nullptr), WAW(nullptr), RED(nullptr),
+ TC_RED(nullptr) {}
- /// @brief Recompute dependences from schedule and memory accesses.
- void recomputeDependences();
+ /// @brief Destructor that will free internal objects.
+ ~Dependences() { releaseMemory(); }
- bool runOnScop(Scop &S) override;
- void printScop(raw_ostream &OS, Scop &S) const override;
- void releaseMemory() override;
- void getAnalysisUsage(AnalysisUsage &AU) const override;
+ /// @brief Calculate and add at the privatization dependences.
+ void addPrivatizationDependences();
-private:
- Scop *S;
+ /// @brief Calculate the dependences for a certain SCoP @p S.
+ void calculateDependences(Scop &S);
+
+ /// @brief Set the reduction dependences for @p MA to @p Deps.
+ void setReductionDependences(MemoryAccess *MA, __isl_take isl_map *Deps);
- /// @brief The different kinds of dependences we calculate.
+ /// @brief Free the objects associated with this dependences struct.
+ ///
+ /// The dependences struct will again be "empty" afterwards.
+ void releaseMemory();
+
+ /// @brief The different basic kinds of dependences we calculate.
isl_union_map *RAW;
isl_union_map *WAR;
isl_union_map *WAW;
- /// @brief The map of reduction dependences
- isl_union_map *RED = nullptr;
+ /// @brief The special reduction dependences.
+ isl_union_map *RED;
- /// @brief The (reverse) transitive closure of reduction dependences
- isl_union_map *TC_RED = nullptr;
+ /// @brief The (reverse) transitive closure of reduction dependences.
+ isl_union_map *TC_RED;
- /// @brief Map from memory accesses to their reduction dependences.
- DenseMap<MemoryAccess *, isl_map *> ReductionDependences;
+ /// @brief Mapping from memory accesses to their reduction dependences.
+ ReductionDependencesMapTy ReductionDependences;
+};
- /// @brief Collect information about the SCoP.
- void collectInfo(Scop &S, isl_union_map **Read, isl_union_map **Write,
- isl_union_map **MayWrite, isl_union_map **AccessSchedule,
- isl_union_map **StmtSchedule);
+class DependenceInfo : public ScopPass {
+public:
+ static char ID;
- /// @brief Calculate and add at the privatization dependences
- void addPrivatizationDependences();
+ /// @brief Construct a new DependenceInfo pass.
+ DependenceInfo() : ScopPass(ID) {}
- /// @brief Calculate the dependences for a certain SCoP.
- void calculateDependences(Scop &S);
+ /// @brief Return the dependence information for the current SCoP.
+ const Dependences &getDependences() { return D; }
- /// @brief Set the reduction dependences for @p MA to @p Deps.
- void setReductionDependences(MemoryAccess *MA, __isl_take isl_map *Deps);
+ /// @brief Recompute dependences from schedule and memory accesses.
+ void recomputeDependences();
+
+ bool runOnScop(Scop &S) override;
+ void printScop(raw_ostream &OS, Scop &) const override { D.print(OS); }
+ void releaseMemory() override { D.releaseMemory(); }
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+ Scop *S;
+
+ /// @brief Dependences struct for the current SCoP.
+ Dependences D;
};
} // End polly namespace.
cl::cat(PollyCategory));
//===----------------------------------------------------------------------===//
-DependenceInfo::DependenceInfo() : ScopPass(ID) { RAW = WAR = WAW = nullptr; }
-void DependenceInfo::collectInfo(Scop &S, isl_union_map **Read,
- isl_union_map **Write,
- isl_union_map **MayWrite,
- isl_union_map **AccessSchedule,
- isl_union_map **StmtSchedule) {
+/// @brief Collect information about the SCoP @p S.
+static void collectInfo(Scop &S, isl_union_map **Read, isl_union_map **Write,
+ isl_union_map **MayWrite,
+ isl_union_map **AccessSchedule,
+ isl_union_map **StmtSchedule) {
isl_space *Space = S.getParamSpace();
*Read = isl_union_map_empty(isl_space_copy(Space));
*Write = isl_union_map_empty(isl_space_copy(Space));
///
/// Note: This function also computes the (reverse) transitive closure of the
/// reduction dependences.
-void DependenceInfo::addPrivatizationDependences() {
+void Dependences::addPrivatizationDependences() {
isl_union_map *PrivRAW, *PrivWAW, *PrivWAR;
// The transitive closure might be over approximated, thus could lead to
isl_union_set_free(Universe);
}
-void DependenceInfo::calculateDependences(Scop &S) {
+void Dependences::calculateDependences(Scop &S) {
isl_union_map *Read, *Write, *MayWrite, *AccessSchedule, *StmtSchedule,
*Schedule;
isl_union_map_domain(StmtSchedule));
DEBUG({
dbgs() << "Wrapped Dependences:\n";
- printScop(dbgs(), S);
+ dump();
dbgs() << "\n";
});
DEBUG({
dbgs() << "Final Wrapped Dependences:\n";
- printScop(dbgs(), S);
+ dump();
dbgs() << "\n";
});
DEBUG({
dbgs() << "Zipped Dependences:\n";
- printScop(dbgs(), S);
+ dump();
dbgs() << "\n";
});
DEBUG({
dbgs() << "Unwrapped Dependences:\n";
- printScop(dbgs(), S);
+ dump();
dbgs() << "\n";
});
RED = isl_union_map_coalesce(RED);
TC_RED = isl_union_map_coalesce(TC_RED);
- DEBUG(printScop(dbgs(), S));
+ DEBUG(dump());
}
-void DependenceInfo::recomputeDependences() {
- releaseMemory();
- calculateDependences(*S);
-}
-
-bool DependenceInfo::runOnScop(Scop &ScopVar) {
- S = &ScopVar;
- recomputeDependences();
- return false;
-}
-
-bool DependenceInfo::isValidScattering(StatementToIslMapTy *NewScattering) {
- Scop &S = *this->S;
-
+bool Dependences::isValidScattering(Scop &S,
+ StatementToIslMapTy *NewScattering) const {
if (LegalityCheckDisabled)
return true;
// dimension, then the loop is parallel. The distance is zero in the current
// dimension if it is a subset of a map with equal values for the current
// dimension.
-bool DependenceInfo::isParallel(isl_union_map *Schedule, isl_union_map *Deps,
- isl_pw_aff **MinDistancePtr) {
+bool Dependences::isParallel(isl_union_map *Schedule, isl_union_map *Deps,
+ isl_pw_aff **MinDistancePtr) const {
isl_set *Deltas, *Distance;
isl_map *ScheduleDeps;
unsigned Dimension;
OS << "n/a\n";
}
-void DependenceInfo::printScop(raw_ostream &OS, Scop &) const {
+void Dependences::print(raw_ostream &OS) const {
OS << "\tRAW dependences:\n\t\t";
printDependencyMap(OS, RAW);
OS << "\tWAR dependences:\n\t\t";
printDependencyMap(OS, TC_RED);
}
-void DependenceInfo::releaseMemory() {
+void Dependences::dump() const { print(dbgs()); }
+
+void Dependences::releaseMemory() {
isl_union_map_free(RAW);
isl_union_map_free(WAR);
isl_union_map_free(WAW);
ReductionDependences.clear();
}
-isl_union_map *DependenceInfo::getDependences(int Kinds) {
+isl_union_map *Dependences::getDependences(int Kinds) const {
assert(hasValidDependences() && "No valid dependences available");
isl_space *Space = isl_union_map_get_space(RAW);
isl_union_map *Deps = isl_union_map_empty(Space);
return Deps;
}
-bool DependenceInfo::hasValidDependences() {
+bool Dependences::hasValidDependences() const {
return (RAW != nullptr) && (WAR != nullptr) && (WAW != nullptr);
}
-isl_map *DependenceInfo::getReductionDependences(MemoryAccess *MA) {
- return isl_map_copy(ReductionDependences[MA]);
+isl_map *Dependences::getReductionDependences(MemoryAccess *MA) const {
+ return isl_map_copy(ReductionDependences.lookup(MA));
}
-void DependenceInfo::setReductionDependences(MemoryAccess *MA, isl_map *D) {
+void Dependences::setReductionDependences(MemoryAccess *MA, isl_map *D) {
assert(ReductionDependences.count(MA) == 0 &&
"Reduction dependences set twice!");
ReductionDependences[MA] = D;
}
+void DependenceInfo::recomputeDependences() {
+ releaseMemory();
+ D.calculateDependences(*S);
+}
+
+bool DependenceInfo::runOnScop(Scop &ScopVar) {
+ S = &ScopVar;
+ recomputeDependences();
+ return false;
+}
+
void DependenceInfo::getAnalysisUsage(AnalysisUsage &AU) const {
ScopPass::getAnalysisUsage(AU);
}
namespace polly {
class IslAst {
public:
- IslAst(Scop *Scop, DependenceInfo &D);
+ IslAst(Scop *Scop, const Dependences &D);
~IslAst();
: Deps(nullptr), InParallelFor(false), LastForNodeId(nullptr) {}
/// @brief The dependence information used for the parallelism check.
- DependenceInfo *Deps;
+ const Dependences *Deps;
/// @brief Flag to indicate that we are inside a parallel for node.
bool InParallelFor;
/// we can perform the parallelism check as we are only interested in a zero
/// (or non-zero) dependence distance on the dimension in question.
static bool astScheduleDimIsParallel(__isl_keep isl_ast_build *Build,
- DependenceInfo *D,
+ const Dependences *D,
IslAstUserPayload *NodeInfo) {
if (!D->hasValidDependences())
return false;
isl_union_map *Schedule = isl_ast_build_get_schedule(Build);
- isl_union_map *Deps =
- D->getDependences(DependenceInfo::TYPE_RAW | DependenceInfo::TYPE_WAW |
- DependenceInfo::TYPE_WAR);
+ isl_union_map *Deps = D->getDependences(
+ Dependences::TYPE_RAW | Dependences::TYPE_WAW | Dependences::TYPE_WAR);
if (!D->isParallel(Schedule, Deps, &NodeInfo->MinimalDependenceDistance) &&
!isl_union_map_free(Schedule))
return false;
- isl_union_map *RedDeps = D->getDependences(DependenceInfo::TYPE_TC_RED);
+ isl_union_map *RedDeps = D->getDependences(Dependences::TYPE_TC_RED);
if (!D->isParallel(Schedule, RedDeps))
NodeInfo->IsReductionParallel = true;
return true;
}
-IslAst::IslAst(Scop *Scop, DependenceInfo &D)
+IslAst::IslAst(Scop *Scop, const Dependences &D)
: S(Scop), Root(nullptr), RunCondition(nullptr) {
bool PerformParallelTest = PollyParallel || DetectParallel ||
S = &Scop;
- DependenceInfo &D = getAnalysis<DependenceInfo>();
+ const Dependences &D = getAnalysis<DependenceInfo>().getDependences();
Ast = new IslAst(&Scop, D);
OS << "New access function '" << *I << "'detected in JSCOP file\n";
}
-typedef DependenceInfo::StatementToIslMapTy StatementToIslMapTy;
+typedef Dependences::StatementToIslMapTy StatementToIslMapTy;
bool JSONImporter::runOnScop(Scop &S) {
Region &R = S.getRegion();
- DependenceInfo *D = &getAnalysis<DependenceInfo>();
+ const Dependences &D = getAnalysis<DependenceInfo>().getDependences();
const DataLayout &DL = getAnalysis<DataLayoutPass>().getDataLayout();
std::string FileName = ImportDir + "/" + getFileName(S);
index++;
}
- if (!D->isValidScattering(&NewScattering)) {
+ if (!D.isValidScattering(S, &NewScattering)) {
errs() << "JScop file contains a scattering that changes the "
<< "dependences. Use -disable-polly-legality to continue anyways\n";
for (StatementToIslMapTy::iterator SI = NewScattering.begin(),
/// combine a certain number of precise steps with one approximating step that
/// simplifies the life set with an affine hull.
bool DeadCodeElim::eliminateDeadCode(Scop &S, int PreciseSteps) {
- DependenceInfo *D = &getAnalysis<DependenceInfo>();
+ DependenceInfo &DI = getAnalysis<DependenceInfo>();
+ const Dependences &D = DI.getDependences();
- if (!D->hasValidDependences())
+ if (!D.hasValidDependences())
return false;
isl_union_set *Live = getLiveOut(S);
isl_union_map *Dep =
- D->getDependences(DependenceInfo::TYPE_RAW | DependenceInfo::TYPE_RED);
+ D.getDependences(Dependences::TYPE_RAW | Dependences::TYPE_RED);
Dep = isl_union_map_reverse(Dep);
if (PreciseSteps == -1)
// FIXME: We can probably avoid the recomputation of all dependences by
// updating them explicitly.
if (Changed)
- D->recomputeDependences();
+ DI.recomputeDependences();
return Changed;
}
return false;
}
- DependenceInfo *D = &getAnalysis<DependenceInfo>();
+ const Dependences &D = getAnalysis<DependenceInfo>().getDependences();
- if (!D->hasValidDependences())
+ if (!D.hasValidDependences())
return false;
isl_schedule_free(LastSchedule);
LastSchedule = nullptr;
// Build input data.
- int ValidityKinds = DependenceInfo::TYPE_RAW | DependenceInfo::TYPE_WAR |
- DependenceInfo::TYPE_WAW;
+ int ValidityKinds =
+ Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW;
int ProximityKinds;
if (OptimizeDeps == "all")
- ProximityKinds = DependenceInfo::TYPE_RAW | DependenceInfo::TYPE_WAR |
- DependenceInfo::TYPE_WAW;
+ ProximityKinds =
+ Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW;
else if (OptimizeDeps == "raw")
- ProximityKinds = DependenceInfo::TYPE_RAW;
+ ProximityKinds = Dependences::TYPE_RAW;
else {
errs() << "Do not know how to optimize for '" << OptimizeDeps << "'"
<< " Falling back to optimizing all dependences.\n";
- ProximityKinds = DependenceInfo::TYPE_RAW | DependenceInfo::TYPE_WAR |
- DependenceInfo::TYPE_WAW;
+ ProximityKinds =
+ Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW;
}
isl_union_set *Domain = S.getDomains();
if (!Domain)
return false;
- isl_union_map *Validity = D->getDependences(ValidityKinds);
- isl_union_map *Proximity = D->getDependences(ProximityKinds);
+ isl_union_map *Validity = D.getDependences(ValidityKinds);
+ isl_union_map *Proximity = D.getDependences(ProximityKinds);
// Simplify the dependences by removing the constraints introduced by the
// domains. This can speed up the scheduling time significantly, as large