|
|
|||
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
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|