Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===--- polly/DependenceInfo.h - Polyhedral dependency analysis *- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// Calculate the data dependency relations for a Scop using ISL.
10
//
11
// The integer set library (ISL) from Sven has an integrated dependency analysis
12
// to calculate data dependences. This pass takes advantage of this and
13
// calculates those dependences of a Scop.
14
//
15
// The dependences in this pass are exact in terms that for a specific read
16
// statement instance only the last write statement instance is returned. In
17
// case of may-writes, a set of possible write instances is returned. This
18
// analysis will never produce redundant dependences.
19
//
20
//===----------------------------------------------------------------------===//
21
 
22
#ifndef POLLY_DEPENDENCE_INFO_H
23
#define POLLY_DEPENDENCE_INFO_H
24
 
25
#include "polly/ScopPass.h"
26
#include "isl/ctx.h"
27
#include "isl/isl-noexceptions.h"
28
 
29
namespace polly {
30
 
31
/// The accumulated dependence information for a SCoP.
32
///
33
/// The Dependences struct holds all dependence information we collect and
34
/// compute for one SCoP. It also offers an interface that allows users to
35
/// query only specific parts.
36
class Dependences final {
37
public:
38
  // Granularities of the current dependence analysis
39
  enum AnalysisLevel {
40
    AL_Statement = 0,
41
    // Distinguish accessed memory references in the same statement
42
    AL_Reference,
43
    // Distinguish memory access instances in the same statement
44
    AL_Access,
45
 
46
    NumAnalysisLevels
47
  };
48
 
49
  /// Map type for reduction dependences.
50
  using ReductionDependencesMapTy = DenseMap<MemoryAccess *, isl_map *>;
51
 
52
  /// Map type to associate statements with schedules.
53
  using StatementToIslMapTy = DenseMap<ScopStmt *, isl::map>;
54
 
55
  /// The type of the dependences.
56
  ///
57
  /// Reduction dependences are separated from RAW/WAW/WAR dependences because
58
  /// we can ignore them during the scheduling. That's because the order
59
  /// in which the reduction statements are executed does not matter. However,
60
  /// if they are executed in parallel we need to take additional measures
61
  /// (e.g, privatization) to ensure a correct result. The (reverse) transitive
62
  /// closure of the reduction dependences are used to check for parallel
63
  /// executed reduction statements during code generation. These dependences
64
  /// connect all instances of a reduction with each other, they are therefore
65
  /// cyclic and possibly "reversed".
66
  enum Type {
67
    // Write after read
68
    TYPE_WAR = 1 << 0,
69
 
70
    // Read after write
71
    TYPE_RAW = 1 << 1,
72
 
73
    // Write after write
74
    TYPE_WAW = 1 << 2,
75
 
76
    // Reduction dependences
77
    TYPE_RED = 1 << 3,
78
 
79
    // Transitive closure of the reduction dependences (& the reverse)
80
    TYPE_TC_RED = 1 << 4,
81
  };
82
 
83
  const std::shared_ptr<isl_ctx> &getSharedIslCtx() const { return IslCtx; }
84
 
85
  /// Get the dependences of type @p Kinds.
86
  ///
87
  /// @param Kinds This integer defines the different kinds of dependences
88
  ///              that will be returned. To return more than one kind, the
89
  ///              different kinds are 'ored' together.
90
  isl::union_map getDependences(int Kinds) const;
91
 
92
  /// Report if valid dependences are available.
93
  bool hasValidDependences() const;
94
 
95
  /// Return the reduction dependences caused by @p MA.
96
  ///
97
  /// @return The reduction dependences caused by @p MA or nullptr if none.
98
  __isl_give isl_map *getReductionDependences(MemoryAccess *MA) const;
99
 
100
  /// Return all reduction dependences.
101
  const ReductionDependencesMapTy &getReductionDependences() const {
102
    return ReductionDependences;
103
  }
104
 
105
  /// Check if a partial schedule is parallel wrt to @p Deps.
106
  ///
107
  /// @param Schedule       The subset of the schedule space that we want to
108
  ///                       check.
109
  /// @param Deps           The dependences @p Schedule needs to respect.
110
  /// @param MinDistancePtr If not nullptr, the minimal dependence distance will
111
  ///                       be returned at the address of that pointer
112
  ///
113
  /// @return Returns true, if executing parallel the outermost dimension of
114
  ///         @p Schedule is valid according to the dependences @p Deps.
115
  bool isParallel(__isl_keep isl_union_map *Schedule,
116
                  __isl_take isl_union_map *Deps,
117
                  __isl_give isl_pw_aff **MinDistancePtr = nullptr) const;
118
 
119
  /// Check if a new schedule is valid.
120
  ///
121
  /// @param S             The current SCoP.
122
  /// @param NewSchedules  The new schedules
123
  ///
124
  /// @return True if the new schedule is valid, false if it reverses
125
  ///         dependences.
126
  bool isValidSchedule(Scop &S, const StatementToIslMapTy &NewSchedules) const;
127
 
128
  /// Return true of the schedule @p NewSched is a schedule for @S that does not
129
  /// violate any dependences.
130
  bool isValidSchedule(Scop &S, isl::schedule NewSched) const;
131
 
132
  /// Print the stored dependence information.
133
  void print(llvm::raw_ostream &OS) const;
134
 
135
  /// Dump the dependence information stored to the dbgs stream.
136
  void dump() const;
137
 
138
  /// Return the granularity of this dependence analysis.
139
  AnalysisLevel getDependenceLevel() { return Level; }
140
 
141
  /// Allow the DependenceInfo access to private members and methods.
142
  ///
143
  /// To restrict access to the internal state, only the DependenceInfo class
144
  /// is able to call or modify a Dependences struct.
145
  friend struct DependenceAnalysis;
146
  friend struct DependenceInfoPrinterPass;
147
  friend class DependenceInfo;
148
  friend class DependenceInfoWrapperPass;
149
 
150
  /// Destructor that will free internal objects.
151
  ~Dependences() { releaseMemory(); }
152
 
153
private:
154
  /// Create an empty dependences struct.
155
  explicit Dependences(const std::shared_ptr<isl_ctx> &IslCtx,
156
                       AnalysisLevel Level)
157
      : RAW(nullptr), WAR(nullptr), WAW(nullptr), RED(nullptr), TC_RED(nullptr),
158
        IslCtx(IslCtx), Level(Level) {}
159
 
160
  /// Calculate and add at the privatization dependences.
161
  void addPrivatizationDependences();
162
 
163
  /// Calculate the dependences for a certain SCoP @p S.
164
  void calculateDependences(Scop &S);
165
 
166
  /// Set the reduction dependences for @p MA to @p Deps.
167
  void setReductionDependences(MemoryAccess *MA, __isl_take isl_map *Deps);
168
 
169
  /// Free the objects associated with this Dependences struct.
170
  ///
171
  /// The Dependences struct will again be "empty" afterwards.
172
  void releaseMemory();
173
 
174
  /// The different basic kinds of dependences we calculate.
175
  isl_union_map *RAW;
176
  isl_union_map *WAR;
177
  isl_union_map *WAW;
178
 
179
  /// The special reduction dependences.
180
  isl_union_map *RED;
181
 
182
  /// The (reverse) transitive closure of reduction dependences.
183
  isl_union_map *TC_RED;
184
 
185
  /// Mapping from memory accesses to their reduction dependences.
186
  ReductionDependencesMapTy ReductionDependences;
187
 
188
  /// Isl context from the SCoP.
189
  std::shared_ptr<isl_ctx> IslCtx;
190
 
191
  /// Granularity of this dependence analysis.
192
  const AnalysisLevel Level;
193
};
194
 
195
struct DependenceAnalysis final : public AnalysisInfoMixin<DependenceAnalysis> {
196
  static AnalysisKey Key;
197
  struct Result {
198
    Scop &S;
199
    std::unique_ptr<Dependences> D[Dependences::NumAnalysisLevels];
200
 
201
    /// Return the dependence information for the current SCoP.
202
    ///
203
    /// @param Level The granularity of dependence analysis result.
204
    ///
205
    /// @return The dependence analysis result
206
    ///
207
    const Dependences &getDependences(Dependences::AnalysisLevel Level);
208
 
209
    /// Recompute dependences from schedule and memory accesses.
210
    const Dependences &recomputeDependences(Dependences::AnalysisLevel Level);
211
 
212
    /// Invalidate the dependence information and recompute it when needed
213
    /// again.
214
    /// May be required when the underlaying Scop was changed in a way that
215
    /// would add new dependencies (e.g. between new statement instances
216
    /// insierted into the SCoP) or intentionally breaks existing ones. It is
217
    /// not required when updating the schedule that conforms the existing
218
    /// dependencies.
219
    void abandonDependences();
220
  };
221
  Result run(Scop &S, ScopAnalysisManager &SAM,
222
             ScopStandardAnalysisResults &SAR);
223
};
224
 
225
struct DependenceInfoPrinterPass final
226
    : PassInfoMixin<DependenceInfoPrinterPass> {
227
  DependenceInfoPrinterPass(raw_ostream &OS) : OS(OS) {}
228
 
229
  PreservedAnalyses run(Scop &S, ScopAnalysisManager &,
230
                        ScopStandardAnalysisResults &, SPMUpdater &);
231
 
232
  raw_ostream &OS;
233
};
234
 
235
class DependenceInfo final : public ScopPass {
236
public:
237
  static char ID;
238
 
239
  /// Construct a new DependenceInfo pass.
240
  DependenceInfo() : ScopPass(ID) {}
241
 
242
  /// Return the dependence information for the current SCoP.
243
  ///
244
  /// @param Level The granularity of dependence analysis result.
245
  ///
246
  /// @return The dependence analysis result
247
  ///
248
  const Dependences &getDependences(Dependences::AnalysisLevel Level);
249
 
250
  /// Recompute dependences from schedule and memory accesses.
251
  const Dependences &recomputeDependences(Dependences::AnalysisLevel Level);
252
 
253
  /// Invalidate the dependence information and recompute it when needed again.
254
  /// May be required when the underlaying Scop was changed in a way that would
255
  /// add new dependencies (e.g. between new statement instances insierted into
256
  /// the SCoP) or intentionally breaks existing ones. It is not required when
257
  /// updating the schedule that conforms the existing dependencies.
258
  void abandonDependences();
259
 
260
  /// Compute the dependence information for the SCoP @p S.
261
  bool runOnScop(Scop &S) override;
262
 
263
  /// Print the dependences for the given SCoP to @p OS.
264
  void printScop(raw_ostream &OS, Scop &) const override;
265
 
266
  /// Release the internal memory.
267
  void releaseMemory() override {
268
    for (auto &d : D)
269
      d.reset();
270
  }
271
 
272
  /// Register all analyses and transformation required.
273
  void getAnalysisUsage(AnalysisUsage &AU) const override;
274
 
275
private:
276
  Scop *S;
277
 
278
  /// Dependences struct for the current SCoP.
279
  std::unique_ptr<Dependences> D[Dependences::NumAnalysisLevels];
280
};
281
 
282
llvm::Pass *createDependenceInfoPass();
283
llvm::Pass *createDependenceInfoPrinterLegacyPass(llvm::raw_ostream &OS);
284
 
285
/// Construct a new DependenceInfoWrapper pass.
286
class DependenceInfoWrapperPass final : public FunctionPass {
287
public:
288
  static char ID;
289
 
290
  /// Construct a new DependenceInfoWrapper pass.
291
  DependenceInfoWrapperPass() : FunctionPass(ID) {}
292
 
293
  /// Return the dependence information for the given SCoP.
294
  ///
295
  /// @param S     SCoP object.
296
  /// @param Level The granularity of dependence analysis result.
297
  ///
298
  /// @return The dependence analysis result
299
  ///
300
  const Dependences &getDependences(Scop *S, Dependences::AnalysisLevel Level);
301
 
302
  /// Recompute dependences from schedule and memory accesses.
303
  const Dependences &recomputeDependences(Scop *S,
304
                                          Dependences::AnalysisLevel Level);
305
 
306
  /// Compute the dependence information on-the-fly for the function.
307
  bool runOnFunction(Function &F) override;
308
 
309
  /// Print the dependences for the current function to @p OS.
310
  void print(raw_ostream &OS, const Module *M = nullptr) const override;
311
 
312
  /// Release the internal memory.
313
  void releaseMemory() override { ScopToDepsMap.clear(); }
314
 
315
  /// Register all analyses and transformation required.
316
  void getAnalysisUsage(AnalysisUsage &AU) const override;
317
 
318
private:
319
  using ScopToDepsMapTy = DenseMap<Scop *, std::unique_ptr<Dependences>>;
320
 
321
  /// Scop to Dependence map for the current function.
322
  ScopToDepsMapTy ScopToDepsMap;
323
};
324
 
325
llvm::Pass *createDependenceInfoWrapperPassPass();
326
llvm::Pass *
327
createDependenceInfoPrinterLegacyFunctionPass(llvm::raw_ostream &OS);
328
 
329
} // namespace polly
330
 
331
namespace llvm {
332
void initializeDependenceInfoPass(llvm::PassRegistry &);
333
void initializeDependenceInfoPrinterLegacyPassPass(llvm::PassRegistry &);
334
void initializeDependenceInfoWrapperPassPass(llvm::PassRegistry &);
335
void initializeDependenceInfoPrinterLegacyFunctionPassPass(
336
    llvm::PassRegistry &);
337
} // namespace llvm
338
 
339
#endif