1 | //===-- ConvertExprToHLFIR.cpp --------------------------------------------===// |
---|---|
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 | #include "flang/Lower/ConvertExprToHLFIR.h" |
14 | #include "flang/Evaluate/shape.h" |
15 | #include "flang/Lower/AbstractConverter.h" |
16 | #include "flang/Lower/Allocatable.h" |
17 | #include "flang/Lower/CallInterface.h" |
18 | #include "flang/Lower/ConvertArrayConstructor.h" |
19 | #include "flang/Lower/ConvertCall.h" |
20 | #include "flang/Lower/ConvertConstant.h" |
21 | #include "flang/Lower/ConvertProcedureDesignator.h" |
22 | #include "flang/Lower/ConvertType.h" |
23 | #include "flang/Lower/ConvertVariable.h" |
24 | #include "flang/Lower/StatementContext.h" |
25 | #include "flang/Lower/SymbolMap.h" |
26 | #include "flang/Optimizer/Builder/Complex.h" |
27 | #include "flang/Optimizer/Builder/IntrinsicCall.h" |
28 | #include "flang/Optimizer/Builder/MutableBox.h" |
29 | #include "flang/Optimizer/Builder/Runtime/Character.h" |
30 | #include "flang/Optimizer/Builder/Runtime/Derived.h" |
31 | #include "flang/Optimizer/Builder/Runtime/Pointer.h" |
32 | #include "flang/Optimizer/Builder/Todo.h" |
33 | #include "flang/Optimizer/Dialect/FIRAttr.h" |
34 | #include "flang/Optimizer/HLFIR/HLFIROps.h" |
35 | #include "mlir/IR/IRMapping.h" |
36 | #include "llvm/ADT/TypeSwitch.h" |
37 | #include <optional> |
38 | |
39 | namespace { |
40 | |
41 | /// Lower Designators to HLFIR. |
42 | class HlfirDesignatorBuilder { |
43 | private: |
44 | /// Internal entry point on the rightest part of a evaluate::Designator. |
45 | template <typename T> |
46 | hlfir::EntityWithAttributes |
47 | genLeafPartRef(const T &designatorNode, |
48 | bool vectorSubscriptDesignatorToValue) { |
49 | hlfir::EntityWithAttributes result = gen(designatorNode); |
50 | if (vectorSubscriptDesignatorToValue) |
51 | return turnVectorSubscriptedDesignatorIntoValue(result); |
52 | return result; |
53 | } |
54 | |
55 | hlfir::EntityWithAttributes |
56 | genDesignatorExpr(const Fortran::lower::SomeExpr &designatorExpr, |
57 | bool vectorSubscriptDesignatorToValue = true); |
58 | |
59 | public: |
60 | HlfirDesignatorBuilder(mlir::Location loc, |
61 | Fortran::lower::AbstractConverter &converter, |
62 | Fortran::lower::SymMap &symMap, |
63 | Fortran::lower::StatementContext &stmtCtx) |
64 | : converter{converter}, symMap{symMap}, stmtCtx{stmtCtx}, loc{loc} {} |
65 | |
66 | /// Public entry points to lower a Designator<T> (given its .u member, to |
67 | /// avoid the template arguments which does not matter here). |
68 | /// This lowers a designator to an hlfir variable SSA value (that can be |
69 | /// assigned to), except for vector subscripted designators that are |
70 | /// lowered by default to hlfir.expr value since they cannot be |
71 | /// represented as HLFIR variable SSA values. |
72 | |
73 | // Character designators variant contains substrings |
74 | using CharacterDesignators = |
75 | decltype(Fortran::evaluate::Designator<Fortran::evaluate::Type< |
76 | Fortran::evaluate::TypeCategory::Character, 1>>::u); |
77 | hlfir::EntityWithAttributes |
78 | gen(const CharacterDesignators &designatorVariant, |
79 | bool vectorSubscriptDesignatorToValue = true) { |
80 | return Fortran::common::visit( |
81 | [&](const auto &x) -> hlfir::EntityWithAttributes { |
82 | return genLeafPartRef(x, vectorSubscriptDesignatorToValue); |
83 | }, |
84 | designatorVariant); |
85 | } |
86 | // Character designators variant contains complex parts |
87 | using RealDesignators = |
88 | decltype(Fortran::evaluate::Designator<Fortran::evaluate::Type< |
89 | Fortran::evaluate::TypeCategory::Real, 4>>::u); |
90 | hlfir::EntityWithAttributes |
91 | gen(const RealDesignators &designatorVariant, |
92 | bool vectorSubscriptDesignatorToValue = true) { |
93 | return Fortran::common::visit( |
94 | [&](const auto &x) -> hlfir::EntityWithAttributes { |
95 | return genLeafPartRef(x, vectorSubscriptDesignatorToValue); |
96 | }, |
97 | designatorVariant); |
98 | } |
99 | // All other designators are similar |
100 | using OtherDesignators = |
101 | decltype(Fortran::evaluate::Designator<Fortran::evaluate::Type< |
102 | Fortran::evaluate::TypeCategory::Integer, 4>>::u); |
103 | hlfir::EntityWithAttributes |
104 | gen(const OtherDesignators &designatorVariant, |
105 | bool vectorSubscriptDesignatorToValue = true) { |
106 | return Fortran::common::visit( |
107 | [&](const auto &x) -> hlfir::EntityWithAttributes { |
108 | return genLeafPartRef(x, vectorSubscriptDesignatorToValue); |
109 | }, |
110 | designatorVariant); |
111 | } |
112 | |
113 | hlfir::EntityWithAttributes |
114 | genNamedEntity(const Fortran::evaluate::NamedEntity &namedEntity, |
115 | bool vectorSubscriptDesignatorToValue = true) { |
116 | if (namedEntity.IsSymbol()) |
117 | return genLeafPartRef( |
118 | Fortran::evaluate::SymbolRef{namedEntity.GetLastSymbol()}, |
119 | vectorSubscriptDesignatorToValue); |
120 | return genLeafPartRef(namedEntity.GetComponent(), |
121 | vectorSubscriptDesignatorToValue); |
122 | } |
123 | |
124 | /// Public entry point to lower a vector subscripted designator to |
125 | /// an hlfir::ElementalAddrOp. |
126 | hlfir::ElementalAddrOp convertVectorSubscriptedExprToElementalAddr( |
127 | const Fortran::lower::SomeExpr &designatorExpr); |
128 | |
129 | std::tuple<mlir::Type, fir::FortranVariableFlagsEnum> |
130 | genComponentDesignatorTypeAndAttributes( |
131 | const Fortran::semantics::Symbol &componentSym, mlir::Type fieldType, |
132 | bool isVolatile) { |
133 | if (mayHaveNonDefaultLowerBounds(partInfo: componentSym)) { |
134 | mlir::Type boxType = fir::BoxType::get(fieldType, isVolatile); |
135 | return std::make_tuple(boxType, |
136 | fir::FortranVariableFlagsEnum::contiguous); |
137 | } |
138 | auto refType = fir::ReferenceType::get(fieldType, isVolatile); |
139 | return std::make_tuple(refType, fir::FortranVariableFlagsEnum{}); |
140 | } |
141 | |
142 | mlir::Value genComponentShape(const Fortran::semantics::Symbol &componentSym, |
143 | mlir::Type fieldType) { |
144 | // For pointers and allocatable components, the |
145 | // shape is deferred and should not be loaded now to preserve |
146 | // pointer/allocatable aspects. |
147 | if (componentSym.Rank() == 0 || |
148 | Fortran::semantics::IsAllocatableOrObjectPointer(&componentSym) || |
149 | Fortran::semantics::IsProcedurePointer(&componentSym)) |
150 | return mlir::Value{}; |
151 | |
152 | fir::FirOpBuilder &builder = getBuilder(); |
153 | mlir::Location loc = getLoc(); |
154 | mlir::Type idxTy = builder.getIndexType(); |
155 | llvm::SmallVector<mlir::Value> extents; |
156 | auto seqTy = mlir::cast<fir::SequenceType>( |
157 | hlfir::getFortranElementOrSequenceType(fieldType)); |
158 | for (auto extent : seqTy.getShape()) { |
159 | if (extent == fir::SequenceType::getUnknownExtent()) { |
160 | // We have already generated invalid hlfir.declare |
161 | // without the type parameters and probably invalid storage |
162 | // for the variable (e.g. fir.alloca without type parameters). |
163 | // So this TODO here is a little bit late, but it matches |
164 | // the non-HLFIR path. |
165 | TODO(loc, "array component shape depending on length parameters"); |
166 | } |
167 | extents.push_back(builder.createIntegerConstant(loc, idxTy, extent)); |
168 | } |
169 | if (!mayHaveNonDefaultLowerBounds(componentSym)) |
170 | return builder.create<fir::ShapeOp>(loc, extents); |
171 | |
172 | llvm::SmallVector<mlir::Value> lbounds; |
173 | if (const auto *objDetails = |
174 | componentSym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) |
175 | for (const Fortran::semantics::ShapeSpec &bounds : objDetails->shape()) |
176 | if (auto lb = bounds.lbound().GetExplicit()) |
177 | if (auto constant = Fortran::evaluate::ToInt64(*lb)) |
178 | lbounds.push_back( |
179 | builder.createIntegerConstant(loc, idxTy, *constant)); |
180 | assert(extents.size() == lbounds.size() && |
181 | "extents and lower bounds must match"); |
182 | return builder.genShape(loc, lbounds, extents); |
183 | } |
184 | |
185 | fir::FortranVariableOpInterface |
186 | gen(const Fortran::evaluate::DataRef &dataRef) { |
187 | return Fortran::common::visit( |
188 | Fortran::common::visitors{[&](const auto &x) { return gen(x); }}, |
189 | dataRef.u); |
190 | } |
191 | |
192 | private: |
193 | /// Struct that is filled while visiting a part-ref (in the "visit" member |
194 | /// function) before the top level "gen" generates an hlfir.declare for the |
195 | /// part ref. It contains the lowered pieces of the part-ref that will |
196 | /// become the operands of an hlfir.declare. |
197 | struct PartInfo { |
198 | std::optional<hlfir::Entity> base; |
199 | std::string componentName{}; |
200 | mlir::Value componentShape; |
201 | hlfir::DesignateOp::Subscripts subscripts; |
202 | std::optional<bool> complexPart; |
203 | mlir::Value resultShape; |
204 | llvm::SmallVector<mlir::Value> typeParams; |
205 | llvm::SmallVector<mlir::Value, 2> substring; |
206 | }; |
207 | |
208 | // Given the value type of a designator (T or fir.array<T>) and the front-end |
209 | // node for the designator, compute the memory type (fir.class, fir.ref, or |
210 | // fir.box)... |
211 | template <typename T> |
212 | mlir::Type computeDesignatorType(mlir::Type resultValueType, |
213 | PartInfo &partInfo, |
214 | const T &designatorNode) { |
215 | // Get base's shape if its a sequence type with no previously computed |
216 | // result shape |
217 | if (partInfo.base && mlir::isa<fir::SequenceType>(resultValueType) && |
218 | !partInfo.resultShape) |
219 | partInfo.resultShape = |
220 | hlfir::genShape(getLoc(), getBuilder(), *partInfo.base); |
221 | |
222 | // Enable volatility on the designatory type if it has the VOLATILE |
223 | // attribute or if the base is volatile. |
224 | bool isVolatile = false; |
225 | |
226 | // Check if this should be a volatile reference |
227 | if constexpr (std::is_same_v<std::decay_t<T>, |
228 | Fortran::evaluate::SymbolRef>) { |
229 | if (designatorNode.get().GetUltimate().attrs().test( |
230 | Fortran::semantics::Attr::VOLATILE)) |
231 | isVolatile = true; |
232 | } else if constexpr (std::is_same_v<std::decay_t<T>, |
233 | Fortran::evaluate::ArrayRef>) { |
234 | if (designatorNode.base().GetLastSymbol().attrs().test( |
235 | Fortran::semantics::Attr::VOLATILE)) |
236 | isVolatile = true; |
237 | } else if constexpr (std::is_same_v<std::decay_t<T>, |
238 | Fortran::evaluate::Component>) { |
239 | if (designatorNode.GetLastSymbol().attrs().test( |
240 | Fortran::semantics::Attr::VOLATILE)) |
241 | isVolatile = true; |
242 | } |
243 | |
244 | // Check if the base type is volatile |
245 | if (partInfo.base.has_value()) { |
246 | mlir::Type baseType = partInfo.base.value().getType(); |
247 | isVolatile = isVolatile || fir::isa_volatile_type(baseType); |
248 | } |
249 | |
250 | // Dynamic type of polymorphic base must be kept if the designator is |
251 | // polymorphic. |
252 | if (isPolymorphic(designatorNode)) |
253 | return fir::ClassType::get(resultValueType, isVolatile); |
254 | |
255 | // Character scalar with dynamic length needs a fir.boxchar to hold the |
256 | // designator length. |
257 | auto charType = mlir::dyn_cast<fir::CharacterType>(resultValueType); |
258 | if (charType && charType.hasDynamicLen()) |
259 | return fir::BoxCharType::get(charType.getContext(), charType.getFKind()); |
260 | |
261 | // Arrays with non default lower bounds or dynamic length or dynamic extent |
262 | // need a fir.box to hold the dynamic or lower bound information. |
263 | if (fir::hasDynamicSize(resultValueType) || |
264 | mayHaveNonDefaultLowerBounds(partInfo)) |
265 | return fir::BoxType::get(resultValueType, isVolatile); |
266 | |
267 | // Non simply contiguous ref require a fir.box to carry the byte stride. |
268 | if (mlir::isa<fir::SequenceType>(resultValueType) && |
269 | !Fortran::evaluate::IsSimplyContiguous( |
270 | designatorNode, getConverter().getFoldingContext(), |
271 | /*namedConstantSectionsAreAlwaysContiguous=*/false)) |
272 | return fir::BoxType::get(resultValueType, isVolatile); |
273 | |
274 | // Other designators can be handled as raw addresses. |
275 | return fir::ReferenceType::get(resultValueType, isVolatile); |
276 | } |
277 | |
278 | template <typename T> |
279 | static bool isPolymorphic(const T &designatorNode) { |
280 | if constexpr (!std::is_same_v<T, Fortran::evaluate::Substring>) { |
281 | return Fortran::semantics::IsPolymorphic(designatorNode.GetLastSymbol()); |
282 | } |
283 | return false; |
284 | } |
285 | |
286 | template <typename T> |
287 | /// Generate an hlfir.designate for a part-ref given a filled PartInfo and the |
288 | /// FIR type for this part-ref. |
289 | fir::FortranVariableOpInterface genDesignate(mlir::Type resultValueType, |
290 | PartInfo &partInfo, |
291 | const T &designatorNode) { |
292 | mlir::Type designatorType = |
293 | computeDesignatorType(resultValueType, partInfo, designatorNode); |
294 | return genDesignate(designatorType, partInfo, /*attributes=*/{}); |
295 | } |
296 | fir::FortranVariableOpInterface |
297 | genDesignate(mlir::Type designatorType, PartInfo &partInfo, |
298 | fir::FortranVariableFlagsAttr attributes) { |
299 | fir::FirOpBuilder &builder = getBuilder(); |
300 | // Once a part with vector subscripts has been lowered, the following |
301 | // hlfir.designator (for the parts on the right of the designator) must |
302 | // be lowered inside the hlfir.elemental_addr because they depend on the |
303 | // hlfir.elemental_addr indices. |
304 | // All the subsequent Fortran indices however, should be lowered before |
305 | // the hlfir.elemental_addr because they should only be evaluated once, |
306 | // hence, the insertion point is restored outside of the |
307 | // hlfir.elemental_addr after generating the hlfir.designate. Example: in |
308 | // "X(VECTOR)%COMP(FOO(), BAR())", the calls to bar() and foo() must be |
309 | // generated outside of the hlfir.elemental, but the related hlfir.designate |
310 | // that depends on the scalar hlfir.designate of X(VECTOR) that was |
311 | // generated inside the hlfir.elemental_addr should be generated in the |
312 | // hlfir.elemental_addr. |
313 | if (auto elementalAddrOp = getVectorSubscriptElementAddrOp()) |
314 | builder.setInsertionPointToEnd(&elementalAddrOp->getBody().front()); |
315 | auto designate = builder.create<hlfir::DesignateOp>( |
316 | getLoc(), designatorType, partInfo.base.value().getBase(), |
317 | partInfo.componentName, partInfo.componentShape, partInfo.subscripts, |
318 | partInfo.substring, partInfo.complexPart, partInfo.resultShape, |
319 | partInfo.typeParams, attributes); |
320 | if (auto elementalAddrOp = getVectorSubscriptElementAddrOp()) |
321 | builder.setInsertionPoint(*elementalAddrOp); |
322 | return mlir::cast<fir::FortranVariableOpInterface>( |
323 | designate.getOperation()); |
324 | } |
325 | |
326 | fir::FortranVariableOpInterface |
327 | gen(const Fortran::evaluate::SymbolRef &symbolRef) { |
328 | if (std::optional<fir::FortranVariableOpInterface> varDef = |
329 | getSymMap().lookupVariableDefinition(symbolRef)) { |
330 | if (symbolRef.get().GetUltimate().test( |
331 | Fortran::semantics::Symbol::Flag::CrayPointee)) { |
332 | // The pointee is represented with a descriptor inheriting |
333 | // the shape and type parameters of the pointee. |
334 | // We have to update the base_addr to point to the current |
335 | // value of the Cray pointer variable. |
336 | fir::FirOpBuilder &builder = getBuilder(); |
337 | fir::FortranVariableOpInterface ptrVar = |
338 | gen(Fortran::semantics::GetCrayPointer(symbolRef)); |
339 | mlir::Value ptrAddr = ptrVar.getBase(); |
340 | |
341 | // Reinterpret the reference to a Cray pointer so that |
342 | // we have a pointer-compatible value after loading |
343 | // the Cray pointer value. |
344 | mlir::Type refPtrType = builder.getRefType( |
345 | fir::PointerType::get(fir::dyn_cast_ptrEleTy(ptrAddr.getType()))); |
346 | mlir::Value cast = builder.createConvert(loc, refPtrType, ptrAddr); |
347 | mlir::Value ptrVal = builder.create<fir::LoadOp>(loc, cast); |
348 | |
349 | // Update the base_addr to the value of the Cray pointer. |
350 | // This is a hacky way to do the update, and it may harm |
351 | // performance around Cray pointer references. |
352 | // TODO: we should introduce an operation that updates |
353 | // just the base_addr of the given box. The CodeGen |
354 | // will just convert it into a single store. |
355 | fir::runtime::genPointerAssociateScalar(builder, loc, varDef->getBase(), |
356 | ptrVal); |
357 | } |
358 | return *varDef; |
359 | } |
360 | llvm::errs() << *symbolRef << "\n"; |
361 | TODO(getLoc(), "lowering symbol to HLFIR"); |
362 | } |
363 | |
364 | fir::FortranVariableOpInterface |
365 | gen(const Fortran::semantics::Symbol &symbol) { |
366 | Fortran::evaluate::SymbolRef symref{symbol}; |
367 | return gen(symref); |
368 | } |
369 | |
370 | fir::FortranVariableOpInterface |
371 | gen(const Fortran::evaluate::Component &component) { |
372 | if (Fortran::semantics::IsAllocatableOrPointer(component.GetLastSymbol())) |
373 | return genWholeAllocatableOrPointerComponent(component); |
374 | PartInfo partInfo; |
375 | mlir::Type resultType = visit(component, partInfo); |
376 | return genDesignate(resultType, partInfo, component); |
377 | } |
378 | |
379 | fir::FortranVariableOpInterface |
380 | gen(const Fortran::evaluate::ArrayRef &arrayRef) { |
381 | PartInfo partInfo; |
382 | mlir::Type resultType = visit(arrayRef, partInfo); |
383 | return genDesignate(resultType, partInfo, arrayRef); |
384 | } |
385 | |
386 | fir::FortranVariableOpInterface |
387 | gen(const Fortran::evaluate::CoarrayRef &coarrayRef) { |
388 | TODO(getLoc(), "coarray: lowering a reference to a coarray object"); |
389 | } |
390 | |
391 | mlir::Type visit(const Fortran::evaluate::CoarrayRef &, PartInfo &) { |
392 | TODO(getLoc(), "coarray: lowering a reference to a coarray object"); |
393 | } |
394 | |
395 | fir::FortranVariableOpInterface |
396 | gen(const Fortran::evaluate::ComplexPart &complexPart) { |
397 | PartInfo partInfo; |
398 | fir::factory::Complex cmplxHelper(getBuilder(), getLoc()); |
399 | |
400 | bool complexBit = |
401 | complexPart.part() == Fortran::evaluate::ComplexPart::Part::IM; |
402 | partInfo.complexPart = {complexBit}; |
403 | |
404 | mlir::Type resultType = visit(complexPart.complex(), partInfo); |
405 | |
406 | // Determine complex part type |
407 | mlir::Type base = hlfir::getFortranElementType(resultType); |
408 | mlir::Type cmplxValueType = cmplxHelper.getComplexPartType(base); |
409 | mlir::Type designatorType = changeElementType(resultType, cmplxValueType); |
410 | |
411 | return genDesignate(designatorType, partInfo, complexPart); |
412 | } |
413 | |
414 | fir::FortranVariableOpInterface |
415 | gen(const Fortran::evaluate::Substring &substring) { |
416 | PartInfo partInfo; |
417 | mlir::Type baseStringType = Fortran::common::visit( |
418 | [&](const auto &x) { return visit(x, partInfo); }, substring.parent()); |
419 | assert(partInfo.typeParams.size() == 1 && "expect base string length"); |
420 | // Compute the substring lower and upper bound. |
421 | partInfo.substring.push_back(genSubscript(substring.lower())); |
422 | if (Fortran::evaluate::MaybeExtentExpr upperBound = substring.upper()) |
423 | partInfo.substring.push_back(genSubscript(*upperBound)); |
424 | else |
425 | partInfo.substring.push_back(partInfo.typeParams[0]); |
426 | fir::FirOpBuilder &builder = getBuilder(); |
427 | mlir::Location loc = getLoc(); |
428 | mlir::Type idxTy = builder.getIndexType(); |
429 | partInfo.substring[0] = |
430 | builder.createConvert(loc, idxTy, partInfo.substring[0]); |
431 | partInfo.substring[1] = |
432 | builder.createConvert(loc, idxTy, partInfo.substring[1]); |
433 | // Try using constant length if available. mlir::arith folding would |
434 | // most likely be able to fold "max(ub-lb+1,0)" too, but getting |
435 | // the constant length in the FIR types would be harder. |
436 | std::optional<int64_t> cstLen = |
437 | Fortran::evaluate::ToInt64(Fortran::evaluate::Fold( |
438 | getConverter().getFoldingContext(), substring.LEN())); |
439 | if (cstLen) { |
440 | partInfo.typeParams[0] = |
441 | builder.createIntegerConstant(loc, idxTy, *cstLen); |
442 | } else { |
443 | // Compute "len = max(ub-lb+1,0)" (Fortran 2018 9.4.1). |
444 | mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); |
445 | auto boundsDiff = builder.create<mlir::arith::SubIOp>( |
446 | loc, partInfo.substring[1], partInfo.substring[0]); |
447 | auto rawLen = builder.create<mlir::arith::AddIOp>(loc, boundsDiff, one); |
448 | partInfo.typeParams[0] = |
449 | fir::factory::genMaxWithZero(builder, loc, rawLen); |
450 | } |
451 | auto kind = mlir::cast<fir::CharacterType>( |
452 | hlfir::getFortranElementType(baseStringType)) |
453 | .getFKind(); |
454 | auto newCharTy = fir::CharacterType::get( |
455 | baseStringType.getContext(), kind, |
456 | cstLen ? *cstLen : fir::CharacterType::unknownLen()); |
457 | mlir::Type resultType = changeElementType(baseStringType, newCharTy); |
458 | return genDesignate(resultType, partInfo, substring); |
459 | } |
460 | |
461 | static mlir::Type changeElementType(mlir::Type type, mlir::Type newEleTy) { |
462 | return llvm::TypeSwitch<mlir::Type, mlir::Type>(type) |
463 | .Case<fir::SequenceType>([&](fir::SequenceType seqTy) -> mlir::Type { |
464 | return fir::SequenceType::get(seqTy.getShape(), newEleTy); |
465 | }) |
466 | .Case<fir::ReferenceType, fir::BoxType, fir::ClassType>( |
467 | [&](auto t) -> mlir::Type { |
468 | using FIRT = decltype(t); |
469 | return FIRT::get(changeElementType(t.getEleTy(), newEleTy), |
470 | t.isVolatile()); |
471 | }) |
472 | .Case<fir::PointerType, fir::HeapType>([&](auto t) -> mlir::Type { |
473 | using FIRT = decltype(t); |
474 | return FIRT::get(changeElementType(t.getEleTy(), newEleTy)); |
475 | }) |
476 | .Default([newEleTy](mlir::Type t) -> mlir::Type { return newEleTy; }); |
477 | } |
478 | |
479 | fir::FortranVariableOpInterface genWholeAllocatableOrPointerComponent( |
480 | const Fortran::evaluate::Component &component) { |
481 | // Generate whole allocatable or pointer component reference. The |
482 | // hlfir.designate result will be a pointer/allocatable. |
483 | PartInfo partInfo; |
484 | mlir::Type componentType = visitComponentImpl(component, partInfo).second; |
485 | const auto isVolatile = |
486 | fir::isa_volatile_type(partInfo.base.value().getBase().getType()); |
487 | mlir::Type designatorType = |
488 | fir::ReferenceType::get(componentType, isVolatile); |
489 | fir::FortranVariableFlagsAttr attributes = |
490 | Fortran::lower::translateSymbolAttributes(getBuilder().getContext(), |
491 | component.GetLastSymbol()); |
492 | return genDesignate(designatorType, partInfo, attributes); |
493 | } |
494 | |
495 | mlir::Type visit(const Fortran::evaluate::DataRef &dataRef, |
496 | PartInfo &partInfo) { |
497 | return Fortran::common::visit( |
498 | [&](const auto &x) { return visit(x, partInfo); }, dataRef.u); |
499 | } |
500 | |
501 | mlir::Type |
502 | visit(const Fortran::evaluate::StaticDataObject::Pointer &staticObject, |
503 | PartInfo &partInfo) { |
504 | fir::FirOpBuilder &builder = getBuilder(); |
505 | mlir::Location loc = getLoc(); |
506 | std::optional<std::string> string = staticObject->AsString(); |
507 | // TODO: see if StaticDataObject can be replaced by something based on |
508 | // Constant<T> to avoid dealing with endianness here for KIND>1. |
509 | // This will also avoid making string copies here. |
510 | if (!string) |
511 | TODO(loc, "StaticDataObject::Pointer substring with kind > 1"); |
512 | fir::ExtendedValue exv = |
513 | fir::factory::createStringLiteral(builder, getLoc(), *string); |
514 | auto flags = fir::FortranVariableFlagsAttr::get( |
515 | builder.getContext(), fir::FortranVariableFlagsEnum::parameter); |
516 | partInfo.base = hlfir::genDeclare(loc, builder, exv, ".stringlit", flags); |
517 | partInfo.typeParams.push_back(fir::getLen(exv)); |
518 | return partInfo.base->getElementOrSequenceType(); |
519 | } |
520 | |
521 | mlir::Type visit(const Fortran::evaluate::SymbolRef &symbolRef, |
522 | PartInfo &partInfo) { |
523 | // A symbol is only visited if there is a following array, substring, or |
524 | // complex reference. If the entity is a pointer or allocatable, this |
525 | // reference designates the target, so the pointer, allocatable must be |
526 | // dereferenced here. |
527 | partInfo.base = |
528 | hlfir::derefPointersAndAllocatables(loc, getBuilder(), gen(symbolRef)); |
529 | hlfir::genLengthParameters(loc, getBuilder(), *partInfo.base, |
530 | partInfo.typeParams); |
531 | return partInfo.base->getElementOrSequenceType(); |
532 | } |
533 | |
534 | mlir::Type visit(const Fortran::evaluate::ArrayRef &arrayRef, |
535 | PartInfo &partInfo) { |
536 | mlir::Type baseType; |
537 | if (const auto *component = arrayRef.base().UnwrapComponent()) { |
538 | // Pointers and allocatable components must be dereferenced since the |
539 | // array ref designates the target (this is done in "visit"). Other |
540 | // components need special care to deal with the array%array_comp(indices) |
541 | // case. |
542 | if (Fortran::semantics::IsAllocatableOrObjectPointer( |
543 | &component->GetLastSymbol())) |
544 | baseType = visit(*component, partInfo); |
545 | else |
546 | baseType = hlfir::getFortranElementOrSequenceType( |
547 | visitComponentImpl(*component, partInfo).second); |
548 | } else { |
549 | baseType = visit(arrayRef.base().GetLastSymbol(), partInfo); |
550 | } |
551 | |
552 | fir::FirOpBuilder &builder = getBuilder(); |
553 | mlir::Location loc = getLoc(); |
554 | mlir::Type idxTy = builder.getIndexType(); |
555 | llvm::SmallVector<std::pair<mlir::Value, mlir::Value>> bounds; |
556 | auto getBaseBounds = [&](unsigned i) { |
557 | if (bounds.empty()) { |
558 | if (partInfo.componentName.empty()) { |
559 | bounds = hlfir::genBounds(loc, builder, partInfo.base.value()); |
560 | } else { |
561 | assert( |
562 | partInfo.componentShape && |
563 | "implicit array section bounds must come from component shape"); |
564 | bounds = hlfir::genBounds(loc, builder, partInfo.componentShape); |
565 | } |
566 | assert(!bounds.empty() && |
567 | "failed to compute implicit array section bounds"); |
568 | } |
569 | return bounds[i]; |
570 | }; |
571 | auto frontEndResultShape = |
572 | Fortran::evaluate::GetShape(converter.getFoldingContext(), arrayRef); |
573 | auto tryGettingExtentFromFrontEnd = |
574 | [&](unsigned dim) -> std::pair<mlir::Value, fir::SequenceType::Extent> { |
575 | // Use constant extent if possible. The main advantage to do this now |
576 | // is to get the best FIR array types as possible while lowering. |
577 | if (frontEndResultShape) |
578 | if (auto maybeI64 = |
579 | Fortran::evaluate::ToInt64(frontEndResultShape->at(dim))) |
580 | return {builder.createIntegerConstant(loc, idxTy, *maybeI64), |
581 | *maybeI64}; |
582 | return {mlir::Value{}, fir::SequenceType::getUnknownExtent()}; |
583 | }; |
584 | llvm::SmallVector<mlir::Value> resultExtents; |
585 | fir::SequenceType::Shape resultTypeShape; |
586 | bool sawVectorSubscripts = false; |
587 | for (auto subscript : llvm::enumerate(arrayRef.subscript())) { |
588 | if (const auto *triplet = |
589 | std::get_if<Fortran::evaluate::Triplet>(&subscript.value().u)) { |
590 | mlir::Value lb, ub; |
591 | if (const auto &lbExpr = triplet->lower()) |
592 | lb = genSubscript(*lbExpr); |
593 | else |
594 | lb = getBaseBounds(subscript.index()).first; |
595 | if (const auto &ubExpr = triplet->upper()) |
596 | ub = genSubscript(*ubExpr); |
597 | else |
598 | ub = getBaseBounds(subscript.index()).second; |
599 | lb = builder.createConvert(loc, idxTy, lb); |
600 | ub = builder.createConvert(loc, idxTy, ub); |
601 | mlir::Value stride = genSubscript(triplet->stride()); |
602 | stride = builder.createConvert(loc, idxTy, stride); |
603 | auto [extentValue, shapeExtent] = |
604 | tryGettingExtentFromFrontEnd(resultExtents.size()); |
605 | resultTypeShape.push_back(shapeExtent); |
606 | if (!extentValue) |
607 | extentValue = |
608 | builder.genExtentFromTriplet(loc, lb, ub, stride, idxTy); |
609 | resultExtents.push_back(extentValue); |
610 | partInfo.subscripts.emplace_back( |
611 | hlfir::DesignateOp::Triplet{lb, ub, stride}); |
612 | } else { |
613 | const auto &expr = |
614 | std::get<Fortran::evaluate::IndirectSubscriptIntegerExpr>( |
615 | subscript.value().u) |
616 | .value(); |
617 | hlfir::Entity subscript = genSubscript(expr); |
618 | partInfo.subscripts.push_back(subscript); |
619 | if (expr.Rank() > 0) { |
620 | sawVectorSubscripts = true; |
621 | auto [extentValue, shapeExtent] = |
622 | tryGettingExtentFromFrontEnd(resultExtents.size()); |
623 | resultTypeShape.push_back(shapeExtent); |
624 | if (!extentValue) |
625 | extentValue = hlfir::genExtent(loc, builder, subscript, /*dim=*/0); |
626 | resultExtents.push_back(extentValue); |
627 | } |
628 | } |
629 | } |
630 | assert(resultExtents.size() == resultTypeShape.size() && |
631 | "inconsistent hlfir.designate shape"); |
632 | |
633 | // For vector subscripts, create an hlfir.elemental_addr and continue |
634 | // lowering the designator inside it as if it was addressing an element of |
635 | // the vector subscripts. |
636 | if (sawVectorSubscripts) |
637 | return createVectorSubscriptElementAddrOp(partInfo, baseType, |
638 | resultExtents); |
639 | |
640 | mlir::Type resultType = |
641 | mlir::cast<fir::SequenceType>(baseType).getElementType(); |
642 | if (!resultTypeShape.empty()) { |
643 | // Ranked array section. The result shape comes from the array section |
644 | // subscripts. |
645 | resultType = fir::SequenceType::get(resultTypeShape, resultType); |
646 | assert(!partInfo.resultShape && |
647 | "Fortran designator can only have one ranked part"); |
648 | partInfo.resultShape = builder.genShape(loc, resultExtents); |
649 | } else if (!partInfo.componentName.empty() && |
650 | partInfo.base.value().isArray()) { |
651 | // This is an array%array_comp(indices) reference. Keep the |
652 | // shape of the base array and not the array_comp. |
653 | auto compBaseTy = partInfo.base->getElementOrSequenceType(); |
654 | resultType = changeElementType(compBaseTy, resultType); |
655 | assert(!partInfo.resultShape && "should not have been computed already"); |
656 | partInfo.resultShape = hlfir::genShape(loc, builder, *partInfo.base); |
657 | } |
658 | return resultType; |
659 | } |
660 | |
661 | static bool |
662 | mayHaveNonDefaultLowerBounds(const Fortran::semantics::Symbol &componentSym) { |
663 | if (const auto *objDetails = |
664 | componentSym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) |
665 | for (const Fortran::semantics::ShapeSpec &bounds : objDetails->shape()) |
666 | if (auto lb = bounds.lbound().GetExplicit()) |
667 | if (auto constant = Fortran::evaluate::ToInt64(*lb)) |
668 | if (!constant || *constant != 1) |
669 | return true; |
670 | return false; |
671 | } |
672 | static bool mayHaveNonDefaultLowerBounds(const PartInfo &partInfo) { |
673 | return partInfo.resultShape && |
674 | mlir::isa<fir::ShiftType, fir::ShapeShiftType>( |
675 | partInfo.resultShape.getType()); |
676 | } |
677 | |
678 | mlir::Type visit(const Fortran::evaluate::Component &component, |
679 | PartInfo &partInfo) { |
680 | if (Fortran::semantics::IsAllocatableOrPointer(component.GetLastSymbol())) { |
681 | // In a visit, the following reference will address the target. Insert |
682 | // the dereference here. |
683 | partInfo.base = genWholeAllocatableOrPointerComponent(component); |
684 | partInfo.base = hlfir::derefPointersAndAllocatables(loc, getBuilder(), |
685 | *partInfo.base); |
686 | hlfir::genLengthParameters(loc, getBuilder(), *partInfo.base, |
687 | partInfo.typeParams); |
688 | return partInfo.base->getElementOrSequenceType(); |
689 | } |
690 | // This function must be called from contexts where the component is not the |
691 | // base of an ArrayRef. In these cases, the component cannot be an array |
692 | // if the base is an array. The code below determines the shape of the |
693 | // component reference if any. |
694 | auto [baseType, componentType] = visitComponentImpl(component, partInfo); |
695 | mlir::Type componentBaseType = |
696 | hlfir::getFortranElementOrSequenceType(componentType); |
697 | if (partInfo.base.value().isArray()) { |
698 | // For array%scalar_comp, the result shape is |
699 | // the one of the base. Compute it here. Note that the lower bounds of the |
700 | // base are not the ones of the resulting reference (that are default |
701 | // ones). |
702 | partInfo.resultShape = hlfir::genShape(loc, getBuilder(), *partInfo.base); |
703 | assert(!partInfo.componentShape && |
704 | "Fortran designators can only have one ranked part"); |
705 | return changeElementType(baseType, componentBaseType); |
706 | } |
707 | |
708 | if (partInfo.complexPart && partInfo.componentShape) { |
709 | // Treat ...array_comp%im/re as ...array_comp(:,:,...)%im/re |
710 | // so that the codegen has the full slice triples for the component |
711 | // readily available. |
712 | fir::FirOpBuilder &builder = getBuilder(); |
713 | mlir::Type idxTy = builder.getIndexType(); |
714 | mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); |
715 | |
716 | llvm::SmallVector<mlir::Value> resultExtents; |
717 | // Collect <lb, ub> pairs from the component shape. |
718 | auto bounds = hlfir::genBounds(loc, builder, partInfo.componentShape); |
719 | for (auto &boundPair : bounds) { |
720 | // The default subscripts are <lb, ub, 1>: |
721 | partInfo.subscripts.emplace_back(hlfir::DesignateOp::Triplet{ |
722 | boundPair.first, boundPair.second, one}); |
723 | auto extentValue = builder.genExtentFromTriplet( |
724 | loc, boundPair.first, boundPair.second, one, idxTy); |
725 | resultExtents.push_back(extentValue); |
726 | } |
727 | // The result shape is: <max((ub - lb + 1) / 1, 0), ...>. |
728 | partInfo.resultShape = builder.genShape(loc, resultExtents); |
729 | return componentBaseType; |
730 | } |
731 | |
732 | // scalar%array_comp or scalar%scalar. In any case the shape of this |
733 | // part-ref is coming from the component. |
734 | partInfo.resultShape = partInfo.componentShape; |
735 | partInfo.componentShape = {}; |
736 | return componentBaseType; |
737 | } |
738 | |
739 | // Returns the <BaseType, ComponentType> pair, computes partInfo.base, |
740 | // partInfo.componentShape and partInfo.typeParams, but does not set the |
741 | // partInfo.resultShape yet. The result shape will be computed after |
742 | // processing a following ArrayRef, if any, and in "visit" otherwise. |
743 | std::pair<mlir::Type, mlir::Type> |
744 | visitComponentImpl(const Fortran::evaluate::Component &component, |
745 | PartInfo &partInfo) { |
746 | fir::FirOpBuilder &builder = getBuilder(); |
747 | // Break the Designator visit here: if the base is an array-ref, a |
748 | // coarray-ref, or another component, this creates another hlfir.designate |
749 | // for it. hlfir.designate is not meant to represent more than one |
750 | // part-ref. |
751 | partInfo.base = gen(component.base()); |
752 | // If the base is an allocatable/pointer, dereference it here since the |
753 | // component ref designates its target. |
754 | partInfo.base = |
755 | hlfir::derefPointersAndAllocatables(loc, builder, *partInfo.base); |
756 | assert(partInfo.typeParams.empty() && "should not have been computed yet"); |
757 | |
758 | hlfir::genLengthParameters(getLoc(), getBuilder(), *partInfo.base, |
759 | partInfo.typeParams); |
760 | mlir::Type baseType = partInfo.base->getElementOrSequenceType(); |
761 | |
762 | // Lower the information about the component (type, length parameters and |
763 | // shape). |
764 | const Fortran::semantics::Symbol &componentSym = component.GetLastSymbol(); |
765 | partInfo.componentName = converter.getRecordTypeFieldName(componentSym); |
766 | auto recordType = |
767 | mlir::cast<fir::RecordType>(hlfir::getFortranElementType(baseType)); |
768 | if (recordType.isDependentType()) |
769 | TODO(getLoc(), "Designate derived type with length parameters in HLFIR"); |
770 | mlir::Type fieldType = recordType.getType(partInfo.componentName); |
771 | assert(fieldType && "component name is not known"); |
772 | mlir::Type fieldBaseType = |
773 | hlfir::getFortranElementOrSequenceType(fieldType); |
774 | partInfo.componentShape = genComponentShape(componentSym, fieldBaseType); |
775 | |
776 | mlir::Type fieldEleType = hlfir::getFortranElementType(fieldBaseType); |
777 | if (fir::isRecordWithTypeParameters(fieldEleType)) |
778 | TODO(loc, |
779 | "lower a component that is a parameterized derived type to HLFIR"); |
780 | if (auto charTy = mlir::dyn_cast<fir::CharacterType>(fieldEleType)) { |
781 | mlir::Location loc = getLoc(); |
782 | mlir::Type idxTy = builder.getIndexType(); |
783 | if (charTy.hasConstantLen()) |
784 | partInfo.typeParams.push_back( |
785 | builder.createIntegerConstant(loc, idxTy, charTy.getLen())); |
786 | else if (!Fortran::semantics::IsAllocatableOrObjectPointer(&componentSym)) |
787 | TODO(loc, "compute character length of automatic character component " |
788 | "in a PDT"); |
789 | // Otherwise, the length of the component is deferred and will only |
790 | // be read when the component is dereferenced. |
791 | } |
792 | return {baseType, fieldType}; |
793 | } |
794 | |
795 | // Compute: "lb + (i-1)*step". |
796 | mlir::Value computeTripletPosition(mlir::Location loc, |
797 | fir::FirOpBuilder &builder, |
798 | hlfir::DesignateOp::Triplet &triplet, |
799 | mlir::Value oneBasedIndex) { |
800 | mlir::Type idxTy = builder.getIndexType(); |
801 | mlir::Value lb = builder.createConvert(loc, idxTy, std::get<0>(triplet)); |
802 | mlir::Value step = builder.createConvert(loc, idxTy, std::get<2>(triplet)); |
803 | mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); |
804 | oneBasedIndex = builder.createConvert(loc, idxTy, oneBasedIndex); |
805 | mlir::Value zeroBased = |
806 | builder.create<mlir::arith::SubIOp>(loc, oneBasedIndex, one); |
807 | mlir::Value offset = |
808 | builder.create<mlir::arith::MulIOp>(loc, zeroBased, step); |
809 | return builder.create<mlir::arith::AddIOp>(loc, lb, offset); |
810 | } |
811 | |
812 | /// Create an hlfir.element_addr operation to deal with vector subscripted |
813 | /// entities. This transforms the current vector subscripted array-ref into a |
814 | /// a scalar array-ref that is addressing the vector subscripted part given |
815 | /// the one based indices of the hlfir.element_addr. |
816 | /// The rest of the designator lowering will continue lowering any further |
817 | /// parts inside the hlfir.elemental as a scalar reference. |
818 | /// At the end of the designator lowering, the hlfir.elemental_addr will |
819 | /// be turned into an hlfir.elemental value, unless the caller of this |
820 | /// utility requested to get the hlfir.elemental_addr instead of lowering |
821 | /// the designator to an mlir::Value. |
822 | mlir::Type createVectorSubscriptElementAddrOp( |
823 | PartInfo &partInfo, mlir::Type baseType, |
824 | llvm::ArrayRef<mlir::Value> resultExtents) { |
825 | fir::FirOpBuilder &builder = getBuilder(); |
826 | mlir::Value shape = builder.genShape(loc, resultExtents); |
827 | // The type parameters to be added on the hlfir.elemental_addr are the ones |
828 | // of the whole designator (not the ones of the vector subscripted part). |
829 | // These are not yet known and will be added when finalizing the designator |
830 | // lowering. |
831 | // The resulting designator may be polymorphic, in which case the resulting |
832 | // type is the base of the vector subscripted part because |
833 | // allocatable/pointer components cannot be referenced after a vector |
834 | // subscripted part. Set the mold to the current base. It will be erased if |
835 | // the resulting designator is not polymorphic. |
836 | assert(partInfo.base.has_value() && |
837 | "vector subscripted part must have a base"); |
838 | mlir::Value mold = *partInfo.base; |
839 | auto elementalAddrOp = builder.create<hlfir::ElementalAddrOp>( |
840 | loc, shape, mold, mlir::ValueRange{}, |
841 | /*isUnordered=*/true); |
842 | setVectorSubscriptElementAddrOp(elementalAddrOp); |
843 | builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front()); |
844 | mlir::Region::BlockArgListType indices = elementalAddrOp.getIndices(); |
845 | auto indicesIterator = indices.begin(); |
846 | auto getNextOneBasedIndex = [&]() -> mlir::Value { |
847 | assert(indicesIterator != indices.end() && "ill formed ElementalAddrOp"); |
848 | return *(indicesIterator++); |
849 | }; |
850 | // Transform the designator into a scalar designator computing the vector |
851 | // subscripted entity element address given one based indices (for the shape |
852 | // of the vector subscripted designator). |
853 | for (hlfir::DesignateOp::Subscript &subscript : partInfo.subscripts) { |
854 | if (auto *triplet = |
855 | std::get_if<hlfir::DesignateOp::Triplet>(&subscript)) { |
856 | // subscript = (lb + (i-1)*step) |
857 | mlir::Value scalarSubscript = computeTripletPosition( |
858 | loc, builder, *triplet, getNextOneBasedIndex()); |
859 | subscript = scalarSubscript; |
860 | } else { |
861 | hlfir::Entity valueSubscript{std::get<mlir::Value>(subscript)}; |
862 | if (valueSubscript.isScalar()) |
863 | continue; |
864 | // subscript = vector(i + (vector_lb-1)) |
865 | hlfir::Entity scalarSubscript = hlfir::getElementAt( |
866 | loc, builder, valueSubscript, {getNextOneBasedIndex()}); |
867 | scalarSubscript = |
868 | hlfir::loadTrivialScalar(loc, builder, scalarSubscript); |
869 | subscript = scalarSubscript; |
870 | } |
871 | } |
872 | builder.setInsertionPoint(elementalAddrOp); |
873 | return mlir::cast<fir::SequenceType>(baseType).getElementType(); |
874 | } |
875 | |
876 | /// Yield the designator for the final part-ref inside the |
877 | /// hlfir.elemental_addr. |
878 | void finalizeElementAddrOp(hlfir::ElementalAddrOp elementalAddrOp, |
879 | hlfir::EntityWithAttributes elementAddr) { |
880 | fir::FirOpBuilder &builder = getBuilder(); |
881 | builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front()); |
882 | if (!elementAddr.isPolymorphic()) |
883 | elementalAddrOp.getMoldMutable().clear(); |
884 | builder.create<hlfir::YieldOp>(loc, elementAddr); |
885 | builder.setInsertionPointAfter(elementalAddrOp); |
886 | } |
887 | |
888 | /// If the lowered designator has vector subscripts turn it into an |
889 | /// ElementalOp, otherwise, return the lowered designator. This should |
890 | /// only be called if the user did not request to get the |
891 | /// hlfir.elemental_addr. In Fortran, vector subscripted designators are only |
892 | /// writable on the left-hand side of an assignment and in input IO |
893 | /// statements. Otherwise, they are not variables (cannot be modified, their |
894 | /// value is taken at the place they appear). |
895 | hlfir::EntityWithAttributes turnVectorSubscriptedDesignatorIntoValue( |
896 | hlfir::EntityWithAttributes loweredDesignator) { |
897 | std::optional<hlfir::ElementalAddrOp> elementalAddrOp = |
898 | getVectorSubscriptElementAddrOp(); |
899 | if (!elementalAddrOp) |
900 | return loweredDesignator; |
901 | finalizeElementAddrOp(*elementalAddrOp, loweredDesignator); |
902 | // This vector subscript designator is only being read, transform the |
903 | // hlfir.elemental_addr into an hlfir.elemental. The content of the |
904 | // hlfir.elemental_addr is cloned, and the resulting address is loaded to |
905 | // get the new element value. |
906 | fir::FirOpBuilder &builder = getBuilder(); |
907 | mlir::Location loc = getLoc(); |
908 | mlir::Value elemental = |
909 | hlfir::cloneToElementalOp(loc, builder, *elementalAddrOp); |
910 | (*elementalAddrOp)->erase(); |
911 | setVectorSubscriptElementAddrOp(std::nullopt); |
912 | fir::FirOpBuilder *bldr = &builder; |
913 | getStmtCtx().attachCleanup( |
914 | [=]() { bldr->create<hlfir::DestroyOp>(loc, elemental); }); |
915 | return hlfir::EntityWithAttributes{elemental}; |
916 | } |
917 | |
918 | /// Lower a subscript expression. If it is a scalar subscript that is a |
919 | /// variable, it is loaded into an integer value. If it is an array (for |
920 | /// vector subscripts) it is dereferenced if this is an allocatable or |
921 | /// pointer. |
922 | template <typename T> |
923 | hlfir::Entity genSubscript(const Fortran::evaluate::Expr<T> &expr); |
924 | |
925 | const std::optional<hlfir::ElementalAddrOp> & |
926 | getVectorSubscriptElementAddrOp() const { |
927 | return vectorSubscriptElementAddrOp; |
928 | } |
929 | void setVectorSubscriptElementAddrOp( |
930 | std::optional<hlfir::ElementalAddrOp> elementalAddrOp) { |
931 | vectorSubscriptElementAddrOp = elementalAddrOp; |
932 | } |
933 | |
934 | mlir::Location getLoc() const { return loc; } |
935 | Fortran::lower::AbstractConverter &getConverter() { return converter; } |
936 | fir::FirOpBuilder &getBuilder() { return converter.getFirOpBuilder(); } |
937 | Fortran::lower::SymMap &getSymMap() { return symMap; } |
938 | Fortran::lower::StatementContext &getStmtCtx() { return stmtCtx; } |
939 | |
940 | Fortran::lower::AbstractConverter &converter; |
941 | Fortran::lower::SymMap &symMap; |
942 | Fortran::lower::StatementContext &stmtCtx; |
943 | // If there is a vector subscript, an elementalAddrOp is created |
944 | // to compute the address of the designator elements. |
945 | std::optional<hlfir::ElementalAddrOp> vectorSubscriptElementAddrOp{}; |
946 | mlir::Location loc; |
947 | }; |
948 | |
949 | hlfir::EntityWithAttributes HlfirDesignatorBuilder::genDesignatorExpr( |
950 | const Fortran::lower::SomeExpr &designatorExpr, |
951 | bool vectorSubscriptDesignatorToValue) { |
952 | // Expr<SomeType> plumbing to unwrap Designator<T> and call |
953 | // gen(Designator<T>.u). |
954 | return Fortran::common::visit( |
955 | [&](const auto &x) -> hlfir::EntityWithAttributes { |
956 | using T = std::decay_t<decltype(x)>; |
957 | if constexpr (Fortran::common::HasMember< |
958 | T, Fortran::lower::CategoryExpression>) { |
959 | if constexpr (T::Result::category == |
960 | Fortran::common::TypeCategory::Derived) { |
961 | return gen(std::get<Fortran::evaluate::Designator< |
962 | Fortran::evaluate::SomeDerived>>(x.u) |
963 | .u, |
964 | vectorSubscriptDesignatorToValue); |
965 | } else { |
966 | return Fortran::common::visit( |
967 | [&](const auto &preciseKind) { |
968 | using TK = |
969 | typename std::decay_t<decltype(preciseKind)>::Result; |
970 | return gen( |
971 | std::get<Fortran::evaluate::Designator<TK>>(preciseKind.u) |
972 | .u, |
973 | vectorSubscriptDesignatorToValue); |
974 | }, |
975 | x.u); |
976 | } |
977 | } else { |
978 | fir::emitFatalError(loc, "unexpected typeless Designator"); |
979 | } |
980 | }, |
981 | designatorExpr.u); |
982 | } |
983 | |
984 | hlfir::ElementalAddrOp |
985 | HlfirDesignatorBuilder::convertVectorSubscriptedExprToElementalAddr( |
986 | const Fortran::lower::SomeExpr &designatorExpr) { |
987 | |
988 | hlfir::EntityWithAttributes elementAddrEntity = genDesignatorExpr( |
989 | designatorExpr, /*vectorSubscriptDesignatorToValue=*/false); |
990 | assert(getVectorSubscriptElementAddrOp().has_value() && |
991 | "expected vector subscripts"); |
992 | hlfir::ElementalAddrOp elementalAddrOp = *getVectorSubscriptElementAddrOp(); |
993 | // Now that the type parameters have been computed, add then to the |
994 | // hlfir.elemental_addr. |
995 | fir::FirOpBuilder &builder = getBuilder(); |
996 | llvm::SmallVector<mlir::Value, 1> lengths; |
997 | hlfir::genLengthParameters(loc, builder, elementAddrEntity, lengths); |
998 | if (!lengths.empty()) |
999 | elementalAddrOp.getTypeparamsMutable().assign(lengths); |
1000 | if (!elementAddrEntity.isPolymorphic()) |
1001 | elementalAddrOp.getMoldMutable().clear(); |
1002 | // Create the hlfir.yield terminator inside the hlfir.elemental_body. |
1003 | builder.setInsertionPointToEnd(&elementalAddrOp.getBody().front()); |
1004 | builder.create<hlfir::YieldOp>(loc, elementAddrEntity); |
1005 | builder.setInsertionPointAfter(elementalAddrOp); |
1006 | // Reset the HlfirDesignatorBuilder state, in case it is used on a new |
1007 | // designator. |
1008 | setVectorSubscriptElementAddrOp(std::nullopt); |
1009 | return elementalAddrOp; |
1010 | } |
1011 | |
1012 | //===--------------------------------------------------------------------===// |
1013 | // Binary Operation implementation |
1014 | //===--------------------------------------------------------------------===// |
1015 | |
1016 | template <typename T> |
1017 | struct BinaryOp {}; |
1018 | |
1019 | #undef GENBIN |
1020 | #define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp) \ |
1021 | template <int KIND> \ |
1022 | struct BinaryOp<Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \ |
1023 | Fortran::common::TypeCategory::GenBinTyCat, KIND>>> { \ |
1024 | using Op = Fortran::evaluate::GenBinEvOp<Fortran::evaluate::Type< \ |
1025 | Fortran::common::TypeCategory::GenBinTyCat, KIND>>; \ |
1026 | static hlfir::EntityWithAttributes gen(mlir::Location loc, \ |
1027 | fir::FirOpBuilder &builder, \ |
1028 | const Op &, hlfir::Entity lhs, \ |
1029 | hlfir::Entity rhs) { \ |
1030 | if constexpr (Fortran::common::TypeCategory::GenBinTyCat == \ |
1031 | Fortran::common::TypeCategory::Unsigned) { \ |
1032 | return hlfir::EntityWithAttributes{ \ |
1033 | builder.createUnsigned<GenBinFirOp>(loc, lhs.getType(), lhs, \ |
1034 | rhs)}; \ |
1035 | } else { \ |
1036 | return hlfir::EntityWithAttributes{ \ |
1037 | builder.create<GenBinFirOp>(loc, lhs, rhs)}; \ |
1038 | } \ |
1039 | } \ |
1040 | }; |
1041 | |
1042 | GENBIN(Add, Integer, mlir::arith::AddIOp) |
1043 | GENBIN(Add, Unsigned, mlir::arith::AddIOp) |
1044 | GENBIN(Add, Real, mlir::arith::AddFOp) |
1045 | GENBIN(Add, Complex, fir::AddcOp) |
1046 | GENBIN(Subtract, Integer, mlir::arith::SubIOp) |
1047 | GENBIN(Subtract, Unsigned, mlir::arith::SubIOp) |
1048 | GENBIN(Subtract, Real, mlir::arith::SubFOp) |
1049 | GENBIN(Subtract, Complex, fir::SubcOp) |
1050 | GENBIN(Multiply, Integer, mlir::arith::MulIOp) |
1051 | GENBIN(Multiply, Unsigned, mlir::arith::MulIOp) |
1052 | GENBIN(Multiply, Real, mlir::arith::MulFOp) |
1053 | GENBIN(Multiply, Complex, fir::MulcOp) |
1054 | GENBIN(Divide, Integer, mlir::arith::DivSIOp) |
1055 | GENBIN(Divide, Unsigned, mlir::arith::DivUIOp) |
1056 | GENBIN(Divide, Real, mlir::arith::DivFOp) |
1057 | |
1058 | template <int KIND> |
1059 | struct BinaryOp<Fortran::evaluate::Divide< |
1060 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>> { |
1061 | using Op = Fortran::evaluate::Divide< |
1062 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>; |
1063 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1064 | fir::FirOpBuilder &builder, const Op &, |
1065 | hlfir::Entity lhs, hlfir::Entity rhs) { |
1066 | mlir::Type ty = Fortran::lower::getFIRType( |
1067 | builder.getContext(), Fortran::common::TypeCategory::Complex, KIND, |
1068 | /*params=*/std::nullopt); |
1069 | return hlfir::EntityWithAttributes{ |
1070 | fir::genDivC(builder, loc, ty, lhs, rhs)}; |
1071 | } |
1072 | }; |
1073 | |
1074 | template <Fortran::common::TypeCategory TC, int KIND> |
1075 | struct BinaryOp<Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>>> { |
1076 | using Op = Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>>; |
1077 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1078 | fir::FirOpBuilder &builder, const Op &, |
1079 | hlfir::Entity lhs, hlfir::Entity rhs) { |
1080 | mlir::Type ty = Fortran::lower::getFIRType(builder.getContext(), TC, KIND, |
1081 | /*params=*/std::nullopt); |
1082 | return hlfir::EntityWithAttributes{fir::genPow(builder, loc, ty, lhs, rhs)}; |
1083 | } |
1084 | }; |
1085 | |
1086 | template <Fortran::common::TypeCategory TC, int KIND> |
1087 | struct BinaryOp< |
1088 | Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>> { |
1089 | using Op = |
1090 | Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>>; |
1091 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1092 | fir::FirOpBuilder &builder, const Op &, |
1093 | hlfir::Entity lhs, hlfir::Entity rhs) { |
1094 | mlir::Type ty = Fortran::lower::getFIRType(builder.getContext(), TC, KIND, |
1095 | /*params=*/std::nullopt); |
1096 | return hlfir::EntityWithAttributes{fir::genPow(builder, loc, ty, lhs, rhs)}; |
1097 | } |
1098 | }; |
1099 | |
1100 | template <Fortran::common::TypeCategory TC, int KIND> |
1101 | struct BinaryOp< |
1102 | Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>>> { |
1103 | using Op = Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>>; |
1104 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1105 | fir::FirOpBuilder &builder, |
1106 | const Op &op, hlfir::Entity lhs, |
1107 | hlfir::Entity rhs) { |
1108 | llvm::SmallVector<mlir::Value, 2> args{lhs, rhs}; |
1109 | fir::ExtendedValue res = op.ordering == Fortran::evaluate::Ordering::Greater |
1110 | ? fir::genMax(builder, loc, args) |
1111 | : fir::genMin(builder, loc, args); |
1112 | return hlfir::EntityWithAttributes{fir::getBase(res)}; |
1113 | } |
1114 | }; |
1115 | |
1116 | // evaluate::Extremum is only created by the front-end when building compiler |
1117 | // generated expressions (like when folding LEN() or shape/bounds inquiries). |
1118 | // MIN and MAX are represented as evaluate::ProcedureRef and are not going |
1119 | // through here. So far the frontend does not generate character Extremum so |
1120 | // there is no way to test it. |
1121 | template <int KIND> |
1122 | struct BinaryOp<Fortran::evaluate::Extremum< |
1123 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>> { |
1124 | using Op = Fortran::evaluate::Extremum< |
1125 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>; |
1126 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1127 | fir::FirOpBuilder &, const Op &, |
1128 | hlfir::Entity, hlfir::Entity) { |
1129 | fir::emitFatalError(loc, "Fortran::evaluate::Extremum are unexpected"); |
1130 | } |
1131 | static void genResultTypeParams(mlir::Location loc, fir::FirOpBuilder &, |
1132 | hlfir::Entity, hlfir::Entity, |
1133 | llvm::SmallVectorImpl<mlir::Value> &) { |
1134 | fir::emitFatalError(loc, "Fortran::evaluate::Extremum are unexpected"); |
1135 | } |
1136 | }; |
1137 | |
1138 | /// Convert parser's INTEGER relational operators to MLIR. |
1139 | static mlir::arith::CmpIPredicate |
1140 | translateSignedRelational(Fortran::common::RelationalOperator rop) { |
1141 | switch (rop) { |
1142 | case Fortran::common::RelationalOperator::LT: |
1143 | return mlir::arith::CmpIPredicate::slt; |
1144 | case Fortran::common::RelationalOperator::LE: |
1145 | return mlir::arith::CmpIPredicate::sle; |
1146 | case Fortran::common::RelationalOperator::EQ: |
1147 | return mlir::arith::CmpIPredicate::eq; |
1148 | case Fortran::common::RelationalOperator::NE: |
1149 | return mlir::arith::CmpIPredicate::ne; |
1150 | case Fortran::common::RelationalOperator::GT: |
1151 | return mlir::arith::CmpIPredicate::sgt; |
1152 | case Fortran::common::RelationalOperator::GE: |
1153 | return mlir::arith::CmpIPredicate::sge; |
1154 | } |
1155 | llvm_unreachable("unhandled INTEGER relational operator"); |
1156 | } |
1157 | |
1158 | static mlir::arith::CmpIPredicate |
1159 | translateUnsignedRelational(Fortran::common::RelationalOperator rop) { |
1160 | switch (rop) { |
1161 | case Fortran::common::RelationalOperator::LT: |
1162 | return mlir::arith::CmpIPredicate::ult; |
1163 | case Fortran::common::RelationalOperator::LE: |
1164 | return mlir::arith::CmpIPredicate::ule; |
1165 | case Fortran::common::RelationalOperator::EQ: |
1166 | return mlir::arith::CmpIPredicate::eq; |
1167 | case Fortran::common::RelationalOperator::NE: |
1168 | return mlir::arith::CmpIPredicate::ne; |
1169 | case Fortran::common::RelationalOperator::GT: |
1170 | return mlir::arith::CmpIPredicate::ugt; |
1171 | case Fortran::common::RelationalOperator::GE: |
1172 | return mlir::arith::CmpIPredicate::uge; |
1173 | } |
1174 | llvm_unreachable("unhandled UNSIGNED relational operator"); |
1175 | } |
1176 | |
1177 | /// Convert parser's REAL relational operators to MLIR. |
1178 | /// The choice of order (O prefix) vs unorder (U prefix) follows Fortran 2018 |
1179 | /// requirements in the IEEE context (table 17.1 of F2018). This choice is |
1180 | /// also applied in other contexts because it is easier and in line with |
1181 | /// other Fortran compilers. |
1182 | /// FIXME: The signaling/quiet aspect of the table 17.1 requirement is not |
1183 | /// fully enforced. FIR and LLVM `fcmp` instructions do not give any guarantee |
1184 | /// whether the comparison will signal or not in case of quiet NaN argument. |
1185 | static mlir::arith::CmpFPredicate |
1186 | translateFloatRelational(Fortran::common::RelationalOperator rop) { |
1187 | switch (rop) { |
1188 | case Fortran::common::RelationalOperator::LT: |
1189 | return mlir::arith::CmpFPredicate::OLT; |
1190 | case Fortran::common::RelationalOperator::LE: |
1191 | return mlir::arith::CmpFPredicate::OLE; |
1192 | case Fortran::common::RelationalOperator::EQ: |
1193 | return mlir::arith::CmpFPredicate::OEQ; |
1194 | case Fortran::common::RelationalOperator::NE: |
1195 | return mlir::arith::CmpFPredicate::UNE; |
1196 | case Fortran::common::RelationalOperator::GT: |
1197 | return mlir::arith::CmpFPredicate::OGT; |
1198 | case Fortran::common::RelationalOperator::GE: |
1199 | return mlir::arith::CmpFPredicate::OGE; |
1200 | } |
1201 | llvm_unreachable("unhandled REAL relational operator"); |
1202 | } |
1203 | |
1204 | template <int KIND> |
1205 | struct BinaryOp<Fortran::evaluate::Relational< |
1206 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>> { |
1207 | using Op = Fortran::evaluate::Relational< |
1208 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>; |
1209 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1210 | fir::FirOpBuilder &builder, |
1211 | const Op &op, hlfir::Entity lhs, |
1212 | hlfir::Entity rhs) { |
1213 | auto cmp = builder.create<mlir::arith::CmpIOp>( |
1214 | loc, translateSignedRelational(op.opr), lhs, rhs); |
1215 | return hlfir::EntityWithAttributes{cmp}; |
1216 | } |
1217 | }; |
1218 | |
1219 | template <int KIND> |
1220 | struct BinaryOp<Fortran::evaluate::Relational< |
1221 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Unsigned, KIND>>> { |
1222 | using Op = Fortran::evaluate::Relational< |
1223 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Unsigned, KIND>>; |
1224 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1225 | fir::FirOpBuilder &builder, |
1226 | const Op &op, hlfir::Entity lhs, |
1227 | hlfir::Entity rhs) { |
1228 | int bits = Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, |
1229 | KIND>::Scalar::bits; |
1230 | auto signlessType = mlir::IntegerType::get( |
1231 | builder.getContext(), bits, |
1232 | mlir::IntegerType::SignednessSemantics::Signless); |
1233 | mlir::Value lhsSL = builder.createConvert(loc, signlessType, lhs); |
1234 | mlir::Value rhsSL = builder.createConvert(loc, signlessType, rhs); |
1235 | auto cmp = builder.create<mlir::arith::CmpIOp>( |
1236 | loc, translateUnsignedRelational(op.opr), lhsSL, rhsSL); |
1237 | return hlfir::EntityWithAttributes{cmp}; |
1238 | } |
1239 | }; |
1240 | |
1241 | template <int KIND> |
1242 | struct BinaryOp<Fortran::evaluate::Relational< |
1243 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>> { |
1244 | using Op = Fortran::evaluate::Relational< |
1245 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>; |
1246 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1247 | fir::FirOpBuilder &builder, |
1248 | const Op &op, hlfir::Entity lhs, |
1249 | hlfir::Entity rhs) { |
1250 | auto cmp = builder.create<mlir::arith::CmpFOp>( |
1251 | loc, translateFloatRelational(op.opr), lhs, rhs); |
1252 | return hlfir::EntityWithAttributes{cmp}; |
1253 | } |
1254 | }; |
1255 | |
1256 | template <int KIND> |
1257 | struct BinaryOp<Fortran::evaluate::Relational< |
1258 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>> { |
1259 | using Op = Fortran::evaluate::Relational< |
1260 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>; |
1261 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1262 | fir::FirOpBuilder &builder, |
1263 | const Op &op, hlfir::Entity lhs, |
1264 | hlfir::Entity rhs) { |
1265 | auto cmp = builder.create<fir::CmpcOp>( |
1266 | loc, translateFloatRelational(op.opr), lhs, rhs); |
1267 | return hlfir::EntityWithAttributes{cmp}; |
1268 | } |
1269 | }; |
1270 | |
1271 | template <int KIND> |
1272 | struct BinaryOp<Fortran::evaluate::Relational< |
1273 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>> { |
1274 | using Op = Fortran::evaluate::Relational< |
1275 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>; |
1276 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1277 | fir::FirOpBuilder &builder, |
1278 | const Op &op, hlfir::Entity lhs, |
1279 | hlfir::Entity rhs) { |
1280 | auto [lhsExv, lhsCleanUp] = |
1281 | hlfir::translateToExtendedValue(loc, builder, lhs); |
1282 | auto [rhsExv, rhsCleanUp] = |
1283 | hlfir::translateToExtendedValue(loc, builder, rhs); |
1284 | auto cmp = fir::runtime::genCharCompare( |
1285 | builder, loc, translateSignedRelational(op.opr), lhsExv, rhsExv); |
1286 | if (lhsCleanUp) |
1287 | (*lhsCleanUp)(); |
1288 | if (rhsCleanUp) |
1289 | (*rhsCleanUp)(); |
1290 | return hlfir::EntityWithAttributes{cmp}; |
1291 | } |
1292 | }; |
1293 | |
1294 | template <int KIND> |
1295 | struct BinaryOp<Fortran::evaluate::LogicalOperation<KIND>> { |
1296 | using Op = Fortran::evaluate::LogicalOperation<KIND>; |
1297 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1298 | fir::FirOpBuilder &builder, |
1299 | const Op &op, hlfir::Entity lhs, |
1300 | hlfir::Entity rhs) { |
1301 | mlir::Type i1Type = builder.getI1Type(); |
1302 | mlir::Value i1Lhs = builder.createConvert(loc, i1Type, lhs); |
1303 | mlir::Value i1Rhs = builder.createConvert(loc, i1Type, rhs); |
1304 | switch (op.logicalOperator) { |
1305 | case Fortran::evaluate::LogicalOperator::And: |
1306 | return hlfir::EntityWithAttributes{ |
1307 | builder.create<mlir::arith::AndIOp>(loc, i1Lhs, i1Rhs)}; |
1308 | case Fortran::evaluate::LogicalOperator::Or: |
1309 | return hlfir::EntityWithAttributes{ |
1310 | builder.create<mlir::arith::OrIOp>(loc, i1Lhs, i1Rhs)}; |
1311 | case Fortran::evaluate::LogicalOperator::Eqv: |
1312 | return hlfir::EntityWithAttributes{builder.create<mlir::arith::CmpIOp>( |
1313 | loc, mlir::arith::CmpIPredicate::eq, i1Lhs, i1Rhs)}; |
1314 | case Fortran::evaluate::LogicalOperator::Neqv: |
1315 | return hlfir::EntityWithAttributes{builder.create<mlir::arith::CmpIOp>( |
1316 | loc, mlir::arith::CmpIPredicate::ne, i1Lhs, i1Rhs)}; |
1317 | case Fortran::evaluate::LogicalOperator::Not: |
1318 | // lib/evaluate expression for .NOT. is Fortran::evaluate::Not<KIND>. |
1319 | llvm_unreachable(".NOT. is not a binary operator"); |
1320 | } |
1321 | llvm_unreachable("unhandled logical operation"); |
1322 | } |
1323 | }; |
1324 | |
1325 | template <int KIND> |
1326 | struct BinaryOp<Fortran::evaluate::ComplexConstructor<KIND>> { |
1327 | using Op = Fortran::evaluate::ComplexConstructor<KIND>; |
1328 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1329 | fir::FirOpBuilder &builder, const Op &, |
1330 | hlfir::Entity lhs, hlfir::Entity rhs) { |
1331 | mlir::Value res = |
1332 | fir::factory::Complex{builder, loc}.createComplex(lhs, rhs); |
1333 | return hlfir::EntityWithAttributes{res}; |
1334 | } |
1335 | }; |
1336 | |
1337 | template <int KIND> |
1338 | struct BinaryOp<Fortran::evaluate::SetLength<KIND>> { |
1339 | using Op = Fortran::evaluate::SetLength<KIND>; |
1340 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1341 | fir::FirOpBuilder &builder, const Op &, |
1342 | hlfir::Entity string, |
1343 | hlfir::Entity length) { |
1344 | // The input length may be a user input and needs to be sanitized as per |
1345 | // Fortran 2018 7.4.4.2 point 5. |
1346 | mlir::Value safeLength = fir::factory::genMaxWithZero(builder, loc, length); |
1347 | return hlfir::EntityWithAttributes{ |
1348 | builder.create<hlfir::SetLengthOp>(loc, string, safeLength)}; |
1349 | } |
1350 | static void |
1351 | genResultTypeParams(mlir::Location, fir::FirOpBuilder &, hlfir::Entity, |
1352 | hlfir::Entity rhs, |
1353 | llvm::SmallVectorImpl<mlir::Value> &resultTypeParams) { |
1354 | resultTypeParams.push_back(rhs); |
1355 | } |
1356 | }; |
1357 | |
1358 | template <int KIND> |
1359 | struct BinaryOp<Fortran::evaluate::Concat<KIND>> { |
1360 | using Op = Fortran::evaluate::Concat<KIND>; |
1361 | hlfir::EntityWithAttributes gen(mlir::Location loc, |
1362 | fir::FirOpBuilder &builder, const Op &, |
1363 | hlfir::Entity lhs, hlfir::Entity rhs) { |
1364 | assert(len && "genResultTypeParams must have been called"); |
1365 | auto concat = |
1366 | builder.create<hlfir::ConcatOp>(loc, mlir::ValueRange{lhs, rhs}, len); |
1367 | return hlfir::EntityWithAttributes{concat.getResult()}; |
1368 | } |
1369 | void |
1370 | genResultTypeParams(mlir::Location loc, fir::FirOpBuilder &builder, |
1371 | hlfir::Entity lhs, hlfir::Entity rhs, |
1372 | llvm::SmallVectorImpl<mlir::Value> &resultTypeParams) { |
1373 | llvm::SmallVector<mlir::Value> lengths; |
1374 | hlfir::genLengthParameters(loc, builder, lhs, lengths); |
1375 | hlfir::genLengthParameters(loc, builder, rhs, lengths); |
1376 | assert(lengths.size() == 2 && "lacks rhs or lhs length"); |
1377 | mlir::Type idxType = builder.getIndexType(); |
1378 | mlir::Value lhsLen = builder.createConvert(loc, idxType, lengths[0]); |
1379 | mlir::Value rhsLen = builder.createConvert(loc, idxType, lengths[1]); |
1380 | len = builder.create<mlir::arith::AddIOp>(loc, lhsLen, rhsLen); |
1381 | resultTypeParams.push_back(len); |
1382 | } |
1383 | |
1384 | private: |
1385 | mlir::Value len{}; |
1386 | }; |
1387 | |
1388 | //===--------------------------------------------------------------------===// |
1389 | // Unary Operation implementation |
1390 | //===--------------------------------------------------------------------===// |
1391 | |
1392 | template <typename T> |
1393 | struct UnaryOp {}; |
1394 | |
1395 | template <int KIND> |
1396 | struct UnaryOp<Fortran::evaluate::Not<KIND>> { |
1397 | using Op = Fortran::evaluate::Not<KIND>; |
1398 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1399 | fir::FirOpBuilder &builder, const Op &, |
1400 | hlfir::Entity lhs) { |
1401 | mlir::Value one = builder.createBool(loc, true); |
1402 | mlir::Value val = builder.createConvert(loc, builder.getI1Type(), lhs); |
1403 | return hlfir::EntityWithAttributes{ |
1404 | builder.create<mlir::arith::XOrIOp>(loc, val, one)}; |
1405 | } |
1406 | }; |
1407 | |
1408 | template <int KIND> |
1409 | struct UnaryOp<Fortran::evaluate::Negate< |
1410 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>> { |
1411 | using Op = Fortran::evaluate::Negate< |
1412 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>; |
1413 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1414 | fir::FirOpBuilder &builder, const Op &, |
1415 | hlfir::Entity lhs) { |
1416 | // Like LLVM, integer negation is the binary op "0 - value" |
1417 | mlir::Type type = Fortran::lower::getFIRType( |
1418 | builder.getContext(), Fortran::common::TypeCategory::Integer, KIND, |
1419 | /*params=*/std::nullopt); |
1420 | mlir::Value zero = builder.createIntegerConstant(loc, type, 0); |
1421 | return hlfir::EntityWithAttributes{ |
1422 | builder.create<mlir::arith::SubIOp>(loc, zero, lhs)}; |
1423 | } |
1424 | }; |
1425 | |
1426 | template <int KIND> |
1427 | struct UnaryOp<Fortran::evaluate::Negate< |
1428 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Unsigned, KIND>>> { |
1429 | using Op = Fortran::evaluate::Negate< |
1430 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Unsigned, KIND>>; |
1431 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1432 | fir::FirOpBuilder &builder, const Op &, |
1433 | hlfir::Entity lhs) { |
1434 | int bits = Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, |
1435 | KIND>::Scalar::bits; |
1436 | mlir::Type signlessType = mlir::IntegerType::get( |
1437 | builder.getContext(), bits, |
1438 | mlir::IntegerType::SignednessSemantics::Signless); |
1439 | mlir::Value zero = builder.createIntegerConstant(loc, signlessType, 0); |
1440 | mlir::Value signless = builder.createConvert(loc, signlessType, lhs); |
1441 | mlir::Value negated = |
1442 | builder.create<mlir::arith::SubIOp>(loc, zero, signless); |
1443 | return hlfir::EntityWithAttributes( |
1444 | builder.createConvert(loc, lhs.getType(), negated)); |
1445 | } |
1446 | }; |
1447 | |
1448 | template <int KIND> |
1449 | struct UnaryOp<Fortran::evaluate::Negate< |
1450 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>> { |
1451 | using Op = Fortran::evaluate::Negate< |
1452 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>; |
1453 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1454 | fir::FirOpBuilder &builder, const Op &, |
1455 | hlfir::Entity lhs) { |
1456 | return hlfir::EntityWithAttributes{ |
1457 | builder.create<mlir::arith::NegFOp>(loc, lhs)}; |
1458 | } |
1459 | }; |
1460 | |
1461 | template <int KIND> |
1462 | struct UnaryOp<Fortran::evaluate::Negate< |
1463 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>> { |
1464 | using Op = Fortran::evaluate::Negate< |
1465 | Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>; |
1466 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1467 | fir::FirOpBuilder &builder, const Op &, |
1468 | hlfir::Entity lhs) { |
1469 | return hlfir::EntityWithAttributes{builder.create<fir::NegcOp>(loc, lhs)}; |
1470 | } |
1471 | }; |
1472 | |
1473 | template <int KIND> |
1474 | struct UnaryOp<Fortran::evaluate::ComplexComponent<KIND>> { |
1475 | using Op = Fortran::evaluate::ComplexComponent<KIND>; |
1476 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1477 | fir::FirOpBuilder &builder, |
1478 | const Op &op, hlfir::Entity lhs) { |
1479 | mlir::Value res = fir::factory::Complex{builder, loc}.extractComplexPart( |
1480 | lhs, op.isImaginaryPart); |
1481 | return hlfir::EntityWithAttributes{res}; |
1482 | } |
1483 | }; |
1484 | |
1485 | template <typename T> |
1486 | struct UnaryOp<Fortran::evaluate::Parentheses<T>> { |
1487 | using Op = Fortran::evaluate::Parentheses<T>; |
1488 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1489 | fir::FirOpBuilder &builder, |
1490 | const Op &op, hlfir::Entity lhs) { |
1491 | if (lhs.isVariable()) |
1492 | return hlfir::EntityWithAttributes{ |
1493 | builder.create<hlfir::AsExprOp>(loc, lhs)}; |
1494 | return hlfir::EntityWithAttributes{ |
1495 | builder.create<hlfir::NoReassocOp>(loc, lhs.getType(), lhs)}; |
1496 | } |
1497 | |
1498 | static void |
1499 | genResultTypeParams(mlir::Location loc, fir::FirOpBuilder &builder, |
1500 | hlfir::Entity lhs, |
1501 | llvm::SmallVectorImpl<mlir::Value> &resultTypeParams) { |
1502 | hlfir::genLengthParameters(loc, builder, lhs, resultTypeParams); |
1503 | } |
1504 | }; |
1505 | |
1506 | template <Fortran::common::TypeCategory TC1, int KIND, |
1507 | Fortran::common::TypeCategory TC2> |
1508 | struct UnaryOp< |
1509 | Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, TC2>> { |
1510 | using Op = |
1511 | Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, TC2>; |
1512 | static hlfir::EntityWithAttributes gen(mlir::Location loc, |
1513 | fir::FirOpBuilder &builder, const Op &, |
1514 | hlfir::Entity lhs) { |
1515 | if constexpr (TC1 == Fortran::common::TypeCategory::Character && |
1516 | TC2 == TC1) { |
1517 | return hlfir::convertCharacterKind(loc, builder, lhs, KIND); |
1518 | } |
1519 | mlir::Type type = Fortran::lower::getFIRType(builder.getContext(), TC1, |
1520 | KIND, /*params=*/std::nullopt); |
1521 | mlir::Value res = builder.convertWithSemantics(loc, type, lhs); |
1522 | return hlfir::EntityWithAttributes{res}; |
1523 | } |
1524 | |
1525 | static void |
1526 | genResultTypeParams(mlir::Location loc, fir::FirOpBuilder &builder, |
1527 | hlfir::Entity lhs, |
1528 | llvm::SmallVectorImpl<mlir::Value> &resultTypeParams) { |
1529 | hlfir::genLengthParameters(loc, builder, lhs, resultTypeParams); |
1530 | } |
1531 | }; |
1532 | |
1533 | static bool hasDeferredCharacterLength(const Fortran::semantics::Symbol &sym) { |
1534 | const Fortran::semantics::DeclTypeSpec *type = sym.GetType(); |
1535 | return type && |
1536 | type->category() == |
1537 | Fortran::semantics::DeclTypeSpec::Category::Character && |
1538 | type->characterTypeSpec().length().isDeferred(); |
1539 | } |
1540 | |
1541 | /// Lower Expr to HLFIR. |
1542 | class HlfirBuilder { |
1543 | public: |
1544 | HlfirBuilder(mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
1545 | Fortran::lower::SymMap &symMap, |
1546 | Fortran::lower::StatementContext &stmtCtx) |
1547 | : converter{converter}, symMap{symMap}, stmtCtx{stmtCtx}, loc{loc} {} |
1548 | |
1549 | template <typename T> |
1550 | hlfir::EntityWithAttributes gen(const Fortran::evaluate::Expr<T> &expr) { |
1551 | if (const Fortran::lower::ExprToValueMap *map = |
1552 | getConverter().getExprOverrides()) { |
1553 | if constexpr (std::is_same_v<T, Fortran::evaluate::SomeType>) { |
1554 | if (auto match = map->find(&expr); match != map->end()) |
1555 | return hlfir::EntityWithAttributes{match->second}; |
1556 | } else { |
1557 | Fortran::lower::SomeExpr someExpr = toEvExpr(expr); |
1558 | if (auto match = map->find(&someExpr); match != map->end()) |
1559 | return hlfir::EntityWithAttributes{match->second}; |
1560 | } |
1561 | } |
1562 | return Fortran::common::visit([&](const auto &x) { return gen(x); }, |
1563 | expr.u); |
1564 | } |
1565 | |
1566 | private: |
1567 | hlfir::EntityWithAttributes |
1568 | gen(const Fortran::evaluate::BOZLiteralConstant &expr) { |
1569 | TODO(getLoc(), "BOZ"); |
1570 | } |
1571 | |
1572 | hlfir::EntityWithAttributes gen(const Fortran::evaluate::NullPointer &expr) { |
1573 | auto nullop = getBuilder().create<hlfir::NullOp>(getLoc()); |
1574 | return mlir::cast<fir::FortranVariableOpInterface>(nullop.getOperation()); |
1575 | } |
1576 | |
1577 | hlfir::EntityWithAttributes |
1578 | gen(const Fortran::evaluate::ProcedureDesignator &proc) { |
1579 | return Fortran::lower::convertProcedureDesignatorToHLFIR( |
1580 | getLoc(), getConverter(), proc, getSymMap(), getStmtCtx()); |
1581 | } |
1582 | |
1583 | hlfir::EntityWithAttributes gen(const Fortran::evaluate::ProcedureRef &expr) { |
1584 | Fortran::evaluate::ProcedureDesignator proc{expr.proc()}; |
1585 | auto procTy{Fortran::lower::translateSignature(proc, getConverter())}; |
1586 | auto result = Fortran::lower::convertCallToHLFIR(getLoc(), getConverter(), |
1587 | expr, procTy.getResult(0), |
1588 | getSymMap(), getStmtCtx()); |
1589 | assert(result.has_value()); |
1590 | return *result; |
1591 | } |
1592 | |
1593 | template <typename T> |
1594 | hlfir::EntityWithAttributes |
1595 | gen(const Fortran::evaluate::Designator<T> &designator) { |
1596 | return HlfirDesignatorBuilder(getLoc(), getConverter(), getSymMap(), |
1597 | getStmtCtx()) |
1598 | .gen(designator.u); |
1599 | } |
1600 | |
1601 | template <typename T> |
1602 | hlfir::EntityWithAttributes |
1603 | gen(const Fortran::evaluate::FunctionRef<T> &expr) { |
1604 | mlir::Type resType = |
1605 | Fortran::lower::TypeBuilder<T>::genType(getConverter(), expr); |
1606 | auto result = Fortran::lower::convertCallToHLFIR( |
1607 | getLoc(), getConverter(), expr, resType, getSymMap(), getStmtCtx()); |
1608 | assert(result.has_value()); |
1609 | return *result; |
1610 | } |
1611 | |
1612 | template <typename T> |
1613 | hlfir::EntityWithAttributes gen(const Fortran::evaluate::Constant<T> &expr) { |
1614 | mlir::Location loc = getLoc(); |
1615 | fir::FirOpBuilder &builder = getBuilder(); |
1616 | fir::ExtendedValue exv = Fortran::lower::convertConstant( |
1617 | converter, loc, expr, /*outlineBigConstantInReadOnlyMemory=*/true); |
1618 | if (const auto *scalarBox = exv.getUnboxed()) |
1619 | if (fir::isa_trivial(scalarBox->getType())) |
1620 | return hlfir::EntityWithAttributes(*scalarBox); |
1621 | if (auto addressOf = fir::getBase(exv).getDefiningOp<fir::AddrOfOp>()) { |
1622 | auto flags = fir::FortranVariableFlagsAttr::get( |
1623 | builder.getContext(), fir::FortranVariableFlagsEnum::parameter); |
1624 | return hlfir::genDeclare( |
1625 | loc, builder, exv, |
1626 | addressOf.getSymbol().getRootReference().getValue(), flags); |
1627 | } |
1628 | fir::emitFatalError(loc, "Constant<T> was lowered to unexpected format"); |
1629 | } |
1630 | |
1631 | template <typename T> |
1632 | hlfir::EntityWithAttributes |
1633 | gen(const Fortran::evaluate::ArrayConstructor<T> &arrayCtor) { |
1634 | return Fortran::lower::ArrayConstructorBuilder<T>::gen( |
1635 | getLoc(), getConverter(), arrayCtor, getSymMap(), getStmtCtx()); |
1636 | } |
1637 | |
1638 | template <typename D, typename R, typename O> |
1639 | hlfir::EntityWithAttributes |
1640 | gen(const Fortran::evaluate::Operation<D, R, O> &op) { |
1641 | auto &builder = getBuilder(); |
1642 | mlir::Location loc = getLoc(); |
1643 | const int rank = op.Rank(); |
1644 | UnaryOp<D> unaryOp; |
1645 | auto left = hlfir::loadTrivialScalar(loc, builder, gen(op.left())); |
1646 | llvm::SmallVector<mlir::Value, 1> typeParams; |
1647 | if constexpr (R::category == Fortran::common::TypeCategory::Character) { |
1648 | unaryOp.genResultTypeParams(loc, builder, left, typeParams); |
1649 | } |
1650 | if (rank == 0) |
1651 | return unaryOp.gen(loc, builder, op.derived(), left); |
1652 | |
1653 | // Elemental expression. |
1654 | mlir::Type elementType; |
1655 | if constexpr (R::category == Fortran::common::TypeCategory::Derived) { |
1656 | if (op.derived().GetType().IsUnlimitedPolymorphic()) |
1657 | elementType = mlir::NoneType::get(builder.getContext()); |
1658 | else |
1659 | elementType = Fortran::lower::translateDerivedTypeToFIRType( |
1660 | getConverter(), op.derived().GetType().GetDerivedTypeSpec()); |
1661 | } else { |
1662 | elementType = |
1663 | Fortran::lower::getFIRType(builder.getContext(), R::category, R::kind, |
1664 | /*params=*/std::nullopt); |
1665 | } |
1666 | mlir::Value shape = hlfir::genShape(loc, builder, left); |
1667 | auto genKernel = [&op, &left, &unaryOp]( |
1668 | mlir::Location l, fir::FirOpBuilder &b, |
1669 | mlir::ValueRange oneBasedIndices) -> hlfir::Entity { |
1670 | auto leftElement = hlfir::getElementAt(l, b, left, oneBasedIndices); |
1671 | auto leftVal = hlfir::loadTrivialScalar(l, b, leftElement); |
1672 | return unaryOp.gen(l, b, op.derived(), leftVal); |
1673 | }; |
1674 | mlir::Value elemental = hlfir::genElementalOp( |
1675 | loc, builder, elementType, shape, typeParams, genKernel, |
1676 | /*isUnordered=*/true, left.isPolymorphic() ? left : mlir::Value{}); |
1677 | fir::FirOpBuilder *bldr = &builder; |
1678 | getStmtCtx().attachCleanup( |
1679 | [=]() { bldr->create<hlfir::DestroyOp>(loc, elemental); }); |
1680 | return hlfir::EntityWithAttributes{elemental}; |
1681 | } |
1682 | |
1683 | template <typename D, typename R, typename LO, typename RO> |
1684 | hlfir::EntityWithAttributes |
1685 | gen(const Fortran::evaluate::Operation<D, R, LO, RO> &op) { |
1686 | auto &builder = getBuilder(); |
1687 | mlir::Location loc = getLoc(); |
1688 | const int rank = op.Rank(); |
1689 | BinaryOp<D> binaryOp; |
1690 | auto left = hlfir::loadTrivialScalar(loc, builder, gen(op.left())); |
1691 | auto right = hlfir::loadTrivialScalar(loc, builder, gen(op.right())); |
1692 | llvm::SmallVector<mlir::Value, 1> typeParams; |
1693 | if constexpr (R::category == Fortran::common::TypeCategory::Character) { |
1694 | binaryOp.genResultTypeParams(loc, builder, left, right, typeParams); |
1695 | } |
1696 | if (rank == 0) |
1697 | return binaryOp.gen(loc, builder, op.derived(), left, right); |
1698 | |
1699 | // Elemental expression. |
1700 | mlir::Type elementType = |
1701 | Fortran::lower::getFIRType(builder.getContext(), R::category, R::kind, |
1702 | /*params=*/std::nullopt); |
1703 | // TODO: "merge" shape, get cst shape from front-end if possible. |
1704 | mlir::Value shape; |
1705 | if (left.isArray()) { |
1706 | shape = hlfir::genShape(loc, builder, left); |
1707 | } else { |
1708 | assert(right.isArray() && "must have at least one array operand"); |
1709 | shape = hlfir::genShape(loc, builder, right); |
1710 | } |
1711 | auto genKernel = [&op, &left, &right, &binaryOp]( |
1712 | mlir::Location l, fir::FirOpBuilder &b, |
1713 | mlir::ValueRange oneBasedIndices) -> hlfir::Entity { |
1714 | auto leftElement = hlfir::getElementAt(l, b, left, oneBasedIndices); |
1715 | auto rightElement = hlfir::getElementAt(l, b, right, oneBasedIndices); |
1716 | auto leftVal = hlfir::loadTrivialScalar(l, b, leftElement); |
1717 | auto rightVal = hlfir::loadTrivialScalar(l, b, rightElement); |
1718 | return binaryOp.gen(l, b, op.derived(), leftVal, rightVal); |
1719 | }; |
1720 | auto iofBackup = builder.getIntegerOverflowFlags(); |
1721 | // nsw is never added to operations on vector subscripts |
1722 | // even if -fno-wrapv is enabled. |
1723 | builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::none); |
1724 | mlir::Value elemental = hlfir::genElementalOp(loc, builder, elementType, |
1725 | shape, typeParams, genKernel, |
1726 | /*isUnordered=*/true); |
1727 | builder.setIntegerOverflowFlags(iofBackup); |
1728 | fir::FirOpBuilder *bldr = &builder; |
1729 | getStmtCtx().attachCleanup( |
1730 | [=]() { bldr->create<hlfir::DestroyOp>(loc, elemental); }); |
1731 | return hlfir::EntityWithAttributes{elemental}; |
1732 | } |
1733 | |
1734 | hlfir::EntityWithAttributes |
1735 | gen(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &op) { |
1736 | return Fortran::common::visit([&](const auto &x) { return gen(x); }, op.u); |
1737 | } |
1738 | |
1739 | hlfir::EntityWithAttributes gen(const Fortran::evaluate::TypeParamInquiry &) { |
1740 | TODO(getLoc(), "lowering type parameter inquiry to HLFIR"); |
1741 | } |
1742 | |
1743 | hlfir::EntityWithAttributes |
1744 | gen(const Fortran::evaluate::DescriptorInquiry &desc) { |
1745 | mlir::Location loc = getLoc(); |
1746 | auto &builder = getBuilder(); |
1747 | hlfir::EntityWithAttributes entity = |
1748 | HlfirDesignatorBuilder(getLoc(), getConverter(), getSymMap(), |
1749 | getStmtCtx()) |
1750 | .genNamedEntity(desc.base()); |
1751 | using ResTy = Fortran::evaluate::DescriptorInquiry::Result; |
1752 | mlir::Type resultType = |
1753 | getConverter().genType(ResTy::category, ResTy::kind); |
1754 | auto castResult = [&](mlir::Value v) { |
1755 | return hlfir::EntityWithAttributes{ |
1756 | builder.createConvert(loc, resultType, v)}; |
1757 | }; |
1758 | switch (desc.field()) { |
1759 | case Fortran::evaluate::DescriptorInquiry::Field::Len: |
1760 | return castResult(hlfir::genCharLength(loc, builder, entity)); |
1761 | case Fortran::evaluate::DescriptorInquiry::Field::LowerBound: |
1762 | return castResult( |
1763 | hlfir::genLBound(loc, builder, entity, desc.dimension())); |
1764 | case Fortran::evaluate::DescriptorInquiry::Field::Extent: |
1765 | return castResult( |
1766 | hlfir::genExtent(loc, builder, entity, desc.dimension())); |
1767 | case Fortran::evaluate::DescriptorInquiry::Field::Rank: |
1768 | return castResult(hlfir::genRank(loc, builder, entity, resultType)); |
1769 | case Fortran::evaluate::DescriptorInquiry::Field::Stride: |
1770 | // So far the front end does not generate this inquiry. |
1771 | TODO(loc, "stride inquiry"); |
1772 | } |
1773 | llvm_unreachable("unknown descriptor inquiry"); |
1774 | } |
1775 | |
1776 | hlfir::EntityWithAttributes |
1777 | gen(const Fortran::evaluate::ImpliedDoIndex &var) { |
1778 | mlir::Value value = symMap.lookupImpliedDo(toStringRef(var.name)); |
1779 | if (!value) |
1780 | fir::emitFatalError(getLoc(), "ac-do-variable has no binding"); |
1781 | // The index value generated by the implied-do has Index type, |
1782 | // while computations based on it inside the loop body are using |
1783 | // the original data type. So we need to cast it appropriately. |
1784 | mlir::Type varTy = getConverter().genType(toEvExpr(var)); |
1785 | value = getBuilder().createConvert(getLoc(), varTy, value); |
1786 | return hlfir::EntityWithAttributes{value}; |
1787 | } |
1788 | |
1789 | static bool |
1790 | isDerivedTypeWithLenParameters(const Fortran::semantics::Symbol &sym) { |
1791 | if (const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType()) |
1792 | if (const Fortran::semantics::DerivedTypeSpec *derived = |
1793 | declTy->AsDerived()) |
1794 | return Fortran::semantics::CountLenParameters(*derived) > 0; |
1795 | return false; |
1796 | } |
1797 | |
1798 | // Construct an entity holding the value specified by the |
1799 | // StructureConstructor. The initialization of the temporary entity |
1800 | // is done component by component with the help of HLFIR operations |
1801 | // DesignateOp and AssignOp. |
1802 | hlfir::EntityWithAttributes |
1803 | gen(const Fortran::evaluate::StructureConstructor &ctor) { |
1804 | mlir::Location loc = getLoc(); |
1805 | fir::FirOpBuilder &builder = getBuilder(); |
1806 | mlir::Type ty = translateSomeExprToFIRType(converter, toEvExpr(ctor)); |
1807 | auto recTy = mlir::cast<fir::RecordType>(ty); |
1808 | |
1809 | if (recTy.isDependentType()) |
1810 | TODO(loc, "structure constructor for derived type with length parameters " |
1811 | "in HLFIR"); |
1812 | |
1813 | // Allocate scalar temporary that will be initialized |
1814 | // with the values specified by the constructor. |
1815 | mlir::Value storagePtr = builder.createTemporary(loc, recTy); |
1816 | auto varOp = hlfir::EntityWithAttributes{builder.create<hlfir::DeclareOp>( |
1817 | loc, storagePtr, "ctor.temp", /*shape=*/nullptr, |
1818 | /*typeparams=*/mlir::ValueRange{}, /*dummy_scope=*/nullptr, |
1819 | fir::FortranVariableFlagsAttr{})}; |
1820 | |
1821 | // Initialize any components that need initialization. |
1822 | mlir::Value box = builder.createBox(loc, fir::ExtendedValue{varOp}); |
1823 | fir::runtime::genDerivedTypeInitialize(builder, loc, box); |
1824 | |
1825 | // StructureConstructor values may relate to name of components in parent |
1826 | // types. These components cannot be addressed directly, the parent |
1827 | // components must be addressed first. The loop below creates all the |
1828 | // required chains of hlfir.designate to address the parent components so |
1829 | // that the StructureConstructor can later be lowered by addressing these |
1830 | // parent components if needed. Note: the front-end orders the components in |
1831 | // structure constructors. |
1832 | using ValueAndParent = std::tuple<const Fortran::lower::SomeExpr &, |
1833 | const Fortran::semantics::Symbol &, |
1834 | hlfir::EntityWithAttributes>; |
1835 | llvm::SmallVector<ValueAndParent> valuesAndParents; |
1836 | for (const auto &value : llvm::reverse(ctor.values())) { |
1837 | const Fortran::semantics::Symbol &compSym = *value.first; |
1838 | hlfir::EntityWithAttributes currentParent = varOp; |
1839 | for (Fortran::lower::ComponentReverseIterator compIterator( |
1840 | ctor.result().derivedTypeSpec()); |
1841 | !compIterator.lookup(compSym.name());) { |
1842 | const auto &parentType = compIterator.advanceToParentType(); |
1843 | llvm::StringRef parentName = toStringRef(parentType.name()); |
1844 | auto baseRecTy = mlir::cast<fir::RecordType>( |
1845 | hlfir::getFortranElementType(currentParent.getType())); |
1846 | auto parentCompType = baseRecTy.getType(parentName); |
1847 | assert(parentCompType && "failed to retrieve parent component type"); |
1848 | mlir::Type designatorType = builder.getRefType(parentCompType); |
1849 | mlir::Value newParent = builder.create<hlfir::DesignateOp>( |
1850 | loc, designatorType, currentParent, parentName, |
1851 | /*compShape=*/mlir::Value{}, hlfir::DesignateOp::Subscripts{}, |
1852 | /*substring=*/mlir::ValueRange{}, |
1853 | /*complexPart=*/std::nullopt, |
1854 | /*shape=*/mlir::Value{}, /*typeParams=*/mlir::ValueRange{}, |
1855 | fir::FortranVariableFlagsAttr{}); |
1856 | currentParent = hlfir::EntityWithAttributes{newParent}; |
1857 | } |
1858 | valuesAndParents.emplace_back( |
1859 | ValueAndParent{value.second.value(), compSym, currentParent}); |
1860 | } |
1861 | |
1862 | HlfirDesignatorBuilder designatorBuilder(loc, converter, symMap, stmtCtx); |
1863 | for (const auto &iter : llvm::reverse(valuesAndParents)) { |
1864 | auto &sym = std::get<const Fortran::semantics::Symbol &>(iter); |
1865 | auto &expr = std::get<const Fortran::lower::SomeExpr &>(iter); |
1866 | auto &baseOp = std::get<hlfir::EntityWithAttributes>(iter); |
1867 | std::string name = converter.getRecordTypeFieldName(sym); |
1868 | |
1869 | // Generate DesignateOp for the component. |
1870 | // The designator's result type is just a reference to the component type, |
1871 | // because the whole component is being designated. |
1872 | auto baseRecTy = mlir::cast<fir::RecordType>( |
1873 | hlfir::getFortranElementType(baseOp.getType())); |
1874 | auto compType = baseRecTy.getType(name); |
1875 | assert(compType && "failed to retrieve component type"); |
1876 | mlir::Value compShape = |
1877 | designatorBuilder.genComponentShape(sym, compType); |
1878 | const bool isDesignatorVolatile = |
1879 | fir::isa_volatile_type(baseOp.getType()); |
1880 | auto [designatorType, extraAttributeFlags] = |
1881 | designatorBuilder.genComponentDesignatorTypeAndAttributes( |
1882 | sym, compType, isDesignatorVolatile); |
1883 | |
1884 | mlir::Type fieldElemType = hlfir::getFortranElementType(compType); |
1885 | llvm::SmallVector<mlir::Value, 1> typeParams; |
1886 | if (auto charType = mlir::dyn_cast<fir::CharacterType>(fieldElemType)) { |
1887 | if (charType.hasConstantLen()) { |
1888 | mlir::Type idxType = builder.getIndexType(); |
1889 | typeParams.push_back( |
1890 | builder.createIntegerConstant(loc, idxType, charType.getLen())); |
1891 | } else if (!hasDeferredCharacterLength(sym)) { |
1892 | // If the length is not deferred, this is a parametrized derived type |
1893 | // where the character length depends on the derived type length |
1894 | // parameters. Otherwise, this is a pointer/allocatable component and |
1895 | // the length will be set during the assignment. |
1896 | TODO(loc, "automatic character component in structure constructor"); |
1897 | } |
1898 | } |
1899 | |
1900 | // Convert component symbol attributes to variable attributes. |
1901 | fir::FortranVariableFlagsAttr attrs = |
1902 | Fortran::lower::translateSymbolAttributes(builder.getContext(), sym, |
1903 | extraAttributeFlags); |
1904 | |
1905 | // Get the component designator. |
1906 | auto lhs = builder.create<hlfir::DesignateOp>( |
1907 | loc, designatorType, baseOp, name, compShape, |
1908 | hlfir::DesignateOp::Subscripts{}, |
1909 | /*substring=*/mlir::ValueRange{}, |
1910 | /*complexPart=*/std::nullopt, |
1911 | /*shape=*/compShape, typeParams, attrs); |
1912 | |
1913 | if (attrs && bitEnumContainsAny(attrs.getFlags(), |
1914 | fir::FortranVariableFlagsEnum::pointer)) { |
1915 | if (Fortran::semantics::IsProcedure(sym)) { |
1916 | // Procedure pointer components. |
1917 | if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>( |
1918 | expr)) { |
1919 | auto boxTy{ |
1920 | Fortran::lower::getUntypedBoxProcType(builder.getContext())}; |
1921 | hlfir::Entity rhs( |
1922 | fir::factory::createNullBoxProc(builder, loc, boxTy)); |
1923 | builder.createStoreWithConvert(loc, rhs, lhs); |
1924 | continue; |
1925 | } |
1926 | hlfir::Entity rhs(getBase(Fortran::lower::convertExprToAddress( |
1927 | loc, converter, expr, symMap, stmtCtx))); |
1928 | builder.createStoreWithConvert(loc, rhs, lhs); |
1929 | continue; |
1930 | } |
1931 | // Pointer component construction is just a copy of the box contents. |
1932 | fir::ExtendedValue lhsExv = |
1933 | hlfir::translateToExtendedValue(loc, builder, lhs); |
1934 | auto *toBox = lhsExv.getBoxOf<fir::MutableBoxValue>(); |
1935 | if (!toBox) |
1936 | fir::emitFatalError(loc, "pointer component designator could not be " |
1937 | "lowered to mutable box"); |
1938 | Fortran::lower::associateMutableBox(converter, loc, *toBox, expr, |
1939 | /*lbounds=*/std::nullopt, stmtCtx); |
1940 | continue; |
1941 | } |
1942 | |
1943 | // Use generic assignment for all the other cases. |
1944 | bool allowRealloc = |
1945 | attrs && |
1946 | bitEnumContainsAny(attrs.getFlags(), |
1947 | fir::FortranVariableFlagsEnum::allocatable); |
1948 | // If the component is allocatable, then we have to check |
1949 | // whether the RHS value is allocatable or not. |
1950 | // If it is not allocatable, then AssignOp can be used directly. |
1951 | // If it is allocatable, then using AssignOp for unallocated RHS |
1952 | // will cause illegal dereference. When an unallocated allocatable |
1953 | // value is used to construct an allocatable component, the component |
1954 | // must just stay unallocated (see Fortran 2018 7.5.10 point 7). |
1955 | |
1956 | // If the component is allocatable and RHS is NULL() expression, then |
1957 | // we can just skip it: the LHS must remain unallocated with its |
1958 | // defined rank. |
1959 | if (allowRealloc && |
1960 | Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(expr)) |
1961 | continue; |
1962 | |
1963 | bool keepLhsLength = false; |
1964 | if (allowRealloc) |
1965 | if (const Fortran::semantics::DeclTypeSpec *declType = sym.GetType()) |
1966 | keepLhsLength = |
1967 | declType->category() == |
1968 | Fortran::semantics::DeclTypeSpec::Category::Character && |
1969 | !declType->characterTypeSpec().length().isDeferred(); |
1970 | // Handle special case when the initializer expression is |
1971 | // '{%SET_LENGTH(x,const_kind)}'. In structure constructor, |
1972 | // SET_LENGTH is used for initializers of non-allocatable character |
1973 | // components so that the front-end can better |
1974 | // fold and work with these structure constructors. |
1975 | // Here, they are just noise since the assignment semantics will deal |
1976 | // with any length mismatch, and creating an extra temp with the lhs |
1977 | // length is useless. |
1978 | // TODO: should this be moved into an hlfir.assign + hlfir.set_length |
1979 | // pattern rewrite? |
1980 | hlfir::Entity rhs = gen(expr); |
1981 | if (auto set_length = rhs.getDefiningOp<hlfir::SetLengthOp>()) |
1982 | rhs = hlfir::Entity{set_length.getString()}; |
1983 | |
1984 | // lambda to generate `lhs = rhs` and deal with potential rhs implicit |
1985 | // cast |
1986 | auto genAssign = [&] { |
1987 | rhs = hlfir::loadTrivialScalar(loc, builder, rhs); |
1988 | auto rhsCastAndCleanup = |
1989 | hlfir::genTypeAndKindConvert(loc, builder, rhs, lhs.getType(), |
1990 | /*preserveLowerBounds=*/allowRealloc); |
1991 | builder.create<hlfir::AssignOp>(loc, rhsCastAndCleanup.first, lhs, |
1992 | allowRealloc, |
1993 | allowRealloc ? keepLhsLength : false, |
1994 | /*temporary_lhs=*/true); |
1995 | if (rhsCastAndCleanup.second) |
1996 | (*rhsCastAndCleanup.second)(); |
1997 | }; |
1998 | |
1999 | if (!allowRealloc || !rhs.isMutableBox()) { |
2000 | genAssign(); |
2001 | continue; |
2002 | } |
2003 | |
2004 | auto [rhsExv, cleanup] = |
2005 | hlfir::translateToExtendedValue(loc, builder, rhs); |
2006 | assert(!cleanup && "unexpected cleanup"); |
2007 | auto *fromBox = rhsExv.getBoxOf<fir::MutableBoxValue>(); |
2008 | if (!fromBox) |
2009 | fir::emitFatalError(loc, "allocatable entity could not be lowered " |
2010 | "to mutable box"); |
2011 | mlir::Value isAlloc = |
2012 | fir::factory::genIsAllocatedOrAssociatedTest(builder, loc, *fromBox); |
2013 | builder.genIfThen(loc, isAlloc).genThen(genAssign).end(); |
2014 | } |
2015 | |
2016 | if (fir::isRecordWithAllocatableMember(recTy)) { |
2017 | // Deallocate allocatable components without calling final subroutines. |
2018 | // The Fortran 2018 section 9.7.3.2 about deallocation is not ruling |
2019 | // about the fate of allocatable components of structure constructors, |
2020 | // and there is no behavior consensus in other compilers. |
2021 | fir::FirOpBuilder *bldr = &builder; |
2022 | getStmtCtx().attachCleanup([=]() { |
2023 | fir::runtime::genDerivedTypeDestroyWithoutFinalization(*bldr, loc, box); |
2024 | }); |
2025 | } |
2026 | return varOp; |
2027 | } |
2028 | |
2029 | mlir::Location getLoc() const { return loc; } |
2030 | Fortran::lower::AbstractConverter &getConverter() { return converter; } |
2031 | fir::FirOpBuilder &getBuilder() { return converter.getFirOpBuilder(); } |
2032 | Fortran::lower::SymMap &getSymMap() { return symMap; } |
2033 | Fortran::lower::StatementContext &getStmtCtx() { return stmtCtx; } |
2034 | |
2035 | Fortran::lower::AbstractConverter &converter; |
2036 | Fortran::lower::SymMap &symMap; |
2037 | Fortran::lower::StatementContext &stmtCtx; |
2038 | mlir::Location loc; |
2039 | }; |
2040 | |
2041 | template <typename T> |
2042 | hlfir::Entity |
2043 | HlfirDesignatorBuilder::genSubscript(const Fortran::evaluate::Expr<T> &expr) { |
2044 | fir::FirOpBuilder &builder = getBuilder(); |
2045 | mlir::arith::IntegerOverflowFlags iofBackup{}; |
2046 | if (!getConverter().getLoweringOptions().getIntegerWrapAround()) { |
2047 | iofBackup = builder.getIntegerOverflowFlags(); |
2048 | builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::nsw); |
2049 | } |
2050 | auto loweredExpr = |
2051 | HlfirBuilder(getLoc(), getConverter(), getSymMap(), getStmtCtx()) |
2052 | .gen(expr); |
2053 | if (!getConverter().getLoweringOptions().getIntegerWrapAround()) |
2054 | builder.setIntegerOverflowFlags(iofBackup); |
2055 | // Skip constant conversions that litters designators and makes generated |
2056 | // IR harder to read: directly use index constants for constant subscripts. |
2057 | mlir::Type idxTy = builder.getIndexType(); |
2058 | if (!loweredExpr.isArray() && loweredExpr.getType() != idxTy) |
2059 | if (auto cstIndex = fir::getIntIfConstant(loweredExpr)) |
2060 | return hlfir::EntityWithAttributes{ |
2061 | builder.createIntegerConstant(getLoc(), idxTy, *cstIndex)}; |
2062 | return hlfir::loadTrivialScalar(loc, builder, loweredExpr); |
2063 | } |
2064 | |
2065 | } // namespace |
2066 | |
2067 | hlfir::EntityWithAttributes Fortran::lower::convertExprToHLFIR( |
2068 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2069 | const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, |
2070 | Fortran::lower::StatementContext &stmtCtx) { |
2071 | return HlfirBuilder(loc, converter, symMap, stmtCtx).gen(expr); |
2072 | } |
2073 | |
2074 | fir::ExtendedValue Fortran::lower::convertToBox( |
2075 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2076 | hlfir::Entity entity, Fortran::lower::StatementContext &stmtCtx, |
2077 | mlir::Type fortranType) { |
2078 | fir::FirOpBuilder &builder = converter.getFirOpBuilder(); |
2079 | auto [exv, cleanup] = hlfir::convertToBox(loc, builder, entity, fortranType); |
2080 | if (cleanup) |
2081 | stmtCtx.attachCleanup(*cleanup); |
2082 | return exv; |
2083 | } |
2084 | |
2085 | fir::ExtendedValue Fortran::lower::convertExprToBox( |
2086 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2087 | const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, |
2088 | Fortran::lower::StatementContext &stmtCtx) { |
2089 | hlfir::EntityWithAttributes loweredExpr = |
2090 | HlfirBuilder(loc, converter, symMap, stmtCtx).gen(expr); |
2091 | return convertToBox(loc, converter, loweredExpr, stmtCtx, |
2092 | converter.genType(expr)); |
2093 | } |
2094 | |
2095 | fir::ExtendedValue Fortran::lower::convertToAddress( |
2096 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2097 | hlfir::Entity entity, Fortran::lower::StatementContext &stmtCtx, |
2098 | mlir::Type fortranType) { |
2099 | fir::FirOpBuilder &builder = converter.getFirOpBuilder(); |
2100 | auto [exv, cleanup] = |
2101 | hlfir::convertToAddress(loc, builder, entity, fortranType); |
2102 | if (cleanup) |
2103 | stmtCtx.attachCleanup(*cleanup); |
2104 | return exv; |
2105 | } |
2106 | |
2107 | fir::ExtendedValue Fortran::lower::convertExprToAddress( |
2108 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2109 | const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, |
2110 | Fortran::lower::StatementContext &stmtCtx) { |
2111 | hlfir::EntityWithAttributes loweredExpr = |
2112 | HlfirBuilder(loc, converter, symMap, stmtCtx).gen(expr); |
2113 | return convertToAddress(loc, converter, loweredExpr, stmtCtx, |
2114 | converter.genType(expr)); |
2115 | } |
2116 | |
2117 | fir::ExtendedValue Fortran::lower::convertToValue( |
2118 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2119 | hlfir::Entity entity, Fortran::lower::StatementContext &stmtCtx) { |
2120 | auto &builder = converter.getFirOpBuilder(); |
2121 | auto [exv, cleanup] = hlfir::convertToValue(loc, builder, entity); |
2122 | if (cleanup) |
2123 | stmtCtx.attachCleanup(*cleanup); |
2124 | return exv; |
2125 | } |
2126 | |
2127 | fir::ExtendedValue Fortran::lower::convertExprToValue( |
2128 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2129 | const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, |
2130 | Fortran::lower::StatementContext &stmtCtx) { |
2131 | hlfir::EntityWithAttributes loweredExpr = |
2132 | HlfirBuilder(loc, converter, symMap, stmtCtx).gen(expr); |
2133 | return convertToValue(loc, converter, loweredExpr, stmtCtx); |
2134 | } |
2135 | |
2136 | fir::ExtendedValue Fortran::lower::convertDataRefToValue( |
2137 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2138 | const Fortran::evaluate::DataRef &dataRef, Fortran::lower::SymMap &symMap, |
2139 | Fortran::lower::StatementContext &stmtCtx) { |
2140 | fir::FortranVariableOpInterface loweredExpr = |
2141 | HlfirDesignatorBuilder(loc, converter, symMap, stmtCtx).gen(dataRef); |
2142 | return convertToValue(loc, converter, loweredExpr, stmtCtx); |
2143 | } |
2144 | |
2145 | fir::MutableBoxValue Fortran::lower::convertExprToMutableBox( |
2146 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2147 | const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) { |
2148 | // Pointers and Allocatable cannot be temporary expressions. Temporaries may |
2149 | // be created while lowering it (e.g. if any indices expression of a |
2150 | // designator create temporaries), but they can be destroyed before using the |
2151 | // lowered pointer or allocatable; |
2152 | Fortran::lower::StatementContext localStmtCtx; |
2153 | hlfir::EntityWithAttributes loweredExpr = |
2154 | HlfirBuilder(loc, converter, symMap, localStmtCtx).gen(expr); |
2155 | fir::ExtendedValue exv = Fortran::lower::translateToExtendedValue( |
2156 | loc, converter.getFirOpBuilder(), loweredExpr, localStmtCtx); |
2157 | auto *mutableBox = exv.getBoxOf<fir::MutableBoxValue>(); |
2158 | assert(mutableBox && "expression could not be lowered to mutable box"); |
2159 | return *mutableBox; |
2160 | } |
2161 | |
2162 | hlfir::ElementalAddrOp |
2163 | Fortran::lower::convertVectorSubscriptedExprToElementalAddr( |
2164 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2165 | const Fortran::lower::SomeExpr &designatorExpr, |
2166 | Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx) { |
2167 | return HlfirDesignatorBuilder(loc, converter, symMap, stmtCtx) |
2168 | .convertVectorSubscriptedExprToElementalAddr(designatorExpr); |
2169 | } |
2170 | |
2171 | hlfir::Entity Fortran::lower::genVectorSubscriptedDesignatorFirstElementAddress( |
2172 | mlir::Location loc, Fortran::lower::AbstractConverter &converter, |
2173 | const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap, |
2174 | Fortran::lower::StatementContext &stmtCtx) { |
2175 | fir::FirOpBuilder &builder = converter.getFirOpBuilder(); |
2176 | |
2177 | // Get a hlfir.elemental_addr op describing the address of the value |
2178 | // indexed from the original array. |
2179 | // Note: the hlfir.elemental_addr op verifier requires it to be inside |
2180 | // of a hlfir.region_assign op. This operation is never seen by the |
2181 | // verifier because it is immediately inlined. |
2182 | hlfir::ElementalAddrOp addrOp = convertVectorSubscriptedExprToElementalAddr( |
2183 | loc, converter, expr, symMap, stmtCtx); |
2184 | if (!addrOp.getCleanup().empty()) |
2185 | TODO(converter.getCurrentLocation(), |
2186 | "Vector subscript requring a cleanup region"); |
2187 | |
2188 | // hlfir.elemental_addr doesn't have a normal lowering because it |
2189 | // can't return a value. Instead we need to inline it here using |
2190 | // values for the first element. Similar to hlfir::inlineElementalOp. |
2191 | |
2192 | mlir::Value one = builder.createIntegerConstant( |
2193 | converter.getCurrentLocation(), builder.getIndexType(), 1); |
2194 | mlir::SmallVector<mlir::Value> oneBasedIndices; |
2195 | oneBasedIndices.resize(addrOp.getIndices().size(), one); |
2196 | |
2197 | mlir::IRMapping mapper; |
2198 | mapper.map(addrOp.getIndices(), oneBasedIndices); |
2199 | assert(addrOp.getElementalRegion().hasOneBlock()); |
2200 | mlir::Operation *newOp; |
2201 | for (mlir::Operation &op : addrOp.getElementalRegion().back().getOperations()) |
2202 | newOp = builder.clone(op, mapper); |
2203 | auto yield = mlir::cast<hlfir::YieldOp>(newOp); |
2204 | |
2205 | addrOp->erase(); |
2206 | |
2207 | if (!yield.getCleanup().empty()) |
2208 | TODO(converter.getCurrentLocation(), |
2209 | "Vector subscript requring element cleanup"); |
2210 | |
2211 | hlfir::Entity result{yield.getEntity()}; |
2212 | yield->erase(); |
2213 | return result; |
2214 | } |
2215 |
Definitions
- HlfirDesignatorBuilder
- genLeafPartRef
- HlfirDesignatorBuilder
- gen
- gen
- gen
- genNamedEntity
- genComponentDesignatorTypeAndAttributes
- genComponentShape
- gen
- PartInfo
- computeDesignatorType
- isPolymorphic
- genDesignate
- genDesignate
- gen
- gen
- gen
- gen
- gen
- visit
- gen
- gen
- changeElementType
- genWholeAllocatableOrPointerComponent
- visit
- visit
- visit
- visit
- mayHaveNonDefaultLowerBounds
- mayHaveNonDefaultLowerBounds
- visit
- visitComponentImpl
- computeTripletPosition
- createVectorSubscriptElementAddrOp
- finalizeElementAddrOp
- turnVectorSubscriptedDesignatorIntoValue
- getVectorSubscriptElementAddrOp
- setVectorSubscriptElementAddrOp
- getLoc
- getConverter
- getBuilder
- getSymMap
- getStmtCtx
- genDesignatorExpr
- convertVectorSubscriptedExprToElementalAddr
- BinaryOp
- translateSignedRelational
- translateUnsignedRelational
- translateFloatRelational
- UnaryOp
- hasDeferredCharacterLength
- HlfirBuilder
- HlfirBuilder
- gen
- gen
- gen
- gen
- gen
- gen
- gen
- gen
- gen
- gen
- gen
- gen
- gen
- gen
- gen
- isDerivedTypeWithLenParameters
- gen
- getLoc
- getConverter
- getBuilder
- getSymMap
- getStmtCtx
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more