summaryrefslogtreecommitdiffstats
path: root/polly/include/polly/DependenceInfo.h
blob: 6198fbf59225370835cef066cf5bc00a0d4d9f65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
//===--- 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"

struct isl_pw_aff;
struct isl_union_map;
struct isl_union_set;
struct isl_map;
struct isl_set;
struct clast_for;

using namespace llvm;

namespace polly {

class Scop;
class ScopStmt;
class MemoryAccess;

/// 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 {
class PassRegistry;
void initializeDependenceInfoPass(llvm::PassRegistry &);
void initializeDependenceInfoWrapperPassPass(llvm::PassRegistry &);
} // namespace llvm

#endif
OpenPOWER on IntegriCloud