xref: /llvm-project/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h (revision 0b54e33fd5ab362dfa5eacb61d7cbdb9cc3a89ac)
1 //===-- Optimizer/Dialect/FIROpsSupport.h -- FIR op support -----*- 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_DIALECT_FIROPSSUPPORT_H
10 #define FORTRAN_OPTIMIZER_DIALECT_FIROPSSUPPORT_H
11 
12 #include "flang/Optimizer/Dialect/FIROps.h"
13 #include "mlir/Dialect/Func/IR/FuncOps.h"
14 #include "mlir/IR/BuiltinOps.h"
15 
16 namespace fir {
17 
18 /// Return true iff the Operation is a non-volatile LoadOp or ArrayLoadOp.
19 inline bool nonVolatileLoad(mlir::Operation *op) {
20   if (auto load = mlir::dyn_cast<fir::LoadOp>(op))
21     return !load->getAttr("volatile");
22   if (auto arrLoad = mlir::dyn_cast<fir::ArrayLoadOp>(op))
23     return !arrLoad->getAttr("volatile");
24   return false;
25 }
26 
27 /// Return true iff the Operation is a call.
28 inline bool isaCall(mlir::Operation *op) {
29   return mlir::isa<fir::CallOp>(op) || mlir::isa<fir::DispatchOp>(op) ||
30          mlir::isa<mlir::func::CallOp>(op) ||
31          mlir::isa<mlir::func::CallIndirectOp>(op);
32 }
33 
34 /// Return true iff the Operation is a fir::CallOp, fir::DispatchOp,
35 /// mlir::CallOp, or mlir::CallIndirectOp and not pure
36 /// NB: This is not the same as `!pureCall(op)`.
37 inline bool impureCall(mlir::Operation *op) {
38   // Should we also auto-detect that the called function is pure if its
39   // arguments are not references?  For now, rely on a "pure" attribute.
40   return op && isaCall(op) && !op->getAttr("pure");
41 }
42 
43 /// Return true iff the Operation is a fir::CallOp, fir::DispatchOp,
44 /// mlir::CallOp, or mlir::CallIndirectOp and is also pure.
45 /// NB: This is not the same as `!impureCall(op)`.
46 inline bool pureCall(mlir::Operation *op) {
47   // Should we also auto-detect that the called function is pure if its
48   // arguments are not references?  For now, rely on a "pure" attribute.
49   return op && isaCall(op) && op->getAttr("pure");
50 }
51 
52 /// Get or create a FuncOp in a module.
53 ///
54 /// If `module` already contains FuncOp `name`, it is returned. Otherwise, a new
55 /// FuncOp is created, and that new FuncOp is returned. A symbol table can
56 /// be provided to speed-up the lookups.
57 mlir::func::FuncOp createFuncOp(mlir::Location loc, mlir::ModuleOp module,
58                                 llvm::StringRef name, mlir::FunctionType type,
59                                 llvm::ArrayRef<mlir::NamedAttribute> attrs = {},
60                                 const mlir::SymbolTable *symbolTable = nullptr);
61 
62 /// Get or create a GlobalOp in a module. A symbol table can be provided to
63 /// speed-up the lookups.
64 fir::GlobalOp createGlobalOp(mlir::Location loc, mlir::ModuleOp module,
65                              llvm::StringRef name, mlir::Type type,
66                              llvm::ArrayRef<mlir::NamedAttribute> attrs = {},
67                              const mlir::SymbolTable *symbolTable = nullptr);
68 
69 /// Attribute to mark Fortran entities with the CONTIGUOUS attribute.
70 constexpr llvm::StringRef getContiguousAttrName() { return "fir.contiguous"; }
71 
72 /// Attribute to mark Fortran entities with the OPTIONAL attribute.
73 constexpr llvm::StringRef getOptionalAttrName() { return "fir.optional"; }
74 
75 /// Attribute to mark Fortran entities with the TARGET attribute.
76 static constexpr llvm::StringRef getTargetAttrName() { return "fir.target"; }
77 
78 /// Attribute to mark Fortran entities with the ASYNCHRONOUS attribute.
79 static constexpr llvm::StringRef getAsynchronousAttrName() {
80   return "fir.asynchronous";
81 }
82 
83 /// Attribute to mark Fortran entities with the VOLATILE attribute.
84 static constexpr llvm::StringRef getVolatileAttrName() {
85   return "fir.volatile";
86 }
87 
88 /// Attribute to mark that a function argument is a character dummy procedure.
89 /// Character dummy procedure have special ABI constraints.
90 static constexpr llvm::StringRef getCharacterProcedureDummyAttrName() {
91   return "fir.char_proc";
92 }
93 
94 /// Attribute to keep track of Fortran scoping information for a symbol.
95 static constexpr llvm::StringRef getSymbolAttrName() {
96   return "fir.bindc_name";
97 }
98 
99 /// Attribute to mark a function that takes a host associations argument.
100 static constexpr llvm::StringRef getHostAssocAttrName() {
101   return "fir.host_assoc";
102 }
103 
104 /// Attribute to link an internal procedure to its host procedure symbol.
105 static constexpr llvm::StringRef getHostSymbolAttrName() {
106   return "fir.host_symbol";
107 }
108 
109 /// Attribute containing the original name of a function from before the
110 /// ExternalNameConverision pass runs
111 static constexpr llvm::StringRef getInternalFuncNameAttrName() {
112   return "fir.internal_name";
113 }
114 
115 /// Does the function, \p func, have a host-associations tuple argument?
116 /// Some internal procedures may have access to host procedure variables.
117 bool hasHostAssociationArgument(mlir::func::FuncOp func);
118 
119 /// Is the function, \p func an internal procedure ?
120 /// Some internal procedures may have access to saved host procedure
121 /// variables even when they do not have a tuple argument.
122 inline bool isInternalProcedure(mlir::func::FuncOp func) {
123   return func->hasAttr(fir::getHostSymbolAttrName());
124 }
125 
126 /// Tell if \p value is:
127 ///   - a function argument that has attribute \p attributeName
128 ///   - or, the result of fir.alloca/fir.allocmem op that has attribute \p
129 ///     attributeName
130 ///   - or, the result of a fir.address_of of a fir.global that has attribute \p
131 ///     attributeName
132 ///   - or, a fir.box loaded from a fir.ref<fir.box> that matches one of the
133 ///     previous cases.
134 bool valueHasFirAttribute(mlir::Value value, llvm::StringRef attributeName);
135 
136 /// A more conservative version of valueHasFirAttribute().
137 /// If `value` is one of the operation/function-argument cases listed
138 /// for valueHasFirAttribute():
139 ///   * if any of the `attributeNames` attributes is set, then the function
140 ///     will return true.
141 ///   * otherwise, it will return false.
142 ///
143 /// Otherwise, the function will return true indicating that the attributes
144 /// may actually be set but we were not able to reach the point of definition
145 /// to confirm that.
146 bool valueMayHaveFirAttributes(mlir::Value value,
147                                llvm::ArrayRef<llvm::StringRef> attributeNames);
148 
149 /// Scan the arguments of a FuncOp to determine if any arguments have the
150 /// attribute `attr` placed on them. This can be used to determine if the
151 /// function has any host associations, for example.
152 bool anyFuncArgsHaveAttr(mlir::func::FuncOp func, llvm::StringRef attr);
153 
154 /// Unwrap integer constant from an mlir::Value.
155 std::optional<std::int64_t> getIntIfConstant(mlir::Value value);
156 
157 static constexpr llvm::StringRef getAdaptToByRefAttrName() {
158   return "adapt.valuebyref";
159 }
160 
161 static constexpr llvm::StringRef getFuncPureAttrName() {
162   return "fir.func_pure";
163 }
164 
165 static constexpr llvm::StringRef getFuncElementalAttrName() {
166   return "fir.func_elemental";
167 }
168 
169 static constexpr llvm::StringRef getFuncRecursiveAttrName() {
170   return "fir.func_recursive";
171 }
172 
173 static constexpr llvm::StringRef getFortranProcedureFlagsAttrName() {
174   return "fir.proc_attrs";
175 }
176 
177 // Attribute for an alloca that is a trivial adaptor for converting a value to
178 // pass-by-ref semantics for a VALUE parameter. The optimizer may be able to
179 // eliminate these.
180 // Template is used to avoid compiler errors in places that don't include
181 // FIRBuilder.h
182 template <typename Builder>
183 inline mlir::NamedAttribute getAdaptToByRefAttr(Builder &builder) {
184   return {mlir::StringAttr::get(builder.getContext(),
185                                 fir::getAdaptToByRefAttrName()),
186           builder.getUnitAttr()};
187 }
188 
189 bool isDummyArgument(mlir::Value v);
190 
191 template <fir::FortranProcedureFlagsEnum Flag>
192 inline bool hasProcedureAttr(fir::FortranProcedureFlagsEnumAttr flags) {
193   return flags && bitEnumContainsAny(flags.getValue(), Flag);
194 }
195 
196 template <fir::FortranProcedureFlagsEnum Flag>
197 inline bool hasProcedureAttr(mlir::Operation *op) {
198   if (auto firCallOp = mlir::dyn_cast<fir::CallOp>(op))
199     return hasProcedureAttr<Flag>(firCallOp.getProcedureAttrsAttr());
200   if (auto firCallOp = mlir::dyn_cast<fir::DispatchOp>(op))
201     return hasProcedureAttr<Flag>(firCallOp.getProcedureAttrsAttr());
202   return hasProcedureAttr<Flag>(
203       op->getAttrOfType<fir::FortranProcedureFlagsEnumAttr>(
204           getFortranProcedureFlagsAttrName()));
205 }
206 
207 inline bool hasBindcAttr(mlir::Operation *op) {
208   return hasProcedureAttr<fir::FortranProcedureFlagsEnum::bind_c>(op);
209 }
210 
211 } // namespace fir
212 
213 #endif // FORTRAN_OPTIMIZER_DIALECT_FIROPSSUPPORT_H
214