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