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