FLANG
AliasAnalysis.h
1//===-- AliasAnalysis.h - Alias Analysis in FIR -----------------*- 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#ifndef FORTRAN_OPTIMIZER_ANALYSIS_ALIASANALYSIS_H
10#define FORTRAN_OPTIMIZER_ANALYSIS_ALIASANALYSIS_H
11
12#include "flang/Common/enum-class.h"
13#include "flang/Common/enum-set.h"
14#include "mlir/Analysis/AliasAnalysis.h"
15#include "mlir/IR/BuiltinAttributes.h"
16#include "mlir/IR/Dominance.h"
17#include "mlir/IR/SymbolTable.h"
18#include "mlir/IR/Value.h"
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/PointerUnion.h"
21#include "llvm/ADT/SmallVector.h"
22#include <cstddef>
23#include <memory>
24#include <utility>
25
26namespace fir {
27
28//===----------------------------------------------------------------------===//
29// AliasAnalysis
30//===----------------------------------------------------------------------===//
32 // Structures to describe the memory source of a value.
33
35 ENUM_CLASS(SourceKind,
38 Allocate,
40 Global,
43 Argument,
46 HostAssoc,
50 Indirect,
53 Unknown);
54
56 ENUM_CLASS(Attribute, Target, Pointer, IntentIn, CrayPointer, CrayPointee);
57
58 // See
59 // https://discourse.llvm.org/t/rfc-distinguish-between-data-and-non-data-in-fir-alias-analysis/78759/1
60 //
61 // It is possible, while following the source of a memory reference through
62 // the use-def chain, to arrive at the same origin, even though the starting
63 // points were known to not alias.
64 //
65 // clang-format off
66 // Example:
67 // ------------------- test.f90 --------------------
68 // module top
69 // real, pointer :: a(:)
70 // end module
71 //
72 // subroutine test()
73 // use top
74 // a(1) = 1
75 // end subroutine
76 // -------------------------------------------------
77 //
78 // flang -fc1 -emit-fir test.f90 -o test.fir
79 //
80 // ------------------- test.fir --------------------
81 // fir.global @_QMtopEa : !fir.box<!fir.ptr<!fir.array<?xf32>>>
82 //
83 // func.func @_QPtest() {
84 // %c1 = arith.constant 1 : index
85 // %cst = arith.constant 1.000000e+00 : f32
86 // %0 = fir.address_of(@_QMtopEa) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
87 // %1 = fir.declare %0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtopEa"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
88 // %2 = fir.load %1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
89 // ...
90 // %5 = fir.array_coor %2 %c1 : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, !fir.shift<1>, index) -> !fir.ref<f32>
91 // fir.store %cst to %5 : !fir.ref<f32>
92 // return
93 // }
94 // -------------------------------------------------
95 //
96 // With high level operations, such as fir.array_coor, it is possible to
97 // reach into the data wrapped by the box (the descriptor). Therefore when
98 // asking about the memory source of %5, we are really asking about the
99 // source of the data of box %2.
100 //
101 // When asking about the source of %0 which is the address of the box, we
102 // reach the same source as in the first case: the global @_QMtopEa. Yet one
103 // source refers to the data while the other refers to the address of the box
104 // itself.
105 //
106 // To distinguish between the two, the isData flag has been added, whereby
107 // data is defined as any memory reference that is not a box reference.
108 // Additionally, because it is relied on in HLFIR lowering, we allow querying
109 // on a box SSA value, which is interpreted as querying on its data.
110 //
111 // So in the above example, !fir.ref<f32> and !fir.box<!fir.ptr<!fir.array<?xf32>>> is data,
112 // while !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> is not data.
113
114 // This also applies to function arguments. In the example below, %arg0
115 // is data, %arg1 is not data but a load of %arg1 is.
116 //
117 // func.func @_QFPtest2(%arg0: !fir.ref<f32>, %arg1: !fir.ref<!fir.box<!fir.ptr<f32>>> ) {
118 // %0 = fir.load %arg1 : !fir.ref<!fir.box<!fir.ptr<f32>>>
119 // ... }
120 //
121 // clang-format on
122
123 struct Source {
124 using SourceUnion = llvm::PointerUnion<mlir::SymbolRefAttr, mlir::Value>;
126
129 SourceUnion u;
130
140 mlir::Operation *instantiationPoint;
141
143 bool isData{false};
144 };
145
149 struct PathStep {
159 Kind kind;
163 mlir::StringAttr component;
164
165 bool operator==(const PathStep &o) const {
166 return kind == o.kind && component == o.component;
167 }
168 bool operator!=(const PathStep &o) const { return !(*this == o); }
169 };
170
182 struct AccessPath {
184
188 bool isApproximate{false};
189
191 bool hasPointerDeref() const {
192 return llvm::any_of(steps, [](const PathStep &s) {
193 return s.kind == PathStep::Kind::PointerDeref;
194 });
195 }
196
197 bool operator==(const AccessPath &o) const {
198 return isApproximate == o.isApproximate && steps == o.steps;
199 }
200 bool operator!=(const AccessPath &o) const { return !(*this == o); }
201
202 void print(llvm::raw_ostream &os) const;
203 };
204
240 mlir::Value scope;
242 mlir::Value declValue;
249 Attributes attributes;
251 bool approximateSource{false};
254 bool isData{false};
255 };
256
257 SourceOrigin origin;
258
260 SourceKind kind;
262 mlir::Type valueType;
264 Attributes attributes;
277
279 void print(llvm::raw_ostream &os) const;
280
282 bool isTargetOrPointer() const;
283
285 bool isTarget() const;
286
288 bool isPointer() const;
289
291 bool isCrayPointer() const;
292
294 bool isCrayPointee() const;
295
297 bool isCrayPointerOrPointee() const;
298
299 bool isDummyArgument() const;
300 bool isData() const;
301 bool isBoxData() const;
302
304 bool isFortranUserVariable() const;
305
312
316 bool mayBeDummyArgOrHostAssoc() const;
318 bool mayBePtrDummyArgOrHostAssoc() const;
320 bool mayBeActualArg() const;
323 bool mayBeActualArgWithPtr(const mlir::Value *val) const;
325
326 mlir::Type getType() const;
327 };
328
329 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
330 const AliasAnalysis::Source &op);
331
333 mlir::AliasResult alias(Source lhsSrc, Source rhsSrc, mlir::Value lhs,
334 mlir::Value rhs);
335
337 mlir::AliasResult alias(mlir::Value lhs, mlir::Value rhs);
338
340 mlir::ModRefResult getModRef(mlir::Operation *op, mlir::Value location);
341
346 mlir::ModRefResult getModRef(mlir::Region &region, mlir::Value location);
347
366 bool getLastInstantiationPoint = false,
367 bool collectScopedOrigins = true);
368
373 void enableSourceCache();
374
376 void disableSourceCache();
377
379 std::size_t getSourceCacheSizeForTesting() const {
380 return getSourceCache.size();
381 }
382
384 std::size_t getSourceCacheHitsForTesting() const { return sourceCacheHits; }
385 std::size_t getSourceCacheMissesForTesting() const {
386 return sourceCacheMisses;
387 }
388
391 static bool isPointerReference(mlir::Type ty);
392
401 bool functionHasMultipleScopes(mlir::Value v);
402
403private:
407 fir::AliasAnalysis::Source getSourceImpl(mlir::Value v,
408 bool getLastInstantiationPoint,
409 bool collectScopedOrigins);
410
412 void clearSourceCache() { getSourceCache.clear(); }
413
420 Source buildSourceAtDeclare(const Source::ScopedOrigin &so);
421
427 mlir::Value getDeclarationScope(mlir::Operation *declareOp);
428
431 static bool isRecordWithPointerComponent(mlir::Type ty);
432
436 const mlir::SymbolTable *getNearestSymbolTable(mlir::Operation *from);
437
441 bool symbolMayHaveTargetAttr(mlir::SymbolRefAttr symbol,
442 mlir::Operation *from);
443
446 bool isCallToFortranUserProcedure(mlir::Operation *op);
447
451 mlir::ModRefResult getCallModRef(mlir::Operation *op, mlir::Value var);
452
466 llvm::DenseMap<mlir::Operation *, mlir::SymbolTable> symTabMap;
467
481 llvm::DenseMap<mlir::Operation *, std::unique_ptr<mlir::DominanceInfo>>
482 domInfoCache;
483 llvm::DenseMap<mlir::Operation *, llvm::SmallVector<mlir::Operation *, 16>>
484 sortedScopeCache;
489 llvm::DenseMap<mlir::Operation *, bool> multiScopeCache;
490
496 llvm::DenseMap<std::pair<mlir::Value, unsigned>, Source> getSourceCache;
497
499 bool sourceCacheEnabled = false;
500
503 std::size_t sourceCacheHits = 0;
504 std::size_t sourceCacheMisses = 0;
505};
506
507inline bool operator==(const AliasAnalysis::Source::SourceOrigin &lhs,
509 return lhs.u == rhs.u && lhs.isData == rhs.isData;
510}
511inline bool operator!=(const AliasAnalysis::Source::SourceOrigin &lhs,
513 return !(lhs == rhs);
514}
515
516inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
517 const AliasAnalysis::Source &op) {
518 op.print(os);
519 return os;
520}
521
522} // namespace fir
523
524#endif // FORTRAN_OPTIMIZER_ANALYSIS_ALIASANALYSIS_H
Definition enum-set.h:28
Definition OpenACC.h:20
Definition AbstractConverter.h:37
Definition AliasAnalysis.h:182
bool hasPointerDeref() const
Return true if any step is a PointerDeref.
Definition AliasAnalysis.h:191
bool isApproximate
Definition AliasAnalysis.h:188
Definition AliasAnalysis.h:149
mlir::StringAttr component
Definition AliasAnalysis.h:163
Kind
Definition AliasAnalysis.h:150
@ Component
Named component access, e.g. xfield.
Definition AliasAnalysis.h:152
@ AllocDeref
Loading an ALLOCATABLE box (fir.load of !fir.box<!fir.heap<...>>).
Definition AliasAnalysis.h:157
@ PointerDeref
Definition AliasAnalysis.h:155
Definition AliasAnalysis.h:236
mlir::Value scope
Definition AliasAnalysis.h:240
AccessPath accessPath
Definition AliasAnalysis.h:245
bool isData
Definition AliasAnalysis.h:254
mlir::Value declValue
Result SSA value of the [hl]fir.declare op.
Definition AliasAnalysis.h:242
bool approximateSource
Whether the path is approximate at the moment of the snapshot.
Definition AliasAnalysis.h:251
Attributes attributes
Definition AliasAnalysis.h:249
Definition AliasAnalysis.h:127
mlir::Operation * instantiationPoint
Definition AliasAnalysis.h:140
SourceUnion u
Source definition of a value.
Definition AliasAnalysis.h:129
bool isData
Whether the source was reached following data or box reference.
Definition AliasAnalysis.h:143
Definition AliasAnalysis.h:123
bool isCrayPointer() const
Return true, if CrayPointer attribute is set.
Definition AliasAnalysis.cpp:434
bool isCapturedInInternalProcedure
Source object is used in an internal procedure via host association.
Definition AliasAnalysis.h:271
bool isFortranUserVariable() const
Is this source a variable from the Fortran source?
Definition AliasAnalysis.cpp:455
Attributes attributes
Attributes of the memory source object, e.g. Target.
Definition AliasAnalysis.h:264
bool isPointer() const
Return true, if Pointer attribute is set.
Definition AliasAnalysis.cpp:426
llvm::SmallVector< ScopedOrigin, 4 > scopedOrigins
Definition AliasAnalysis.h:276
SourceKind kind
Kind of the memory source.
Definition AliasAnalysis.h:260
bool isCrayPointee() const
Return true, if CrayPointee attribute is set.
Definition AliasAnalysis.cpp:430
void print(llvm::raw_ostream &os) const
Print information about the memory source to os.
Definition AliasAnalysis.cpp:383
bool mayBePtrDummyArgOrHostAssoc() const
mayBeDummyArgOrHostAssoc and the address of a pointer?
Definition AliasAnalysis.cpp:470
bool isTargetOrPointer() const
Return true, if Target or Pointer attribute is set.
Definition AliasAnalysis.cpp:417
bool mayBeDummyArgOrHostAssoc() const
Definition AliasAnalysis.cpp:466
AccessPath accessPath
The structured access path from the root variable.
Definition AliasAnalysis.h:269
bool approximateSource
Definition AliasAnalysis.h:267
bool mayBeActualArgWithPtr(const mlir::Value *val) const
Definition AliasAnalysis.cpp:485
mlir::Type valueType
Value type of the source definition.
Definition AliasAnalysis.h:262
bool isCrayPointerOrPointee() const
Return true, if CrayPointer or CrayPointee attribute is set.
Definition AliasAnalysis.cpp:438
bool isTarget() const
Return true, if Target attribute is set.
Definition AliasAnalysis.cpp:422
bool mayBeActualArg() const
The address of an actual argument of the current function?
Definition AliasAnalysis.cpp:481
Definition AliasAnalysis.h:31
std::size_t getSourceCacheSizeForTesting() const
Testing only: number of entries currently held in the getSource() cache.
Definition AliasAnalysis.h:379
void enableSourceCache()
Definition AliasAnalysis.cpp:1176
fir::AliasAnalysis::Source getSource(mlir::Value, bool getLastInstantiationPoint=false, bool collectScopedOrigins=true)
Definition AliasAnalysis.cpp:1183
mlir::AliasResult alias(Source lhsSrc, Source rhsSrc, mlir::Value lhs, mlir::Value rhs)
Given the values and their sources, return their aliasing behavior.
Definition AliasAnalysis.cpp:655
void disableSourceCache()
Disable getSource() memoization and drop any cached entries.
Definition AliasAnalysis.cpp:1178
static bool isPointerReference(mlir::Type ty)
Definition AliasAnalysis.cpp:409
std::size_t getSourceCacheHitsForTesting() const
Testing only: cumulative getSource() cache hits / misses on this instance.
Definition AliasAnalysis.h:384
ENUM_CLASS(Attribute, Target, Pointer, IntentIn, CrayPointer, CrayPointee)
Attributes of the memory source object.
bool functionHasMultipleScopes(mlir::Value v)
Definition AliasAnalysis.cpp:1890
ENUM_CLASS(SourceKind, Allocate, Global, Argument, HostAssoc, Indirect, Unknown)
Kind of the memory source referenced by a value.
mlir::ModRefResult getModRef(mlir::Operation *op, mlir::Value location)
Return the modify-reference behavior of op on location.