Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- FirBuilder.h -- FIR operation builder -------------------*- 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 | // Builder routines for constructing the FIR dialect of MLIR. As FIR is a |
10 | // dialect of MLIR, it makes extensive use of MLIR interfaces and MLIR's coding |
11 | // style (https://mlir.llvm.org/getting_started/DeveloperGuide/) is used in this |
12 | // module. |
13 | // |
14 | //===----------------------------------------------------------------------===// |
15 | |
16 | #ifndef FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H |
17 | #define FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H |
18 | |
19 | #include "flang/Optimizer/Dialect/FIROps.h" |
20 | #include "flang/Optimizer/Dialect/FIROpsSupport.h" |
21 | #include "flang/Optimizer/Dialect/FIRType.h" |
22 | #include "flang/Optimizer/Dialect/Support/FIRContext.h" |
23 | #include "flang/Optimizer/Dialect/Support/KindMapping.h" |
24 | #include "flang/Support/MathOptionsBase.h" |
25 | #include "mlir/IR/Builders.h" |
26 | #include "mlir/IR/BuiltinOps.h" |
27 | #include "llvm/ADT/DenseMap.h" |
28 | #include <optional> |
29 | #include <utility> |
30 | |
31 | namespace mlir { |
32 | class DataLayout; |
33 | class SymbolTable; |
34 | } |
35 | |
36 | namespace fir { |
37 | class AbstractArrayBox; |
38 | class ExtendedValue; |
39 | class MutableBoxValue; |
40 | class BoxValue; |
41 | |
42 | /// Get the integer type with a pointer size. |
43 | inline mlir::Type getIntPtrType(mlir::OpBuilder &builder) { |
44 | // TODO: Delay the need of such type until codegen or find a way to use |
45 | // llvm::DataLayout::getPointerSizeInBits here. |
46 | return builder.getI64Type(); |
47 | } |
48 | |
49 | //===----------------------------------------------------------------------===// |
50 | // FirOpBuilder |
51 | //===----------------------------------------------------------------------===// |
52 | |
53 | /// Extends the MLIR OpBuilder to provide methods for building common FIR |
54 | /// patterns. |
55 | class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener { |
56 | public: |
57 | explicit FirOpBuilder(mlir::Operation *op, fir::KindMapping kindMap, |
58 | mlir::SymbolTable *symbolTable = nullptr) |
59 | : OpBuilder{op, /*listener=*/this}, kindMap{std::move(kindMap)}, |
60 | symbolTable{symbolTable} { |
61 | auto fmi = mlir::dyn_cast<mlir::arith::ArithFastMathInterface>(*op); |
62 | if (fmi) { |
63 | // Set the builder with FastMathFlags attached to the operation. |
64 | setFastMathFlags(fmi.getFastMathFlagsAttr().getValue()); |
65 | } |
66 | } |
67 | explicit FirOpBuilder(mlir::OpBuilder &builder, fir::KindMapping kindMap, |
68 | mlir::SymbolTable *symbolTable = nullptr) |
69 | : OpBuilder(builder), OpBuilder::Listener(), kindMap{std::move(kindMap)}, |
70 | symbolTable{symbolTable} { |
71 | setListener(this); |
72 | } |
73 | explicit FirOpBuilder(mlir::OpBuilder &builder, mlir::ModuleOp mod) |
74 | : OpBuilder(builder), OpBuilder::Listener(), |
75 | kindMap{getKindMapping(mod)} { |
76 | setListener(this); |
77 | } |
78 | explicit FirOpBuilder(mlir::OpBuilder &builder, fir::KindMapping kindMap, |
79 | mlir::Operation *op) |
80 | : OpBuilder(builder), OpBuilder::Listener(), kindMap{std::move(kindMap)} { |
81 | setListener(this); |
82 | auto fmi = mlir::dyn_cast<mlir::arith::ArithFastMathInterface>(*op); |
83 | if (fmi) { |
84 | // Set the builder with FastMathFlags attached to the operation. |
85 | setFastMathFlags(fmi.getFastMathFlagsAttr().getValue()); |
86 | } |
87 | } |
88 | FirOpBuilder(mlir::OpBuilder &builder, mlir::Operation *op) |
89 | : FirOpBuilder(builder, fir::getKindMapping(op), op) {} |
90 | |
91 | // The listener self-reference has to be updated in case of copy-construction. |
92 | FirOpBuilder(const FirOpBuilder &other) |
93 | : OpBuilder(other), OpBuilder::Listener(), kindMap{other.kindMap}, |
94 | fastMathFlags{other.fastMathFlags}, |
95 | integerOverflowFlags{other.integerOverflowFlags}, |
96 | symbolTable{other.symbolTable} { |
97 | setListener(this); |
98 | } |
99 | |
100 | FirOpBuilder(FirOpBuilder &&other) |
101 | : OpBuilder(other), OpBuilder::Listener(), |
102 | kindMap{std::move(other.kindMap)}, fastMathFlags{other.fastMathFlags}, |
103 | integerOverflowFlags{other.integerOverflowFlags}, |
104 | symbolTable{other.symbolTable} { |
105 | setListener(this); |
106 | } |
107 | |
108 | /// Get the current Region of the insertion point. |
109 | mlir::Region &getRegion() { return *getBlock()->getParent(); } |
110 | |
111 | /// Get the current Module |
112 | mlir::ModuleOp getModule() { |
113 | return getRegion().getParentOfType<mlir::ModuleOp>(); |
114 | } |
115 | |
116 | /// Get the current Function |
117 | mlir::func::FuncOp getFunction() { |
118 | return getRegion().getParentOfType<mlir::func::FuncOp>(); |
119 | } |
120 | |
121 | /// Get a reference to the kind map. |
122 | const fir::KindMapping &getKindMap() { return kindMap; } |
123 | |
124 | /// Get func.func/fir.global symbol table attached to this builder if any. |
125 | mlir::SymbolTable *getMLIRSymbolTable() { return symbolTable; } |
126 | |
127 | /// Get the default integer type |
128 | [[maybe_unused]] mlir::IntegerType getDefaultIntegerType() { |
129 | return getIntegerType( |
130 | getKindMap().getIntegerBitsize(getKindMap().defaultIntegerKind())); |
131 | } |
132 | |
133 | /// The LHS and RHS are not always in agreement in terms of type. In some |
134 | /// cases, the disagreement is between COMPLEX and other scalar types. In that |
135 | /// case, the conversion must insert (extract) out of a COMPLEX value to have |
136 | /// the proper semantics and be strongly typed. E.g., converting an integer |
137 | /// (real) to a complex, the real part is filled using the integer (real) |
138 | /// after type conversion and the imaginary part is zero. |
139 | mlir::Value convertWithSemantics(mlir::Location loc, mlir::Type toTy, |
140 | mlir::Value val, |
141 | bool allowCharacterConversion = false, |
142 | bool allowRebox = false); |
143 | |
144 | /// Get the entry block of the current Function |
145 | mlir::Block *getEntryBlock() { return &getFunction().front(); } |
146 | |
147 | /// Get the block for adding Allocas. If OpenMP is enabled then get the |
148 | /// the alloca block from an Operation which can be Outlined. Otherwise |
149 | /// use the entry block of the current Function |
150 | mlir::Block *getAllocaBlock(); |
151 | |
152 | /// Safely create a reference type to the type `eleTy`. |
153 | mlir::Type getRefType(mlir::Type eleTy, bool isVolatile = false); |
154 | |
155 | /// Create a sequence of `eleTy` with `rank` dimensions of unknown size. |
156 | mlir::Type getVarLenSeqTy(mlir::Type eleTy, unsigned rank = 1); |
157 | |
158 | /// Get character length type. |
159 | mlir::Type getCharacterLengthType() { return getIndexType(); } |
160 | |
161 | /// Get the integer type whose bit width corresponds to the width of pointer |
162 | /// types, or is bigger. |
163 | mlir::Type getIntPtrType() { return fir::getIntPtrType(*this); } |
164 | |
165 | /// Wrap `str` to a SymbolRefAttr. |
166 | mlir::SymbolRefAttr getSymbolRefAttr(llvm::StringRef str) { |
167 | return mlir::SymbolRefAttr::get(getContext(), str); |
168 | } |
169 | |
170 | /// Get the mlir float type that implements Fortran REAL(kind). |
171 | mlir::Type getRealType(int kind); |
172 | |
173 | fir::BoxProcType getBoxProcType(mlir::FunctionType funcTy) { |
174 | return fir::BoxProcType::get(getContext(), funcTy); |
175 | } |
176 | |
177 | /// Create a null constant memory reference of type \p ptrType. |
178 | /// If \p ptrType is not provided, !fir.ref<none> type will be used. |
179 | mlir::Value createNullConstant(mlir::Location loc, mlir::Type ptrType = {}); |
180 | |
181 | /// Create an integer constant of type \p type and value \p i. |
182 | /// Should not be used with negative values with integer types of more |
183 | /// than 64 bits. |
184 | mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType, |
185 | std::int64_t i); |
186 | |
187 | /// Create an integer of \p integerType where all the bits have been set to |
188 | /// ones. Safe to use regardless of integerType bitwidth. |
189 | mlir::Value createAllOnesInteger(mlir::Location loc, mlir::Type integerType); |
190 | |
191 | /// Create -1 constant of \p integerType. Safe to use regardless of |
192 | /// integerType bitwidth. |
193 | mlir::Value createMinusOneInteger(mlir::Location loc, |
194 | mlir::Type integerType) { |
195 | return createAllOnesInteger(loc, integerType); |
196 | } |
197 | |
198 | /// Create a real constant from an integer value. |
199 | mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType, |
200 | llvm::APFloat::integerPart val); |
201 | |
202 | /// Create a real constant from an APFloat value. |
203 | mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType, |
204 | const llvm::APFloat &val); |
205 | |
206 | /// Create a real constant of type \p realType with a value zero. |
207 | mlir::Value createRealZeroConstant(mlir::Location loc, mlir::Type realType) { |
208 | return createRealConstant(loc, realType, 0u); |
209 | } |
210 | |
211 | /// Create a slot for a local on the stack. Besides the variable's type and |
212 | /// shape, it may be given name, pinned, or target attributes. |
213 | mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty, |
214 | llvm::StringRef uniqName, llvm::StringRef name, |
215 | bool pinned, llvm::ArrayRef<mlir::Value> shape, |
216 | llvm::ArrayRef<mlir::Value> lenParams, |
217 | bool asTarget = false); |
218 | mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty, |
219 | llvm::StringRef uniqName, llvm::StringRef name, |
220 | llvm::ArrayRef<mlir::Value> shape, |
221 | llvm::ArrayRef<mlir::Value> lenParams, |
222 | bool asTarget = false); |
223 | |
224 | /// Create a two dimensional ArrayAttr containing integer data as |
225 | /// IntegerAttrs, effectively: ArrayAttr<ArrayAttr<IntegerAttr>>>. |
226 | mlir::ArrayAttr create2DI64ArrayAttr( |
227 | llvm::SmallVectorImpl<llvm::SmallVector<int64_t>> &intData); |
228 | |
229 | /// Create a temporary using `fir.alloca`. This function does not hoist. |
230 | /// It is the callers responsibility to set the insertion point if |
231 | /// hoisting is required. |
232 | mlir::Value createTemporaryAlloc( |
233 | mlir::Location loc, mlir::Type type, llvm::StringRef name, |
234 | mlir::ValueRange lenParams = {}, mlir::ValueRange shape = {}, |
235 | llvm::ArrayRef<mlir::NamedAttribute> attrs = {}, |
236 | std::optional<Fortran::common::CUDADataAttr> cudaAttr = std::nullopt); |
237 | |
238 | /// Create a temporary. A temp is allocated using `fir.alloca` and can be read |
239 | /// and written using `fir.load` and `fir.store`, resp. The temporary can be |
240 | /// given a name via a front-end `Symbol` or a `StringRef`. |
241 | mlir::Value createTemporary( |
242 | mlir::Location loc, mlir::Type type, llvm::StringRef name = {}, |
243 | mlir::ValueRange shape = {}, mlir::ValueRange lenParams = {}, |
244 | llvm::ArrayRef<mlir::NamedAttribute> attrs = {}, |
245 | std::optional<Fortran::common::CUDADataAttr> cudaAttr = std::nullopt); |
246 | |
247 | /// Create an unnamed and untracked temporary on the stack. |
248 | mlir::Value createTemporary(mlir::Location loc, mlir::Type type, |
249 | mlir::ValueRange shape) { |
250 | return createTemporary(loc, type, llvm::StringRef{}, shape); |
251 | } |
252 | |
253 | mlir::Value createTemporary(mlir::Location loc, mlir::Type type, |
254 | llvm::ArrayRef<mlir::NamedAttribute> attrs) { |
255 | return createTemporary(loc, type, llvm::StringRef{}, {}, {}, attrs); |
256 | } |
257 | |
258 | mlir::Value createTemporary(mlir::Location loc, mlir::Type type, |
259 | llvm::StringRef name, |
260 | llvm::ArrayRef<mlir::NamedAttribute> attrs) { |
261 | return createTemporary(loc, type, name, {}, {}, attrs); |
262 | } |
263 | |
264 | /// Create a temporary on the heap. |
265 | mlir::Value |
266 | createHeapTemporary(mlir::Location loc, mlir::Type type, |
267 | llvm::StringRef name = {}, mlir::ValueRange shape = {}, |
268 | mlir::ValueRange lenParams = {}, |
269 | llvm::ArrayRef<mlir::NamedAttribute> attrs = {}); |
270 | |
271 | /// Sample genDeclare callback for createArrayTemp() below. |
272 | /// It creates fir.declare operation using the given operands. |
273 | /// \p memref is the base of the allocated temporary, |
274 | /// which may be !fir.ref<!fir.array<>> or !fir.box/class<>. |
275 | static mlir::Value genTempDeclareOp(fir::FirOpBuilder &builder, |
276 | mlir::Location loc, mlir::Value memref, |
277 | llvm::StringRef name, mlir::Value shape, |
278 | llvm::ArrayRef<mlir::Value> typeParams, |
279 | fir::FortranVariableFlagsAttr attrs); |
280 | |
281 | /// Create a temporary with the given \p baseType, |
282 | /// \p shape, \p extents and \p typeParams. An optional |
283 | /// \p polymorphicMold specifies the entity which dynamic type |
284 | /// has to be used for the allocation. |
285 | /// \p genDeclare callback generates a declare operation |
286 | /// for the created temporary. FIR passes may use genTempDeclareOp() |
287 | /// function above that creates fir.declare. |
288 | /// HLFIR passes may provide their own callback that generates |
289 | /// hlfir.declare. Some passes may provide a callback that |
290 | /// just passes through the base of the temporary. |
291 | /// If \p useStack is true, the function will try to do the allocation |
292 | /// in stack memory (which is not always possible currently). |
293 | /// The first return value is the base of the temporary object, |
294 | /// which may be !fir.ref<!fir.array<>> or !fir.box/class<>. |
295 | /// The second return value is true, if the actual allocation |
296 | /// was done in heap memory. |
297 | std::pair<mlir::Value, bool> createAndDeclareTemp( |
298 | mlir::Location loc, mlir::Type baseType, mlir::Value shape, |
299 | llvm::ArrayRef<mlir::Value> extents, |
300 | llvm::ArrayRef<mlir::Value> typeParams, |
301 | const std::function<decltype(genTempDeclareOp)> &genDeclare, |
302 | mlir::Value polymorphicMold, bool useStack, llvm::StringRef tmpName); |
303 | /// Create and declare an array temporary. |
304 | std::pair<mlir::Value, bool> |
305 | createArrayTemp(mlir::Location loc, fir::SequenceType arrayType, |
306 | mlir::Value shape, llvm::ArrayRef<mlir::Value> extents, |
307 | llvm::ArrayRef<mlir::Value> typeParams, |
308 | const std::function<decltype(genTempDeclareOp)> &genDeclare, |
309 | mlir::Value polymorphicMold, bool useStack = false, |
310 | llvm::StringRef tmpName = ".tmp.array") { |
311 | return createAndDeclareTemp(loc, arrayType, shape, extents, typeParams, |
312 | genDeclare, polymorphicMold, useStack, tmpName); |
313 | } |
314 | |
315 | /// Create an LLVM stack save intrinsic op. Returns the saved stack pointer. |
316 | /// The stack address space is fetched from the data layout of the current |
317 | /// module. |
318 | mlir::Value genStackSave(mlir::Location loc); |
319 | |
320 | /// Create an LLVM stack restore intrinsic op. stackPointer should be a value |
321 | /// previously returned from genStackSave. |
322 | void genStackRestore(mlir::Location loc, mlir::Value stackPointer); |
323 | |
324 | /// Create a global value. |
325 | fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type, |
326 | llvm::StringRef name, |
327 | mlir::StringAttr linkage = {}, |
328 | mlir::Attribute value = {}, bool isConst = false, |
329 | bool isTarget = false, |
330 | cuf::DataAttributeAttr dataAttr = {}); |
331 | |
332 | fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type, |
333 | llvm::StringRef name, bool isConst, bool isTarget, |
334 | std::function<void(FirOpBuilder &)> bodyBuilder, |
335 | mlir::StringAttr linkage = {}, |
336 | cuf::DataAttributeAttr dataAttr = {}); |
337 | |
338 | /// Create a global constant (read-only) value. |
339 | fir::GlobalOp createGlobalConstant(mlir::Location loc, mlir::Type type, |
340 | llvm::StringRef name, |
341 | mlir::StringAttr linkage = {}, |
342 | mlir::Attribute value = {}) { |
343 | return createGlobal(loc, type, name, linkage, value, /*isConst=*/true, |
344 | /*isTarget=*/false); |
345 | } |
346 | |
347 | fir::GlobalOp |
348 | createGlobalConstant(mlir::Location loc, mlir::Type type, |
349 | llvm::StringRef name, |
350 | std::function<void(FirOpBuilder &)> bodyBuilder, |
351 | mlir::StringAttr linkage = {}) { |
352 | return createGlobal(loc, type, name, /*isConst=*/true, /*isTarget=*/false, |
353 | bodyBuilder, linkage); |
354 | } |
355 | |
356 | /// Convert a StringRef string into a fir::StringLitOp. |
357 | fir::StringLitOp createStringLitOp(mlir::Location loc, |
358 | llvm::StringRef string); |
359 | |
360 | std::pair<fir::TypeInfoOp, mlir::OpBuilder::InsertPoint> |
361 | createTypeInfoOp(mlir::Location loc, fir::RecordType recordType, |
362 | fir::RecordType parentType); |
363 | |
364 | //===--------------------------------------------------------------------===// |
365 | // Linkage helpers (inline). The default linkage is external. |
366 | //===--------------------------------------------------------------------===// |
367 | |
368 | mlir::StringAttr createCommonLinkage() { return getStringAttr("common"); } |
369 | |
370 | mlir::StringAttr createInternalLinkage() { return getStringAttr("internal"); } |
371 | |
372 | mlir::StringAttr createLinkOnceLinkage() { return getStringAttr("linkonce"); } |
373 | |
374 | mlir::StringAttr createLinkOnceODRLinkage() { |
375 | return getStringAttr("linkonce_odr"); |
376 | } |
377 | |
378 | mlir::StringAttr createWeakLinkage() { return getStringAttr("weak"); } |
379 | |
380 | /// Get a function by name. If the function exists in the current module, it |
381 | /// is returned. Otherwise, a null FuncOp is returned. |
382 | mlir::func::FuncOp getNamedFunction(llvm::StringRef name) { |
383 | return getNamedFunction(getModule(), getMLIRSymbolTable(), name); |
384 | } |
385 | static mlir::func::FuncOp |
386 | getNamedFunction(mlir::ModuleOp module, const mlir::SymbolTable *symbolTable, |
387 | llvm::StringRef name); |
388 | |
389 | /// Get a function by symbol name. The result will be null if there is no |
390 | /// function with the given symbol in the module. |
391 | mlir::func::FuncOp getNamedFunction(mlir::SymbolRefAttr symbol) { |
392 | return getNamedFunction(getModule(), getMLIRSymbolTable(), symbol); |
393 | } |
394 | static mlir::func::FuncOp |
395 | getNamedFunction(mlir::ModuleOp module, const mlir::SymbolTable *symbolTable, |
396 | mlir::SymbolRefAttr symbol); |
397 | |
398 | fir::GlobalOp getNamedGlobal(llvm::StringRef name) { |
399 | return getNamedGlobal(getModule(), getMLIRSymbolTable(), name); |
400 | } |
401 | |
402 | static fir::GlobalOp getNamedGlobal(mlir::ModuleOp module, |
403 | const mlir::SymbolTable *symbolTable, |
404 | llvm::StringRef name); |
405 | |
406 | /// Lazy creation of fir.convert op. |
407 | mlir::Value createConvert(mlir::Location loc, mlir::Type toTy, |
408 | mlir::Value val); |
409 | |
410 | /// Create a fir.convert op with a volatile cast if the source value's type |
411 | /// does not match the target type's volatility. |
412 | mlir::Value createConvertWithVolatileCast(mlir::Location loc, mlir::Type toTy, |
413 | mlir::Value val); |
414 | |
415 | /// Cast \p value to have \p isVolatile volatility. |
416 | mlir::Value createVolatileCast(mlir::Location loc, bool isVolatile, |
417 | mlir::Value value); |
418 | |
419 | /// Create a fir.store of \p val into \p addr. A lazy conversion |
420 | /// of \p val to the element type of \p addr is created if needed. |
421 | void createStoreWithConvert(mlir::Location loc, mlir::Value val, |
422 | mlir::Value addr); |
423 | |
424 | /// Create a fir.load if \p val is a reference or pointer type. Return the |
425 | /// result of the load if it was created, otherwise return \p val |
426 | mlir::Value loadIfRef(mlir::Location loc, mlir::Value val); |
427 | |
428 | /// Determine if the named function is already in the module. Return the |
429 | /// instance if found, otherwise add a new named function to the module. |
430 | mlir::func::FuncOp createFunction(mlir::Location loc, llvm::StringRef name, |
431 | mlir::FunctionType ty) { |
432 | return createFunction(loc, getModule(), name, ty, getMLIRSymbolTable()); |
433 | } |
434 | |
435 | static mlir::func::FuncOp createFunction(mlir::Location loc, |
436 | mlir::ModuleOp module, |
437 | llvm::StringRef name, |
438 | mlir::FunctionType ty, |
439 | mlir::SymbolTable *); |
440 | |
441 | /// Returns a named function for a Fortran runtime API, creating |
442 | /// it, if it does not exist in the module yet. |
443 | /// If \p isIO is set to true, then the function corresponds |
444 | /// to one of Fortran runtime IO APIs. |
445 | mlir::func::FuncOp createRuntimeFunction(mlir::Location loc, |
446 | llvm::StringRef name, |
447 | mlir::FunctionType ty, |
448 | bool isIO = false); |
449 | |
450 | /// Cast the input value to IndexType. |
451 | mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) { |
452 | return createConvert(loc, getIndexType(), val); |
453 | } |
454 | |
455 | /// Construct one of the two forms of shape op from an array box. |
456 | mlir::Value genShape(mlir::Location loc, const fir::AbstractArrayBox &arr); |
457 | mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift, |
458 | llvm::ArrayRef<mlir::Value> exts); |
459 | mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> exts); |
460 | mlir::Value genShift(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift); |
461 | |
462 | /// Create one of the shape ops given an extended value. For a boxed value, |
463 | /// this may create a `fir.shift` op. |
464 | mlir::Value createShape(mlir::Location loc, const fir::ExtendedValue &exv); |
465 | |
466 | /// Create a slice op extended value. The value to be sliced, `exv`, must be |
467 | /// an array. |
468 | mlir::Value createSlice(mlir::Location loc, const fir::ExtendedValue &exv, |
469 | mlir::ValueRange triples, mlir::ValueRange path); |
470 | |
471 | /// Create a boxed value (Fortran descriptor) to be passed to the runtime. |
472 | /// \p exv is an extended value holding a memory reference to the object that |
473 | /// must be boxed. This function will crash if provided something that is not |
474 | /// a memory reference type. |
475 | /// Array entities are boxed with a shape and possibly a shift. Character |
476 | /// entities are boxed with a LEN parameter. |
477 | mlir::Value createBox(mlir::Location loc, const fir::ExtendedValue &exv, |
478 | bool isPolymorphic = false, bool isAssumedType = false); |
479 | |
480 | mlir::Value createBox(mlir::Location loc, mlir::Type boxType, |
481 | mlir::Value addr, mlir::Value shape, mlir::Value slice, |
482 | llvm::ArrayRef<mlir::Value> lengths, mlir::Value tdesc); |
483 | |
484 | /// Create constant i1 with value 1. if \p b is true or 0. otherwise |
485 | mlir::Value createBool(mlir::Location loc, bool b) { |
486 | return createIntegerConstant(loc, getIntegerType(1), b ? 1 : 0); |
487 | } |
488 | |
489 | //===--------------------------------------------------------------------===// |
490 | // If-Then-Else generation helper |
491 | //===--------------------------------------------------------------------===// |
492 | |
493 | /// Helper class to create if-then-else in a structured way: |
494 | /// Usage: genIfOp().genThen([&](){...}).genElse([&](){...}).end(); |
495 | /// Alternatively, getResults() can be used instead of end() to end the ifOp |
496 | /// and get the ifOp results. |
497 | class IfBuilder { |
498 | public: |
499 | IfBuilder(fir::IfOp ifOp, FirOpBuilder &builder) |
500 | : ifOp{ifOp}, builder{builder} {} |
501 | template <typename CC> |
502 | IfBuilder &genThen(CC func) { |
503 | builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); |
504 | func(); |
505 | return *this; |
506 | } |
507 | template <typename CC> |
508 | IfBuilder &genElse(CC func) { |
509 | assert(!ifOp.getElseRegion().empty() && "must have else region"); |
510 | builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); |
511 | func(); |
512 | return *this; |
513 | } |
514 | void end() { builder.setInsertionPointAfter(ifOp); } |
515 | |
516 | /// End the IfOp and return the results if any. |
517 | mlir::Operation::result_range getResults() { |
518 | end(); |
519 | return ifOp.getResults(); |
520 | } |
521 | |
522 | fir::IfOp &getIfOp() { return ifOp; }; |
523 | |
524 | private: |
525 | fir::IfOp ifOp; |
526 | FirOpBuilder &builder; |
527 | }; |
528 | |
529 | /// Create an IfOp and returns an IfBuilder that can generate the else/then |
530 | /// bodies. |
531 | IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results, |
532 | mlir::Value cdt, bool withElseRegion) { |
533 | auto op = create<fir::IfOp>(loc, results, cdt, withElseRegion); |
534 | return IfBuilder(op, *this); |
535 | } |
536 | |
537 | /// Create an IfOp with no "else" region, and no result values. |
538 | /// Usage: genIfThen(loc, cdt).genThen(lambda).end(); |
539 | IfBuilder genIfThen(mlir::Location loc, mlir::Value cdt) { |
540 | auto op = create<fir::IfOp>(loc, std::nullopt, cdt, false); |
541 | return IfBuilder(op, *this); |
542 | } |
543 | |
544 | /// Create an IfOp with an "else" region, and no result values. |
545 | /// Usage: genIfThenElse(loc, cdt).genThen(lambda).genElse(lambda).end(); |
546 | IfBuilder genIfThenElse(mlir::Location loc, mlir::Value cdt) { |
547 | auto op = create<fir::IfOp>(loc, std::nullopt, cdt, true); |
548 | return IfBuilder(op, *this); |
549 | } |
550 | |
551 | mlir::Value genNot(mlir::Location loc, mlir::Value boolean) { |
552 | return create<mlir::arith::CmpIOp>(loc, mlir::arith::CmpIPredicate::eq, |
553 | boolean, createBool(loc, false)); |
554 | } |
555 | |
556 | /// Generate code testing \p addr is not a null address. |
557 | mlir::Value genIsNotNullAddr(mlir::Location loc, mlir::Value addr); |
558 | |
559 | /// Generate code testing \p addr is a null address. |
560 | mlir::Value genIsNullAddr(mlir::Location loc, mlir::Value addr); |
561 | |
562 | /// Compute the extent of (lb:ub:step) as max((ub-lb+step)/step, 0). See |
563 | /// Fortran 2018 9.5.3.3.2 section for more details. |
564 | mlir::Value genExtentFromTriplet(mlir::Location loc, mlir::Value lb, |
565 | mlir::Value ub, mlir::Value step, |
566 | mlir::Type type); |
567 | |
568 | /// Create an AbsentOp of \p argTy type and handle special cases, such as |
569 | /// Character Procedure Tuple arguments. |
570 | mlir::Value genAbsentOp(mlir::Location loc, mlir::Type argTy); |
571 | |
572 | /// Set default FastMathFlags value for all operations |
573 | /// supporting mlir::arith::FastMathAttr that will be created |
574 | /// by this builder. |
575 | void setFastMathFlags(mlir::arith::FastMathFlags flags) { |
576 | fastMathFlags = flags; |
577 | } |
578 | |
579 | /// Set default FastMathFlags value from the passed MathOptionsBase |
580 | /// config. |
581 | void setFastMathFlags(Fortran::common::MathOptionsBase options); |
582 | |
583 | /// Get current FastMathFlags value. |
584 | mlir::arith::FastMathFlags getFastMathFlags() const { return fastMathFlags; } |
585 | |
586 | /// Stringify FastMathFlags set in a way |
587 | /// that the string may be used for mangling a function name. |
588 | /// If FastMathFlags are set to 'none', then the result is an empty |
589 | /// string. |
590 | std::string getFastMathFlagsString() { |
591 | mlir::arith::FastMathFlags flags = getFastMathFlags(); |
592 | if (flags == mlir::arith::FastMathFlags::none) |
593 | return {}; |
594 | |
595 | std::string fmfString{mlir::arith::stringifyFastMathFlags(flags)}; |
596 | std::replace(fmfString.begin(), fmfString.end(), ',', '_'); |
597 | return fmfString; |
598 | } |
599 | |
600 | /// Set default IntegerOverflowFlags value for all operations |
601 | /// supporting mlir::arith::IntegerOverflowFlagsAttr that will be created |
602 | /// by this builder. |
603 | void setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags flags) { |
604 | integerOverflowFlags = flags; |
605 | } |
606 | |
607 | /// Get current IntegerOverflowFlags value. |
608 | mlir::arith::IntegerOverflowFlags getIntegerOverflowFlags() const { |
609 | return integerOverflowFlags; |
610 | } |
611 | |
612 | /// Dump the current function. (debug) |
613 | LLVM_DUMP_METHOD void dumpFunc(); |
614 | |
615 | /// FirOpBuilder hook for creating new operation. |
616 | void notifyOperationInserted(mlir::Operation *op, |
617 | mlir::OpBuilder::InsertPoint previous) override { |
618 | // We only care about newly created operations. |
619 | if (previous.isSet()) |
620 | return; |
621 | setCommonAttributes(op); |
622 | } |
623 | |
624 | /// Construct a data layout on demand and return it |
625 | mlir::DataLayout &getDataLayout(); |
626 | |
627 | /// Convert operands &/or result from/to unsigned so that the operation |
628 | /// only receives/produces signless operands. |
629 | template <typename OpTy> |
630 | mlir::Value createUnsigned(mlir::Location loc, mlir::Type resultType, |
631 | mlir::Value left, mlir::Value right) { |
632 | if (!resultType.isIntOrFloat()) |
633 | return create<OpTy>(loc, resultType, left, right); |
634 | mlir::Type signlessType = mlir::IntegerType::get( |
635 | getContext(), resultType.getIntOrFloatBitWidth(), |
636 | mlir::IntegerType::SignednessSemantics::Signless); |
637 | mlir::Type opResType = resultType; |
638 | if (left.getType().isUnsignedInteger()) { |
639 | left = createConvert(loc, signlessType, left); |
640 | opResType = signlessType; |
641 | } |
642 | if (right.getType().isUnsignedInteger()) { |
643 | right = createConvert(loc, signlessType, right); |
644 | opResType = signlessType; |
645 | } |
646 | mlir::Value result = create<OpTy>(loc, opResType, left, right); |
647 | if (resultType.isUnsignedInteger()) |
648 | result = createConvert(loc, resultType, result); |
649 | return result; |
650 | } |
651 | |
652 | /// Compare two pointer-like values using the given predicate. |
653 | mlir::Value genPtrCompare(mlir::Location loc, |
654 | mlir::arith::CmpIPredicate predicate, |
655 | mlir::Value ptr1, mlir::Value ptr2) { |
656 | ptr1 = createConvert(loc, getIndexType(), ptr1); |
657 | ptr2 = createConvert(loc, getIndexType(), ptr2); |
658 | return create<mlir::arith::CmpIOp>(loc, predicate, ptr1, ptr2); |
659 | } |
660 | |
661 | private: |
662 | /// Set attributes (e.g. FastMathAttr) to \p op operation |
663 | /// based on the current attributes setting. |
664 | void setCommonAttributes(mlir::Operation *op) const; |
665 | |
666 | KindMapping kindMap; |
667 | |
668 | /// FastMathFlags that need to be set for operations that support |
669 | /// mlir::arith::FastMathAttr. |
670 | mlir::arith::FastMathFlags fastMathFlags{}; |
671 | |
672 | /// IntegerOverflowFlags that need to be set for operations that support |
673 | /// mlir::arith::IntegerOverflowFlagsAttr. |
674 | mlir::arith::IntegerOverflowFlags integerOverflowFlags{}; |
675 | |
676 | /// fir::GlobalOp and func::FuncOp symbol table to speed-up |
677 | /// lookups. |
678 | mlir::SymbolTable *symbolTable = nullptr; |
679 | |
680 | /// DataLayout constructed on demand. Access via getDataLayout(). |
681 | /// Stored via a unique_ptr rather than an optional so as not to bloat this |
682 | /// class when most instances won't ever need a data layout. |
683 | std::unique_ptr<mlir::DataLayout> dataLayout = nullptr; |
684 | }; |
685 | |
686 | } // namespace fir |
687 | |
688 | namespace fir::factory { |
689 | |
690 | //===----------------------------------------------------------------------===// |
691 | // ExtendedValue inquiry helpers |
692 | //===----------------------------------------------------------------------===// |
693 | |
694 | /// Read or get character length from \p box that must contain a character |
695 | /// entity. If the length value is contained in the ExtendedValue, this will |
696 | /// not generate any code, otherwise this will generate a read of the fir.box |
697 | /// describing the entity. |
698 | mlir::Value readCharLen(fir::FirOpBuilder &builder, mlir::Location loc, |
699 | const fir::ExtendedValue &box); |
700 | |
701 | /// Read or get the extent in dimension \p dim of the array described by \p box. |
702 | mlir::Value readExtent(fir::FirOpBuilder &builder, mlir::Location loc, |
703 | const fir::ExtendedValue &box, unsigned dim); |
704 | |
705 | /// Read or get the lower bound in dimension \p dim of the array described by |
706 | /// \p box. If the lower bound is left default in the ExtendedValue, |
707 | /// \p defaultValue will be returned. |
708 | mlir::Value readLowerBound(fir::FirOpBuilder &builder, mlir::Location loc, |
709 | const fir::ExtendedValue &box, unsigned dim, |
710 | mlir::Value defaultValue); |
711 | |
712 | /// Read extents from \p box. |
713 | llvm::SmallVector<mlir::Value> readExtents(fir::FirOpBuilder &builder, |
714 | mlir::Location loc, |
715 | const fir::BoxValue &box); |
716 | |
717 | /// Read a fir::BoxValue into an fir::UnboxValue, a fir::ArrayBoxValue or a |
718 | /// fir::CharArrayBoxValue. This should only be called if the fir::BoxValue is |
719 | /// known to be contiguous given the context (or if the resulting address will |
720 | /// not be used). If the value is polymorphic, its dynamic type will be lost. |
721 | /// This must not be used on unlimited polymorphic and assumed rank entities. |
722 | fir::ExtendedValue readBoxValue(fir::FirOpBuilder &builder, mlir::Location loc, |
723 | const fir::BoxValue &box); |
724 | |
725 | /// Get the lower bounds of \p exv. NB: returns an empty vector if the lower |
726 | /// bounds are all ones, which is the default in Fortran. |
727 | llvm::SmallVector<mlir::Value> |
728 | getNonDefaultLowerBounds(fir::FirOpBuilder &builder, mlir::Location loc, |
729 | const fir::ExtendedValue &exv); |
730 | |
731 | /// Return LEN parameters associated to \p exv that are not deferred (that are |
732 | /// available without having to read any fir.box values). Empty if \p exv has no |
733 | /// LEN parameters or if they are all deferred. |
734 | llvm::SmallVector<mlir::Value> |
735 | getNonDeferredLenParams(const fir::ExtendedValue &exv); |
736 | |
737 | //===----------------------------------------------------------------------===// |
738 | // String literal helper helpers |
739 | //===----------------------------------------------------------------------===// |
740 | |
741 | /// Create a !fir.char<1> string literal global and returns a fir::CharBoxValue |
742 | /// with its address and length. |
743 | fir::ExtendedValue createStringLiteral(fir::FirOpBuilder &, mlir::Location, |
744 | llvm::StringRef string); |
745 | |
746 | /// Unique a compiler generated identifier. A short prefix should be provided |
747 | /// to hint at the origin of the identifier. |
748 | std::string uniqueCGIdent(llvm::StringRef prefix, llvm::StringRef name); |
749 | |
750 | /// Lowers the extents from the sequence type to Values. |
751 | /// Any unknown extents are lowered to undefined values. |
752 | llvm::SmallVector<mlir::Value> createExtents(fir::FirOpBuilder &builder, |
753 | mlir::Location loc, |
754 | fir::SequenceType seqTy); |
755 | |
756 | //===--------------------------------------------------------------------===// |
757 | // Location helpers |
758 | //===--------------------------------------------------------------------===// |
759 | |
760 | /// Generate a string literal containing the file name and return its address |
761 | mlir::Value locationToFilename(fir::FirOpBuilder &, mlir::Location); |
762 | /// Generate a constant of the given type with the location line number |
763 | mlir::Value locationToLineNo(fir::FirOpBuilder &, mlir::Location, mlir::Type); |
764 | |
765 | //===--------------------------------------------------------------------===// |
766 | // ExtendedValue helpers |
767 | //===--------------------------------------------------------------------===// |
768 | |
769 | /// Return the extended value for a component of a derived type instance given |
770 | /// the address of the component. |
771 | fir::ExtendedValue componentToExtendedValue(fir::FirOpBuilder &builder, |
772 | mlir::Location loc, |
773 | mlir::Value component); |
774 | |
775 | /// Given the address of an array element and the ExtendedValue describing the |
776 | /// array, returns the ExtendedValue describing the array element. The purpose |
777 | /// is to propagate the LEN parameters of the array to the element. This can be |
778 | /// used for elements of `array` or `array(i:j:k)`. If \p element belongs to an |
779 | /// array section `array%x` whose base is \p array, |
780 | /// arraySectionElementToExtendedValue must be used instead. |
781 | fir::ExtendedValue arrayElementToExtendedValue(fir::FirOpBuilder &builder, |
782 | mlir::Location loc, |
783 | const fir::ExtendedValue &array, |
784 | mlir::Value element); |
785 | |
786 | /// Build the ExtendedValue for \p element that is an element of an array or |
787 | /// array section with \p array base (`array` or `array(i:j:k)%x%y`). |
788 | /// If it is an array section, \p slice must be provided and be a fir::SliceOp |
789 | /// that describes the section. |
790 | fir::ExtendedValue arraySectionElementToExtendedValue( |
791 | fir::FirOpBuilder &builder, mlir::Location loc, |
792 | const fir::ExtendedValue &array, mlir::Value element, mlir::Value slice); |
793 | |
794 | /// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalars. The |
795 | /// assignment follows Fortran intrinsic assignment semantic (10.2.1.3). |
796 | void genScalarAssignment(fir::FirOpBuilder &builder, mlir::Location loc, |
797 | const fir::ExtendedValue &lhs, |
798 | const fir::ExtendedValue &rhs, |
799 | bool needFinalization = false, |
800 | bool isTemporaryLHS = false); |
801 | |
802 | /// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalar derived |
803 | /// types. The assignment follows Fortran intrinsic assignment semantic for |
804 | /// derived types (10.2.1.3 point 13). |
805 | void genRecordAssignment(fir::FirOpBuilder &builder, mlir::Location loc, |
806 | const fir::ExtendedValue &lhs, |
807 | const fir::ExtendedValue &rhs, |
808 | bool needFinalization = false, |
809 | bool isTemporaryLHS = false); |
810 | |
811 | /// Builds and returns the type of a ragged array header used to cache mask |
812 | /// evaluations. RaggedArrayHeader is defined in |
813 | /// flang/include/flang/Runtime/ragged.h. |
814 | mlir::TupleType getRaggedArrayHeaderType(fir::FirOpBuilder &builder); |
815 | |
816 | /// Generate the, possibly dynamic, LEN of a CHARACTER. \p arrLoad determines |
817 | /// the base array. After applying \p path, the result must be a reference to a |
818 | /// `!fir.char` type object. \p substring must have 0, 1, or 2 members. The |
819 | /// first member is the starting offset. The second is the ending offset. |
820 | mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc, |
821 | fir::ArrayLoadOp arrLoad, |
822 | llvm::ArrayRef<mlir::Value> path, |
823 | llvm::ArrayRef<mlir::Value> substring); |
824 | mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc, |
825 | fir::SequenceType seqTy, mlir::Value memref, |
826 | llvm::ArrayRef<mlir::Value> typeParams, |
827 | llvm::ArrayRef<mlir::Value> path, |
828 | llvm::ArrayRef<mlir::Value> substring); |
829 | |
830 | /// Create the zero value of a given the numerical or logical \p type (`false` |
831 | /// for logical types). |
832 | mlir::Value createZeroValue(fir::FirOpBuilder &builder, mlir::Location loc, |
833 | mlir::Type type); |
834 | |
835 | /// Get the integer constants of triplet and compute the extent. |
836 | std::optional<std::int64_t> getExtentFromTriplet(mlir::Value lb, mlir::Value ub, |
837 | mlir::Value stride); |
838 | |
839 | /// Compute the extent value given the lower bound \lb and upper bound \ub. |
840 | /// All inputs must have the same SSA integer type. |
841 | mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc, |
842 | mlir::Value lb, mlir::Value ub); |
843 | mlir::Value computeExtent(fir::FirOpBuilder &builder, mlir::Location loc, |
844 | mlir::Value lb, mlir::Value ub, mlir::Value zero, |
845 | mlir::Value one); |
846 | |
847 | /// Generate max(\p value, 0) where \p value is a scalar integer. |
848 | mlir::Value genMaxWithZero(fir::FirOpBuilder &builder, mlir::Location loc, |
849 | mlir::Value value); |
850 | mlir::Value genMaxWithZero(fir::FirOpBuilder &builder, mlir::Location loc, |
851 | mlir::Value value, mlir::Value zero); |
852 | |
853 | /// The type(C_PTR/C_FUNPTR) is defined as the derived type with only one |
854 | /// component of integer 64, and the component is the C address. Get the C |
855 | /// address. |
856 | mlir::Value genCPtrOrCFunptrAddr(fir::FirOpBuilder &builder, mlir::Location loc, |
857 | mlir::Value cPtr, mlir::Type ty); |
858 | |
859 | /// The type(C_DEVPTR) is defined as the derived type with only one |
860 | /// component of C_PTR type. Get the C address from the C_PTR component. |
861 | mlir::Value genCDevPtrAddr(fir::FirOpBuilder &builder, mlir::Location loc, |
862 | mlir::Value cDevPtr, mlir::Type ty); |
863 | |
864 | /// Get the C address value. |
865 | mlir::Value genCPtrOrCFunptrValue(fir::FirOpBuilder &builder, |
866 | mlir::Location loc, mlir::Value cPtr); |
867 | |
868 | /// Create a fir.box from a fir::ExtendedValue and wrap it in a fir::BoxValue |
869 | /// to keep all the lower bound and explicit parameter information. |
870 | fir::BoxValue createBoxValue(fir::FirOpBuilder &builder, mlir::Location loc, |
871 | const fir::ExtendedValue &exv); |
872 | |
873 | /// Generate Null BoxProc for procedure pointer null initialization. |
874 | mlir::Value createNullBoxProc(fir::FirOpBuilder &builder, mlir::Location loc, |
875 | mlir::Type boxType); |
876 | |
877 | /// Convert a value to a new type. Return the value directly if it has the right |
878 | /// type. |
879 | mlir::Value createConvert(mlir::OpBuilder &, mlir::Location, mlir::Type, |
880 | mlir::Value); |
881 | |
882 | /// Set internal linkage attribute on a function. |
883 | void setInternalLinkage(mlir::func::FuncOp); |
884 | |
885 | llvm::SmallVector<mlir::Value> |
886 | elideExtentsAlreadyInType(mlir::Type type, mlir::ValueRange shape); |
887 | |
888 | llvm::SmallVector<mlir::Value> |
889 | elideLengthsAlreadyInType(mlir::Type type, mlir::ValueRange lenParams); |
890 | |
891 | /// Get the address space which should be used for allocas |
892 | uint64_t getAllocaAddressSpace(const mlir::DataLayout *dataLayout); |
893 | |
894 | /// The two vectors of MLIR values have the following property: |
895 | /// \p extents1[i] must have the same value as \p extents2[i] |
896 | /// The function returns a new vector of MLIR values that preserves |
897 | /// the same property vs \p extents1 and \p extents2, but allows |
898 | /// more optimizations. For example, if extents1[j] is a known constant, |
899 | /// and extents2[j] is not, then result[j] is the MLIR value extents1[j]. |
900 | llvm::SmallVector<mlir::Value> deduceOptimalExtents(mlir::ValueRange extents1, |
901 | mlir::ValueRange extents2); |
902 | |
903 | /// Given array extents generate code that sets them all to zeroes, |
904 | /// if the array is empty, e.g.: |
905 | /// %false = arith.constant false |
906 | /// %c0 = arith.constant 0 : index |
907 | /// %p1 = arith.cmpi eq, %e0, %c0 : index |
908 | /// %p2 = arith.ori %false, %p1 : i1 |
909 | /// %p3 = arith.cmpi eq, %e1, %c0 : index |
910 | /// %p4 = arith.ori %p1, %p2 : i1 |
911 | /// %result0 = arith.select %p4, %c0, %e0 : index |
912 | /// %result1 = arith.select %p4, %c0, %e1 : index |
913 | llvm::SmallVector<mlir::Value> updateRuntimeExtentsForEmptyArrays( |
914 | fir::FirOpBuilder &builder, mlir::Location loc, mlir::ValueRange extents); |
915 | |
916 | /// Given \p box of type fir::BaseBoxType representing an array, |
917 | /// the function generates code to fetch the lower bounds, |
918 | /// the extents and the strides from the box. The values are returned via |
919 | /// \p lbounds, \p extents and \p strides. |
920 | void genDimInfoFromBox(fir::FirOpBuilder &builder, mlir::Location loc, |
921 | mlir::Value box, |
922 | llvm::SmallVectorImpl<mlir::Value> *lbounds, |
923 | llvm::SmallVectorImpl<mlir::Value> *extents, |
924 | llvm::SmallVectorImpl<mlir::Value> *strides); |
925 | |
926 | /// Generate an LLVM dialect lifetime start marker at the current insertion |
927 | /// point given an fir.alloca and its constant size in bytes. Returns the value |
928 | /// to be passed to the lifetime end marker. |
929 | mlir::Value genLifetimeStart(mlir::OpBuilder &builder, mlir::Location loc, |
930 | fir::AllocaOp alloc, int64_t size, |
931 | const mlir::DataLayout *dl); |
932 | |
933 | /// Generate an LLVM dialect lifetime end marker at the current insertion point |
934 | /// given an llvm.ptr value and the constant size in bytes of its storage. |
935 | void genLifetimeEnd(mlir::OpBuilder &builder, mlir::Location loc, |
936 | mlir::Value mem, int64_t size); |
937 | |
938 | } // namespace fir::factory |
939 | |
940 | #endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H |
941 |
Warning: This file is not a C or C++ file. It does not have highlighting.