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/FIRType.h"
21 #include "flang/Optimizer/Support/KindMapping.h"
22 #include "mlir/IR/Builders.h"
23 #include "mlir/IR/BuiltinOps.h"
24 #include "llvm/ADT/DenseMap.h"
25 #include "llvm/ADT/Optional.h"
26 
27 namespace fir {
28 class AbstractArrayBox;
29 class ExtendedValue;
30 class BoxValue;
31 
32 //===----------------------------------------------------------------------===//
33 // FirOpBuilder
34 //===----------------------------------------------------------------------===//
35 
36 /// Extends the MLIR OpBuilder to provide methods for building common FIR
37 /// patterns.
38 class FirOpBuilder : public mlir::OpBuilder {
39 public:
FirOpBuilder(mlir::Operation * op,const fir::KindMapping & kindMap)40   explicit FirOpBuilder(mlir::Operation *op, const fir::KindMapping &kindMap)
41       : OpBuilder{op}, kindMap{kindMap} {}
FirOpBuilder(mlir::OpBuilder & builder,const fir::KindMapping & kindMap)42   explicit FirOpBuilder(mlir::OpBuilder &builder,
43                         const fir::KindMapping &kindMap)
44       : OpBuilder{builder}, kindMap{kindMap} {}
45 
46   /// Get the current Region of the insertion point.
getRegion()47   mlir::Region &getRegion() { return *getBlock()->getParent(); }
48 
49   /// Get the current Module
getModule()50   mlir::ModuleOp getModule() {
51     return getRegion().getParentOfType<mlir::ModuleOp>();
52   }
53 
54   /// Get the current Function
getFunction()55   mlir::func::FuncOp getFunction() {
56     return getRegion().getParentOfType<mlir::func::FuncOp>();
57   }
58 
59   /// Get a reference to the kind map.
getKindMap()60   const fir::KindMapping &getKindMap() { return kindMap; }
61 
62   /// Get the default integer type
getDefaultIntegerType()63   [[maybe_unused]] mlir::IntegerType getDefaultIntegerType() {
64     return getIntegerType(
65         getKindMap().getIntegerBitsize(getKindMap().defaultIntegerKind()));
66   }
67 
68   /// The LHS and RHS are not always in agreement in terms of type. In some
69   /// cases, the disagreement is between COMPLEX and other scalar types. In that
70   /// case, the conversion must insert (extract) out of a COMPLEX value to have
71   /// the proper semantics and be strongly typed. E.g., converting an integer
72   /// (real) to a complex, the real part is filled using the integer (real)
73   /// after type conversion and the imaginary part is zero.
74   mlir::Value convertWithSemantics(mlir::Location loc, mlir::Type toTy,
75                                    mlir::Value val,
76                                    bool allowCharacterConversion = false);
77 
78   /// Get the entry block of the current Function
getEntryBlock()79   mlir::Block *getEntryBlock() { return &getFunction().front(); }
80 
81   /// Get the block for adding Allocas. If OpenMP is enabled then get the
82   /// the alloca block from an Operation which can be Outlined. Otherwise
83   /// use the entry block of the current Function
84   mlir::Block *getAllocaBlock();
85 
86   /// Safely create a reference type to the type `eleTy`.
87   mlir::Type getRefType(mlir::Type eleTy);
88 
89   /// Create a sequence of `eleTy` with `rank` dimensions of unknown size.
90   mlir::Type getVarLenSeqTy(mlir::Type eleTy, unsigned rank = 1);
91 
92   /// Get character length type.
getCharacterLengthType()93   mlir::Type getCharacterLengthType() { return getIndexType(); }
94 
95   /// Get the integer type whose bit width corresponds to the width of pointer
96   /// types, or is bigger.
getIntPtrType()97   mlir::Type getIntPtrType() {
98     // TODO: Delay the need of such type until codegen or find a way to use
99     // llvm::DataLayout::getPointerSizeInBits here.
100     return getI64Type();
101   }
102 
103   /// Wrap `str` to a SymbolRefAttr.
getSymbolRefAttr(llvm::StringRef str)104   mlir::SymbolRefAttr getSymbolRefAttr(llvm::StringRef str) {
105     return mlir::SymbolRefAttr::get(getContext(), str);
106   }
107 
108   /// Get the mlir float type that implements Fortran REAL(kind).
109   mlir::Type getRealType(int kind);
110 
getBoxProcType(mlir::FunctionType funcTy)111   fir::BoxProcType getBoxProcType(mlir::FunctionType funcTy) {
112     return fir::BoxProcType::get(getContext(), funcTy);
113   }
114 
115   /// Create a null constant memory reference of type \p ptrType.
116   /// If \p ptrType is not provided, !fir.ref<none> type will be used.
117   mlir::Value createNullConstant(mlir::Location loc, mlir::Type ptrType = {});
118 
119   /// Create an integer constant of type \p type and value \p i.
120   mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType,
121                                     std::int64_t i);
122 
123   /// Create a real constant from an integer value.
124   mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType,
125                                  llvm::APFloat::integerPart val);
126 
127   /// Create a real constant from an APFloat value.
128   mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType,
129                                  const llvm::APFloat &val);
130 
131   /// Create a real constant of type \p realType with a value zero.
createRealZeroConstant(mlir::Location loc,mlir::Type realType)132   mlir::Value createRealZeroConstant(mlir::Location loc, mlir::Type realType) {
133     return createRealConstant(loc, realType, 0u);
134   }
135 
136   /// Create a slot for a local on the stack. Besides the variable's type and
137   /// shape, it may be given name, pinned, or target attributes.
138   mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty,
139                             llvm::StringRef uniqName, llvm::StringRef name,
140                             bool pinned, llvm::ArrayRef<mlir::Value> shape,
141                             llvm::ArrayRef<mlir::Value> lenParams,
142                             bool asTarget = false);
143   mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty,
144                             llvm::StringRef uniqName, llvm::StringRef name,
145                             llvm::ArrayRef<mlir::Value> shape,
146                             llvm::ArrayRef<mlir::Value> lenParams,
147                             bool asTarget = false);
148 
149   /// Create a temporary. A temp is allocated using `fir.alloca` and can be read
150   /// and written using `fir.load` and `fir.store`, resp.  The temporary can be
151   /// given a name via a front-end `Symbol` or a `StringRef`.
152   mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
153                               llvm::StringRef name = {},
154                               mlir::ValueRange shape = {},
155                               mlir::ValueRange lenParams = {},
156                               llvm::ArrayRef<mlir::NamedAttribute> attrs = {});
157 
158   /// Create an unnamed and untracked temporary on the stack.
createTemporary(mlir::Location loc,mlir::Type type,mlir::ValueRange shape)159   mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
160                               mlir::ValueRange shape) {
161     return createTemporary(loc, type, llvm::StringRef{}, shape);
162   }
163 
createTemporary(mlir::Location loc,mlir::Type type,llvm::ArrayRef<mlir::NamedAttribute> attrs)164   mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
165                               llvm::ArrayRef<mlir::NamedAttribute> attrs) {
166     return createTemporary(loc, type, llvm::StringRef{}, {}, {}, attrs);
167   }
168 
createTemporary(mlir::Location loc,mlir::Type type,llvm::StringRef name,llvm::ArrayRef<mlir::NamedAttribute> attrs)169   mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
170                               llvm::StringRef name,
171                               llvm::ArrayRef<mlir::NamedAttribute> attrs) {
172     return createTemporary(loc, type, name, {}, {}, attrs);
173   }
174 
175   /// Create a global value.
176   fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type,
177                              llvm::StringRef name,
178                              mlir::StringAttr linkage = {},
179                              mlir::Attribute value = {}, bool isConst = false);
180 
181   fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type,
182                              llvm::StringRef name, bool isConst,
183                              std::function<void(FirOpBuilder &)> bodyBuilder,
184                              mlir::StringAttr linkage = {});
185 
186   /// Create a global constant (read-only) value.
187   fir::GlobalOp createGlobalConstant(mlir::Location loc, mlir::Type type,
188                                      llvm::StringRef name,
189                                      mlir::StringAttr linkage = {},
190                                      mlir::Attribute value = {}) {
191     return createGlobal(loc, type, name, linkage, value, /*isConst=*/true);
192   }
193 
194   fir::GlobalOp
195   createGlobalConstant(mlir::Location loc, mlir::Type type,
196                        llvm::StringRef name,
197                        std::function<void(FirOpBuilder &)> bodyBuilder,
198                        mlir::StringAttr linkage = {}) {
199     return createGlobal(loc, type, name, /*isConst=*/true, bodyBuilder,
200                         linkage);
201   }
202 
203   /// Convert a StringRef string into a fir::StringLitOp.
204   fir::StringLitOp createStringLitOp(mlir::Location loc,
205                                      llvm::StringRef string);
206 
207   //===--------------------------------------------------------------------===//
208   // Linkage helpers (inline). The default linkage is external.
209   //===--------------------------------------------------------------------===//
210 
createCommonLinkage()211   mlir::StringAttr createCommonLinkage() { return getStringAttr("common"); }
212 
createInternalLinkage()213   mlir::StringAttr createInternalLinkage() { return getStringAttr("internal"); }
214 
createLinkOnceLinkage()215   mlir::StringAttr createLinkOnceLinkage() { return getStringAttr("linkonce"); }
216 
createLinkOnceODRLinkage()217   mlir::StringAttr createLinkOnceODRLinkage() {
218     return getStringAttr("linkonce_odr");
219   }
220 
createWeakLinkage()221   mlir::StringAttr createWeakLinkage() { return getStringAttr("weak"); }
222 
223   /// Get a function by name. If the function exists in the current module, it
224   /// is returned. Otherwise, a null FuncOp is returned.
getNamedFunction(llvm::StringRef name)225   mlir::func::FuncOp getNamedFunction(llvm::StringRef name) {
226     return getNamedFunction(getModule(), name);
227   }
228   static mlir::func::FuncOp getNamedFunction(mlir::ModuleOp module,
229                                              llvm::StringRef name);
230 
231   /// Get a function by symbol name. The result will be null if there is no
232   /// function with the given symbol in the module.
getNamedFunction(mlir::SymbolRefAttr symbol)233   mlir::func::FuncOp getNamedFunction(mlir::SymbolRefAttr symbol) {
234     return getNamedFunction(getModule(), symbol);
235   }
236   static mlir::func::FuncOp getNamedFunction(mlir::ModuleOp module,
237                                              mlir::SymbolRefAttr symbol);
238 
getNamedGlobal(llvm::StringRef name)239   fir::GlobalOp getNamedGlobal(llvm::StringRef name) {
240     return getNamedGlobal(getModule(), name);
241   }
242 
243   static fir::GlobalOp getNamedGlobal(mlir::ModuleOp module,
244                                       llvm::StringRef name);
245 
246   /// Lazy creation of fir.convert op.
247   mlir::Value createConvert(mlir::Location loc, mlir::Type toTy,
248                             mlir::Value val);
249 
250   /// Create a fir.store of \p val into \p addr. A lazy conversion
251   /// of \p val to the element type of \p addr is created if needed.
252   void createStoreWithConvert(mlir::Location loc, mlir::Value val,
253                               mlir::Value addr);
254 
255   /// Create a new FuncOp. If the function may have already been created, use
256   /// `addNamedFunction` instead.
createFunction(mlir::Location loc,llvm::StringRef name,mlir::FunctionType ty)257   mlir::func::FuncOp createFunction(mlir::Location loc, llvm::StringRef name,
258                                     mlir::FunctionType ty) {
259     return createFunction(loc, getModule(), name, ty);
260   }
261 
262   static mlir::func::FuncOp createFunction(mlir::Location loc,
263                                            mlir::ModuleOp module,
264                                            llvm::StringRef name,
265                                            mlir::FunctionType ty);
266 
267   /// Determine if the named function is already in the module. Return the
268   /// instance if found, otherwise add a new named function to the module.
addNamedFunction(mlir::Location loc,llvm::StringRef name,mlir::FunctionType ty)269   mlir::func::FuncOp addNamedFunction(mlir::Location loc, llvm::StringRef name,
270                                       mlir::FunctionType ty) {
271     if (auto func = getNamedFunction(name))
272       return func;
273     return createFunction(loc, name, ty);
274   }
275 
addNamedFunction(mlir::Location loc,mlir::ModuleOp module,llvm::StringRef name,mlir::FunctionType ty)276   static mlir::func::FuncOp addNamedFunction(mlir::Location loc,
277                                              mlir::ModuleOp module,
278                                              llvm::StringRef name,
279                                              mlir::FunctionType ty) {
280     if (auto func = getNamedFunction(module, name))
281       return func;
282     return createFunction(loc, module, name, ty);
283   }
284 
285   /// Cast the input value to IndexType.
convertToIndexType(mlir::Location loc,mlir::Value val)286   mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) {
287     return createConvert(loc, getIndexType(), val);
288   }
289 
290   /// Construct one of the two forms of shape op from an array box.
291   mlir::Value genShape(mlir::Location loc, const fir::AbstractArrayBox &arr);
292   mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift,
293                        llvm::ArrayRef<mlir::Value> exts);
294   mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> exts);
295 
296   /// Create one of the shape ops given an extended value. For a boxed value,
297   /// this may create a `fir.shift` op.
298   mlir::Value createShape(mlir::Location loc, const fir::ExtendedValue &exv);
299 
300   /// Create a slice op extended value. The value to be sliced, `exv`, must be
301   /// an array.
302   mlir::Value createSlice(mlir::Location loc, const fir::ExtendedValue &exv,
303                           mlir::ValueRange triples, mlir::ValueRange path);
304 
305   /// Create a boxed value (Fortran descriptor) to be passed to the runtime.
306   /// \p exv is an extended value holding a memory reference to the object that
307   /// must be boxed. This function will crash if provided something that is not
308   /// a memory reference type.
309   /// Array entities are boxed with a shape and possibly a shift. Character
310   /// entities are boxed with a LEN parameter.
311   mlir::Value createBox(mlir::Location loc, const fir::ExtendedValue &exv);
312 
313   /// Create constant i1 with value 1. if \p b is true or 0. otherwise
createBool(mlir::Location loc,bool b)314   mlir::Value createBool(mlir::Location loc, bool b) {
315     return createIntegerConstant(loc, getIntegerType(1), b ? 1 : 0);
316   }
317 
318   //===--------------------------------------------------------------------===//
319   // If-Then-Else generation helper
320   //===--------------------------------------------------------------------===//
321 
322   /// Helper class to create if-then-else in a structured way:
323   /// Usage: genIfOp().genThen([&](){...}).genElse([&](){...}).end();
324   /// Alternatively, getResults() can be used instead of end() to end the ifOp
325   /// and get the ifOp results.
326   class IfBuilder {
327   public:
IfBuilder(fir::IfOp ifOp,FirOpBuilder & builder)328     IfBuilder(fir::IfOp ifOp, FirOpBuilder &builder)
329         : ifOp{ifOp}, builder{builder} {}
330     template <typename CC>
genThen(CC func)331     IfBuilder &genThen(CC func) {
332       builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
333       func();
334       return *this;
335     }
336     template <typename CC>
genElse(CC func)337     IfBuilder &genElse(CC func) {
338       assert(!ifOp.getElseRegion().empty() && "must have else region");
339       builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
340       func();
341       return *this;
342     }
end()343     void end() { builder.setInsertionPointAfter(ifOp); }
344 
345     /// End the IfOp and return the results if any.
getResults()346     mlir::Operation::result_range getResults() {
347       end();
348       return ifOp.getResults();
349     }
350 
getIfOp()351     fir::IfOp &getIfOp() { return ifOp; };
352 
353   private:
354     fir::IfOp ifOp;
355     FirOpBuilder &builder;
356   };
357 
358   /// Create an IfOp and returns an IfBuilder that can generate the else/then
359   /// bodies.
genIfOp(mlir::Location loc,mlir::TypeRange results,mlir::Value cdt,bool withElseRegion)360   IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results,
361                     mlir::Value cdt, bool withElseRegion) {
362     auto op = create<fir::IfOp>(loc, results, cdt, withElseRegion);
363     return IfBuilder(op, *this);
364   }
365 
366   /// Create an IfOp with no "else" region, and no result values.
367   /// Usage: genIfThen(loc, cdt).genThen(lambda).end();
genIfThen(mlir::Location loc,mlir::Value cdt)368   IfBuilder genIfThen(mlir::Location loc, mlir::Value cdt) {
369     auto op = create<fir::IfOp>(loc, llvm::None, cdt, false);
370     return IfBuilder(op, *this);
371   }
372 
373   /// Create an IfOp with an "else" region, and no result values.
374   /// Usage: genIfThenElse(loc, cdt).genThen(lambda).genElse(lambda).end();
genIfThenElse(mlir::Location loc,mlir::Value cdt)375   IfBuilder genIfThenElse(mlir::Location loc, mlir::Value cdt) {
376     auto op = create<fir::IfOp>(loc, llvm::None, cdt, true);
377     return IfBuilder(op, *this);
378   }
379 
380   /// Generate code testing \p addr is not a null address.
381   mlir::Value genIsNotNullAddr(mlir::Location loc, mlir::Value addr);
382 
383   /// Generate code testing \p addr is a null address.
384   mlir::Value genIsNullAddr(mlir::Location loc, mlir::Value addr);
385 
386   /// Compute the extent of (lb:ub:step) as max((ub-lb+step)/step, 0). See
387   /// Fortran 2018 9.5.3.3.2 section for more details.
388   mlir::Value genExtentFromTriplet(mlir::Location loc, mlir::Value lb,
389                                    mlir::Value ub, mlir::Value step,
390                                    mlir::Type type);
391 
392   /// Dump the current function. (debug)
393   LLVM_DUMP_METHOD void dumpFunc();
394 
395 private:
396   const KindMapping &kindMap;
397 };
398 
399 } // namespace fir
400 
401 namespace fir::factory {
402 
403 //===----------------------------------------------------------------------===//
404 // ExtendedValue inquiry helpers
405 //===----------------------------------------------------------------------===//
406 
407 /// Read or get character length from \p box that must contain a character
408 /// entity. If the length value is contained in the ExtendedValue, this will
409 /// not generate any code, otherwise this will generate a read of the fir.box
410 /// describing the entity.
411 mlir::Value readCharLen(fir::FirOpBuilder &builder, mlir::Location loc,
412                         const fir::ExtendedValue &box);
413 
414 /// Read or get the extent in dimension \p dim of the array described by \p box.
415 mlir::Value readExtent(fir::FirOpBuilder &builder, mlir::Location loc,
416                        const fir::ExtendedValue &box, unsigned dim);
417 
418 /// Read or get the lower bound in dimension \p dim of the array described by
419 /// \p box. If the lower bound is left default in the ExtendedValue,
420 /// \p defaultValue will be returned.
421 mlir::Value readLowerBound(fir::FirOpBuilder &builder, mlir::Location loc,
422                            const fir::ExtendedValue &box, unsigned dim,
423                            mlir::Value defaultValue);
424 
425 /// Read extents from \p box.
426 llvm::SmallVector<mlir::Value> readExtents(fir::FirOpBuilder &builder,
427                                            mlir::Location loc,
428                                            const fir::BoxValue &box);
429 
430 /// Read a fir::BoxValue into an fir::UnboxValue, a fir::ArrayBoxValue or a
431 /// fir::CharArrayBoxValue. This should only be called if the fir::BoxValue is
432 /// known to be contiguous given the context (or if the resulting address will
433 /// not be used). If the value is polymorphic, its dynamic type will be lost.
434 /// This must not be used on unlimited polymorphic and assumed rank entities.
435 fir::ExtendedValue readBoxValue(fir::FirOpBuilder &builder, mlir::Location loc,
436                                 const fir::BoxValue &box);
437 
438 /// Get the lower bounds of \p exv. NB: returns an empty vector if the lower
439 /// bounds are all ones, which is the default in Fortran.
440 llvm::SmallVector<mlir::Value>
441 getNonDefaultLowerBounds(fir::FirOpBuilder &builder, mlir::Location loc,
442                          const fir::ExtendedValue &exv);
443 
444 /// Return LEN parameters associated to \p exv that are not deferred (that are
445 /// available without having to read any fir.box values). Empty if \p exv has no
446 /// LEN parameters or if they are all deferred.
447 llvm::SmallVector<mlir::Value>
448 getNonDeferredLenParams(const fir::ExtendedValue &exv);
449 
450 //===----------------------------------------------------------------------===//
451 // String literal helper helpers
452 //===----------------------------------------------------------------------===//
453 
454 /// Create a !fir.char<1> string literal global and returns a fir::CharBoxValue
455 /// with its address and length.
456 fir::ExtendedValue createStringLiteral(fir::FirOpBuilder &, mlir::Location,
457                                        llvm::StringRef string);
458 
459 /// Unique a compiler generated identifier. A short prefix should be provided
460 /// to hint at the origin of the identifier.
461 std::string uniqueCGIdent(llvm::StringRef prefix, llvm::StringRef name);
462 
463 /// Lowers the extents from the sequence type to Values.
464 /// Any unknown extents are lowered to undefined values.
465 llvm::SmallVector<mlir::Value> createExtents(fir::FirOpBuilder &builder,
466                                              mlir::Location loc,
467                                              fir::SequenceType seqTy);
468 
469 //===--------------------------------------------------------------------===//
470 // Location helpers
471 //===--------------------------------------------------------------------===//
472 
473 /// Generate a string literal containing the file name and return its address
474 mlir::Value locationToFilename(fir::FirOpBuilder &, mlir::Location);
475 /// Generate a constant of the given type with the location line number
476 mlir::Value locationToLineNo(fir::FirOpBuilder &, mlir::Location, mlir::Type);
477 
478 //===--------------------------------------------------------------------===//
479 // ExtendedValue helpers
480 //===--------------------------------------------------------------------===//
481 
482 /// Return the extended value for a component of a derived type instance given
483 /// the address of the component.
484 fir::ExtendedValue componentToExtendedValue(fir::FirOpBuilder &builder,
485                                             mlir::Location loc,
486                                             mlir::Value component);
487 
488 /// Given the address of an array element and the ExtendedValue describing the
489 /// array, returns the ExtendedValue describing the array element. The purpose
490 /// is to propagate the LEN parameters of the array to the element. This can be
491 /// used for elements of `array` or `array(i:j:k)`. If \p element belongs to an
492 /// array section `array%x` whose base is \p array,
493 /// arraySectionElementToExtendedValue must be used instead.
494 fir::ExtendedValue arrayElementToExtendedValue(fir::FirOpBuilder &builder,
495                                                mlir::Location loc,
496                                                const fir::ExtendedValue &array,
497                                                mlir::Value element);
498 
499 /// Build the ExtendedValue for \p element that is an element of an array or
500 /// array section with \p array base (`array` or `array(i:j:k)%x%y`).
501 /// If it is an array section, \p slice must be provided and be a fir::SliceOp
502 /// that describes the section.
503 fir::ExtendedValue arraySectionElementToExtendedValue(
504     fir::FirOpBuilder &builder, mlir::Location loc,
505     const fir::ExtendedValue &array, mlir::Value element, mlir::Value slice);
506 
507 /// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalars. The
508 /// assignment follows Fortran intrinsic assignment semantic (10.2.1.3).
509 void genScalarAssignment(fir::FirOpBuilder &builder, mlir::Location loc,
510                          const fir::ExtendedValue &lhs,
511                          const fir::ExtendedValue &rhs);
512 /// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalar derived
513 /// types. The assignment follows Fortran intrinsic assignment semantic for
514 /// derived types (10.2.1.3 point 13).
515 void genRecordAssignment(fir::FirOpBuilder &builder, mlir::Location loc,
516                          const fir::ExtendedValue &lhs,
517                          const fir::ExtendedValue &rhs);
518 
519 /// Builds and returns the type of a ragged array header used to cache mask
520 /// evaluations. RaggedArrayHeader is defined in
521 /// flang/include/flang/Runtime/ragged.h.
522 mlir::TupleType getRaggedArrayHeaderType(fir::FirOpBuilder &builder);
523 
524 /// Generate the, possibly dynamic, LEN of a CHARACTER. \p arrLoad determines
525 /// the base array. After applying \p path, the result must be a reference to a
526 /// `!fir.char` type object. \p substring must have 0, 1, or 2 members. The
527 /// first member is the starting offset. The second is the ending offset.
528 mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc,
529                               fir::ArrayLoadOp arrLoad,
530                               llvm::ArrayRef<mlir::Value> path,
531                               llvm::ArrayRef<mlir::Value> substring);
532 mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc,
533                               fir::SequenceType seqTy, mlir::Value memref,
534                               llvm::ArrayRef<mlir::Value> typeParams,
535                               llvm::ArrayRef<mlir::Value> path,
536                               llvm::ArrayRef<mlir::Value> substring);
537 
538 /// Create the zero value of a given the numerical or logical \p type (`false`
539 /// for logical types).
540 mlir::Value createZeroValue(fir::FirOpBuilder &builder, mlir::Location loc,
541                             mlir::Type type);
542 
543 /// Unwrap integer constant from an mlir::Value.
544 llvm::Optional<std::int64_t> getIntIfConstant(mlir::Value value);
545 
546 /// Get the integer constants of triplet and compute the extent.
547 llvm::Optional<std::int64_t>
548 getExtentFromTriplet(mlir::Value lb, mlir::Value ub, mlir::Value stride);
549 
550 /// Generate max(\p value, 0) where \p value is a scalar integer.
551 mlir::Value genMaxWithZero(fir::FirOpBuilder &builder, mlir::Location loc,
552                            mlir::Value value);
553 
554 } // namespace fir::factory
555 
556 #endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H
557