1 //===--- polly/DependenceInfo.h - Polyhedral dependency analysis *- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Calculate the data dependency relations for a Scop using ISL.
12 // The integer set library (ISL) from Sven has an integrated dependency analysis
13 // to calculate data dependences. This pass takes advantage of this and
14 // calculates those dependences of a Scop.
16 // The dependences in this pass are exact in terms that for a specific read
17 // statement instance only the last write statement instance is returned. In
18 // case of may-writes, a set of possible write instances is returned. This
19 // analysis will never produce redundant dependences.
21 //===----------------------------------------------------------------------===//
23 #ifndef POLLY_DEPENDENCE_INFO_H
24 #define POLLY_DEPENDENCE_INFO_H
26 #include "polly/ScopPass.h"
44 /// The accumulated dependence information for a SCoP.
46 /// The Dependences struct holds all dependence information we collect and
47 /// compute for one SCoP. It also offers an interface that allows users to
48 /// query only specific parts.
50 // Granularities of the current dependence analysis
53 // Distinguish accessed memory references in the same statement
55 // Distinguish memory access instances in the same statement
61 /// Map type for reduction dependences.
62 using ReductionDependencesMapTy
= DenseMap
<MemoryAccess
*, isl_map
*>;
64 /// Map type to associate statements with schedules.
65 using StatementToIslMapTy
= DenseMap
<ScopStmt
*, isl_map
*>;
67 /// The type of the dependences.
69 /// Reduction dependences are separated from RAW/WAW/WAR dependences because
70 /// we can ignore them during the scheduling. That's because the order
71 /// in which the reduction statements are executed does not matter. However,
72 /// if they are executed in parallel we need to take additional measures
73 /// (e.g, privatization) to ensure a correct result. The (reverse) transitive
74 /// closure of the reduction dependences are used to check for parallel
75 /// executed reduction statements during code generation. These dependences
76 /// connect all instances of a reduction with each other, they are therefore
77 /// cyclic and possibly "reversed".
88 // Reduction dependences
91 // Transitive closure of the reduction dependences (& the reverse)
95 /// Get the dependences of type @p Kinds.
97 /// @param Kinds This integer defines the different kinds of dependences
98 /// that will be returned. To return more than one kind, the
99 /// different kinds are 'ored' together.
100 __isl_give isl_union_map
*getDependences(int Kinds
) const;
102 /// Report if valid dependences are available.
103 bool hasValidDependences() const;
105 /// Return the reduction dependences caused by @p MA.
107 /// @return The reduction dependences caused by @p MA or nullptr if none.
108 __isl_give isl_map
*getReductionDependences(MemoryAccess
*MA
) const;
110 /// Return all reduction dependences.
111 const ReductionDependencesMapTy
&getReductionDependences() const {
112 return ReductionDependences
;
115 /// Check if a partial schedule is parallel wrt to @p Deps.
117 /// @param Schedule The subset of the schedule space that we want to
119 /// @param Deps The dependences @p Schedule needs to respect.
120 /// @param MinDistancePtr If not nullptr, the minimal dependence distance will
121 /// be returned at the address of that pointer
123 /// @return Returns true, if executing parallel the outermost dimension of
124 /// @p Schedule is valid according to the dependences @p Deps.
125 bool isParallel(__isl_keep isl_union_map
*Schedule
,
126 __isl_take isl_union_map
*Deps
,
127 __isl_give isl_pw_aff
**MinDistancePtr
= nullptr) const;
129 /// Check if a new schedule is valid.
131 /// @param S The current SCoP.
132 /// @param NewSchedules The new schedules
134 /// @return True if the new schedule is valid, false if it reverses
136 bool isValidSchedule(Scop
&S
, StatementToIslMapTy
*NewSchedules
) const;
138 /// Print the stored dependence information.
139 void print(llvm::raw_ostream
&OS
) const;
141 /// Dump the dependence information stored to the dbgs stream.
144 /// Return the granularity of this dependence analysis.
145 AnalysisLevel
getDependenceLevel() { return Level
; }
147 /// Allow the DependenceInfo access to private members and methods.
149 /// To restrict access to the internal state, only the DependenceInfo class
150 /// is able to call or modify a Dependences struct.
151 friend struct DependenceAnalysis
;
152 friend struct DependenceInfoPrinterPass
;
153 friend class DependenceInfo
;
154 friend class DependenceInfoWrapperPass
;
156 /// Destructor that will free internal objects.
157 ~Dependences() { releaseMemory(); }
160 /// Create an empty dependences struct.
161 explicit Dependences(const std::shared_ptr
<isl_ctx
> &IslCtx
,
163 : RAW(nullptr), WAR(nullptr), WAW(nullptr), RED(nullptr), TC_RED(nullptr),
164 IslCtx(IslCtx
), Level(Level
) {}
166 /// Calculate and add at the privatization dependences.
167 void addPrivatizationDependences();
169 /// Calculate the dependences for a certain SCoP @p S.
170 void calculateDependences(Scop
&S
);
172 /// Set the reduction dependences for @p MA to @p Deps.
173 void setReductionDependences(MemoryAccess
*MA
, __isl_take isl_map
*Deps
);
175 /// Free the objects associated with this Dependences struct.
177 /// The Dependences struct will again be "empty" afterwards.
178 void releaseMemory();
180 /// The different basic kinds of dependences we calculate.
185 /// The special reduction dependences.
188 /// The (reverse) transitive closure of reduction dependences.
189 isl_union_map
*TC_RED
;
191 /// Mapping from memory accesses to their reduction dependences.
192 ReductionDependencesMapTy ReductionDependences
;
194 /// Isl context from the SCoP.
195 std::shared_ptr
<isl_ctx
> IslCtx
;
197 /// Granularity of this dependence analysis.
198 const AnalysisLevel Level
;
201 struct DependenceAnalysis
: public AnalysisInfoMixin
<DependenceAnalysis
> {
202 static AnalysisKey Key
;
205 std::unique_ptr
<Dependences
> D
[Dependences::NumAnalysisLevels
];
207 /// Return the dependence information for the current SCoP.
209 /// @param Level The granularity of dependence analysis result.
211 /// @return The dependence analysis result
213 const Dependences
&getDependences(Dependences::AnalysisLevel Level
);
215 /// Recompute dependences from schedule and memory accesses.
216 const Dependences
&recomputeDependences(Dependences::AnalysisLevel Level
);
218 Result
run(Scop
&S
, ScopAnalysisManager
&SAM
,
219 ScopStandardAnalysisResults
&SAR
);
222 struct DependenceInfoPrinterPass
223 : public PassInfoMixin
<DependenceInfoPrinterPass
> {
224 DependenceInfoPrinterPass(raw_ostream
&OS
) : OS(OS
) {}
226 PreservedAnalyses
run(Scop
&S
, ScopAnalysisManager
&,
227 ScopStandardAnalysisResults
&, SPMUpdater
&);
232 class DependenceInfo
: public ScopPass
{
236 /// Construct a new DependenceInfo pass.
237 DependenceInfo() : ScopPass(ID
) {}
239 /// Return the dependence information for the current SCoP.
241 /// @param Level The granularity of dependence analysis result.
243 /// @return The dependence analysis result
245 const Dependences
&getDependences(Dependences::AnalysisLevel Level
);
247 /// Recompute dependences from schedule and memory accesses.
248 const Dependences
&recomputeDependences(Dependences::AnalysisLevel Level
);
250 /// Compute the dependence information for the SCoP @p S.
251 bool runOnScop(Scop
&S
) override
;
253 /// Print the dependences for the given SCoP to @p OS.
254 void printScop(raw_ostream
&OS
, Scop
&) const override
;
256 /// Release the internal memory.
257 void releaseMemory() override
{
262 /// Register all analyses and transformation required.
263 void getAnalysisUsage(AnalysisUsage
&AU
) const override
;
268 /// Dependences struct for the current SCoP.
269 std::unique_ptr
<Dependences
> D
[Dependences::NumAnalysisLevels
];
272 /// Construct a new DependenceInfoWrapper pass.
273 class DependenceInfoWrapperPass
: public FunctionPass
{
277 /// Construct a new DependenceInfoWrapper pass.
278 DependenceInfoWrapperPass() : FunctionPass(ID
) {}
280 /// Return the dependence information for the given SCoP.
282 /// @param S SCoP object.
283 /// @param Level The granularity of dependence analysis result.
285 /// @return The dependence analysis result
287 const Dependences
&getDependences(Scop
*S
, Dependences::AnalysisLevel Level
);
289 /// Recompute dependences from schedule and memory accesses.
290 const Dependences
&recomputeDependences(Scop
*S
,
291 Dependences::AnalysisLevel Level
);
293 /// Compute the dependence information on-the-fly for the function.
294 bool runOnFunction(Function
&F
) override
;
296 /// Print the dependences for the current function to @p OS.
297 void print(raw_ostream
&OS
, const Module
*M
= nullptr) const override
;
299 /// Release the internal memory.
300 void releaseMemory() override
{ ScopToDepsMap
.clear(); }
302 /// Register all analyses and transformation required.
303 void getAnalysisUsage(AnalysisUsage
&AU
) const override
;
306 using ScopToDepsMapTy
= DenseMap
<Scop
*, std::unique_ptr
<Dependences
>>;
308 /// Scop to Dependence map for the current function.
309 ScopToDepsMapTy ScopToDepsMap
;
316 void initializeDependenceInfoPass(llvm::PassRegistry
&);
317 void initializeDependenceInfoWrapperPassPass(llvm::PassRegistry
&);