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/Value.h" 16 #include "llvm/ADT/PointerUnion.h" 17 18 namespace fir { 19 20 //===----------------------------------------------------------------------===// 21 // AliasAnalysis 22 //===----------------------------------------------------------------------===// 23 struct AliasAnalysis { 24 // Structures to describe the memory source of a value. 25 26 /// Kind of the memory source referenced by a value. 27 ENUM_CLASS(SourceKind, 28 /// Unique memory allocated by an operation, e.g. 29 /// by fir::AllocaOp or fir::AllocMemOp. 30 Allocate, 31 /// A global object allocated statically on the module level. 32 Global, 33 /// Memory allocated outside of a function and passed 34 /// to the function as a by-ref argument. 35 Argument, 36 /// Represents memory allocated outside of a function 37 /// and passed to the function via host association tuple. 38 HostAssoc, 39 /// Represents memory allocated by unknown means and 40 /// with the memory address defined by a memory reading 41 /// operation (e.g. fir::LoadOp). 42 Indirect, 43 /// Starting point to the analysis whereby nothing is known about 44 /// the source 45 Unknown); 46 47 /// Attributes of the memory source object. 48 ENUM_CLASS(Attribute, Target, Pointer, IntentIn); 49 50 // See 51 // https://discourse.llvm.org/t/rfc-distinguish-between-data-and-non-data-in-fir-alias-analysis/78759/1 52 // 53 // It is possible, while following the source of a memory reference through 54 // the use-def chain, to arrive at the same origin, even though the starting 55 // points were known to not alias. 56 // 57 // clang-format off 58 // Example: 59 // ------------------- test.f90 -------------------- 60 // module top 61 // real, pointer :: a(:) 62 // end module 63 // 64 // subroutine test() 65 // use top 66 // a(1) = 1 67 // end subroutine 68 // ------------------------------------------------- 69 // 70 // flang -fc1 -emit-fir test.f90 -o test.fir 71 // 72 // ------------------- test.fir -------------------- 73 // fir.global @_QMtopEa : !fir.box<!fir.ptr<!fir.array<?xf32>>> 74 // 75 // func.func @_QPtest() { 76 // %c1 = arith.constant 1 : index 77 // %cst = arith.constant 1.000000e+00 : f32 78 // %0 = fir.address_of(@_QMtopEa) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> 79 // %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>>>> 80 // %2 = fir.load %1 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> 81 // ... 82 // %5 = fir.array_coor %2 %c1 : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, !fir.shift<1>, index) -> !fir.ref<f32> 83 // fir.store %cst to %5 : !fir.ref<f32> 84 // return 85 // } 86 // ------------------------------------------------- 87 // 88 // With high level operations, such as fir.array_coor, it is possible to 89 // reach into the data wrapped by the box (the descriptor). Therefore when 90 // asking about the memory source of %5, we are really asking about the 91 // source of the data of box %2. 92 // 93 // When asking about the source of %0 which is the address of the box, we 94 // reach the same source as in the first case: the global @_QMtopEa. Yet one 95 // source refers to the data while the other refers to the address of the box 96 // itself. 97 // 98 // To distinguish between the two, the isData flag has been added, whereby 99 // data is defined as any memory reference that is not a box reference. 100 // Additionally, because it is relied on in HLFIR lowering, we allow querying 101 // on a box SSA value, which is interpreted as querying on its data. 102 // 103 // So in the above example, !fir.ref<f32> and !fir.box<!fir.ptr<!fir.array<?xf32>>> is data, 104 // while !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>> is not data. 105 106 // This also applies to function arguments. In the example below, %arg0 107 // is data, %arg1 is not data but a load of %arg1 is. 108 // 109 // func.func @_QFPtest2(%arg0: !fir.ref<f32>, %arg1: !fir.ref<!fir.box<!fir.ptr<f32>>> ) { 110 // %0 = fir.load %arg1 : !fir.ref<!fir.box<!fir.ptr<f32>>> 111 // ... } 112 // 113 // clang-format on 114 115 struct Source { 116 using SourceUnion = llvm::PointerUnion<mlir::SymbolRefAttr, mlir::Value>; 117 using Attributes = Fortran::common::EnumSet<Attribute, Attribute_enumSize>; 118 119 struct SourceOrigin { 120 /// Source definition of a value. 121 SourceUnion u; 122 123 /// A value definition denoting the place where the corresponding 124 /// source variable was instantiated by the front-end. 125 /// Currently, it is the result of [hl]fir.declare of the source, 126 /// if we can reach it. 127 /// It helps to identify the scope where the corresponding variable 128 /// was defined in the original Fortran source, e.g. when MLIR 129 /// inlining happens an inlined fir.declare of the callee's 130 /// dummy argument identifies the scope where the source 131 /// may be treated as a dummy argument. 132 mlir::Operation *instantiationPoint; 133 134 /// Whether the source was reached following data or box reference 135 bool isData{false}; 136 }; 137 138 SourceOrigin origin; 139 140 /// Kind of the memory source. 141 SourceKind kind; 142 /// Value type of the source definition. 143 mlir::Type valueType; 144 /// Attributes of the memory source object, e.g. Target. 145 Attributes attributes; 146 /// Have we lost precision following the source such that 147 /// even an exact match cannot be MustAlias? 148 bool approximateSource; 149 /// Source object is used in an internal procedure via host association. 150 bool isCapturedInInternalProcedure{false}; 151 152 /// Print information about the memory source to `os`. 153 void print(llvm::raw_ostream &os) const; 154 155 /// Return true, if Target or Pointer attribute is set. 156 bool isTargetOrPointer() const; 157 158 bool isDummyArgument() const; 159 bool isData() const; 160 bool isBoxData() const; 161 162 /// Is this source a variable from the Fortran source? 163 bool isFortranUserVariable() const; 164 165 /// @name Dummy Argument Aliasing 166 /// 167 /// Check conditions related to dummy argument aliasing. 168 /// 169 /// For all uses, a result of false can prevent MayAlias from being 170 /// reported, so the list of cases where false is returned is conservative. 171 172 ///@{ 173 /// The address of a (possibly host associated) dummy argument of the 174 /// current function? 175 bool mayBeDummyArgOrHostAssoc() const; 176 /// \c mayBeDummyArgOrHostAssoc and the address of a pointer? 177 bool mayBePtrDummyArgOrHostAssoc() const; 178 /// The address of an actual argument of the current function? 179 bool mayBeActualArg() const; 180 /// \c mayBeActualArg and the address of either a pointer or a composite 181 /// with a pointer component? 182 bool mayBeActualArgWithPtr(const mlir::Value *val) const; 183 ///@} 184 185 mlir::Type getType() const; 186 }; 187 188 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, 189 const AliasAnalysis::Source &op); 190 191 /// Given the values and their sources, return their aliasing behavior. 192 mlir::AliasResult alias(Source lhsSrc, Source rhsSrc, mlir::Value lhs, 193 mlir::Value rhs); 194 195 /// Given two values, return their aliasing behavior. 196 mlir::AliasResult alias(mlir::Value lhs, mlir::Value rhs); 197 198 /// Return the modify-reference behavior of `op` on `location`. 199 mlir::ModRefResult getModRef(mlir::Operation *op, mlir::Value location); 200 201 /// Return the modify-reference behavior of operations inside `region` on 202 /// `location`. Contrary to getModRef(operation, location), this will visit 203 /// nested regions recursively according to the HasRecursiveMemoryEffects 204 /// trait. 205 mlir::ModRefResult getModRef(mlir::Region ®ion, mlir::Value location); 206 207 /// Return the memory source of a value. 208 /// If getLastInstantiationPoint is true, the search for the source 209 /// will stop at [hl]fir.declare if it represents a dummy 210 /// argument declaration (i.e. it has the dummy_scope operand). 211 fir::AliasAnalysis::Source getSource(mlir::Value, 212 bool getLastInstantiationPoint = false); 213 214 private: 215 /// Return true, if `ty` is a reference type to an object of derived type 216 /// that contains a component with POINTER attribute. 217 static bool isRecordWithPointerComponent(mlir::Type ty); 218 219 /// Return true, if `ty` is a reference type to a boxed 220 /// POINTER object or a raw fir::PointerType. 221 static bool isPointerReference(mlir::Type ty); 222 }; 223 224 inline bool operator==(const AliasAnalysis::Source::SourceOrigin &lhs, 225 const AliasAnalysis::Source::SourceOrigin &rhs) { 226 return lhs.u == rhs.u && lhs.isData == rhs.isData; 227 } 228 inline bool operator!=(const AliasAnalysis::Source::SourceOrigin &lhs, 229 const AliasAnalysis::Source::SourceOrigin &rhs) { 230 return !(lhs == rhs); 231 } 232 233 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, 234 const AliasAnalysis::Source &op) { 235 op.print(os); 236 return os; 237 } 238 239 } // namespace fir 240 241 #endif // FORTRAN_OPTIMIZER_ANALYSIS_ALIASANALYSIS_H 242