| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- //===--- polly/DependenceInfo.h - Polyhedral dependency analysis *- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // Calculate the data dependency relations for a Scop using ISL.
- //
- // The integer set library (ISL) from Sven has an integrated dependency analysis
- // to calculate data dependences. This pass takes advantage of this and
- // calculates those dependences of a Scop.
- //
- // The dependences in this pass are exact in terms that for a specific read
- // statement instance only the last write statement instance is returned. In
- // case of may-writes, a set of possible write instances is returned. This
- // analysis will never produce redundant dependences.
- //
- //===----------------------------------------------------------------------===//
- #ifndef POLLY_DEPENDENCE_INFO_H
- #define POLLY_DEPENDENCE_INFO_H
- #include "polly/ScopPass.h"
- #include "isl/ctx.h"
- #include "isl/isl-noexceptions.h"
- namespace polly {
- /// 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 {
- // Granularities of the current dependence analysis
- enum AnalysisLevel {
- AL_Statement = 0,
- // Distinguish accessed memory references in the same statement
- AL_Reference,
- // Distinguish memory access instances in the same statement
- AL_Access,
- NumAnalysisLevels
- };
- /// Map type for reduction dependences.
- using ReductionDependencesMapTy = DenseMap<MemoryAccess *, isl_map *>;
- /// Map type to associate statements with schedules.
- using StatementToIslMapTy = DenseMap<ScopStmt *, isl::map>;
- /// The type of the dependences.
- ///
- /// Reduction dependences are separated from RAW/WAW/WAR dependences because
- /// we can ignore them during the scheduling. That's because the order
- /// in which the reduction statements are executed does not matter. However,
- /// if they are executed in parallel we need to take additional measures
- /// (e.g, privatization) to ensure a correct result. The (reverse) transitive
- /// closure of the reduction dependences are used to check for parallel
- /// executed reduction statements during code generation. These dependences
- /// connect all instances of a reduction with each other, they are therefore
- /// cyclic and possibly "reversed".
- enum Type {
- // Write after read
- TYPE_WAR = 1 << 0,
- // Read after write
- TYPE_RAW = 1 << 1,
- // Write after write
- TYPE_WAW = 1 << 2,
- // Reduction dependences
- TYPE_RED = 1 << 3,
- // Transitive closure of the reduction dependences (& the reverse)
- TYPE_TC_RED = 1 << 4,
- };
- const std::shared_ptr<isl_ctx> &getSharedIslCtx() const { return IslCtx; }
- /// 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::union_map getDependences(int Kinds) const;
- /// Report if valid dependences are available.
- bool hasValidDependences() const;
- /// Return the reduction dependences caused by @p MA.
- ///
- /// @return The reduction dependences caused by @p MA or nullptr if none.
- __isl_give isl_map *getReductionDependences(MemoryAccess *MA) const;
- /// Return all reduction dependences.
- const ReductionDependencesMapTy &getReductionDependences() const {
- return ReductionDependences;
- }
- /// Check if a partial schedule is parallel wrt to @p Deps.
- ///
- /// @param Schedule The subset of the schedule space that we want to
- /// check.
- /// @param Deps The dependences @p Schedule needs to respect.
- /// @param MinDistancePtr If not nullptr, the minimal dependence distance will
- /// be returned at the address of that pointer
- ///
- /// @return Returns true, if executing parallel the outermost dimension of
- /// @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) const;
- /// Check if a new schedule is valid.
- ///
- /// @param S The current SCoP.
- /// @param NewSchedules The new schedules
- ///
- /// @return True if the new schedule is valid, false if it reverses
- /// dependences.
- bool isValidSchedule(Scop &S, const StatementToIslMapTy &NewSchedules) const;
- /// Print the stored dependence information.
- void print(llvm::raw_ostream &OS) const;
- /// Dump the dependence information stored to the dbgs stream.
- void dump() const;
- /// Return the granularity of this dependence analysis.
- AnalysisLevel getDependenceLevel() { return Level; }
- /// Allow the DependenceInfo access to private members and methods.
- ///
- /// To restrict access to the internal state, only the DependenceInfo class
- /// is able to call or modify a Dependences struct.
- friend struct DependenceAnalysis;
- friend struct DependenceInfoPrinterPass;
- friend class DependenceInfo;
- friend class DependenceInfoWrapperPass;
- /// Destructor that will free internal objects.
- ~Dependences() { releaseMemory(); }
- private:
- /// Create an empty dependences struct.
- explicit Dependences(const std::shared_ptr<isl_ctx> &IslCtx,
- AnalysisLevel Level)
- : RAW(nullptr), WAR(nullptr), WAW(nullptr), RED(nullptr), TC_RED(nullptr),
- IslCtx(IslCtx), Level(Level) {}
- /// Calculate and add at the privatization dependences.
- void addPrivatizationDependences();
- /// Calculate the dependences for a certain SCoP @p S.
- void calculateDependences(Scop &S);
- /// Set the reduction dependences for @p MA to @p Deps.
- void setReductionDependences(MemoryAccess *MA, __isl_take isl_map *Deps);
- /// Free the objects associated with this Dependences struct.
- ///
- /// The Dependences struct will again be "empty" afterwards.
- void releaseMemory();
- /// The different basic kinds of dependences we calculate.
- isl_union_map *RAW;
- isl_union_map *WAR;
- isl_union_map *WAW;
- /// The special reduction dependences.
- isl_union_map *RED;
- /// The (reverse) transitive closure of reduction dependences.
- isl_union_map *TC_RED;
- /// Mapping from memory accesses to their reduction dependences.
- ReductionDependencesMapTy ReductionDependences;
- /// Isl context from the SCoP.
- std::shared_ptr<isl_ctx> IslCtx;
- /// Granularity of this dependence analysis.
- const AnalysisLevel Level;
- };
- struct DependenceAnalysis : public AnalysisInfoMixin<DependenceAnalysis> {
- static AnalysisKey Key;
- struct Result {
- Scop &S;
- std::unique_ptr<Dependences> D[Dependences::NumAnalysisLevels];
- /// Return the dependence information for the current SCoP.
- ///
- /// @param Level The granularity of dependence analysis result.
- ///
- /// @return The dependence analysis result
- ///
- const Dependences &getDependences(Dependences::AnalysisLevel Level);
- /// Recompute dependences from schedule and memory accesses.
- const Dependences &recomputeDependences(Dependences::AnalysisLevel Level);
- };
- Result run(Scop &S, ScopAnalysisManager &SAM,
- ScopStandardAnalysisResults &SAR);
- };
- struct DependenceInfoPrinterPass
- : public PassInfoMixin<DependenceInfoPrinterPass> {
- DependenceInfoPrinterPass(raw_ostream &OS) : OS(OS) {}
- PreservedAnalyses run(Scop &S, ScopAnalysisManager &,
- ScopStandardAnalysisResults &, SPMUpdater &);
- raw_ostream &OS;
- };
- class DependenceInfo : public ScopPass {
- public:
- static char ID;
- /// Construct a new DependenceInfo pass.
- DependenceInfo() : ScopPass(ID) {}
- /// Return the dependence information for the current SCoP.
- ///
- /// @param Level The granularity of dependence analysis result.
- ///
- /// @return The dependence analysis result
- ///
- const Dependences &getDependences(Dependences::AnalysisLevel Level);
- /// Recompute dependences from schedule and memory accesses.
- const Dependences &recomputeDependences(Dependences::AnalysisLevel Level);
- /// Compute the dependence information for the SCoP @p S.
- bool runOnScop(Scop &S) override;
- /// Print the dependences for the given SCoP to @p OS.
- void printScop(raw_ostream &OS, Scop &) const override;
- /// Release the internal memory.
- void releaseMemory() override {
- for (auto &d : D)
- d.reset();
- }
- /// Register all analyses and transformation required.
- void getAnalysisUsage(AnalysisUsage &AU) const override;
- private:
- Scop *S;
- /// Dependences struct for the current SCoP.
- std::unique_ptr<Dependences> D[Dependences::NumAnalysisLevels];
- };
- /// Construct a new DependenceInfoWrapper pass.
- class DependenceInfoWrapperPass : public FunctionPass {
- public:
- static char ID;
- /// Construct a new DependenceInfoWrapper pass.
- DependenceInfoWrapperPass() : FunctionPass(ID) {}
- /// Return the dependence information for the given SCoP.
- ///
- /// @param S SCoP object.
- /// @param Level The granularity of dependence analysis result.
- ///
- /// @return The dependence analysis result
- ///
- const Dependences &getDependences(Scop *S, Dependences::AnalysisLevel Level);
- /// Recompute dependences from schedule and memory accesses.
- const Dependences &recomputeDependences(Scop *S,
- Dependences::AnalysisLevel Level);
- /// Compute the dependence information on-the-fly for the function.
- bool runOnFunction(Function &F) override;
- /// Print the dependences for the current function to @p OS.
- void print(raw_ostream &OS, const Module *M = nullptr) const override;
- /// Release the internal memory.
- void releaseMemory() override { ScopToDepsMap.clear(); }
- /// Register all analyses and transformation required.
- void getAnalysisUsage(AnalysisUsage &AU) const override;
- private:
- using ScopToDepsMapTy = DenseMap<Scop *, std::unique_ptr<Dependences>>;
- /// Scop to Dependence map for the current function.
- ScopToDepsMapTy ScopToDepsMap;
- };
- } // namespace polly
- namespace llvm {
- void initializeDependenceInfoPass(llvm::PassRegistry &);
- void initializeDependenceInfoWrapperPassPass(llvm::PassRegistry &);
- } // namespace llvm
- #endif
|