Break circular dependency between FIR dialect and utilities
[llvm-project.git] / flang / include / flang / Optimizer / Builder / FIRBuilder.h
blob0dbd77823d8f8593145cda16864d8cbdf107a265
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.
14 //===----------------------------------------------------------------------===//
16 #ifndef FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H
17 #define FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H
19 #include "flang/Common/MathOptionsBase.h"
20 #include "flang/Optimizer/Dialect/FIROps.h"
21 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
22 #include "flang/Optimizer/Dialect/FIRType.h"
23 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
24 #include "mlir/IR/Builders.h"
25 #include "mlir/IR/BuiltinOps.h"
26 #include "llvm/ADT/DenseMap.h"
27 #include <optional>
29 namespace fir {
30 class AbstractArrayBox;
31 class ExtendedValue;
32 class MutableBoxValue;
33 class BoxValue;
35 //===----------------------------------------------------------------------===//
36 // FirOpBuilder
37 //===----------------------------------------------------------------------===//
39 /// Extends the MLIR OpBuilder to provide methods for building common FIR
40 /// patterns.
41 class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
42 public:
43 explicit FirOpBuilder(mlir::Operation *op, const fir::KindMapping &kindMap)
44 : OpBuilder{op, /*listener=*/this}, kindMap{kindMap} {}
45 explicit FirOpBuilder(mlir::OpBuilder &builder,
46 const fir::KindMapping &kindMap)
47 : OpBuilder(builder), OpBuilder::Listener(), kindMap{kindMap} {
48 setListener(this);
51 // The listener self-reference has to be updated in case of copy-construction.
52 FirOpBuilder(const FirOpBuilder &other)
53 : OpBuilder(other), OpBuilder::Listener(), kindMap{other.kindMap},
54 fastMathFlags{other.fastMathFlags} {
55 setListener(this);
58 /// Get the current Region of the insertion point.
59 mlir::Region &getRegion() { return *getBlock()->getParent(); }
61 /// Get the current Module
62 mlir::ModuleOp getModule() {
63 return getRegion().getParentOfType<mlir::ModuleOp>();
66 /// Get the current Function
67 mlir::func::FuncOp getFunction() {
68 return getRegion().getParentOfType<mlir::func::FuncOp>();
71 /// Get a reference to the kind map.
72 const fir::KindMapping &getKindMap() { return kindMap; }
74 /// Get the default integer type
75 [[maybe_unused]] mlir::IntegerType getDefaultIntegerType() {
76 return getIntegerType(
77 getKindMap().getIntegerBitsize(getKindMap().defaultIntegerKind()));
80 /// The LHS and RHS are not always in agreement in terms of type. In some
81 /// cases, the disagreement is between COMPLEX and other scalar types. In that
82 /// case, the conversion must insert (extract) out of a COMPLEX value to have
83 /// the proper semantics and be strongly typed. E.g., converting an integer
84 /// (real) to a complex, the real part is filled using the integer (real)
85 /// after type conversion and the imaginary part is zero.
86 mlir::Value convertWithSemantics(mlir::Location loc, mlir::Type toTy,
87 mlir::Value val,
88 bool allowCharacterConversion = false);
90 /// Get the entry block of the current Function
91 mlir::Block *getEntryBlock() { return &getFunction().front(); }
93 /// Get the block for adding Allocas. If OpenMP is enabled then get the
94 /// the alloca block from an Operation which can be Outlined. Otherwise
95 /// use the entry block of the current Function
96 mlir::Block *getAllocaBlock();
98 /// Safely create a reference type to the type `eleTy`.
99 mlir::Type getRefType(mlir::Type eleTy);
101 /// Create a sequence of `eleTy` with `rank` dimensions of unknown size.
102 mlir::Type getVarLenSeqTy(mlir::Type eleTy, unsigned rank = 1);
104 /// Get character length type.
105 mlir::Type getCharacterLengthType() { return getIndexType(); }
107 /// Get the integer type whose bit width corresponds to the width of pointer
108 /// types, or is bigger.
109 mlir::Type getIntPtrType() {
110 // TODO: Delay the need of such type until codegen or find a way to use
111 // llvm::DataLayout::getPointerSizeInBits here.
112 return getI64Type();
115 /// Wrap `str` to a SymbolRefAttr.
116 mlir::SymbolRefAttr getSymbolRefAttr(llvm::StringRef str) {
117 return mlir::SymbolRefAttr::get(getContext(), str);
120 /// Get the mlir float type that implements Fortran REAL(kind).
121 mlir::Type getRealType(int kind);
123 fir::BoxProcType getBoxProcType(mlir::FunctionType funcTy) {
124 return fir::BoxProcType::get(getContext(), funcTy);
127 /// Create a null constant memory reference of type \p ptrType.
128 /// If \p ptrType is not provided, !fir.ref<none> type will be used.
129 mlir::Value createNullConstant(mlir::Location loc, mlir::Type ptrType = {});
131 /// Create an integer constant of type \p type and value \p i.
132 mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType,
133 std::int64_t i);
135 /// Create a real constant from an integer value.
136 mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType,
137 llvm::APFloat::integerPart val);
139 /// Create a real constant from an APFloat value.
140 mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType,
141 const llvm::APFloat &val);
143 /// Create a real constant of type \p realType with a value zero.
144 mlir::Value createRealZeroConstant(mlir::Location loc, mlir::Type realType) {
145 return createRealConstant(loc, realType, 0u);
148 /// Create a slot for a local on the stack. Besides the variable's type and
149 /// shape, it may be given name, pinned, or target attributes.
150 mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty,
151 llvm::StringRef uniqName, llvm::StringRef name,
152 bool pinned, llvm::ArrayRef<mlir::Value> shape,
153 llvm::ArrayRef<mlir::Value> lenParams,
154 bool asTarget = false);
155 mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty,
156 llvm::StringRef uniqName, llvm::StringRef name,
157 llvm::ArrayRef<mlir::Value> shape,
158 llvm::ArrayRef<mlir::Value> lenParams,
159 bool asTarget = false);
161 /// Create a temporary. A temp is allocated using `fir.alloca` and can be read
162 /// and written using `fir.load` and `fir.store`, resp. The temporary can be
163 /// given a name via a front-end `Symbol` or a `StringRef`.
164 mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
165 llvm::StringRef name = {},
166 mlir::ValueRange shape = {},
167 mlir::ValueRange lenParams = {},
168 llvm::ArrayRef<mlir::NamedAttribute> attrs = {});
170 /// Create an unnamed and untracked temporary on the stack.
171 mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
172 mlir::ValueRange shape) {
173 return createTemporary(loc, type, llvm::StringRef{}, shape);
176 mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
177 llvm::ArrayRef<mlir::NamedAttribute> attrs) {
178 return createTemporary(loc, type, llvm::StringRef{}, {}, {}, attrs);
181 mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
182 llvm::StringRef name,
183 llvm::ArrayRef<mlir::NamedAttribute> attrs) {
184 return createTemporary(loc, type, name, {}, {}, attrs);
187 /// Create a temporary on the heap.
188 mlir::Value
189 createHeapTemporary(mlir::Location loc, mlir::Type type,
190 llvm::StringRef name = {}, mlir::ValueRange shape = {},
191 mlir::ValueRange lenParams = {},
192 llvm::ArrayRef<mlir::NamedAttribute> attrs = {});
194 /// Create a global value.
195 fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type,
196 llvm::StringRef name,
197 mlir::StringAttr linkage = {},
198 mlir::Attribute value = {}, bool isConst = false,
199 bool isTarget = false);
201 fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type,
202 llvm::StringRef name, bool isConst, bool isTarget,
203 std::function<void(FirOpBuilder &)> bodyBuilder,
204 mlir::StringAttr linkage = {});
206 /// Create a global constant (read-only) value.
207 fir::GlobalOp createGlobalConstant(mlir::Location loc, mlir::Type type,
208 llvm::StringRef name,
209 mlir::StringAttr linkage = {},
210 mlir::Attribute value = {}) {
211 return createGlobal(loc, type, name, linkage, value, /*isConst=*/true,
212 /*isTarget=*/false);
215 fir::GlobalOp
216 createGlobalConstant(mlir::Location loc, mlir::Type type,
217 llvm::StringRef name,
218 std::function<void(FirOpBuilder &)> bodyBuilder,
219 mlir::StringAttr linkage = {}) {
220 return createGlobal(loc, type, name, /*isConst=*/true, /*isTarget=*/false,
221 bodyBuilder, linkage);
224 /// Create a fir::DispatchTable operation.
225 fir::DispatchTableOp createDispatchTableOp(mlir::Location loc,
226 llvm::StringRef name,
227 llvm::StringRef parentName);
229 /// Convert a StringRef string into a fir::StringLitOp.
230 fir::StringLitOp createStringLitOp(mlir::Location loc,
231 llvm::StringRef string);
233 //===--------------------------------------------------------------------===//
234 // Linkage helpers (inline). The default linkage is external.
235 //===--------------------------------------------------------------------===//
237 mlir::StringAttr createCommonLinkage() { return getStringAttr("common"); }
239 mlir::StringAttr createInternalLinkage() { return getStringAttr("internal"); }
241 mlir::StringAttr createLinkOnceLinkage() { return getStringAttr("linkonce"); }
243 mlir::StringAttr createLinkOnceODRLinkage() {
244 return getStringAttr("linkonce_odr");
247 mlir::StringAttr createWeakLinkage() { return getStringAttr("weak"); }
249 /// Get a function by name. If the function exists in the current module, it
250 /// is returned. Otherwise, a null FuncOp is returned.
251 mlir::func::FuncOp getNamedFunction(llvm::StringRef name) {
252 return getNamedFunction(getModule(), name);
254 static mlir::func::FuncOp getNamedFunction(mlir::ModuleOp module,
255 llvm::StringRef name);
257 /// Get a function by symbol name. The result will be null if there is no
258 /// function with the given symbol in the module.
259 mlir::func::FuncOp getNamedFunction(mlir::SymbolRefAttr symbol) {
260 return getNamedFunction(getModule(), symbol);
262 static mlir::func::FuncOp getNamedFunction(mlir::ModuleOp module,
263 mlir::SymbolRefAttr symbol);
265 fir::GlobalOp getNamedGlobal(llvm::StringRef name) {
266 return getNamedGlobal(getModule(), name);
269 static fir::GlobalOp getNamedGlobal(mlir::ModuleOp module,
270 llvm::StringRef name);
272 /// Lazy creation of fir.convert op.
273 mlir::Value createConvert(mlir::Location loc, mlir::Type toTy,
274 mlir::Value val);
276 /// Create a fir.store of \p val into \p addr. A lazy conversion
277 /// of \p val to the element type of \p addr is created if needed.
278 void createStoreWithConvert(mlir::Location loc, mlir::Value val,
279 mlir::Value addr);
281 /// Create a new FuncOp. If the function may have already been created, use
282 /// `addNamedFunction` instead.
283 mlir::func::FuncOp createFunction(mlir::Location loc, llvm::StringRef name,
284 mlir::FunctionType ty) {
285 return createFunction(loc, getModule(), name, ty);
288 static mlir::func::FuncOp createFunction(mlir::Location loc,
289 mlir::ModuleOp module,
290 llvm::StringRef name,
291 mlir::FunctionType ty);
293 /// Determine if the named function is already in the module. Return the
294 /// instance if found, otherwise add a new named function to the module.
295 mlir::func::FuncOp addNamedFunction(mlir::Location loc, llvm::StringRef name,
296 mlir::FunctionType ty) {
297 if (auto func = getNamedFunction(name))
298 return func;
299 return createFunction(loc, name, ty);
302 static mlir::func::FuncOp addNamedFunction(mlir::Location loc,
303 mlir::ModuleOp module,
304 llvm::StringRef name,
305 mlir::FunctionType ty) {
306 if (auto func = getNamedFunction(module, name))
307 return func;
308 return createFunction(loc, module, name, ty);
311 /// Cast the input value to IndexType.
312 mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) {
313 return createConvert(loc, getIndexType(), val);
316 /// Construct one of the two forms of shape op from an array box.
317 mlir::Value genShape(mlir::Location loc, const fir::AbstractArrayBox &arr);
318 mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift,
319 llvm::ArrayRef<mlir::Value> exts);
320 mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> exts);
321 mlir::Value genShift(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift);
323 /// Create one of the shape ops given an extended value. For a boxed value,
324 /// this may create a `fir.shift` op.
325 mlir::Value createShape(mlir::Location loc, const fir::ExtendedValue &exv);
327 /// Create a slice op extended value. The value to be sliced, `exv`, must be
328 /// an array.
329 mlir::Value createSlice(mlir::Location loc, const fir::ExtendedValue &exv,
330 mlir::ValueRange triples, mlir::ValueRange path);
332 /// Create a boxed value (Fortran descriptor) to be passed to the runtime.
333 /// \p exv is an extended value holding a memory reference to the object that
334 /// must be boxed. This function will crash if provided something that is not
335 /// a memory reference type.
336 /// Array entities are boxed with a shape and possibly a shift. Character
337 /// entities are boxed with a LEN parameter.
338 mlir::Value createBox(mlir::Location loc, const fir::ExtendedValue &exv,
339 bool isPolymorphic = false);
341 mlir::Value createBox(mlir::Location loc, mlir::Type boxType,
342 mlir::Value addr, mlir::Value shape, mlir::Value slice,
343 llvm::ArrayRef<mlir::Value> lengths, mlir::Value tdesc);
345 /// Create constant i1 with value 1. if \p b is true or 0. otherwise
346 mlir::Value createBool(mlir::Location loc, bool b) {
347 return createIntegerConstant(loc, getIntegerType(1), b ? 1 : 0);
350 //===--------------------------------------------------------------------===//
351 // If-Then-Else generation helper
352 //===--------------------------------------------------------------------===//
354 /// Helper class to create if-then-else in a structured way:
355 /// Usage: genIfOp().genThen([&](){...}).genElse([&](){...}).end();
356 /// Alternatively, getResults() can be used instead of end() to end the ifOp
357 /// and get the ifOp results.
358 class IfBuilder {
359 public:
360 IfBuilder(fir::IfOp ifOp, FirOpBuilder &builder)
361 : ifOp{ifOp}, builder{builder} {}
362 template <typename CC>
363 IfBuilder &genThen(CC func) {
364 builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
365 func();
366 return *this;
368 template <typename CC>
369 IfBuilder &genElse(CC func) {
370 assert(!ifOp.getElseRegion().empty() && "must have else region");
371 builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
372 func();
373 return *this;
375 void end() { builder.setInsertionPointAfter(ifOp); }
377 /// End the IfOp and return the results if any.
378 mlir::Operation::result_range getResults() {
379 end();
380 return ifOp.getResults();
383 fir::IfOp &getIfOp() { return ifOp; };
385 private:
386 fir::IfOp ifOp;
387 FirOpBuilder &builder;
390 /// Create an IfOp and returns an IfBuilder that can generate the else/then
391 /// bodies.
392 IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results,
393 mlir::Value cdt, bool withElseRegion) {
394 auto op = create<fir::IfOp>(loc, results, cdt, withElseRegion);
395 return IfBuilder(op, *this);
398 /// Create an IfOp with no "else" region, and no result values.
399 /// Usage: genIfThen(loc, cdt).genThen(lambda).end();
400 IfBuilder genIfThen(mlir::Location loc, mlir::Value cdt) {
401 auto op = create<fir::IfOp>(loc, std::nullopt, cdt, false);
402 return IfBuilder(op, *this);
405 /// Create an IfOp with an "else" region, and no result values.
406 /// Usage: genIfThenElse(loc, cdt).genThen(lambda).genElse(lambda).end();
407 IfBuilder genIfThenElse(mlir::Location loc, mlir::Value cdt) {
408 auto op = create<fir::IfOp>(loc, std::nullopt, cdt, true);
409 return IfBuilder(op, *this);
412 mlir::Value genNot(mlir::Location loc, mlir::Value boolean) {
413 return create<mlir::arith::CmpIOp>(loc, mlir::arith::CmpIPredicate::eq,
414 boolean, createBool(loc, false));
417 /// Generate code testing \p addr is not a null address.
418 mlir::Value genIsNotNullAddr(mlir::Location loc, mlir::Value addr);
420 /// Generate code testing \p addr is a null address.
421 mlir::Value genIsNullAddr(mlir::Location loc, mlir::Value addr);
423 /// Compute the extent of (lb:ub:step) as max((ub-lb+step)/step, 0). See
424 /// Fortran 2018 9.5.3.3.2 section for more details.
425 mlir::Value genExtentFromTriplet(mlir::Location loc, mlir::Value lb,
426 mlir::Value ub, mlir::Value step,
427 mlir::Type type);
429 /// Create an AbsentOp of \p argTy type and handle special cases, such as
430 /// Character Procedure Tuple arguments.
431 mlir::Value genAbsentOp(mlir::Location loc, mlir::Type argTy);
433 /// Set default FastMathFlags value for all operations
434 /// supporting mlir::arith::FastMathAttr that will be created
435 /// by this builder.
436 void setFastMathFlags(mlir::arith::FastMathFlags flags) {
437 fastMathFlags = flags;
440 /// Set default FastMathFlags value from the passed MathOptionsBase
441 /// config.
442 void setFastMathFlags(Fortran::common::MathOptionsBase options);
444 /// Get current FastMathFlags value.
445 mlir::arith::FastMathFlags getFastMathFlags() const { return fastMathFlags; }
447 /// Dump the current function. (debug)
448 LLVM_DUMP_METHOD void dumpFunc();
450 /// FirOpBuilder hook for creating new operation.
451 void notifyOperationInserted(mlir::Operation *op) override {
452 setCommonAttributes(op);
455 private:
456 /// Set attributes (e.g. FastMathAttr) to \p op operation
457 /// based on the current attributes setting.
458 void setCommonAttributes(mlir::Operation *op) const;
460 const KindMapping &kindMap;
462 /// FastMathFlags that need to be set for operations that support
463 /// mlir::arith::FastMathAttr.
464 mlir::arith::FastMathFlags fastMathFlags{};
467 } // namespace fir
469 namespace fir::factory {
471 //===----------------------------------------------------------------------===//
472 // ExtendedValue inquiry helpers
473 //===----------------------------------------------------------------------===//
475 /// Read or get character length from \p box that must contain a character
476 /// entity. If the length value is contained in the ExtendedValue, this will
477 /// not generate any code, otherwise this will generate a read of the fir.box
478 /// describing the entity.
479 mlir::Value readCharLen(fir::FirOpBuilder &builder, mlir::Location loc,
480 const fir::ExtendedValue &box);
482 /// Read or get the extent in dimension \p dim of the array described by \p box.
483 mlir::Value readExtent(fir::FirOpBuilder &builder, mlir::Location loc,
484 const fir::ExtendedValue &box, unsigned dim);
486 /// Read or get the lower bound in dimension \p dim of the array described by
487 /// \p box. If the lower bound is left default in the ExtendedValue,
488 /// \p defaultValue will be returned.
489 mlir::Value readLowerBound(fir::FirOpBuilder &builder, mlir::Location loc,
490 const fir::ExtendedValue &box, unsigned dim,
491 mlir::Value defaultValue);
493 /// Read extents from \p box.
494 llvm::SmallVector<mlir::Value> readExtents(fir::FirOpBuilder &builder,
495 mlir::Location loc,
496 const fir::BoxValue &box);
498 /// Read a fir::BoxValue into an fir::UnboxValue, a fir::ArrayBoxValue or a
499 /// fir::CharArrayBoxValue. This should only be called if the fir::BoxValue is
500 /// known to be contiguous given the context (or if the resulting address will
501 /// not be used). If the value is polymorphic, its dynamic type will be lost.
502 /// This must not be used on unlimited polymorphic and assumed rank entities.
503 fir::ExtendedValue readBoxValue(fir::FirOpBuilder &builder, mlir::Location loc,
504 const fir::BoxValue &box);
506 /// Get the lower bounds of \p exv. NB: returns an empty vector if the lower
507 /// bounds are all ones, which is the default in Fortran.
508 llvm::SmallVector<mlir::Value>
509 getNonDefaultLowerBounds(fir::FirOpBuilder &builder, mlir::Location loc,
510 const fir::ExtendedValue &exv);
512 /// Return LEN parameters associated to \p exv that are not deferred (that are
513 /// available without having to read any fir.box values). Empty if \p exv has no
514 /// LEN parameters or if they are all deferred.
515 llvm::SmallVector<mlir::Value>
516 getNonDeferredLenParams(const fir::ExtendedValue &exv);
518 //===----------------------------------------------------------------------===//
519 // String literal helper helpers
520 //===----------------------------------------------------------------------===//
522 /// Create a !fir.char<1> string literal global and returns a fir::CharBoxValue
523 /// with its address and length.
524 fir::ExtendedValue createStringLiteral(fir::FirOpBuilder &, mlir::Location,
525 llvm::StringRef string);
527 /// Unique a compiler generated identifier. A short prefix should be provided
528 /// to hint at the origin of the identifier.
529 std::string uniqueCGIdent(llvm::StringRef prefix, llvm::StringRef name);
531 /// Lowers the extents from the sequence type to Values.
532 /// Any unknown extents are lowered to undefined values.
533 llvm::SmallVector<mlir::Value> createExtents(fir::FirOpBuilder &builder,
534 mlir::Location loc,
535 fir::SequenceType seqTy);
537 //===--------------------------------------------------------------------===//
538 // Location helpers
539 //===--------------------------------------------------------------------===//
541 /// Generate a string literal containing the file name and return its address
542 mlir::Value locationToFilename(fir::FirOpBuilder &, mlir::Location);
543 /// Generate a constant of the given type with the location line number
544 mlir::Value locationToLineNo(fir::FirOpBuilder &, mlir::Location, mlir::Type);
546 //===--------------------------------------------------------------------===//
547 // ExtendedValue helpers
548 //===--------------------------------------------------------------------===//
550 /// Return the extended value for a component of a derived type instance given
551 /// the address of the component.
552 fir::ExtendedValue componentToExtendedValue(fir::FirOpBuilder &builder,
553 mlir::Location loc,
554 mlir::Value component);
556 /// Given the address of an array element and the ExtendedValue describing the
557 /// array, returns the ExtendedValue describing the array element. The purpose
558 /// is to propagate the LEN parameters of the array to the element. This can be
559 /// used for elements of `array` or `array(i:j:k)`. If \p element belongs to an
560 /// array section `array%x` whose base is \p array,
561 /// arraySectionElementToExtendedValue must be used instead.
562 fir::ExtendedValue arrayElementToExtendedValue(fir::FirOpBuilder &builder,
563 mlir::Location loc,
564 const fir::ExtendedValue &array,
565 mlir::Value element);
567 /// Build the ExtendedValue for \p element that is an element of an array or
568 /// array section with \p array base (`array` or `array(i:j:k)%x%y`).
569 /// If it is an array section, \p slice must be provided and be a fir::SliceOp
570 /// that describes the section.
571 fir::ExtendedValue arraySectionElementToExtendedValue(
572 fir::FirOpBuilder &builder, mlir::Location loc,
573 const fir::ExtendedValue &array, mlir::Value element, mlir::Value slice);
575 /// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalars. The
576 /// assignment follows Fortran intrinsic assignment semantic (10.2.1.3).
577 void genScalarAssignment(fir::FirOpBuilder &builder, mlir::Location loc,
578 const fir::ExtendedValue &lhs,
579 const fir::ExtendedValue &rhs);
580 /// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalar derived
581 /// types. The assignment follows Fortran intrinsic assignment semantic for
582 /// derived types (10.2.1.3 point 13).
583 void genRecordAssignment(fir::FirOpBuilder &builder, mlir::Location loc,
584 const fir::ExtendedValue &lhs,
585 const fir::ExtendedValue &rhs,
586 bool needFinalization = false);
588 /// Builds and returns the type of a ragged array header used to cache mask
589 /// evaluations. RaggedArrayHeader is defined in
590 /// flang/include/flang/Runtime/ragged.h.
591 mlir::TupleType getRaggedArrayHeaderType(fir::FirOpBuilder &builder);
593 /// Generate the, possibly dynamic, LEN of a CHARACTER. \p arrLoad determines
594 /// the base array. After applying \p path, the result must be a reference to a
595 /// `!fir.char` type object. \p substring must have 0, 1, or 2 members. The
596 /// first member is the starting offset. The second is the ending offset.
597 mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc,
598 fir::ArrayLoadOp arrLoad,
599 llvm::ArrayRef<mlir::Value> path,
600 llvm::ArrayRef<mlir::Value> substring);
601 mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc,
602 fir::SequenceType seqTy, mlir::Value memref,
603 llvm::ArrayRef<mlir::Value> typeParams,
604 llvm::ArrayRef<mlir::Value> path,
605 llvm::ArrayRef<mlir::Value> substring);
607 /// Create the zero value of a given the numerical or logical \p type (`false`
608 /// for logical types).
609 mlir::Value createZeroValue(fir::FirOpBuilder &builder, mlir::Location loc,
610 mlir::Type type);
612 /// Get the integer constants of triplet and compute the extent.
613 std::optional<std::int64_t> getExtentFromTriplet(mlir::Value lb, mlir::Value ub,
614 mlir::Value stride);
616 /// Generate max(\p value, 0) where \p value is a scalar integer.
617 mlir::Value genMaxWithZero(fir::FirOpBuilder &builder, mlir::Location loc,
618 mlir::Value value);
620 /// The type(C_PTR/C_FUNPTR) is defined as the derived type with only one
621 /// component of integer 64, and the component is the C address. Get the C
622 /// address.
623 mlir::Value genCPtrOrCFunptrAddr(fir::FirOpBuilder &builder, mlir::Location loc,
624 mlir::Value cPtr, mlir::Type ty);
626 /// Get the C address value.
627 mlir::Value genCPtrOrCFunptrValue(fir::FirOpBuilder &builder,
628 mlir::Location loc, mlir::Value cPtr);
630 /// Create a fir.box from a fir::ExtendedValue and wrap it in a fir::BoxValue
631 /// to keep all the lower bound and explicit parameter information.
632 fir::BoxValue createBoxValue(fir::FirOpBuilder &builder, mlir::Location loc,
633 const fir::ExtendedValue &exv);
634 } // namespace fir::factory
636 #endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H