1 //===-- FirBuilder.h -- FIR operation builder -------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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
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"
30 class AbstractArrayBox
;
32 class MutableBoxValue
;
35 //===----------------------------------------------------------------------===//
37 //===----------------------------------------------------------------------===//
39 /// Extends the MLIR OpBuilder to provide methods for building common FIR
41 class FirOpBuilder
: public mlir::OpBuilder
, public mlir::OpBuilder::Listener
{
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
} {
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
} {
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
,
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.
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
,
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.
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,
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
,
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
,
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
))
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
))
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
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.
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());
368 template <typename CC
>
369 IfBuilder
&genElse(CC func
) {
370 assert(!ifOp
.getElseRegion().empty() && "must have else region");
371 builder
.setInsertionPointToStart(&ifOp
.getElseRegion().front());
375 void end() { builder
.setInsertionPointAfter(ifOp
); }
377 /// End the IfOp and return the results if any.
378 mlir::Operation::result_range
getResults() {
380 return ifOp
.getResults();
383 fir::IfOp
&getIfOp() { return ifOp
; };
387 FirOpBuilder
&builder
;
390 /// Create an IfOp and returns an IfBuilder that can generate the else/then
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
,
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
436 void setFastMathFlags(mlir::arith::FastMathFlags flags
) {
437 fastMathFlags
= flags
;
440 /// Set default FastMathFlags value from the passed MathOptionsBase
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
);
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
{};
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
,
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
,
535 fir::SequenceType seqTy
);
537 //===--------------------------------------------------------------------===//
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
,
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
,
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
,
612 /// Get the integer constants of triplet and compute the extent.
613 std::optional
<std::int64_t> getExtentFromTriplet(mlir::Value lb
, mlir::Value ub
,
616 /// Generate max(\p value, 0) where \p value is a scalar integer.
617 mlir::Value
genMaxWithZero(fir::FirOpBuilder
&builder
, mlir::Location loc
,
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
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