Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:48:20

0001 //===--- polly/DependenceInfo.h - Polyhedral dependency analysis *- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // Calculate the data dependency relations for a Scop using ISL.
0010 //
0011 // The integer set library (ISL) from Sven has an integrated dependency analysis
0012 // to calculate data dependences. This pass takes advantage of this and
0013 // calculates those dependences of a Scop.
0014 //
0015 // The dependences in this pass are exact in terms that for a specific read
0016 // statement instance only the last write statement instance is returned. In
0017 // case of may-writes, a set of possible write instances is returned. This
0018 // analysis will never produce redundant dependences.
0019 //
0020 //===----------------------------------------------------------------------===//
0021 
0022 #ifndef POLLY_DEPENDENCE_INFO_H
0023 #define POLLY_DEPENDENCE_INFO_H
0024 
0025 #include "polly/ScopPass.h"
0026 #include "isl/ctx.h"
0027 #include "isl/isl-noexceptions.h"
0028 
0029 namespace polly {
0030 
0031 /// The accumulated dependence information for a SCoP.
0032 ///
0033 /// The Dependences struct holds all dependence information we collect and
0034 /// compute for one SCoP. It also offers an interface that allows users to
0035 /// query only specific parts.
0036 class Dependences final {
0037 public:
0038   // Granularities of the current dependence analysis
0039   enum AnalysisLevel {
0040     AL_Statement = 0,
0041     // Distinguish accessed memory references in the same statement
0042     AL_Reference,
0043     // Distinguish memory access instances in the same statement
0044     AL_Access,
0045 
0046     NumAnalysisLevels
0047   };
0048 
0049   /// Map type for reduction dependences.
0050   using ReductionDependencesMapTy = DenseMap<MemoryAccess *, isl_map *>;
0051 
0052   /// Map type to associate statements with schedules.
0053   using StatementToIslMapTy = DenseMap<ScopStmt *, isl::map>;
0054 
0055   /// The type of the dependences.
0056   ///
0057   /// Reduction dependences are separated from RAW/WAW/WAR dependences because
0058   /// we can ignore them during the scheduling. That's because the order
0059   /// in which the reduction statements are executed does not matter. However,
0060   /// if they are executed in parallel we need to take additional measures
0061   /// (e.g, privatization) to ensure a correct result. The (reverse) transitive
0062   /// closure of the reduction dependences are used to check for parallel
0063   /// executed reduction statements during code generation. These dependences
0064   /// connect all instances of a reduction with each other, they are therefore
0065   /// cyclic and possibly "reversed".
0066   enum Type {
0067     // Write after read
0068     TYPE_WAR = 1 << 0,
0069 
0070     // Read after write
0071     TYPE_RAW = 1 << 1,
0072 
0073     // Write after write
0074     TYPE_WAW = 1 << 2,
0075 
0076     // Reduction dependences
0077     TYPE_RED = 1 << 3,
0078 
0079     // Transitive closure of the reduction dependences (& the reverse)
0080     TYPE_TC_RED = 1 << 4,
0081   };
0082 
0083   const std::shared_ptr<isl_ctx> &getSharedIslCtx() const { return IslCtx; }
0084 
0085   /// Get the dependences of type @p Kinds.
0086   ///
0087   /// @param Kinds This integer defines the different kinds of dependences
0088   ///              that will be returned. To return more than one kind, the
0089   ///              different kinds are 'ored' together.
0090   isl::union_map getDependences(int Kinds) const;
0091 
0092   /// Report if valid dependences are available.
0093   bool hasValidDependences() const;
0094 
0095   /// Return the reduction dependences caused by @p MA.
0096   ///
0097   /// @return The reduction dependences caused by @p MA or nullptr if none.
0098   __isl_give isl_map *getReductionDependences(MemoryAccess *MA) const;
0099 
0100   /// Return all reduction dependences.
0101   const ReductionDependencesMapTy &getReductionDependences() const {
0102     return ReductionDependences;
0103   }
0104 
0105   /// Check if a partial schedule is parallel wrt to @p Deps.
0106   ///
0107   /// @param Schedule       The subset of the schedule space that we want to
0108   ///                       check.
0109   /// @param Deps           The dependences @p Schedule needs to respect.
0110   /// @param MinDistancePtr If not nullptr, the minimal dependence distance will
0111   ///                       be returned at the address of that pointer
0112   ///
0113   /// @return Returns true, if executing parallel the outermost dimension of
0114   ///         @p Schedule is valid according to the dependences @p Deps.
0115   bool isParallel(__isl_keep isl_union_map *Schedule,
0116                   __isl_take isl_union_map *Deps,
0117                   __isl_give isl_pw_aff **MinDistancePtr = nullptr) const;
0118 
0119   /// Check if a new schedule is valid.
0120   ///
0121   /// @param S             The current SCoP.
0122   /// @param NewSchedules  The new schedules
0123   ///
0124   /// @return True if the new schedule is valid, false if it reverses
0125   ///         dependences.
0126   bool isValidSchedule(Scop &S, const StatementToIslMapTy &NewSchedules) const;
0127 
0128   /// Return true of the schedule @p NewSched is a schedule for @S that does not
0129   /// violate any dependences.
0130   bool isValidSchedule(Scop &S, isl::schedule NewSched) const;
0131 
0132   /// Print the stored dependence information.
0133   void print(llvm::raw_ostream &OS) const;
0134 
0135   /// Dump the dependence information stored to the dbgs stream.
0136   void dump() const;
0137 
0138   /// Return the granularity of this dependence analysis.
0139   AnalysisLevel getDependenceLevel() { return Level; }
0140 
0141   /// Allow the DependenceInfo access to private members and methods.
0142   ///
0143   /// To restrict access to the internal state, only the DependenceInfo class
0144   /// is able to call or modify a Dependences struct.
0145   friend struct DependenceAnalysis;
0146   friend struct DependenceInfoPrinterPass;
0147   friend class DependenceInfo;
0148   friend class DependenceInfoWrapperPass;
0149 
0150   /// Destructor that will free internal objects.
0151   ~Dependences() { releaseMemory(); }
0152 
0153 private:
0154   /// Create an empty dependences struct.
0155   explicit Dependences(const std::shared_ptr<isl_ctx> &IslCtx,
0156                        AnalysisLevel Level)
0157       : RAW(nullptr), WAR(nullptr), WAW(nullptr), RED(nullptr), TC_RED(nullptr),
0158         IslCtx(IslCtx), Level(Level) {}
0159 
0160   /// Calculate and add at the privatization dependences.
0161   void addPrivatizationDependences();
0162 
0163   /// Calculate the dependences for a certain SCoP @p S.
0164   void calculateDependences(Scop &S);
0165 
0166   /// Set the reduction dependences for @p MA to @p Deps.
0167   void setReductionDependences(MemoryAccess *MA, __isl_take isl_map *Deps);
0168 
0169   /// Free the objects associated with this Dependences struct.
0170   ///
0171   /// The Dependences struct will again be "empty" afterwards.
0172   void releaseMemory();
0173 
0174   /// The different basic kinds of dependences we calculate.
0175   isl_union_map *RAW;
0176   isl_union_map *WAR;
0177   isl_union_map *WAW;
0178 
0179   /// The special reduction dependences.
0180   isl_union_map *RED;
0181 
0182   /// The (reverse) transitive closure of reduction dependences.
0183   isl_union_map *TC_RED;
0184 
0185   /// Mapping from memory accesses to their reduction dependences.
0186   ReductionDependencesMapTy ReductionDependences;
0187 
0188   /// Isl context from the SCoP.
0189   std::shared_ptr<isl_ctx> IslCtx;
0190 
0191   /// Granularity of this dependence analysis.
0192   const AnalysisLevel Level;
0193 };
0194 
0195 struct DependenceAnalysis final : public AnalysisInfoMixin<DependenceAnalysis> {
0196   static AnalysisKey Key;
0197   struct Result {
0198     Scop &S;
0199     std::unique_ptr<Dependences> D[Dependences::NumAnalysisLevels];
0200 
0201     /// Return the dependence information for the current SCoP.
0202     ///
0203     /// @param Level The granularity of dependence analysis result.
0204     ///
0205     /// @return The dependence analysis result
0206     ///
0207     const Dependences &getDependences(Dependences::AnalysisLevel Level);
0208 
0209     /// Recompute dependences from schedule and memory accesses.
0210     const Dependences &recomputeDependences(Dependences::AnalysisLevel Level);
0211 
0212     /// Invalidate the dependence information and recompute it when needed
0213     /// again.
0214     /// May be required when the underlying Scop was changed in a way that
0215     /// would add new dependencies (e.g. between new statement instances
0216     /// insierted into the SCoP) or intentionally breaks existing ones. It is
0217     /// not required when updating the schedule that conforms the existing
0218     /// dependencies.
0219     void abandonDependences();
0220   };
0221   Result run(Scop &S, ScopAnalysisManager &SAM,
0222              ScopStandardAnalysisResults &SAR);
0223 };
0224 
0225 struct DependenceInfoPrinterPass final
0226     : PassInfoMixin<DependenceInfoPrinterPass> {
0227   DependenceInfoPrinterPass(raw_ostream &OS) : OS(OS) {}
0228 
0229   PreservedAnalyses run(Scop &S, ScopAnalysisManager &,
0230                         ScopStandardAnalysisResults &, SPMUpdater &);
0231 
0232   raw_ostream &OS;
0233 };
0234 
0235 class DependenceInfo final : public ScopPass {
0236 public:
0237   static char ID;
0238 
0239   /// Construct a new DependenceInfo pass.
0240   DependenceInfo() : ScopPass(ID) {}
0241 
0242   /// Return the dependence information for the current SCoP.
0243   ///
0244   /// @param Level The granularity of dependence analysis result.
0245   ///
0246   /// @return The dependence analysis result
0247   ///
0248   const Dependences &getDependences(Dependences::AnalysisLevel Level);
0249 
0250   /// Recompute dependences from schedule and memory accesses.
0251   const Dependences &recomputeDependences(Dependences::AnalysisLevel Level);
0252 
0253   /// Invalidate the dependence information and recompute it when needed again.
0254   /// May be required when the underlying Scop was changed in a way that would
0255   /// add new dependencies (e.g. between new statement instances insierted into
0256   /// the SCoP) or intentionally breaks existing ones. It is not required when
0257   /// updating the schedule that conforms the existing dependencies.
0258   void abandonDependences();
0259 
0260   /// Compute the dependence information for the SCoP @p S.
0261   bool runOnScop(Scop &S) override;
0262 
0263   /// Print the dependences for the given SCoP to @p OS.
0264   void printScop(raw_ostream &OS, Scop &) const override;
0265 
0266   /// Release the internal memory.
0267   void releaseMemory() override {
0268     for (auto &d : D)
0269       d.reset();
0270   }
0271 
0272   /// Register all analyses and transformation required.
0273   void getAnalysisUsage(AnalysisUsage &AU) const override;
0274 
0275 private:
0276   Scop *S;
0277 
0278   /// Dependences struct for the current SCoP.
0279   std::unique_ptr<Dependences> D[Dependences::NumAnalysisLevels];
0280 };
0281 
0282 llvm::Pass *createDependenceInfoPass();
0283 llvm::Pass *createDependenceInfoPrinterLegacyPass(llvm::raw_ostream &OS);
0284 
0285 /// Construct a new DependenceInfoWrapper pass.
0286 class DependenceInfoWrapperPass final : public FunctionPass {
0287 public:
0288   static char ID;
0289 
0290   /// Construct a new DependenceInfoWrapper pass.
0291   DependenceInfoWrapperPass() : FunctionPass(ID) {}
0292 
0293   /// Return the dependence information for the given SCoP.
0294   ///
0295   /// @param S     SCoP object.
0296   /// @param Level The granularity of dependence analysis result.
0297   ///
0298   /// @return The dependence analysis result
0299   ///
0300   const Dependences &getDependences(Scop *S, Dependences::AnalysisLevel Level);
0301 
0302   /// Recompute dependences from schedule and memory accesses.
0303   const Dependences &recomputeDependences(Scop *S,
0304                                           Dependences::AnalysisLevel Level);
0305 
0306   /// Compute the dependence information on-the-fly for the function.
0307   bool runOnFunction(Function &F) override;
0308 
0309   /// Print the dependences for the current function to @p OS.
0310   void print(raw_ostream &OS, const Module *M = nullptr) const override;
0311 
0312   /// Release the internal memory.
0313   void releaseMemory() override { ScopToDepsMap.clear(); }
0314 
0315   /// Register all analyses and transformation required.
0316   void getAnalysisUsage(AnalysisUsage &AU) const override;
0317 
0318 private:
0319   using ScopToDepsMapTy = DenseMap<Scop *, std::unique_ptr<Dependences>>;
0320 
0321   /// Scop to Dependence map for the current function.
0322   ScopToDepsMapTy ScopToDepsMap;
0323 };
0324 
0325 llvm::Pass *createDependenceInfoWrapperPassPass();
0326 llvm::Pass *
0327 createDependenceInfoPrinterLegacyFunctionPass(llvm::raw_ostream &OS);
0328 
0329 } // namespace polly
0330 
0331 namespace llvm {
0332 void initializeDependenceInfoPass(llvm::PassRegistry &);
0333 void initializeDependenceInfoPrinterLegacyPassPass(llvm::PassRegistry &);
0334 void initializeDependenceInfoWrapperPassPass(llvm::PassRegistry &);
0335 void initializeDependenceInfoPrinterLegacyFunctionPassPass(
0336     llvm::PassRegistry &);
0337 } // namespace llvm
0338 
0339 #endif