xref: /llvm-project/mlir/include/mlir/Analysis/AliasAnalysis.h (revision 5146f84fd616084fb63025a3e8a172179137b1ce)
1 //===- AliasAnalysis.h - Alias Analysis in MLIR -----------------*- 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 // This header file defines utilities and analyses for performing alias queries
10 // and related memory queries in MLIR.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef MLIR_ANALYSIS_ALIASANALYSIS_H_
15 #define MLIR_ANALYSIS_ALIASANALYSIS_H_
16 
17 #include "mlir/IR/Operation.h"
18 
19 namespace mlir {
20 
21 //===----------------------------------------------------------------------===//
22 // AliasResult
23 //===----------------------------------------------------------------------===//
24 
25 /// The possible results of an alias query.
26 class AliasResult {
27 public:
28   enum Kind {
29     /// The two locations do not alias at all.
30     ///
31     /// This value is arranged to convert to false, while all other values
32     /// convert to true. This allows a boolean context to convert the result to
33     /// a binary flag indicating whether there is the possibility of aliasing.
34     NoAlias = 0,
35     /// The two locations may or may not alias. This is the least precise
36     /// result.
37     MayAlias,
38     /// The two locations alias, but only due to a partial overlap.
39     PartialAlias,
40     /// The two locations precisely alias each other.
41     MustAlias,
42   };
43 
AliasResult(Kind kind)44   AliasResult(Kind kind) : kind(kind) {}
45   bool operator==(const AliasResult &other) const { return kind == other.kind; }
46   bool operator!=(const AliasResult &other) const { return !(*this == other); }
47 
48   /// Allow conversion to bool to signal if there is an aliasing or not.
49   explicit operator bool() const { return kind != NoAlias; }
50 
51   /// Merge this alias result with `other` and return a new result that
52   /// represents the conservative merge of both results. If the results
53   /// represent a known alias, the stronger alias is chosen (i.e.
54   /// Partial+Must=Must). If the two results are conflicting, MayAlias is
55   /// returned.
56   AliasResult merge(AliasResult other) const;
57 
58   /// Returns if this result indicates no possibility of aliasing.
isNo()59   bool isNo() const { return kind == NoAlias; }
60 
61   /// Returns if this result is a may alias.
isMay()62   bool isMay() const { return kind == MayAlias; }
63 
64   /// Returns if this result is a must alias.
isMust()65   bool isMust() const { return kind == MustAlias; }
66 
67   /// Returns if this result is a partial alias.
isPartial()68   bool isPartial() const { return kind == PartialAlias; }
69 
70   /// Print this alias result to the provided output stream.
71   void print(raw_ostream &os) const;
72 
73 private:
74   /// The internal kind of the result.
75   Kind kind;
76 };
77 
78 inline raw_ostream &operator<<(raw_ostream &os, const AliasResult &result) {
79   result.print(os);
80   return os;
81 }
82 
83 //===----------------------------------------------------------------------===//
84 // ModRefResult
85 //===----------------------------------------------------------------------===//
86 
87 /// The possible results of whether a memory access modifies or references
88 /// a memory location. The possible results are: no access at all, a
89 /// modification, a reference, or both a modification and a reference.
90 class [[nodiscard]] ModRefResult {
91   /// Note: This is a simplified version of the ModRefResult in
92   /// `llvm/Analysis/AliasAnalysis.h`, and namely removes the `Must` concept. If
93   /// this becomes useful/necessary we should add it here.
94   enum class Kind {
95     /// The access neither references nor modifies the value stored in memory.
96     NoModRef = 0,
97     /// The access may reference the value stored in memory.
98     Ref = 1,
99     /// The access may modify the value stored in memory.
100     Mod = 2,
101     /// The access may reference and may modify the value stored in memory.
102     ModRef = Ref | Mod,
103   };
104 
105 public:
106   bool operator==(const ModRefResult &rhs) const { return kind == rhs.kind; }
107   bool operator!=(const ModRefResult &rhs) const { return !(*this == rhs); }
108 
109   /// Return a new result that indicates that the memory access neither
110   /// references nor modifies the value stored in memory.
getNoModRef()111   static ModRefResult getNoModRef() { return Kind::NoModRef; }
112 
113   /// Return a new result that indicates that the memory access may reference
114   /// the value stored in memory.
getRef()115   static ModRefResult getRef() { return Kind::Ref; }
116 
117   /// Return a new result that indicates that the memory access may modify the
118   /// value stored in memory.
getMod()119   static ModRefResult getMod() { return Kind::Mod; }
120 
121   /// Return a new result that indicates that the memory access may reference
122   /// and may modify the value stored in memory.
getModAndRef()123   static ModRefResult getModAndRef() { return Kind::ModRef; }
124 
125   /// Returns if this result does not modify or reference memory.
isNoModRef()126   [[nodiscard]] bool isNoModRef() const { return kind == Kind::NoModRef; }
127 
128   /// Returns if this result modifies memory.
isMod()129   [[nodiscard]] bool isMod() const {
130     return static_cast<int>(kind) & static_cast<int>(Kind::Mod);
131   }
132 
133   /// Returns if this result references memory.
isRef()134   [[nodiscard]] bool isRef() const {
135     return static_cast<int>(kind) & static_cast<int>(Kind::Ref);
136   }
137 
138   /// Returns if this result modifies *or* references memory.
isModOrRef()139   [[nodiscard]] bool isModOrRef() const { return kind != Kind::NoModRef; }
140 
141   /// Returns if this result modifies *and* references memory.
isModAndRef()142   [[nodiscard]] bool isModAndRef() const { return kind == Kind::ModRef; }
143 
144   /// Merge this ModRef result with `other` and return the result.
merge(const ModRefResult & other)145   ModRefResult merge(const ModRefResult &other) {
146     return ModRefResult(static_cast<Kind>(static_cast<int>(kind) |
147                                           static_cast<int>(other.kind)));
148   }
149   /// Intersect this ModRef result with `other` and return the result.
intersect(const ModRefResult & other)150   ModRefResult intersect(const ModRefResult &other) {
151     return ModRefResult(static_cast<Kind>(static_cast<int>(kind) &
152                                           static_cast<int>(other.kind)));
153   }
154 
155   /// Print this ModRef result to the provided output stream.
156   void print(raw_ostream &os) const;
157 
158 private:
ModRefResult(Kind kind)159   ModRefResult(Kind kind) : kind(kind) {}
160 
161   /// The internal kind of the result.
162   Kind kind;
163 };
164 
165 inline raw_ostream &operator<<(raw_ostream &os, const ModRefResult &result) {
166   result.print(os);
167   return os;
168 }
169 
170 //===----------------------------------------------------------------------===//
171 // AliasAnalysisTraits
172 //===----------------------------------------------------------------------===//
173 
174 namespace detail {
175 /// This class contains various internal trait classes used by the main
176 /// AliasAnalysis class below.
177 struct AliasAnalysisTraits {
178   /// This class represents the `Concept` of an alias analysis implementation.
179   /// It is the abstract base class used by the AliasAnalysis class for
180   /// querying into derived analysis implementations.
181   class Concept {
182   public:
183     virtual ~Concept() = default;
184 
185     /// Given two values, return their aliasing behavior.
186     virtual AliasResult alias(Value lhs, Value rhs) = 0;
187 
188     /// Return the modify-reference behavior of `op` on `location`.
189     virtual ModRefResult getModRef(Operation *op, Value location) = 0;
190   };
191 
192   /// This class represents the `Model` of an alias analysis implementation
193   /// `ImplT`. A model is instantiated for each alias analysis implementation
194   /// to implement the `Concept` without the need for the derived
195   /// implementation to inherit from the `Concept` class.
196   template <typename ImplT>
197   class Model final : public Concept {
198   public:
ModelAliasAnalysisTraits199     explicit Model(ImplT &&impl) : impl(std::forward<ImplT>(impl)) {}
200     ~Model() override = default;
201 
202     /// Given two values, return their aliasing behavior.
aliasAliasAnalysisTraits203     AliasResult alias(Value lhs, Value rhs) final {
204       return impl.alias(lhs, rhs);
205     }
206 
207     /// Return the modify-reference behavior of `op` on `location`.
getModRefAliasAnalysisTraits208     ModRefResult getModRef(Operation *op, Value location) final {
209       return impl.getModRef(op, location);
210     }
211 
212   private:
213     ImplT impl;
214   };
215 };
216 } // namespace detail
217 
218 //===----------------------------------------------------------------------===//
219 // AliasAnalysis
220 //===----------------------------------------------------------------------===//
221 
222 /// This class represents the main alias analysis interface in MLIR. It
223 /// functions as an aggregate of various different alias analysis
224 /// implementations. This aggregation allows for utilizing the strengths of
225 /// different alias analysis implementations that either target or have access
226 /// to different aliasing information. This is especially important for MLIR
227 /// given the scope of different types of memory models and aliasing behaviors.
228 /// For users of this analysis that want to perform aliasing queries, see the
229 /// `Alias Queries` section below for the available methods. For users of this
230 /// analysis that want to add a new alias analysis implementation to the
231 /// aggregate, see the `Alias Implementations` section below.
232 class AliasAnalysis {
233   using Concept = detail::AliasAnalysisTraits::Concept;
234   template <typename ImplT>
235   using Model = detail::AliasAnalysisTraits::Model<ImplT>;
236 
237 public:
238   AliasAnalysis(Operation *op);
239 
240   //===--------------------------------------------------------------------===//
241   // Alias Implementations
242   //===--------------------------------------------------------------------===//
243 
244   /// Add a new alias analysis implementation `AnalysisT` to this analysis
245   /// aggregate. This allows for users to access this implementation when
246   /// performing alias queries. Implementations added here must provide the
247   /// following:
248   ///   * AnalysisT(AnalysisT &&)
249   ///   * AliasResult alias(Value lhs, Value rhs)
250   ///     - This method returns an `AliasResult` that corresponds to the
251   ///       aliasing behavior between `lhs` and `rhs`. The conservative "I don't
252   ///       know" result of this method should be MayAlias.
253   ///   * ModRefResult getModRef(Operation *op, Value location)
254   ///     - This method returns a `ModRefResult` that corresponds to the
255   ///       modify-reference behavior of `op` on the given `location`. The
256   ///       conservative "I don't know" result of this method should be ModRef.
257   template <typename AnalysisT>
addAnalysisImplementation(AnalysisT && analysis)258   void addAnalysisImplementation(AnalysisT &&analysis) {
259     aliasImpls.push_back(
260         std::make_unique<Model<AnalysisT>>(std::forward<AnalysisT>(analysis)));
261   }
262 
263   //===--------------------------------------------------------------------===//
264   // Alias Queries
265   //===--------------------------------------------------------------------===//
266 
267   /// Given two values, return their aliasing behavior.
268   AliasResult alias(Value lhs, Value rhs);
269 
270   //===--------------------------------------------------------------------===//
271   // ModRef Queries
272   //===--------------------------------------------------------------------===//
273 
274   /// Return the modify-reference behavior of `op` on `location`.
275   ModRefResult getModRef(Operation *op, Value location);
276 
277 private:
278   /// A set of internal alias analysis implementations.
279   SmallVector<std::unique_ptr<Concept>, 4> aliasImpls;
280 };
281 
282 } // namespace mlir
283 
284 #endif // MLIR_ANALYSIS_ALIASANALYSIS_H_
285