1 //===-- HLFIRTools.cpp ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Tools to manipulate HLFIR variable and expressions
11 //===----------------------------------------------------------------------===//
13 #include "flang/Optimizer/Builder/HLFIRTools.h"
14 #include "flang/Optimizer/Builder/Character.h"
15 #include "flang/Optimizer/Builder/FIRBuilder.h"
16 #include "flang/Optimizer/Builder/MutableBox.h"
17 #include "flang/Optimizer/Builder/Runtime/Allocatable.h"
18 #include "flang/Optimizer/Builder/Todo.h"
19 #include "flang/Optimizer/HLFIR/HLFIROps.h"
20 #include "mlir/IR/IRMapping.h"
21 #include "mlir/Support/LLVM.h"
22 #include "llvm/ADT/TypeSwitch.h"
25 // Return explicit extents. If the base is a fir.box, this won't read it to
26 // return the extents and will instead return an empty vector.
27 llvm::SmallVector
<mlir::Value
>
28 hlfir::getExplicitExtentsFromShape(mlir::Value shape
,
29 fir::FirOpBuilder
&builder
) {
30 llvm::SmallVector
<mlir::Value
> result
;
31 auto *shapeOp
= shape
.getDefiningOp();
32 if (auto s
= mlir::dyn_cast_or_null
<fir::ShapeOp
>(shapeOp
)) {
33 auto e
= s
.getExtents();
34 result
.append(e
.begin(), e
.end());
35 } else if (auto s
= mlir::dyn_cast_or_null
<fir::ShapeShiftOp
>(shapeOp
)) {
36 auto e
= s
.getExtents();
37 result
.append(e
.begin(), e
.end());
38 } else if (mlir::dyn_cast_or_null
<fir::ShiftOp
>(shapeOp
)) {
40 } else if (auto s
= mlir::dyn_cast_or_null
<hlfir::ShapeOfOp
>(shapeOp
)) {
41 hlfir::ExprType expr
= s
.getExpr().getType().cast
<hlfir::ExprType
>();
42 llvm::ArrayRef
<int64_t> exprShape
= expr
.getShape();
43 mlir::Type indexTy
= builder
.getIndexType();
44 fir::ShapeType shapeTy
= shape
.getType().cast
<fir::ShapeType
>();
45 result
.reserve(shapeTy
.getRank());
46 for (unsigned i
= 0; i
< shapeTy
.getRank(); ++i
) {
47 int64_t extent
= exprShape
[i
];
48 mlir::Value extentVal
;
49 if (extent
== expr
.getUnknownExtent()) {
50 auto op
= builder
.create
<hlfir::GetExtentOp
>(shape
.getLoc(), shape
, i
);
51 extentVal
= op
.getResult();
54 builder
.createIntegerConstant(shape
.getLoc(), indexTy
, extent
);
56 result
.emplace_back(extentVal
);
59 TODO(shape
.getLoc(), "read fir.shape to get extents");
63 static llvm::SmallVector
<mlir::Value
>
64 getExplicitExtents(fir::FortranVariableOpInterface var
,
65 fir::FirOpBuilder
&builder
) {
66 if (mlir::Value shape
= var
.getShape())
67 return hlfir::getExplicitExtentsFromShape(var
.getShape(), builder
);
71 // Return explicit lower bounds. For pointers and allocatables, this will not
72 // read the lower bounds and instead return an empty vector.
73 static llvm::SmallVector
<mlir::Value
>
74 getExplicitLboundsFromShape(mlir::Value shape
) {
75 llvm::SmallVector
<mlir::Value
> result
;
76 auto *shapeOp
= shape
.getDefiningOp();
77 if (auto s
= mlir::dyn_cast_or_null
<fir::ShapeOp
>(shapeOp
)) {
79 } else if (auto s
= mlir::dyn_cast_or_null
<fir::ShapeShiftOp
>(shapeOp
)) {
80 auto e
= s
.getOrigins();
81 result
.append(e
.begin(), e
.end());
82 } else if (auto s
= mlir::dyn_cast_or_null
<fir::ShiftOp
>(shapeOp
)) {
83 auto e
= s
.getOrigins();
84 result
.append(e
.begin(), e
.end());
86 TODO(shape
.getLoc(), "read fir.shape to get lower bounds");
90 static llvm::SmallVector
<mlir::Value
>
91 getExplicitLbounds(fir::FortranVariableOpInterface var
) {
92 if (mlir::Value shape
= var
.getShape())
93 return getExplicitLboundsFromShape(shape
);
98 genLboundsAndExtentsFromBox(mlir::Location loc
, fir::FirOpBuilder
&builder
,
99 hlfir::Entity boxEntity
,
100 llvm::SmallVectorImpl
<mlir::Value
> &lbounds
,
101 llvm::SmallVectorImpl
<mlir::Value
> *extents
) {
102 assert(boxEntity
.getType().isa
<fir::BaseBoxType
>() && "must be a box");
103 mlir::Type idxTy
= builder
.getIndexType();
104 const int rank
= boxEntity
.getRank();
105 for (int i
= 0; i
< rank
; ++i
) {
106 mlir::Value dim
= builder
.createIntegerConstant(loc
, idxTy
, i
);
107 auto dimInfo
= builder
.create
<fir::BoxDimsOp
>(loc
, idxTy
, idxTy
, idxTy
,
109 lbounds
.push_back(dimInfo
.getLowerBound());
111 extents
->push_back(dimInfo
.getExtent());
115 static llvm::SmallVector
<mlir::Value
>
116 getNonDefaultLowerBounds(mlir::Location loc
, fir::FirOpBuilder
&builder
,
117 hlfir::Entity entity
) {
118 if (!entity
.hasNonDefaultLowerBounds())
120 if (auto varIface
= entity
.getIfVariableInterface()) {
121 llvm::SmallVector
<mlir::Value
> lbounds
= getExplicitLbounds(varIface
);
122 if (!lbounds
.empty())
125 if (entity
.isMutableBox())
126 entity
= hlfir::derefPointersAndAllocatables(loc
, builder
, entity
);
127 llvm::SmallVector
<mlir::Value
> lowerBounds
;
128 genLboundsAndExtentsFromBox(loc
, builder
, entity
, lowerBounds
,
129 /*extents=*/nullptr);
133 static llvm::SmallVector
<mlir::Value
> toSmallVector(mlir::ValueRange range
) {
134 llvm::SmallVector
<mlir::Value
> res
;
135 res
.append(range
.begin(), range
.end());
139 static llvm::SmallVector
<mlir::Value
> getExplicitTypeParams(hlfir::Entity var
) {
140 if (auto varIface
= var
.getMaybeDereferencedVariableInterface())
141 return toSmallVector(varIface
.getExplicitTypeParams());
145 static mlir::Value
tryGettingNonDeferredCharLen(hlfir::Entity var
) {
146 if (auto varIface
= var
.getMaybeDereferencedVariableInterface())
147 if (!varIface
.getExplicitTypeParams().empty())
148 return varIface
.getExplicitTypeParams()[0];
149 return mlir::Value
{};
152 static mlir::Value
genCharacterVariableLength(mlir::Location loc
,
153 fir::FirOpBuilder
&builder
,
155 if (mlir::Value len
= tryGettingNonDeferredCharLen(var
))
157 auto charType
= var
.getFortranElementType().cast
<fir::CharacterType
>();
158 if (charType
.hasConstantLen())
159 return builder
.createIntegerConstant(loc
, builder
.getIndexType(),
161 if (var
.isMutableBox())
162 var
= hlfir::Entity
{builder
.create
<fir::LoadOp
>(loc
, var
)};
163 mlir::Value len
= fir::factory::CharacterExprHelper
{builder
, loc
}.getLength(
165 assert(len
&& "failed to retrieve length");
169 static fir::CharBoxValue
genUnboxChar(mlir::Location loc
,
170 fir::FirOpBuilder
&builder
,
171 mlir::Value boxChar
) {
172 if (auto emboxChar
= boxChar
.getDefiningOp
<fir::EmboxCharOp
>())
173 return {emboxChar
.getMemref(), emboxChar
.getLen()};
174 mlir::Type refType
= fir::ReferenceType::get(
175 boxChar
.getType().cast
<fir::BoxCharType
>().getEleTy());
176 auto unboxed
= builder
.create
<fir::UnboxCharOp
>(
177 loc
, refType
, builder
.getIndexType(), boxChar
);
178 mlir::Value addr
= unboxed
.getResult(0);
179 mlir::Value len
= unboxed
.getResult(1);
180 if (auto varIface
= boxChar
.getDefiningOp
<fir::FortranVariableOpInterface
>())
181 if (mlir::Value explicitlen
= varIface
.getExplicitCharLen())
186 mlir::Value
hlfir::Entity::getFirBase() const {
187 if (fir::FortranVariableOpInterface variable
= getIfVariableInterface()) {
189 mlir::dyn_cast
<hlfir::DeclareOp
>(variable
.getOperation()))
190 return declareOp
.getOriginalBase();
191 if (auto associateOp
=
192 mlir::dyn_cast
<hlfir::AssociateOp
>(variable
.getOperation()))
193 return associateOp
.getFirBase();
198 fir::FortranVariableOpInterface
199 hlfir::genDeclare(mlir::Location loc
, fir::FirOpBuilder
&builder
,
200 const fir::ExtendedValue
&exv
, llvm::StringRef name
,
201 fir::FortranVariableFlagsAttr flags
) {
203 mlir::Value base
= fir::getBase(exv
);
204 assert(fir::conformsWithPassByRef(base
.getType()) &&
205 "entity being declared must be in memory");
206 mlir::Value shapeOrShift
;
207 llvm::SmallVector
<mlir::Value
> lenParams
;
209 [&](const fir::CharBoxValue
&box
) {
210 lenParams
.emplace_back(box
.getLen());
212 [&](const fir::ArrayBoxValue
&) {
213 shapeOrShift
= builder
.createShape(loc
, exv
);
215 [&](const fir::CharArrayBoxValue
&box
) {
216 shapeOrShift
= builder
.createShape(loc
, exv
);
217 lenParams
.emplace_back(box
.getLen());
219 [&](const fir::BoxValue
&box
) {
220 if (!box
.getLBounds().empty())
221 shapeOrShift
= builder
.createShape(loc
, exv
);
222 lenParams
.append(box
.getExplicitParameters().begin(),
223 box
.getExplicitParameters().end());
225 [&](const fir::MutableBoxValue
&box
) {
226 lenParams
.append(box
.nonDeferredLenParams().begin(),
227 box
.nonDeferredLenParams().end());
229 [](const auto &) {});
230 auto declareOp
= builder
.create
<hlfir::DeclareOp
>(
231 loc
, base
, name
, shapeOrShift
, lenParams
, flags
);
232 return mlir::cast
<fir::FortranVariableOpInterface
>(declareOp
.getOperation());
235 hlfir::AssociateOp
hlfir::genAssociateExpr(mlir::Location loc
,
236 fir::FirOpBuilder
&builder
,
238 mlir::Type variableType
,
239 llvm::StringRef name
) {
240 assert(value
.isValue() && "must not be a variable");
243 shape
= genShape(loc
, builder
, value
);
245 mlir::Value source
= value
;
246 // Lowered scalar expression values for numerical and logical may have a
247 // different type than what is required for the type in memory (logical
248 // expressions are typically manipulated as i1, but needs to be stored
249 // according to the fir.logical<kind> so that the storage size is correct).
250 // Character length mismatches are ignored (it is ok for one to be dynamic
251 // and the other static).
252 mlir::Type varEleTy
= getFortranElementType(variableType
);
253 mlir::Type valueEleTy
= getFortranElementType(value
.getType());
254 if (varEleTy
!= valueEleTy
&& !(valueEleTy
.isa
<fir::CharacterType
>() &&
255 varEleTy
.isa
<fir::CharacterType
>())) {
256 assert(value
.isScalar() && fir::isa_trivial(value
.getType()));
257 source
= builder
.createConvert(loc
, fir::unwrapPassByRefType(variableType
),
260 llvm::SmallVector
<mlir::Value
> lenParams
;
261 genLengthParameters(loc
, builder
, value
, lenParams
);
262 return builder
.create
<hlfir::AssociateOp
>(loc
, source
, name
, shape
, lenParams
,
263 fir::FortranVariableFlagsAttr
{});
266 mlir::Value
hlfir::genVariableRawAddress(mlir::Location loc
,
267 fir::FirOpBuilder
&builder
,
269 assert(var
.isVariable() && "only address of variables can be taken");
270 mlir::Value baseAddr
= var
.getFirBase();
271 if (var
.isMutableBox())
272 baseAddr
= builder
.create
<fir::LoadOp
>(loc
, baseAddr
);
274 if (var
.getType().isa
<fir::BoxCharType
>())
275 baseAddr
= genUnboxChar(loc
, builder
, var
.getBase()).getAddr();
276 if (baseAddr
.getType().isa
<fir::BaseBoxType
>())
277 baseAddr
= builder
.create
<fir::BoxAddrOp
>(loc
, baseAddr
);
281 mlir::Value
hlfir::genVariableBoxChar(mlir::Location loc
,
282 fir::FirOpBuilder
&builder
,
284 assert(var
.isVariable() && "only address of variables can be taken");
285 if (var
.getType().isa
<fir::BoxCharType
>())
287 mlir::Value addr
= genVariableRawAddress(loc
, builder
, var
);
288 llvm::SmallVector
<mlir::Value
> lengths
;
289 genLengthParameters(loc
, builder
, var
, lengths
);
290 assert(lengths
.size() == 1);
291 auto charType
= var
.getFortranElementType().cast
<fir::CharacterType
>();
293 fir::BoxCharType::get(builder
.getContext(), charType
.getFKind());
295 builder
.createConvert(loc
, fir::ReferenceType::get(charType
), addr
);
296 return builder
.create
<fir::EmboxCharOp
>(loc
, boxCharType
, scalarAddr
,
300 hlfir::Entity
hlfir::genVariableBox(mlir::Location loc
,
301 fir::FirOpBuilder
&builder
,
303 assert(var
.isVariable() && "must be a variable");
304 var
= hlfir::derefPointersAndAllocatables(loc
, builder
, var
);
305 if (var
.getType().isa
<fir::BaseBoxType
>())
307 // Note: if the var is not a fir.box/fir.class at that point, it has default
308 // lower bounds and is not polymorphic.
310 var
.isArray() ? hlfir::genShape(loc
, builder
, var
) : mlir::Value
{};
311 llvm::SmallVector
<mlir::Value
> typeParams
;
313 var
.getFortranElementType().dyn_cast
<fir::CharacterType
>();
314 if (!maybeCharType
|| maybeCharType
.hasDynamicLen())
315 hlfir::genLengthParameters(loc
, builder
, var
, typeParams
);
316 mlir::Value addr
= var
.getBase();
317 if (var
.getType().isa
<fir::BoxCharType
>())
318 addr
= genVariableRawAddress(loc
, builder
, var
);
319 mlir::Type boxType
= fir::BoxType::get(var
.getElementOrSequenceType());
321 builder
.create
<fir::EmboxOp
>(loc
, boxType
, addr
, shape
,
322 /*slice=*/mlir::Value
{}, typeParams
);
323 return hlfir::Entity
{embox
.getResult()};
326 hlfir::Entity
hlfir::loadTrivialScalar(mlir::Location loc
,
327 fir::FirOpBuilder
&builder
,
329 entity
= derefPointersAndAllocatables(loc
, builder
, entity
);
330 if (entity
.isVariable() && entity
.isScalar() &&
331 fir::isa_trivial(entity
.getFortranElementType())) {
332 return Entity
{builder
.create
<fir::LoadOp
>(loc
, entity
)};
337 hlfir::Entity
hlfir::getElementAt(mlir::Location loc
,
338 fir::FirOpBuilder
&builder
, Entity entity
,
339 mlir::ValueRange oneBasedIndices
) {
340 if (entity
.isScalar())
342 llvm::SmallVector
<mlir::Value
> lenParams
;
343 genLengthParameters(loc
, builder
, entity
, lenParams
);
344 if (entity
.getType().isa
<hlfir::ExprType
>())
345 return hlfir::Entity
{builder
.create
<hlfir::ApplyOp
>(
346 loc
, entity
, oneBasedIndices
, lenParams
)};
347 // Build hlfir.designate. The lower bounds may need to be added to
348 // the oneBasedIndices since hlfir.designate expect indices
349 // based on the array operand lower bounds.
350 mlir::Type resultType
= hlfir::getVariableElementType(entity
);
351 hlfir::DesignateOp designate
;
352 llvm::SmallVector
<mlir::Value
> lbounds
=
353 getNonDefaultLowerBounds(loc
, builder
, entity
);
354 if (!lbounds
.empty()) {
355 llvm::SmallVector
<mlir::Value
> indices
;
356 mlir::Type idxTy
= builder
.getIndexType();
357 mlir::Value one
= builder
.createIntegerConstant(loc
, idxTy
, 1);
358 for (auto [oneBased
, lb
] : llvm::zip(oneBasedIndices
, lbounds
)) {
359 auto lbIdx
= builder
.createConvert(loc
, idxTy
, lb
);
360 auto oneBasedIdx
= builder
.createConvert(loc
, idxTy
, oneBased
);
361 auto shift
= builder
.create
<mlir::arith::SubIOp
>(loc
, lbIdx
, one
);
363 builder
.create
<mlir::arith::AddIOp
>(loc
, oneBasedIdx
, shift
);
364 indices
.push_back(index
);
366 designate
= builder
.create
<hlfir::DesignateOp
>(loc
, resultType
, entity
,
369 designate
= builder
.create
<hlfir::DesignateOp
>(loc
, resultType
, entity
,
370 oneBasedIndices
, lenParams
);
372 return mlir::cast
<fir::FortranVariableOpInterface
>(designate
.getOperation());
375 static mlir::Value
genUBound(mlir::Location loc
, fir::FirOpBuilder
&builder
,
376 mlir::Value lb
, mlir::Value extent
,
378 if (auto constantLb
= fir::getIntIfConstant(lb
))
379 if (*constantLb
== 1)
381 extent
= builder
.createConvert(loc
, one
.getType(), extent
);
382 lb
= builder
.createConvert(loc
, one
.getType(), lb
);
383 auto add
= builder
.create
<mlir::arith::AddIOp
>(loc
, lb
, extent
);
384 return builder
.create
<mlir::arith::SubIOp
>(loc
, add
, one
);
387 llvm::SmallVector
<std::pair
<mlir::Value
, mlir::Value
>>
388 hlfir::genBounds(mlir::Location loc
, fir::FirOpBuilder
&builder
,
390 if (entity
.getType().isa
<hlfir::ExprType
>())
391 TODO(loc
, "bounds of expressions in hlfir");
392 auto [exv
, cleanup
] = translateToExtendedValue(loc
, builder
, entity
);
393 assert(!cleanup
&& "translation of entity should not yield cleanup");
394 if (const auto *mutableBox
= exv
.getBoxOf
<fir::MutableBoxValue
>())
395 exv
= fir::factory::genMutableBoxRead(builder
, loc
, *mutableBox
);
396 mlir::Type idxTy
= builder
.getIndexType();
397 mlir::Value one
= builder
.createIntegerConstant(loc
, idxTy
, 1);
398 llvm::SmallVector
<std::pair
<mlir::Value
, mlir::Value
>> result
;
399 for (unsigned dim
= 0; dim
< exv
.rank(); ++dim
) {
400 mlir::Value extent
= fir::factory::readExtent(builder
, loc
, exv
, dim
);
401 mlir::Value lb
= fir::factory::readLowerBound(builder
, loc
, exv
, dim
, one
);
402 mlir::Value ub
= genUBound(loc
, builder
, lb
, extent
, one
);
403 result
.push_back({lb
, ub
});
408 llvm::SmallVector
<std::pair
<mlir::Value
, mlir::Value
>>
409 hlfir::genBounds(mlir::Location loc
, fir::FirOpBuilder
&builder
,
411 assert((shape
.getType().isa
<fir::ShapeShiftType
>() ||
412 shape
.getType().isa
<fir::ShapeType
>()) &&
413 "shape must contain extents");
414 auto extents
= hlfir::getExplicitExtentsFromShape(shape
, builder
);
415 auto lowers
= getExplicitLboundsFromShape(shape
);
416 assert(lowers
.empty() || lowers
.size() == extents
.size());
417 mlir::Type idxTy
= builder
.getIndexType();
418 mlir::Value one
= builder
.createIntegerConstant(loc
, idxTy
, 1);
419 llvm::SmallVector
<std::pair
<mlir::Value
, mlir::Value
>> result
;
420 for (auto extent
: llvm::enumerate(extents
)) {
421 mlir::Value lb
= lowers
.empty() ? one
: lowers
[extent
.index()];
422 mlir::Value ub
= lowers
.empty()
424 : genUBound(loc
, builder
, lb
, extent
.value(), one
);
425 result
.push_back({lb
, ub
});
430 llvm::SmallVector
<mlir::Value
> hlfir::genLowerbounds(mlir::Location loc
,
431 fir::FirOpBuilder
&builder
,
434 llvm::SmallVector
<mlir::Value
> lbounds
;
436 lbounds
= getExplicitLboundsFromShape(shape
);
437 if (!lbounds
.empty())
440 builder
.createIntegerConstant(loc
, builder
.getIndexType(), 1);
441 return llvm::SmallVector
<mlir::Value
>(rank
, one
);
444 static hlfir::Entity
followShapeInducingSource(hlfir::Entity entity
) {
446 if (auto reassoc
= entity
.getDefiningOp
<hlfir::NoReassocOp
>()) {
447 entity
= hlfir::Entity
{reassoc
.getVal()};
450 if (auto asExpr
= entity
.getDefiningOp
<hlfir::AsExprOp
>()) {
451 entity
= hlfir::Entity
{asExpr
.getVar()};
459 static mlir::Value
computeVariableExtent(mlir::Location loc
,
460 fir::FirOpBuilder
&builder
,
461 hlfir::Entity variable
,
462 fir::SequenceType seqTy
,
464 mlir::Type idxTy
= builder
.getIndexType();
465 if (seqTy
.getShape().size() > dim
) {
466 fir::SequenceType::Extent typeExtent
= seqTy
.getShape()[dim
];
467 if (typeExtent
!= fir::SequenceType::getUnknownExtent())
468 return builder
.createIntegerConstant(loc
, idxTy
, typeExtent
);
470 assert(variable
.getType().isa
<fir::BaseBoxType
>() &&
471 "array variable with dynamic extent must be boxed");
472 mlir::Value dimVal
= builder
.createIntegerConstant(loc
, idxTy
, dim
);
473 auto dimInfo
= builder
.create
<fir::BoxDimsOp
>(loc
, idxTy
, idxTy
, idxTy
,
475 return dimInfo
.getExtent();
477 llvm::SmallVector
<mlir::Value
> getVariableExtents(mlir::Location loc
,
478 fir::FirOpBuilder
&builder
,
479 hlfir::Entity variable
) {
480 llvm::SmallVector
<mlir::Value
> extents
;
481 if (fir::FortranVariableOpInterface varIface
=
482 variable
.getIfVariableInterface()) {
483 extents
= getExplicitExtents(varIface
, builder
);
484 if (!extents
.empty())
488 if (variable
.isMutableBox())
489 variable
= hlfir::derefPointersAndAllocatables(loc
, builder
, variable
);
490 // Use the type shape information, and/or the fir.box/fir.class shape
491 // information if any extents are not static.
492 fir::SequenceType seqTy
=
493 hlfir::getFortranElementOrSequenceType(variable
.getType())
494 .cast
<fir::SequenceType
>();
495 unsigned rank
= seqTy
.getShape().size();
496 for (unsigned dim
= 0; dim
< rank
; ++dim
)
498 computeVariableExtent(loc
, builder
, variable
, seqTy
, dim
));
502 static mlir::Value
tryRetrievingShapeOrShift(hlfir::Entity entity
) {
503 if (entity
.getType().isa
<hlfir::ExprType
>()) {
504 if (auto elemental
= entity
.getDefiningOp
<hlfir::ElementalOp
>())
505 return elemental
.getShape();
506 return mlir::Value
{};
508 if (auto varIface
= entity
.getIfVariableInterface())
509 return varIface
.getShape();
513 mlir::Value
hlfir::genShape(mlir::Location loc
, fir::FirOpBuilder
&builder
,
514 hlfir::Entity entity
) {
515 assert(entity
.isArray() && "entity must be an array");
516 entity
= followShapeInducingSource(entity
);
517 assert(entity
&& "what?");
518 if (auto shape
= tryRetrievingShapeOrShift(entity
)) {
519 if (shape
.getType().isa
<fir::ShapeType
>())
521 if (shape
.getType().isa
<fir::ShapeShiftType
>())
522 if (auto s
= shape
.getDefiningOp
<fir::ShapeShiftOp
>())
523 return builder
.create
<fir::ShapeOp
>(loc
, s
.getExtents());
525 if (entity
.getType().isa
<hlfir::ExprType
>())
526 return builder
.create
<hlfir::ShapeOfOp
>(loc
, entity
.getBase());
527 // There is no shape lying around for this entity. Retrieve the extents and
528 // build a new fir.shape.
529 return builder
.create
<fir::ShapeOp
>(loc
,
530 getVariableExtents(loc
, builder
, entity
));
533 llvm::SmallVector
<mlir::Value
>
534 hlfir::getIndexExtents(mlir::Location loc
, fir::FirOpBuilder
&builder
,
536 llvm::SmallVector
<mlir::Value
> extents
=
537 hlfir::getExplicitExtentsFromShape(shape
, builder
);
538 mlir::Type indexType
= builder
.getIndexType();
539 for (auto &extent
: extents
)
540 extent
= builder
.createConvert(loc
, indexType
, extent
);
544 mlir::Value
hlfir::genExtent(mlir::Location loc
, fir::FirOpBuilder
&builder
,
545 hlfir::Entity entity
, unsigned dim
) {
546 entity
= followShapeInducingSource(entity
);
547 if (auto shape
= tryRetrievingShapeOrShift(entity
)) {
548 auto extents
= hlfir::getExplicitExtentsFromShape(shape
, builder
);
549 if (!extents
.empty()) {
550 assert(extents
.size() > dim
&& "bad inquiry");
554 if (entity
.isVariable()) {
555 if (entity
.isMutableBox())
556 entity
= hlfir::derefPointersAndAllocatables(loc
, builder
, entity
);
557 // Use the type shape information, and/or the fir.box/fir.class shape
558 // information if any extents are not static.
559 fir::SequenceType seqTy
=
560 hlfir::getFortranElementOrSequenceType(entity
.getType())
561 .cast
<fir::SequenceType
>();
562 return computeVariableExtent(loc
, builder
, entity
, seqTy
, dim
);
564 TODO(loc
, "get extent from HLFIR expr without producer holding the shape");
567 mlir::Value
hlfir::genLBound(mlir::Location loc
, fir::FirOpBuilder
&builder
,
568 hlfir::Entity entity
, unsigned dim
) {
569 if (!entity
.hasNonDefaultLowerBounds())
570 return builder
.createIntegerConstant(loc
, builder
.getIndexType(), 1);
571 if (auto shape
= tryRetrievingShapeOrShift(entity
)) {
572 auto lbounds
= getExplicitLboundsFromShape(shape
);
573 if (!lbounds
.empty()) {
574 assert(lbounds
.size() > dim
&& "bad inquiry");
578 if (entity
.isMutableBox())
579 entity
= hlfir::derefPointersAndAllocatables(loc
, builder
, entity
);
580 assert(entity
.getType().isa
<fir::BaseBoxType
>() && "must be a box");
581 mlir::Type idxTy
= builder
.getIndexType();
582 mlir::Value dimVal
= builder
.createIntegerConstant(loc
, idxTy
, dim
);
584 builder
.create
<fir::BoxDimsOp
>(loc
, idxTy
, idxTy
, idxTy
, entity
, dimVal
);
585 return dimInfo
.getLowerBound();
588 void hlfir::genLengthParameters(mlir::Location loc
, fir::FirOpBuilder
&builder
,
590 llvm::SmallVectorImpl
<mlir::Value
> &result
) {
591 if (!entity
.hasLengthParameters())
593 if (entity
.getType().isa
<hlfir::ExprType
>()) {
594 mlir::Value expr
= entity
;
595 if (auto reassoc
= expr
.getDefiningOp
<hlfir::NoReassocOp
>())
596 expr
= reassoc
.getVal();
597 // Going through fir::ExtendedValue would create a temp,
598 // which is not desired for an inquiry.
599 // TODO: make this an interface when adding further character producing ops.
600 if (auto concat
= expr
.getDefiningOp
<hlfir::ConcatOp
>()) {
601 result
.push_back(concat
.getLength());
603 } else if (auto concat
= expr
.getDefiningOp
<hlfir::SetLengthOp
>()) {
604 result
.push_back(concat
.getLength());
606 } else if (auto asExpr
= expr
.getDefiningOp
<hlfir::AsExprOp
>()) {
607 hlfir::genLengthParameters(loc
, builder
, hlfir::Entity
{asExpr
.getVar()},
610 } else if (auto elemental
= expr
.getDefiningOp
<hlfir::ElementalOp
>()) {
611 result
.append(elemental
.getTypeparams().begin(),
612 elemental
.getTypeparams().end());
614 } else if (auto apply
= expr
.getDefiningOp
<hlfir::ApplyOp
>()) {
615 result
.append(apply
.getTypeparams().begin(), apply
.getTypeparams().end());
618 if (entity
.isCharacter()) {
619 result
.push_back(builder
.create
<hlfir::GetLengthOp
>(loc
, expr
));
622 TODO(loc
, "inquire PDTs length parameters of hlfir.expr");
625 if (entity
.isCharacter()) {
626 result
.push_back(genCharacterVariableLength(loc
, builder
, entity
));
629 TODO(loc
, "inquire PDTs length parameters in HLFIR");
632 mlir::Value
hlfir::genCharLength(mlir::Location loc
, fir::FirOpBuilder
&builder
,
633 hlfir::Entity entity
) {
634 llvm::SmallVector
<mlir::Value
, 1> lenParams
;
635 genLengthParameters(loc
, builder
, entity
, lenParams
);
636 assert(lenParams
.size() == 1 && "characters must have one length parameters");
640 // Return a "shape" that can be used in fir.embox/fir.rebox with \p exv base.
641 static mlir::Value
asEmboxShape(mlir::Location loc
, fir::FirOpBuilder
&builder
,
642 const fir::ExtendedValue
&exv
,
646 // fir.rebox does not need and does not accept extents (fir.shape or
647 // fir.shape_shift) since this information is already in the input fir.box,
648 // it only accepts fir.shift because local lower bounds may not be reflected
650 if (fir::getBase(exv
).getType().isa
<fir::BaseBoxType
>() &&
651 !shape
.getType().isa
<fir::ShiftType
>())
652 return builder
.createShape(loc
, exv
);
656 std::pair
<mlir::Value
, mlir::Value
> hlfir::genVariableFirBaseShapeAndParams(
657 mlir::Location loc
, fir::FirOpBuilder
&builder
, Entity entity
,
658 llvm::SmallVectorImpl
<mlir::Value
> &typeParams
) {
659 auto [exv
, cleanup
] = translateToExtendedValue(loc
, builder
, entity
);
660 assert(!cleanup
&& "variable to Exv should not produce cleanup");
661 if (entity
.hasLengthParameters()) {
662 auto params
= fir::getTypeParams(exv
);
663 typeParams
.append(params
.begin(), params
.end());
665 if (entity
.isScalar())
666 return {fir::getBase(exv
), mlir::Value
{}};
667 if (auto variableInterface
= entity
.getIfVariableInterface())
668 return {fir::getBase(exv
),
669 asEmboxShape(loc
, builder
, exv
, variableInterface
.getShape())};
670 return {fir::getBase(exv
), builder
.createShape(loc
, exv
)};
673 hlfir::Entity
hlfir::derefPointersAndAllocatables(mlir::Location loc
,
674 fir::FirOpBuilder
&builder
,
676 if (entity
.isMutableBox()) {
677 hlfir::Entity boxLoad
{builder
.create
<fir::LoadOp
>(loc
, entity
)};
678 if (entity
.isScalar()) {
679 if (!entity
.isPolymorphic() && !entity
.hasLengthParameters())
680 return hlfir::Entity
{builder
.create
<fir::BoxAddrOp
>(loc
, boxLoad
)};
681 mlir::Type elementType
= boxLoad
.getFortranElementType();
682 if (auto charType
= elementType
.dyn_cast
<fir::CharacterType
>()) {
683 mlir::Value base
= builder
.create
<fir::BoxAddrOp
>(loc
, boxLoad
);
684 if (charType
.hasConstantLen())
685 return hlfir::Entity
{base
};
686 mlir::Value len
= genCharacterVariableLength(loc
, builder
, entity
);
688 fir::BoxCharType::get(builder
.getContext(), charType
.getFKind());
689 return hlfir::Entity
{
690 builder
.create
<fir::EmboxCharOp
>(loc
, boxCharType
, base
, len
)
694 // Otherwise, the entity is either an array, a polymorphic entity, or a
695 // derived type with length parameters. All these entities require a fir.box
696 // or fir.class to hold bounds, dynamic type or length parameter
697 // information. Keep them boxed.
703 mlir::Type
hlfir::getVariableElementType(hlfir::Entity variable
) {
704 assert(variable
.isVariable() && "entity must be a variable");
705 if (variable
.isScalar())
706 return variable
.getType();
707 mlir::Type eleTy
= variable
.getFortranElementType();
708 if (variable
.isPolymorphic())
709 return fir::ClassType::get(eleTy
);
710 if (auto charType
= eleTy
.dyn_cast
<fir::CharacterType
>()) {
711 if (charType
.hasDynamicLen())
712 return fir::BoxCharType::get(charType
.getContext(), charType
.getFKind());
713 } else if (fir::isRecordWithTypeParameters(eleTy
)) {
714 return fir::BoxType::get(eleTy
);
716 return fir::ReferenceType::get(eleTy
);
719 mlir::Type
hlfir::getEntityElementType(hlfir::Entity entity
) {
720 if (entity
.isVariable())
721 return getVariableElementType(entity
);
722 if (entity
.isScalar())
723 return entity
.getType();
724 auto exprType
= mlir::dyn_cast
<hlfir::ExprType
>(entity
.getType());
725 assert(exprType
&& "array value must be an hlfir.expr");
726 return exprType
.getElementExprType();
729 static hlfir::ExprType
getArrayExprType(mlir::Type elementType
,
730 mlir::Value shape
, bool isPolymorphic
) {
731 unsigned rank
= shape
.getType().cast
<fir::ShapeType
>().getRank();
732 hlfir::ExprType::Shape
typeShape(rank
, hlfir::ExprType::getUnknownExtent());
733 if (auto shapeOp
= shape
.getDefiningOp
<fir::ShapeOp
>())
734 for (auto extent
: llvm::enumerate(shapeOp
.getExtents()))
735 if (auto cstExtent
= fir::getIntIfConstant(extent
.value()))
736 typeShape
[extent
.index()] = *cstExtent
;
737 return hlfir::ExprType::get(elementType
.getContext(), typeShape
, elementType
,
741 hlfir::ElementalOp
hlfir::genElementalOp(
742 mlir::Location loc
, fir::FirOpBuilder
&builder
, mlir::Type elementType
,
743 mlir::Value shape
, mlir::ValueRange typeParams
,
744 const ElementalKernelGenerator
&genKernel
, bool isUnordered
,
745 mlir::Value polymorphicMold
, mlir::Type exprType
) {
747 exprType
= getArrayExprType(elementType
, shape
, !!polymorphicMold
);
748 auto elementalOp
= builder
.create
<hlfir::ElementalOp
>(
749 loc
, exprType
, shape
, polymorphicMold
, typeParams
, isUnordered
);
750 auto insertPt
= builder
.saveInsertionPoint();
751 builder
.setInsertionPointToStart(elementalOp
.getBody());
752 mlir::Value elementResult
= genKernel(loc
, builder
, elementalOp
.getIndices());
753 // Numerical and logical scalars may be lowered to another type than the
754 // Fortran expression type (e.g i1 instead of fir.logical). Array expression
755 // values are typed according to their Fortran type. Insert a cast if needed
757 if (fir::isa_trivial(elementResult
.getType()))
758 elementResult
= builder
.createConvert(loc
, elementType
, elementResult
);
759 builder
.create
<hlfir::YieldElementOp
>(loc
, elementResult
);
760 builder
.restoreInsertionPoint(insertPt
);
764 // TODO: we do not actually need to clone the YieldElementOp,
765 // because returning its getElementValue() operand should be enough
766 // for all callers of this function.
767 hlfir::YieldElementOp
768 hlfir::inlineElementalOp(mlir::Location loc
, fir::FirOpBuilder
&builder
,
769 hlfir::ElementalOp elemental
,
770 mlir::ValueRange oneBasedIndices
) {
771 // hlfir.elemental region is a SizedRegion<1>.
772 assert(elemental
.getRegion().hasOneBlock() &&
773 "expect elemental region to have one block");
774 mlir::IRMapping mapper
;
775 mapper
.map(elemental
.getIndices(), oneBasedIndices
);
776 mlir::Operation
*newOp
;
777 for (auto &op
: elemental
.getRegion().back().getOperations())
778 newOp
= builder
.clone(op
, mapper
);
779 auto yield
= mlir::dyn_cast_or_null
<hlfir::YieldElementOp
>(newOp
);
780 assert(yield
&& "last ElementalOp operation must be am hlfir.yield_element");
784 mlir::Value
hlfir::inlineElementalOp(
785 mlir::Location loc
, fir::FirOpBuilder
&builder
,
786 hlfir::ElementalOpInterface elemental
, mlir::ValueRange oneBasedIndices
,
787 mlir::IRMapping
&mapper
,
788 const std::function
<bool(hlfir::ElementalOp
)> &mustRecursivelyInline
) {
789 mlir::Region
®ion
= elemental
.getElementalRegion();
790 // hlfir.elemental region is a SizedRegion<1>.
791 assert(region
.hasOneBlock() && "elemental region must have one block");
792 mapper
.map(elemental
.getIndices(), oneBasedIndices
);
793 for (auto &op
: region
.front().without_terminator()) {
794 if (auto apply
= mlir::dyn_cast
<hlfir::ApplyOp
>(op
))
795 if (auto appliedElemental
=
796 apply
.getExpr().getDefiningOp
<hlfir::ElementalOp
>())
797 if (mustRecursivelyInline(appliedElemental
)) {
798 llvm::SmallVector
<mlir::Value
> clonedApplyIndices
;
799 for (auto indice
: apply
.getIndices())
800 clonedApplyIndices
.push_back(mapper
.lookupOrDefault(indice
));
801 hlfir::ElementalOpInterface elementalIface
=
802 mlir::cast
<hlfir::ElementalOpInterface
>(
803 appliedElemental
.getOperation());
804 mlir::Value inlined
= inlineElementalOp(loc
, builder
, elementalIface
,
805 clonedApplyIndices
, mapper
,
806 mustRecursivelyInline
);
807 mapper
.map(apply
.getResult(), inlined
);
810 (void)builder
.clone(op
, mapper
);
812 return mapper
.lookupOrDefault(elemental
.getElementEntity());
815 hlfir::LoopNest
hlfir::genLoopNest(mlir::Location loc
,
816 fir::FirOpBuilder
&builder
,
817 mlir::ValueRange extents
, bool isUnordered
) {
818 hlfir::LoopNest loopNest
;
819 assert(!extents
.empty() && "must have at least one extent");
820 auto insPt
= builder
.saveInsertionPoint();
821 loopNest
.oneBasedIndices
.assign(extents
.size(), mlir::Value
{});
822 // Build loop nest from column to row.
823 auto one
= builder
.create
<mlir::arith::ConstantIndexOp
>(loc
, 1);
824 mlir::Type indexType
= builder
.getIndexType();
825 unsigned dim
= extents
.size() - 1;
826 for (auto extent
: llvm::reverse(extents
)) {
827 auto ub
= builder
.createConvert(loc
, indexType
, extent
);
829 builder
.create
<fir::DoLoopOp
>(loc
, one
, ub
, one
, isUnordered
);
830 builder
.setInsertionPointToStart(loopNest
.innerLoop
.getBody());
831 // Reverse the indices so they are in column-major order.
832 loopNest
.oneBasedIndices
[dim
--] = loopNest
.innerLoop
.getInductionVar();
833 if (!loopNest
.outerLoop
)
834 loopNest
.outerLoop
= loopNest
.innerLoop
;
836 builder
.restoreInsertionPoint(insPt
);
840 static fir::ExtendedValue
841 translateVariableToExtendedValue(mlir::Location loc
, fir::FirOpBuilder
&builder
,
842 hlfir::Entity variable
) {
843 assert(variable
.isVariable() && "must be a variable");
844 /// When going towards FIR, use the original base value to avoid
845 /// introducing descriptors at runtime when they are not required.
846 mlir::Value firBase
= variable
.getFirBase();
847 if (variable
.isMutableBox())
848 return fir::MutableBoxValue(firBase
, getExplicitTypeParams(variable
),
849 fir::MutableProperties
{});
851 if (firBase
.getType().isa
<fir::BaseBoxType
>()) {
852 if (!variable
.isSimplyContiguous() || variable
.isPolymorphic() ||
853 variable
.isDerivedWithLengthParameters() || variable
.isOptional()) {
854 llvm::SmallVector
<mlir::Value
> nonDefaultLbounds
=
855 getNonDefaultLowerBounds(loc
, builder
, variable
);
856 return fir::BoxValue(firBase
, nonDefaultLbounds
,
857 getExplicitTypeParams(variable
));
859 // Otherwise, the variable can be represented in a fir::ExtendedValue
860 // without the overhead of a fir.box.
861 firBase
= genVariableRawAddress(loc
, builder
, variable
);
864 if (variable
.isScalar()) {
865 if (variable
.isCharacter()) {
866 if (firBase
.getType().isa
<fir::BoxCharType
>())
867 return genUnboxChar(loc
, builder
, firBase
);
868 mlir::Value len
= genCharacterVariableLength(loc
, builder
, variable
);
869 return fir::CharBoxValue
{firBase
, len
};
873 llvm::SmallVector
<mlir::Value
> extents
;
874 llvm::SmallVector
<mlir::Value
> nonDefaultLbounds
;
875 if (variable
.getType().isa
<fir::BaseBoxType
>() &&
876 !variable
.getIfVariableInterface()) {
877 // This special case avoids generating two sets of identical
878 // fir.box_dim to get both the lower bounds and extents.
879 genLboundsAndExtentsFromBox(loc
, builder
, variable
, nonDefaultLbounds
,
882 extents
= getVariableExtents(loc
, builder
, variable
);
883 nonDefaultLbounds
= getNonDefaultLowerBounds(loc
, builder
, variable
);
885 if (variable
.isCharacter())
886 return fir::CharArrayBoxValue
{
887 firBase
, genCharacterVariableLength(loc
, builder
, variable
), extents
,
889 return fir::ArrayBoxValue
{firBase
, extents
, nonDefaultLbounds
};
893 hlfir::translateToExtendedValue(mlir::Location loc
, fir::FirOpBuilder
&builder
,
894 fir::FortranVariableOpInterface var
) {
895 return translateVariableToExtendedValue(loc
, builder
, var
);
898 std::pair
<fir::ExtendedValue
, std::optional
<hlfir::CleanupFunction
>>
899 hlfir::translateToExtendedValue(mlir::Location loc
, fir::FirOpBuilder
&builder
,
900 hlfir::Entity entity
) {
901 if (entity
.isVariable())
902 return {translateVariableToExtendedValue(loc
, builder
, entity
),
905 if (entity
.isProcedure()) {
906 if (fir::isCharacterProcedureTuple(entity
.getType())) {
907 auto [boxProc
, len
] = fir::factory::extractCharacterProcedureTuple(
908 builder
, loc
, entity
, /*openBoxProc=*/false);
909 return {fir::CharBoxValue
{boxProc
, len
}, std::nullopt
};
911 return {static_cast<mlir::Value
>(entity
), std::nullopt
};
914 if (entity
.getType().isa
<hlfir::ExprType
>()) {
915 hlfir::AssociateOp associate
= hlfir::genAssociateExpr(
916 loc
, builder
, entity
, entity
.getType(), "adapt.valuebyref");
917 auto *bldr
= &builder
;
918 hlfir::CleanupFunction cleanup
= [bldr
, loc
, associate
]() -> void {
919 bldr
->create
<hlfir::EndAssociateOp
>(loc
, associate
);
921 hlfir::Entity temp
{associate
.getBase()};
922 return {translateToExtendedValue(loc
, builder
, temp
).first
, cleanup
};
924 return {{static_cast<mlir::Value
>(entity
)}, {}};
927 std::pair
<fir::ExtendedValue
, std::optional
<hlfir::CleanupFunction
>>
928 hlfir::convertToValue(mlir::Location loc
, fir::FirOpBuilder
&builder
,
929 const hlfir::Entity
&entity
) {
930 // Load scalar references to integer, logical, real, or complex value
931 // to an mlir value, dereference allocatable and pointers, and get rid
932 // of fir.box that are not needed or create a copy into contiguous memory.
933 auto derefedAndLoadedEntity
= loadTrivialScalar(loc
, builder
, entity
);
934 return translateToExtendedValue(loc
, builder
, derefedAndLoadedEntity
);
937 static fir::ExtendedValue
placeTrivialInMemory(mlir::Location loc
,
938 fir::FirOpBuilder
&builder
,
940 mlir::Type targetType
) {
941 auto temp
= builder
.createTemporary(loc
, targetType
);
942 if (targetType
!= val
.getType())
943 builder
.createStoreWithConvert(loc
, val
, temp
);
945 builder
.create
<fir::StoreOp
>(loc
, val
, temp
);
949 std::pair
<fir::ExtendedValue
, std::optional
<hlfir::CleanupFunction
>>
950 hlfir::convertToBox(mlir::Location loc
, fir::FirOpBuilder
&builder
,
951 const hlfir::Entity
&entity
, mlir::Type targetType
) {
952 auto [exv
, cleanup
] = translateToExtendedValue(loc
, builder
, entity
);
953 // Procedure entities should not go through createBoxValue that embox
954 // object entities. Return the fir.boxproc directly.
955 if (entity
.isProcedure())
956 return {exv
, cleanup
};
957 mlir::Value base
= fir::getBase(exv
);
958 if (fir::isa_trivial(base
.getType()))
959 exv
= placeTrivialInMemory(loc
, builder
, base
, targetType
);
960 fir::BoxValue box
= fir::factory::createBoxValue(builder
, loc
, exv
);
961 return {box
, cleanup
};
964 std::pair
<fir::ExtendedValue
, std::optional
<hlfir::CleanupFunction
>>
965 hlfir::convertToAddress(mlir::Location loc
, fir::FirOpBuilder
&builder
,
966 const hlfir::Entity
&entity
, mlir::Type targetType
) {
967 hlfir::Entity derefedEntity
=
968 hlfir::derefPointersAndAllocatables(loc
, builder
, entity
);
969 auto [exv
, cleanup
] =
970 hlfir::translateToExtendedValue(loc
, builder
, derefedEntity
);
971 mlir::Value base
= fir::getBase(exv
);
972 if (fir::isa_trivial(base
.getType()))
973 exv
= placeTrivialInMemory(loc
, builder
, base
, targetType
);
974 return {exv
, cleanup
};
979 /// hlfir.elemental_addr %shape : !fir.shape<1> {
982 /// %hlfir.yield %scalarAddress : fir.ref<T>
989 /// %expr = hlfir.elemental %shape : (!fir.shape<1>) -> hlfir.expr<?xT> {
992 /// %value = fir.load %scalarAddress : fir.ref<T>
993 /// %hlfir.yield_element %value : T
997 hlfir::cloneToElementalOp(mlir::Location loc
, fir::FirOpBuilder
&builder
,
998 hlfir::ElementalAddrOp elementalAddrOp
) {
999 hlfir::Entity scalarAddress
=
1000 hlfir::Entity
{mlir::cast
<hlfir::YieldOp
>(
1001 elementalAddrOp
.getBody().back().getTerminator())
1003 llvm::SmallVector
<mlir::Value
, 1> typeParams
;
1004 hlfir::genLengthParameters(loc
, builder
, scalarAddress
, typeParams
);
1006 builder
.setInsertionPointAfter(elementalAddrOp
);
1007 auto genKernel
= [&](mlir::Location l
, fir::FirOpBuilder
&b
,
1008 mlir::ValueRange oneBasedIndices
) -> hlfir::Entity
{
1009 mlir::IRMapping mapper
;
1010 mapper
.map(elementalAddrOp
.getIndices(), oneBasedIndices
);
1011 mlir::Operation
*newOp
= nullptr;
1012 for (auto &op
: elementalAddrOp
.getBody().back().getOperations())
1013 newOp
= b
.clone(op
, mapper
);
1014 auto newYielOp
= mlir::dyn_cast_or_null
<hlfir::YieldOp
>(newOp
);
1015 assert(newYielOp
&& "hlfir.elemental_addr is ill formed");
1016 hlfir::Entity newAddr
{newYielOp
.getEntity()};
1018 return hlfir::loadTrivialScalar(l
, b
, newAddr
);
1020 mlir::Type elementType
= scalarAddress
.getFortranElementType();
1021 return hlfir::genElementalOp(loc
, builder
, elementType
,
1022 elementalAddrOp
.getShape(), typeParams
,
1023 genKernel
, !elementalAddrOp
.isOrdered());
1026 bool hlfir::elementalOpMustProduceTemp(hlfir::ElementalOp elemental
) {
1027 for (mlir::Operation
*useOp
: elemental
->getUsers())
1028 if (auto destroy
= mlir::dyn_cast
<hlfir::DestroyOp
>(useOp
))
1029 if (destroy
.mustFinalizeExpr())
1035 std::pair
<hlfir::Entity
, mlir::Value
>
1036 hlfir::createTempFromMold(mlir::Location loc
, fir::FirOpBuilder
&builder
,
1037 hlfir::Entity mold
) {
1038 llvm::SmallVector
<mlir::Value
> lenParams
;
1039 hlfir::genLengthParameters(loc
, builder
, mold
, lenParams
);
1040 llvm::StringRef tmpName
{".tmp"};
1042 mlir::Value isHeapAlloc
;
1043 mlir::Value shape
{};
1044 fir::FortranVariableFlagsAttr declAttrs
;
1046 if (mold
.isPolymorphic()) {
1047 // Create unallocated polymorphic temporary using the dynamic type
1048 // of the mold. The static type of the temporary matches
1049 // the static type of the mold, but then the dynamic type
1050 // of the mold is applied to the temporary's descriptor.
1053 hlfir::genShape(loc
, builder
, mold
);
1055 // Create polymorphic allocatable box on the stack.
1056 mlir::Type boxHeapType
= fir::HeapType::get(fir::unwrapRefType(
1057 mlir::cast
<fir::BaseBoxType
>(mold
.getType()).getEleTy()));
1058 // The box must be initialized, because AllocatableApplyMold
1059 // may read its contents (e.g. for checking whether it is allocated).
1060 alloc
= fir::factory::genNullBoxStorage(builder
, loc
,
1061 fir::ClassType::get(boxHeapType
));
1062 // The temporary is unallocated even after AllocatableApplyMold below.
1063 // If the temporary is used as assignment LHS it will be automatically
1064 // allocated on the heap, as long as we use Assign family
1065 // runtime functions. So set MustFree to true.
1066 isHeapAlloc
= builder
.createBool(loc
, true);
1067 declAttrs
= fir::FortranVariableFlagsAttr::get(
1068 builder
.getContext(), fir::FortranVariableFlagsEnum::allocatable
);
1069 } else if (mold
.isArray()) {
1070 mlir::Type sequenceType
=
1071 hlfir::getFortranElementOrSequenceType(mold
.getType());
1072 shape
= hlfir::genShape(loc
, builder
, mold
);
1073 auto extents
= hlfir::getIndexExtents(loc
, builder
, shape
);
1074 alloc
= builder
.createHeapTemporary(loc
, sequenceType
, tmpName
, extents
,
1076 isHeapAlloc
= builder
.createBool(loc
, true);
1078 alloc
= builder
.createTemporary(loc
, mold
.getFortranElementType(), tmpName
,
1079 /*shape=*/std::nullopt
, lenParams
);
1080 isHeapAlloc
= builder
.createBool(loc
, false);
1082 auto declareOp
= builder
.create
<hlfir::DeclareOp
>(loc
, alloc
, tmpName
, shape
,
1083 lenParams
, declAttrs
);
1084 if (mold
.isPolymorphic()) {
1085 int rank
= mold
.getRank();
1086 // TODO: should probably read rank from the mold.
1088 TODO(loc
, "create temporary for assumed rank polymorphic");
1089 fir::runtime::genAllocatableApplyMold(builder
, loc
, alloc
,
1090 mold
.getFirBase(), rank
);
1093 return {hlfir::Entity
{declareOp
.getBase()}, isHeapAlloc
};