1 //===-- Lower/ConvertExpr.h -- lowering of expressions ----------*- 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 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10 // 11 //===----------------------------------------------------------------------===// 12 /// 13 /// Implements the conversion from Fortran::evaluate::Expr trees to FIR. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #ifndef FORTRAN_LOWER_CONVERTEXPR_H 18 #define FORTRAN_LOWER_CONVERTEXPR_H 19 20 #include "flang/Lower/Support/Utils.h" 21 #include "flang/Optimizer/Builder/BoxValue.h" 22 #include "flang/Optimizer/Builder/FIRBuilder.h" 23 #include <optional> 24 25 namespace mlir { 26 class Location; 27 class Value; 28 } // namespace mlir 29 30 namespace fir { 31 class AllocMemOp; 32 class ArrayLoadOp; 33 class ShapeOp; 34 } // namespace fir 35 36 namespace Fortran::lower { 37 38 class AbstractConverter; 39 class ExplicitIterSpace; 40 class ImplicitIterSpace; 41 class StatementContext; 42 class SymMap; 43 44 /// Create an extended expression value. 45 fir::ExtendedValue createSomeExtendedExpression(mlir::Location loc, 46 AbstractConverter &converter, 47 const SomeExpr &expr, 48 SymMap &symMap, 49 StatementContext &stmtCtx); 50 51 /// Create the IR for the expression \p expr in an initialization context. 52 /// Expressions that appear in initializers may not allocate temporaries, do not 53 /// have a stack, etc. 54 fir::ExtendedValue createSomeInitializerExpression(mlir::Location loc, 55 AbstractConverter &converter, 56 const SomeExpr &expr, 57 SymMap &symMap, 58 StatementContext &stmtCtx); 59 60 /// Create an extended expression address. 61 fir::ExtendedValue createSomeExtendedAddress(mlir::Location loc, 62 AbstractConverter &converter, 63 const SomeExpr &expr, 64 SymMap &symMap, 65 StatementContext &stmtCtx); 66 67 /// Create an address in an initializer context. Must be a constant or a symbol 68 /// to be resolved at link-time. Expressions that appear in initializers may not 69 /// allocate temporaries, do not have a stack, etc. 70 fir::ExtendedValue createInitializerAddress(mlir::Location loc, 71 AbstractConverter &converter, 72 const SomeExpr &expr, 73 SymMap &symMap, 74 StatementContext &stmtCtx); 75 76 /// Create the address of the box. 77 /// \p expr must be the designator of an allocatable/pointer entity. 78 fir::MutableBoxValue createMutableBox(mlir::Location loc, 79 AbstractConverter &converter, 80 const SomeExpr &expr, SymMap &symMap); 81 82 /// Return true iff the expression is pointing to a parent component. 83 bool isParentComponent(const SomeExpr &expr); 84 85 /// Update the extended value to represent the parent component. 86 fir::ExtendedValue updateBoxForParentComponent(AbstractConverter &converter, 87 fir::ExtendedValue exv, 88 const SomeExpr &expr); 89 90 /// Create a fir::BoxValue describing the value of \p expr. 91 /// If \p expr is a variable without vector subscripts, the fir::BoxValue 92 /// described the variable storage. Otherwise, the created fir::BoxValue 93 /// describes a temporary storage containing \p expr evaluation, and clean-up 94 /// for the temporary is added to the provided StatementContext \p stmtCtx. 95 fir::ExtendedValue createBoxValue(mlir::Location loc, 96 AbstractConverter &converter, 97 const SomeExpr &expr, SymMap &symMap, 98 StatementContext &stmtCtx); 99 100 /// Lower an array assignment expression. 101 /// 102 /// 1. Evaluate the lhs to determine the rank and how to form the ArrayLoad 103 /// (e.g., if there is a slicing op). 104 /// 2. Scan the rhs, creating the ArrayLoads and evaluate the scalar subparts to 105 /// be added to the map. 106 /// 3. Create the loop nest and evaluate the elemental expression, threading the 107 /// results. 108 /// 4. Copy the resulting array back with ArrayMergeStore to the lhs as 109 /// determined per step 1. 110 void createSomeArrayAssignment(AbstractConverter &converter, 111 const SomeExpr &lhs, const SomeExpr &rhs, 112 SymMap &symMap, StatementContext &stmtCtx); 113 114 /// Lower an array assignment expression with a pre-evaluated left hand side. 115 /// 116 /// 1. Scan the rhs, creating the ArrayLoads and evaluate the scalar subparts to 117 /// be added to the map. 118 /// 2. Create the loop nest and evaluate the elemental expression, threading the 119 /// results. 120 /// 3. Copy the resulting array back with ArrayMergeStore to the lhs as 121 /// determined per step 1. 122 void createSomeArrayAssignment(AbstractConverter &converter, 123 const fir::ExtendedValue &lhs, 124 const SomeExpr &rhs, SymMap &symMap, 125 StatementContext &stmtCtx); 126 127 /// Lower an array assignment expression with pre-evaluated left and right 128 /// hand sides. This implements an array copy taking into account 129 /// non-contiguity and potential overlaps. 130 void createSomeArrayAssignment(AbstractConverter &converter, 131 const fir::ExtendedValue &lhs, 132 const fir::ExtendedValue &rhs, SymMap &symMap, 133 StatementContext &stmtCtx); 134 135 /// Common entry point for both explicit iteration spaces and implicit iteration 136 /// spaces with masks. 137 /// 138 /// For an implicit iteration space with masking, lowers an array assignment 139 /// expression with masking expression(s). 140 /// 141 /// 1. Evaluate the lhs to determine the rank and how to form the ArrayLoad 142 /// (e.g., if there is a slicing op). 143 /// 2. Scan the rhs, creating the ArrayLoads and evaluate the scalar subparts to 144 /// be added to the map. 145 /// 3. Create the loop nest. 146 /// 4. Create the masking condition. Step 5 is conditionally executed only when 147 /// the mask condition evaluates to true. 148 /// 5. Evaluate the elemental expression, threading the results. 149 /// 6. Copy the resulting array back with ArrayMergeStore to the lhs as 150 /// determined per step 1. 151 /// 152 /// For an explicit iteration space, lower a scalar or array assignment 153 /// expression with a user-defined iteration space and possibly with masking 154 /// expression(s). 155 /// 156 /// If the expression is scalar, then the assignment is an array assignment but 157 /// the array accesses are explicitly defined by the user and not implied for 158 /// each element in the array. Mask expressions are optional. 159 /// 160 /// If the expression has rank, then the assignment has a combined user-defined 161 /// iteration space as well as a inner (subordinate) implied iteration 162 /// space. The implied iteration space may include WHERE conditions, `masks`. 163 void createAnyMaskedArrayAssignment(AbstractConverter &converter, 164 const SomeExpr &lhs, const SomeExpr &rhs, 165 ExplicitIterSpace &explicitIterSpace, 166 ImplicitIterSpace &implicitIterSpace, 167 SymMap &symMap, StatementContext &stmtCtx); 168 169 /// Lower an assignment to an allocatable array, allocating the array if 170 /// it is not allocated yet or reallocation it if it does not conform 171 /// with the right hand side. 172 void createAllocatableArrayAssignment(AbstractConverter &converter, 173 const SomeExpr &lhs, const SomeExpr &rhs, 174 ExplicitIterSpace &explicitIterSpace, 175 ImplicitIterSpace &implicitIterSpace, 176 SymMap &symMap, 177 StatementContext &stmtCtx); 178 179 /// Lower a pointer assignment in an explicit iteration space. The explicit 180 /// space iterates over a data structure with a type of `!fir.array<... 181 /// !fir.box<!fir.ptr<T>> ...>`. Lower the assignment by copying the rhs box 182 /// value to each array element. 183 void createArrayOfPointerAssignment( 184 AbstractConverter &converter, const SomeExpr &lhs, const SomeExpr &rhs, 185 ExplicitIterSpace &explicitIterSpace, ImplicitIterSpace &implicitIterSpace, 186 const llvm::SmallVector<mlir::Value> &lbounds, 187 std::optional<llvm::SmallVector<mlir::Value>> ubounds, SymMap &symMap, 188 StatementContext &stmtCtx); 189 190 /// Lower an array expression with "parallel" semantics. Such a rhs expression 191 /// is fully evaluated prior to being assigned back to a temporary array. 192 fir::ExtendedValue createSomeArrayTempValue(AbstractConverter &converter, 193 const SomeExpr &expr, 194 SymMap &symMap, 195 StatementContext &stmtCtx); 196 197 /// Somewhat similar to createSomeArrayTempValue, but the temporary buffer is 198 /// allocated lazily (inside the loops instead of before the loops) to 199 /// accomodate buffers with shapes that cannot be precomputed. In fact, the 200 /// buffer need not even be hyperrectangular. The buffer may be created as an 201 /// instance of a ragged array, which may be useful if an array's extents are 202 /// functions of other loop indices. The ragged array structure is built with \p 203 /// raggedHeader being the root header variable. The header is a tuple of 204 /// `{rank, data-is-headers, [data]*, [extents]*}`, which is built recursively. 205 /// The base header, \p raggedHeader, must be initialized to zeros. 206 void createLazyArrayTempValue(AbstractConverter &converter, 207 const SomeExpr &expr, mlir::Value raggedHeader, 208 SymMap &symMap, StatementContext &stmtCtx); 209 210 /// Lower an array expression to a value of type box. The expression must be a 211 /// variable. 212 fir::ExtendedValue createSomeArrayBox(AbstractConverter &converter, 213 const SomeExpr &expr, SymMap &symMap, 214 StatementContext &stmtCtx); 215 216 /// Lower a subroutine call. This handles both elemental and non elemental 217 /// subroutines. \p isUserDefAssignment must be set if this is called in the 218 /// context of a user defined assignment. For subroutines with alternate 219 /// returns, the returned value indicates which label the code should jump to. 220 /// The returned value is null otherwise. 221 mlir::Value createSubroutineCall(AbstractConverter &converter, 222 const evaluate::ProcedureRef &call, 223 ExplicitIterSpace &explicitIterSpace, 224 ImplicitIterSpace &implicitIterSpace, 225 SymMap &symMap, StatementContext &stmtCtx, 226 bool isUserDefAssignment); 227 228 mlir::Value addCrayPointerInst(mlir::Location loc, fir::FirOpBuilder &builder, 229 mlir::Value ptrVal, mlir::Type ptrTy, 230 mlir::Type pteTy); 231 } // namespace Fortran::lower 232 233 #endif // FORTRAN_LOWER_CONVERTEXPR_H 234