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"
23 #include <mlir/Dialect/OpenMP/OpenMPDialect.h>
26 // Return explicit extents. If the base is a fir.box, this won't read it to
27 // return the extents and will instead return an empty vector.
28 llvm::SmallVector
<mlir::Value
>
29 hlfir::getExplicitExtentsFromShape(mlir::Value shape
,
30 fir::FirOpBuilder
&builder
) {
31 llvm::SmallVector
<mlir::Value
> result
;
32 auto *shapeOp
= shape
.getDefiningOp();
33 if (auto s
= mlir::dyn_cast_or_null
<fir::ShapeOp
>(shapeOp
)) {
34 auto e
= s
.getExtents();
35 result
.append(e
.begin(), e
.end());
36 } else if (auto s
= mlir::dyn_cast_or_null
<fir::ShapeShiftOp
>(shapeOp
)) {
37 auto e
= s
.getExtents();
38 result
.append(e
.begin(), e
.end());
39 } else if (mlir::dyn_cast_or_null
<fir::ShiftOp
>(shapeOp
)) {
41 } else if (auto s
= mlir::dyn_cast_or_null
<hlfir::ShapeOfOp
>(shapeOp
)) {
42 hlfir::ExprType expr
= mlir::cast
<hlfir::ExprType
>(s
.getExpr().getType());
43 llvm::ArrayRef
<int64_t> exprShape
= expr
.getShape();
44 mlir::Type indexTy
= builder
.getIndexType();
45 fir::ShapeType shapeTy
= mlir::cast
<fir::ShapeType
>(shape
.getType());
46 result
.reserve(shapeTy
.getRank());
47 for (unsigned i
= 0; i
< shapeTy
.getRank(); ++i
) {
48 int64_t extent
= exprShape
[i
];
49 mlir::Value extentVal
;
50 if (extent
== expr
.getUnknownExtent()) {
51 auto op
= builder
.create
<hlfir::GetExtentOp
>(shape
.getLoc(), shape
, i
);
52 extentVal
= op
.getResult();
55 builder
.createIntegerConstant(shape
.getLoc(), indexTy
, extent
);
57 result
.emplace_back(extentVal
);
60 TODO(shape
.getLoc(), "read fir.shape to get extents");
64 static llvm::SmallVector
<mlir::Value
>
65 getExplicitExtents(fir::FortranVariableOpInterface var
,
66 fir::FirOpBuilder
&builder
) {
67 if (mlir::Value shape
= var
.getShape())
68 return hlfir::getExplicitExtentsFromShape(var
.getShape(), builder
);
72 // Return explicit lower bounds. For pointers and allocatables, this will not
73 // read the lower bounds and instead return an empty vector.
74 static llvm::SmallVector
<mlir::Value
>
75 getExplicitLboundsFromShape(mlir::Value shape
) {
76 llvm::SmallVector
<mlir::Value
> result
;
77 auto *shapeOp
= shape
.getDefiningOp();
78 if (auto s
= mlir::dyn_cast_or_null
<fir::ShapeOp
>(shapeOp
)) {
80 } else if (auto s
= mlir::dyn_cast_or_null
<fir::ShapeShiftOp
>(shapeOp
)) {
81 auto e
= s
.getOrigins();
82 result
.append(e
.begin(), e
.end());
83 } else if (auto s
= mlir::dyn_cast_or_null
<fir::ShiftOp
>(shapeOp
)) {
84 auto e
= s
.getOrigins();
85 result
.append(e
.begin(), e
.end());
87 TODO(shape
.getLoc(), "read fir.shape to get lower bounds");
91 static llvm::SmallVector
<mlir::Value
>
92 getExplicitLbounds(fir::FortranVariableOpInterface var
) {
93 if (mlir::Value shape
= var
.getShape())
94 return getExplicitLboundsFromShape(shape
);
99 genLboundsAndExtentsFromBox(mlir::Location loc
, fir::FirOpBuilder
&builder
,
100 hlfir::Entity boxEntity
,
101 llvm::SmallVectorImpl
<mlir::Value
> &lbounds
,
102 llvm::SmallVectorImpl
<mlir::Value
> *extents
) {
103 assert(mlir::isa
<fir::BaseBoxType
>(boxEntity
.getType()) && "must be a box");
104 mlir::Type idxTy
= builder
.getIndexType();
105 const int rank
= boxEntity
.getRank();
106 for (int i
= 0; i
< rank
; ++i
) {
107 mlir::Value dim
= builder
.createIntegerConstant(loc
, idxTy
, i
);
108 auto dimInfo
= builder
.create
<fir::BoxDimsOp
>(loc
, idxTy
, idxTy
, idxTy
,
110 lbounds
.push_back(dimInfo
.getLowerBound());
112 extents
->push_back(dimInfo
.getExtent());
116 static llvm::SmallVector
<mlir::Value
>
117 getNonDefaultLowerBounds(mlir::Location loc
, fir::FirOpBuilder
&builder
,
118 hlfir::Entity entity
) {
119 assert(!entity
.isAssumedRank() &&
120 "cannot compute assumed rank bounds statically");
121 if (!entity
.mayHaveNonDefaultLowerBounds())
123 if (auto varIface
= entity
.getIfVariableInterface()) {
124 llvm::SmallVector
<mlir::Value
> lbounds
= getExplicitLbounds(varIface
);
125 if (!lbounds
.empty())
128 if (entity
.isMutableBox())
129 entity
= hlfir::derefPointersAndAllocatables(loc
, builder
, entity
);
130 llvm::SmallVector
<mlir::Value
> lowerBounds
;
131 genLboundsAndExtentsFromBox(loc
, builder
, entity
, lowerBounds
,
132 /*extents=*/nullptr);
136 static llvm::SmallVector
<mlir::Value
> toSmallVector(mlir::ValueRange range
) {
137 llvm::SmallVector
<mlir::Value
> res
;
138 res
.append(range
.begin(), range
.end());
142 static llvm::SmallVector
<mlir::Value
> getExplicitTypeParams(hlfir::Entity var
) {
143 if (auto varIface
= var
.getMaybeDereferencedVariableInterface())
144 return toSmallVector(varIface
.getExplicitTypeParams());
148 static mlir::Value
tryGettingNonDeferredCharLen(hlfir::Entity var
) {
149 if (auto varIface
= var
.getMaybeDereferencedVariableInterface())
150 if (!varIface
.getExplicitTypeParams().empty())
151 return varIface
.getExplicitTypeParams()[0];
152 return mlir::Value
{};
155 static mlir::Value
genCharacterVariableLength(mlir::Location loc
,
156 fir::FirOpBuilder
&builder
,
158 if (mlir::Value len
= tryGettingNonDeferredCharLen(var
))
160 auto charType
= mlir::cast
<fir::CharacterType
>(var
.getFortranElementType());
161 if (charType
.hasConstantLen())
162 return builder
.createIntegerConstant(loc
, builder
.getIndexType(),
164 if (var
.isMutableBox())
165 var
= hlfir::Entity
{builder
.create
<fir::LoadOp
>(loc
, var
)};
166 mlir::Value len
= fir::factory::CharacterExprHelper
{builder
, loc
}.getLength(
168 assert(len
&& "failed to retrieve length");
172 static fir::CharBoxValue
genUnboxChar(mlir::Location loc
,
173 fir::FirOpBuilder
&builder
,
174 mlir::Value boxChar
) {
175 if (auto emboxChar
= boxChar
.getDefiningOp
<fir::EmboxCharOp
>())
176 return {emboxChar
.getMemref(), emboxChar
.getLen()};
177 mlir::Type refType
= fir::ReferenceType::get(
178 mlir::cast
<fir::BoxCharType
>(boxChar
.getType()).getEleTy());
179 auto unboxed
= builder
.create
<fir::UnboxCharOp
>(
180 loc
, refType
, builder
.getIndexType(), boxChar
);
181 mlir::Value addr
= unboxed
.getResult(0);
182 mlir::Value len
= unboxed
.getResult(1);
183 if (auto varIface
= boxChar
.getDefiningOp
<fir::FortranVariableOpInterface
>())
184 if (mlir::Value explicitlen
= varIface
.getExplicitCharLen())
189 mlir::Value
hlfir::Entity::getFirBase() const {
190 if (fir::FortranVariableOpInterface variable
= getIfVariableInterface()) {
192 mlir::dyn_cast
<hlfir::DeclareOp
>(variable
.getOperation()))
193 return declareOp
.getOriginalBase();
194 if (auto associateOp
=
195 mlir::dyn_cast
<hlfir::AssociateOp
>(variable
.getOperation()))
196 return associateOp
.getFirBase();
201 static bool isShapeWithLowerBounds(mlir::Value shape
) {
204 auto shapeTy
= shape
.getType();
205 return mlir::isa
<fir::ShiftType
>(shapeTy
) ||
206 mlir::isa
<fir::ShapeShiftType
>(shapeTy
);
209 bool hlfir::Entity::mayHaveNonDefaultLowerBounds() const {
210 if (!isBoxAddressOrValue() || isScalar())
214 if (auto varIface
= getIfVariableInterface())
215 return isShapeWithLowerBounds(varIface
.getShape());
216 // Go through chain of fir.box converts.
217 if (auto convert
= getDefiningOp
<fir::ConvertOp
>())
218 return hlfir::Entity
{convert
.getValue()}.mayHaveNonDefaultLowerBounds();
219 // TODO: Embox and Rebox do not have hlfir variable interface, but are
220 // easy to reason about.
224 fir::FortranVariableOpInterface
225 hlfir::genDeclare(mlir::Location loc
, fir::FirOpBuilder
&builder
,
226 const fir::ExtendedValue
&exv
, llvm::StringRef name
,
227 fir::FortranVariableFlagsAttr flags
, mlir::Value dummyScope
,
228 cuf::DataAttributeAttr dataAttr
) {
230 mlir::Value base
= fir::getBase(exv
);
231 assert(fir::conformsWithPassByRef(base
.getType()) &&
232 "entity being declared must be in memory");
233 mlir::Value shapeOrShift
;
234 llvm::SmallVector
<mlir::Value
> lenParams
;
236 [&](const fir::CharBoxValue
&box
) {
237 lenParams
.emplace_back(box
.getLen());
239 [&](const fir::ArrayBoxValue
&) {
240 shapeOrShift
= builder
.createShape(loc
, exv
);
242 [&](const fir::CharArrayBoxValue
&box
) {
243 shapeOrShift
= builder
.createShape(loc
, exv
);
244 lenParams
.emplace_back(box
.getLen());
246 [&](const fir::BoxValue
&box
) {
247 if (!box
.getLBounds().empty())
248 shapeOrShift
= builder
.createShape(loc
, exv
);
249 lenParams
.append(box
.getExplicitParameters().begin(),
250 box
.getExplicitParameters().end());
252 [&](const fir::MutableBoxValue
&box
) {
253 lenParams
.append(box
.nonDeferredLenParams().begin(),
254 box
.nonDeferredLenParams().end());
256 [](const auto &) {});
257 auto declareOp
= builder
.create
<hlfir::DeclareOp
>(
258 loc
, base
, name
, shapeOrShift
, lenParams
, dummyScope
, flags
, dataAttr
);
259 return mlir::cast
<fir::FortranVariableOpInterface
>(declareOp
.getOperation());
263 hlfir::genAssociateExpr(mlir::Location loc
, fir::FirOpBuilder
&builder
,
264 hlfir::Entity value
, mlir::Type variableType
,
265 llvm::StringRef name
,
266 std::optional
<mlir::NamedAttribute
> attr
) {
267 assert(value
.isValue() && "must not be a variable");
270 shape
= genShape(loc
, builder
, value
);
272 mlir::Value source
= value
;
273 // Lowered scalar expression values for numerical and logical may have a
274 // different type than what is required for the type in memory (logical
275 // expressions are typically manipulated as i1, but needs to be stored
276 // according to the fir.logical<kind> so that the storage size is correct).
277 // Character length mismatches are ignored (it is ok for one to be dynamic
278 // and the other static).
279 mlir::Type varEleTy
= getFortranElementType(variableType
);
280 mlir::Type valueEleTy
= getFortranElementType(value
.getType());
281 if (varEleTy
!= valueEleTy
&& !(mlir::isa
<fir::CharacterType
>(valueEleTy
) &&
282 mlir::isa
<fir::CharacterType
>(varEleTy
))) {
283 assert(value
.isScalar() && fir::isa_trivial(value
.getType()));
284 source
= builder
.createConvert(loc
, fir::unwrapPassByRefType(variableType
),
287 llvm::SmallVector
<mlir::Value
> lenParams
;
288 genLengthParameters(loc
, builder
, value
, lenParams
);
290 assert(name
.empty() && "It attribute is provided, no-name is expected");
291 return builder
.create
<hlfir::AssociateOp
>(loc
, source
, shape
, lenParams
,
292 fir::FortranVariableFlagsAttr
{},
293 llvm::ArrayRef
{*attr
});
295 return builder
.create
<hlfir::AssociateOp
>(loc
, source
, name
, shape
, lenParams
,
296 fir::FortranVariableFlagsAttr
{});
299 mlir::Value
hlfir::genVariableRawAddress(mlir::Location loc
,
300 fir::FirOpBuilder
&builder
,
302 assert(var
.isVariable() && "only address of variables can be taken");
303 mlir::Value baseAddr
= var
.getFirBase();
304 if (var
.isMutableBox())
305 baseAddr
= builder
.create
<fir::LoadOp
>(loc
, baseAddr
);
307 if (mlir::isa
<fir::BoxCharType
>(var
.getType()))
308 baseAddr
= genUnboxChar(loc
, builder
, var
.getBase()).getAddr();
309 if (mlir::isa
<fir::BaseBoxType
>(baseAddr
.getType()))
310 baseAddr
= builder
.create
<fir::BoxAddrOp
>(loc
, baseAddr
);
314 mlir::Value
hlfir::genVariableBoxChar(mlir::Location loc
,
315 fir::FirOpBuilder
&builder
,
317 assert(var
.isVariable() && "only address of variables can be taken");
318 if (mlir::isa
<fir::BoxCharType
>(var
.getType()))
320 mlir::Value addr
= genVariableRawAddress(loc
, builder
, var
);
321 llvm::SmallVector
<mlir::Value
> lengths
;
322 genLengthParameters(loc
, builder
, var
, lengths
);
323 assert(lengths
.size() == 1);
324 auto charType
= mlir::cast
<fir::CharacterType
>(var
.getFortranElementType());
326 fir::BoxCharType::get(builder
.getContext(), charType
.getFKind());
328 builder
.createConvert(loc
, fir::ReferenceType::get(charType
), addr
);
329 return builder
.create
<fir::EmboxCharOp
>(loc
, boxCharType
, scalarAddr
,
333 hlfir::Entity
hlfir::genVariableBox(mlir::Location loc
,
334 fir::FirOpBuilder
&builder
,
336 assert(var
.isVariable() && "must be a variable");
337 var
= hlfir::derefPointersAndAllocatables(loc
, builder
, var
);
338 if (mlir::isa
<fir::BaseBoxType
>(var
.getType()))
340 // Note: if the var is not a fir.box/fir.class at that point, it has default
341 // lower bounds and is not polymorphic.
343 var
.isArray() ? hlfir::genShape(loc
, builder
, var
) : mlir::Value
{};
344 llvm::SmallVector
<mlir::Value
> typeParams
;
346 mlir::dyn_cast
<fir::CharacterType
>(var
.getFortranElementType());
347 if (!maybeCharType
|| maybeCharType
.hasDynamicLen())
348 hlfir::genLengthParameters(loc
, builder
, var
, typeParams
);
349 mlir::Value addr
= var
.getBase();
350 if (mlir::isa
<fir::BoxCharType
>(var
.getType()))
351 addr
= genVariableRawAddress(loc
, builder
, var
);
352 mlir::Type boxType
= fir::BoxType::get(var
.getElementOrSequenceType());
354 builder
.create
<fir::EmboxOp
>(loc
, boxType
, addr
, shape
,
355 /*slice=*/mlir::Value
{}, typeParams
);
356 return hlfir::Entity
{embox
.getResult()};
359 hlfir::Entity
hlfir::loadTrivialScalar(mlir::Location loc
,
360 fir::FirOpBuilder
&builder
,
362 entity
= derefPointersAndAllocatables(loc
, builder
, entity
);
363 if (entity
.isVariable() && entity
.isScalar() &&
364 fir::isa_trivial(entity
.getFortranElementType())) {
365 return Entity
{builder
.create
<fir::LoadOp
>(loc
, entity
)};
370 hlfir::Entity
hlfir::getElementAt(mlir::Location loc
,
371 fir::FirOpBuilder
&builder
, Entity entity
,
372 mlir::ValueRange oneBasedIndices
) {
373 if (entity
.isScalar())
375 llvm::SmallVector
<mlir::Value
> lenParams
;
376 genLengthParameters(loc
, builder
, entity
, lenParams
);
377 if (mlir::isa
<hlfir::ExprType
>(entity
.getType()))
378 return hlfir::Entity
{builder
.create
<hlfir::ApplyOp
>(
379 loc
, entity
, oneBasedIndices
, lenParams
)};
380 // Build hlfir.designate. The lower bounds may need to be added to
381 // the oneBasedIndices since hlfir.designate expect indices
382 // based on the array operand lower bounds.
383 mlir::Type resultType
= hlfir::getVariableElementType(entity
);
384 hlfir::DesignateOp designate
;
385 llvm::SmallVector
<mlir::Value
> lbounds
=
386 getNonDefaultLowerBounds(loc
, builder
, entity
);
387 if (!lbounds
.empty()) {
388 llvm::SmallVector
<mlir::Value
> indices
;
389 mlir::Type idxTy
= builder
.getIndexType();
390 mlir::Value one
= builder
.createIntegerConstant(loc
, idxTy
, 1);
391 for (auto [oneBased
, lb
] : llvm::zip(oneBasedIndices
, lbounds
)) {
392 auto lbIdx
= builder
.createConvert(loc
, idxTy
, lb
);
393 auto oneBasedIdx
= builder
.createConvert(loc
, idxTy
, oneBased
);
394 auto shift
= builder
.create
<mlir::arith::SubIOp
>(loc
, lbIdx
, one
);
396 builder
.create
<mlir::arith::AddIOp
>(loc
, oneBasedIdx
, shift
);
397 indices
.push_back(index
);
399 designate
= builder
.create
<hlfir::DesignateOp
>(loc
, resultType
, entity
,
402 designate
= builder
.create
<hlfir::DesignateOp
>(loc
, resultType
, entity
,
403 oneBasedIndices
, lenParams
);
405 return mlir::cast
<fir::FortranVariableOpInterface
>(designate
.getOperation());
408 static mlir::Value
genUBound(mlir::Location loc
, fir::FirOpBuilder
&builder
,
409 mlir::Value lb
, mlir::Value extent
,
411 if (auto constantLb
= fir::getIntIfConstant(lb
))
412 if (*constantLb
== 1)
414 extent
= builder
.createConvert(loc
, one
.getType(), extent
);
415 lb
= builder
.createConvert(loc
, one
.getType(), lb
);
416 auto add
= builder
.create
<mlir::arith::AddIOp
>(loc
, lb
, extent
);
417 return builder
.create
<mlir::arith::SubIOp
>(loc
, add
, one
);
420 llvm::SmallVector
<std::pair
<mlir::Value
, mlir::Value
>>
421 hlfir::genBounds(mlir::Location loc
, fir::FirOpBuilder
&builder
,
423 if (mlir::isa
<hlfir::ExprType
>(entity
.getType()))
424 TODO(loc
, "bounds of expressions in hlfir");
425 auto [exv
, cleanup
] = translateToExtendedValue(loc
, builder
, entity
);
426 assert(!cleanup
&& "translation of entity should not yield cleanup");
427 if (const auto *mutableBox
= exv
.getBoxOf
<fir::MutableBoxValue
>())
428 exv
= fir::factory::genMutableBoxRead(builder
, loc
, *mutableBox
);
429 mlir::Type idxTy
= builder
.getIndexType();
430 mlir::Value one
= builder
.createIntegerConstant(loc
, idxTy
, 1);
431 llvm::SmallVector
<std::pair
<mlir::Value
, mlir::Value
>> result
;
432 for (unsigned dim
= 0; dim
< exv
.rank(); ++dim
) {
433 mlir::Value extent
= fir::factory::readExtent(builder
, loc
, exv
, dim
);
434 mlir::Value lb
= fir::factory::readLowerBound(builder
, loc
, exv
, dim
, one
);
435 mlir::Value ub
= genUBound(loc
, builder
, lb
, extent
, one
);
436 result
.push_back({lb
, ub
});
441 llvm::SmallVector
<std::pair
<mlir::Value
, mlir::Value
>>
442 hlfir::genBounds(mlir::Location loc
, fir::FirOpBuilder
&builder
,
444 assert((mlir::isa
<fir::ShapeShiftType
>(shape
.getType()) ||
445 mlir::isa
<fir::ShapeType
>(shape
.getType())) &&
446 "shape must contain extents");
447 auto extents
= hlfir::getExplicitExtentsFromShape(shape
, builder
);
448 auto lowers
= getExplicitLboundsFromShape(shape
);
449 assert(lowers
.empty() || lowers
.size() == extents
.size());
450 mlir::Type idxTy
= builder
.getIndexType();
451 mlir::Value one
= builder
.createIntegerConstant(loc
, idxTy
, 1);
452 llvm::SmallVector
<std::pair
<mlir::Value
, mlir::Value
>> result
;
453 for (auto extent
: llvm::enumerate(extents
)) {
454 mlir::Value lb
= lowers
.empty() ? one
: lowers
[extent
.index()];
455 mlir::Value ub
= lowers
.empty()
457 : genUBound(loc
, builder
, lb
, extent
.value(), one
);
458 result
.push_back({lb
, ub
});
463 llvm::SmallVector
<mlir::Value
> hlfir::genLowerbounds(mlir::Location loc
,
464 fir::FirOpBuilder
&builder
,
467 llvm::SmallVector
<mlir::Value
> lbounds
;
469 lbounds
= getExplicitLboundsFromShape(shape
);
470 if (!lbounds
.empty())
473 builder
.createIntegerConstant(loc
, builder
.getIndexType(), 1);
474 return llvm::SmallVector
<mlir::Value
>(rank
, one
);
477 static hlfir::Entity
followShapeInducingSource(hlfir::Entity entity
) {
479 if (auto reassoc
= entity
.getDefiningOp
<hlfir::NoReassocOp
>()) {
480 entity
= hlfir::Entity
{reassoc
.getVal()};
483 if (auto asExpr
= entity
.getDefiningOp
<hlfir::AsExprOp
>()) {
484 entity
= hlfir::Entity
{asExpr
.getVar()};
492 static mlir::Value
computeVariableExtent(mlir::Location loc
,
493 fir::FirOpBuilder
&builder
,
494 hlfir::Entity variable
,
495 fir::SequenceType seqTy
,
497 mlir::Type idxTy
= builder
.getIndexType();
498 if (seqTy
.getShape().size() > dim
) {
499 fir::SequenceType::Extent typeExtent
= seqTy
.getShape()[dim
];
500 if (typeExtent
!= fir::SequenceType::getUnknownExtent())
501 return builder
.createIntegerConstant(loc
, idxTy
, typeExtent
);
503 assert(mlir::isa
<fir::BaseBoxType
>(variable
.getType()) &&
504 "array variable with dynamic extent must be boxed");
505 mlir::Value dimVal
= builder
.createIntegerConstant(loc
, idxTy
, dim
);
506 auto dimInfo
= builder
.create
<fir::BoxDimsOp
>(loc
, idxTy
, idxTy
, idxTy
,
508 return dimInfo
.getExtent();
510 llvm::SmallVector
<mlir::Value
> getVariableExtents(mlir::Location loc
,
511 fir::FirOpBuilder
&builder
,
512 hlfir::Entity variable
) {
513 llvm::SmallVector
<mlir::Value
> extents
;
514 if (fir::FortranVariableOpInterface varIface
=
515 variable
.getIfVariableInterface()) {
516 extents
= getExplicitExtents(varIface
, builder
);
517 if (!extents
.empty())
521 if (variable
.isMutableBox())
522 variable
= hlfir::derefPointersAndAllocatables(loc
, builder
, variable
);
523 // Use the type shape information, and/or the fir.box/fir.class shape
524 // information if any extents are not static.
525 fir::SequenceType seqTy
= mlir::cast
<fir::SequenceType
>(
526 hlfir::getFortranElementOrSequenceType(variable
.getType()));
527 unsigned rank
= seqTy
.getShape().size();
528 for (unsigned dim
= 0; dim
< rank
; ++dim
)
530 computeVariableExtent(loc
, builder
, variable
, seqTy
, dim
));
534 static mlir::Value
tryRetrievingShapeOrShift(hlfir::Entity entity
) {
535 if (mlir::isa
<hlfir::ExprType
>(entity
.getType())) {
536 if (auto elemental
= entity
.getDefiningOp
<hlfir::ElementalOp
>())
537 return elemental
.getShape();
538 return mlir::Value
{};
540 if (auto varIface
= entity
.getIfVariableInterface())
541 return varIface
.getShape();
545 mlir::Value
hlfir::genShape(mlir::Location loc
, fir::FirOpBuilder
&builder
,
546 hlfir::Entity entity
) {
547 assert(entity
.isArray() && "entity must be an array");
548 entity
= followShapeInducingSource(entity
);
549 assert(entity
&& "what?");
550 if (auto shape
= tryRetrievingShapeOrShift(entity
)) {
551 if (mlir::isa
<fir::ShapeType
>(shape
.getType()))
553 if (mlir::isa
<fir::ShapeShiftType
>(shape
.getType()))
554 if (auto s
= shape
.getDefiningOp
<fir::ShapeShiftOp
>())
555 return builder
.create
<fir::ShapeOp
>(loc
, s
.getExtents());
557 if (mlir::isa
<hlfir::ExprType
>(entity
.getType()))
558 return builder
.create
<hlfir::ShapeOfOp
>(loc
, entity
.getBase());
559 // There is no shape lying around for this entity. Retrieve the extents and
560 // build a new fir.shape.
561 return builder
.create
<fir::ShapeOp
>(loc
,
562 getVariableExtents(loc
, builder
, entity
));
565 llvm::SmallVector
<mlir::Value
>
566 hlfir::getIndexExtents(mlir::Location loc
, fir::FirOpBuilder
&builder
,
568 llvm::SmallVector
<mlir::Value
> extents
=
569 hlfir::getExplicitExtentsFromShape(shape
, builder
);
570 mlir::Type indexType
= builder
.getIndexType();
571 for (auto &extent
: extents
)
572 extent
= builder
.createConvert(loc
, indexType
, extent
);
576 mlir::Value
hlfir::genExtent(mlir::Location loc
, fir::FirOpBuilder
&builder
,
577 hlfir::Entity entity
, unsigned dim
) {
578 entity
= followShapeInducingSource(entity
);
579 if (auto shape
= tryRetrievingShapeOrShift(entity
)) {
580 auto extents
= hlfir::getExplicitExtentsFromShape(shape
, builder
);
581 if (!extents
.empty()) {
582 assert(extents
.size() > dim
&& "bad inquiry");
586 if (entity
.isVariable()) {
587 if (entity
.isMutableBox())
588 entity
= hlfir::derefPointersAndAllocatables(loc
, builder
, entity
);
589 // Use the type shape information, and/or the fir.box/fir.class shape
590 // information if any extents are not static.
591 fir::SequenceType seqTy
= mlir::cast
<fir::SequenceType
>(
592 hlfir::getFortranElementOrSequenceType(entity
.getType()));
593 return computeVariableExtent(loc
, builder
, entity
, seqTy
, dim
);
595 TODO(loc
, "get extent from HLFIR expr without producer holding the shape");
598 mlir::Value
hlfir::genLBound(mlir::Location loc
, fir::FirOpBuilder
&builder
,
599 hlfir::Entity entity
, unsigned dim
) {
600 if (!entity
.mayHaveNonDefaultLowerBounds())
601 return builder
.createIntegerConstant(loc
, builder
.getIndexType(), 1);
602 if (auto shape
= tryRetrievingShapeOrShift(entity
)) {
603 auto lbounds
= getExplicitLboundsFromShape(shape
);
604 if (!lbounds
.empty()) {
605 assert(lbounds
.size() > dim
&& "bad inquiry");
609 if (entity
.isMutableBox())
610 entity
= hlfir::derefPointersAndAllocatables(loc
, builder
, entity
);
611 assert(mlir::isa
<fir::BaseBoxType
>(entity
.getType()) && "must be a box");
612 mlir::Type idxTy
= builder
.getIndexType();
613 mlir::Value dimVal
= builder
.createIntegerConstant(loc
, idxTy
, dim
);
615 builder
.create
<fir::BoxDimsOp
>(loc
, idxTy
, idxTy
, idxTy
, entity
, dimVal
);
616 return dimInfo
.getLowerBound();
619 void hlfir::genLengthParameters(mlir::Location loc
, fir::FirOpBuilder
&builder
,
621 llvm::SmallVectorImpl
<mlir::Value
> &result
) {
622 if (!entity
.hasLengthParameters())
624 if (mlir::isa
<hlfir::ExprType
>(entity
.getType())) {
625 mlir::Value expr
= entity
;
626 if (auto reassoc
= expr
.getDefiningOp
<hlfir::NoReassocOp
>())
627 expr
= reassoc
.getVal();
628 // Going through fir::ExtendedValue would create a temp,
629 // which is not desired for an inquiry.
630 // TODO: make this an interface when adding further character producing ops.
631 if (auto concat
= expr
.getDefiningOp
<hlfir::ConcatOp
>()) {
632 result
.push_back(concat
.getLength());
634 } else if (auto concat
= expr
.getDefiningOp
<hlfir::SetLengthOp
>()) {
635 result
.push_back(concat
.getLength());
637 } else if (auto asExpr
= expr
.getDefiningOp
<hlfir::AsExprOp
>()) {
638 hlfir::genLengthParameters(loc
, builder
, hlfir::Entity
{asExpr
.getVar()},
641 } else if (auto elemental
= expr
.getDefiningOp
<hlfir::ElementalOp
>()) {
642 result
.append(elemental
.getTypeparams().begin(),
643 elemental
.getTypeparams().end());
645 } else if (auto apply
= expr
.getDefiningOp
<hlfir::ApplyOp
>()) {
646 result
.append(apply
.getTypeparams().begin(), apply
.getTypeparams().end());
649 if (entity
.isCharacter()) {
650 result
.push_back(builder
.create
<hlfir::GetLengthOp
>(loc
, expr
));
653 TODO(loc
, "inquire PDTs length parameters of hlfir.expr");
656 if (entity
.isCharacter()) {
657 result
.push_back(genCharacterVariableLength(loc
, builder
, entity
));
660 TODO(loc
, "inquire PDTs length parameters in HLFIR");
663 mlir::Value
hlfir::genCharLength(mlir::Location loc
, fir::FirOpBuilder
&builder
,
664 hlfir::Entity entity
) {
665 llvm::SmallVector
<mlir::Value
, 1> lenParams
;
666 genLengthParameters(loc
, builder
, entity
, lenParams
);
667 assert(lenParams
.size() == 1 && "characters must have one length parameters");
671 mlir::Value
hlfir::genRank(mlir::Location loc
, fir::FirOpBuilder
&builder
,
672 hlfir::Entity entity
, mlir::Type resultType
) {
673 if (!entity
.isAssumedRank())
674 return builder
.createIntegerConstant(loc
, resultType
, entity
.getRank());
675 assert(entity
.isBoxAddressOrValue() &&
676 "assumed-ranks are box addresses or values");
677 return builder
.create
<fir::BoxRankOp
>(loc
, resultType
, entity
);
680 // Return a "shape" that can be used in fir.embox/fir.rebox with \p exv base.
681 static mlir::Value
asEmboxShape(mlir::Location loc
, fir::FirOpBuilder
&builder
,
682 const fir::ExtendedValue
&exv
,
686 // fir.rebox does not need and does not accept extents (fir.shape or
687 // fir.shape_shift) since this information is already in the input fir.box,
688 // it only accepts fir.shift because local lower bounds may not be reflected
690 if (mlir::isa
<fir::BaseBoxType
>(fir::getBase(exv
).getType()) &&
691 !mlir::isa
<fir::ShiftType
>(shape
.getType()))
692 return builder
.createShape(loc
, exv
);
696 std::pair
<mlir::Value
, mlir::Value
> hlfir::genVariableFirBaseShapeAndParams(
697 mlir::Location loc
, fir::FirOpBuilder
&builder
, Entity entity
,
698 llvm::SmallVectorImpl
<mlir::Value
> &typeParams
) {
699 auto [exv
, cleanup
] = translateToExtendedValue(loc
, builder
, entity
);
700 assert(!cleanup
&& "variable to Exv should not produce cleanup");
701 if (entity
.hasLengthParameters()) {
702 auto params
= fir::getTypeParams(exv
);
703 typeParams
.append(params
.begin(), params
.end());
705 if (entity
.isScalar())
706 return {fir::getBase(exv
), mlir::Value
{}};
707 if (auto variableInterface
= entity
.getIfVariableInterface())
708 return {fir::getBase(exv
),
709 asEmboxShape(loc
, builder
, exv
, variableInterface
.getShape())};
710 return {fir::getBase(exv
), builder
.createShape(loc
, exv
)};
713 hlfir::Entity
hlfir::derefPointersAndAllocatables(mlir::Location loc
,
714 fir::FirOpBuilder
&builder
,
716 if (entity
.isMutableBox()) {
717 hlfir::Entity boxLoad
{builder
.create
<fir::LoadOp
>(loc
, entity
)};
718 if (entity
.isScalar()) {
719 if (!entity
.isPolymorphic() && !entity
.hasLengthParameters())
720 return hlfir::Entity
{builder
.create
<fir::BoxAddrOp
>(loc
, boxLoad
)};
721 mlir::Type elementType
= boxLoad
.getFortranElementType();
722 if (auto charType
= mlir::dyn_cast
<fir::CharacterType
>(elementType
)) {
723 mlir::Value base
= builder
.create
<fir::BoxAddrOp
>(loc
, boxLoad
);
724 if (charType
.hasConstantLen())
725 return hlfir::Entity
{base
};
726 mlir::Value len
= genCharacterVariableLength(loc
, builder
, entity
);
728 fir::BoxCharType::get(builder
.getContext(), charType
.getFKind());
729 return hlfir::Entity
{
730 builder
.create
<fir::EmboxCharOp
>(loc
, boxCharType
, base
, len
)
734 // Otherwise, the entity is either an array, a polymorphic entity, or a
735 // derived type with length parameters. All these entities require a fir.box
736 // or fir.class to hold bounds, dynamic type or length parameter
737 // information. Keep them boxed.
739 } else if (entity
.isProcedurePointer()) {
740 return hlfir::Entity
{builder
.create
<fir::LoadOp
>(loc
, entity
)};
745 mlir::Type
hlfir::getVariableElementType(hlfir::Entity variable
) {
746 assert(variable
.isVariable() && "entity must be a variable");
747 if (variable
.isScalar())
748 return variable
.getType();
749 mlir::Type eleTy
= variable
.getFortranElementType();
750 if (variable
.isPolymorphic())
751 return fir::ClassType::get(eleTy
);
752 if (auto charType
= mlir::dyn_cast
<fir::CharacterType
>(eleTy
)) {
753 if (charType
.hasDynamicLen())
754 return fir::BoxCharType::get(charType
.getContext(), charType
.getFKind());
755 } else if (fir::isRecordWithTypeParameters(eleTy
)) {
756 return fir::BoxType::get(eleTy
);
758 return fir::ReferenceType::get(eleTy
);
761 mlir::Type
hlfir::getEntityElementType(hlfir::Entity entity
) {
762 if (entity
.isVariable())
763 return getVariableElementType(entity
);
764 if (entity
.isScalar())
765 return entity
.getType();
766 auto exprType
= mlir::dyn_cast
<hlfir::ExprType
>(entity
.getType());
767 assert(exprType
&& "array value must be an hlfir.expr");
768 return exprType
.getElementExprType();
771 static hlfir::ExprType
getArrayExprType(mlir::Type elementType
,
772 mlir::Value shape
, bool isPolymorphic
) {
773 unsigned rank
= mlir::cast
<fir::ShapeType
>(shape
.getType()).getRank();
774 hlfir::ExprType::Shape
typeShape(rank
, hlfir::ExprType::getUnknownExtent());
775 if (auto shapeOp
= shape
.getDefiningOp
<fir::ShapeOp
>())
776 for (auto extent
: llvm::enumerate(shapeOp
.getExtents()))
777 if (auto cstExtent
= fir::getIntIfConstant(extent
.value()))
778 typeShape
[extent
.index()] = *cstExtent
;
779 return hlfir::ExprType::get(elementType
.getContext(), typeShape
, elementType
,
783 hlfir::ElementalOp
hlfir::genElementalOp(
784 mlir::Location loc
, fir::FirOpBuilder
&builder
, mlir::Type elementType
,
785 mlir::Value shape
, mlir::ValueRange typeParams
,
786 const ElementalKernelGenerator
&genKernel
, bool isUnordered
,
787 mlir::Value polymorphicMold
, mlir::Type exprType
) {
789 exprType
= getArrayExprType(elementType
, shape
, !!polymorphicMold
);
790 auto elementalOp
= builder
.create
<hlfir::ElementalOp
>(
791 loc
, exprType
, shape
, polymorphicMold
, typeParams
, isUnordered
);
792 auto insertPt
= builder
.saveInsertionPoint();
793 builder
.setInsertionPointToStart(elementalOp
.getBody());
794 mlir::Value elementResult
= genKernel(loc
, builder
, elementalOp
.getIndices());
795 // Numerical and logical scalars may be lowered to another type than the
796 // Fortran expression type (e.g i1 instead of fir.logical). Array expression
797 // values are typed according to their Fortran type. Insert a cast if needed
799 if (fir::isa_trivial(elementResult
.getType()))
800 elementResult
= builder
.createConvert(loc
, elementType
, elementResult
);
801 builder
.create
<hlfir::YieldElementOp
>(loc
, elementResult
);
802 builder
.restoreInsertionPoint(insertPt
);
806 // TODO: we do not actually need to clone the YieldElementOp,
807 // because returning its getElementValue() operand should be enough
808 // for all callers of this function.
809 hlfir::YieldElementOp
810 hlfir::inlineElementalOp(mlir::Location loc
, fir::FirOpBuilder
&builder
,
811 hlfir::ElementalOp elemental
,
812 mlir::ValueRange oneBasedIndices
) {
813 // hlfir.elemental region is a SizedRegion<1>.
814 assert(elemental
.getRegion().hasOneBlock() &&
815 "expect elemental region to have one block");
816 mlir::IRMapping mapper
;
817 mapper
.map(elemental
.getIndices(), oneBasedIndices
);
818 mlir::Operation
*newOp
;
819 for (auto &op
: elemental
.getRegion().back().getOperations())
820 newOp
= builder
.clone(op
, mapper
);
821 auto yield
= mlir::dyn_cast_or_null
<hlfir::YieldElementOp
>(newOp
);
822 assert(yield
&& "last ElementalOp operation must be am hlfir.yield_element");
826 mlir::Value
hlfir::inlineElementalOp(
827 mlir::Location loc
, fir::FirOpBuilder
&builder
,
828 hlfir::ElementalOpInterface elemental
, mlir::ValueRange oneBasedIndices
,
829 mlir::IRMapping
&mapper
,
830 const std::function
<bool(hlfir::ElementalOp
)> &mustRecursivelyInline
) {
831 mlir::Region
®ion
= elemental
.getElementalRegion();
832 // hlfir.elemental region is a SizedRegion<1>.
833 assert(region
.hasOneBlock() && "elemental region must have one block");
834 mapper
.map(elemental
.getIndices(), oneBasedIndices
);
835 for (auto &op
: region
.front().without_terminator()) {
836 if (auto apply
= mlir::dyn_cast
<hlfir::ApplyOp
>(op
))
837 if (auto appliedElemental
=
838 apply
.getExpr().getDefiningOp
<hlfir::ElementalOp
>())
839 if (mustRecursivelyInline(appliedElemental
)) {
840 llvm::SmallVector
<mlir::Value
> clonedApplyIndices
;
841 for (auto indice
: apply
.getIndices())
842 clonedApplyIndices
.push_back(mapper
.lookupOrDefault(indice
));
843 hlfir::ElementalOpInterface elementalIface
=
844 mlir::cast
<hlfir::ElementalOpInterface
>(
845 appliedElemental
.getOperation());
846 mlir::Value inlined
= inlineElementalOp(loc
, builder
, elementalIface
,
847 clonedApplyIndices
, mapper
,
848 mustRecursivelyInline
);
849 mapper
.map(apply
.getResult(), inlined
);
852 (void)builder
.clone(op
, mapper
);
854 return mapper
.lookupOrDefault(elemental
.getElementEntity());
857 hlfir::LoopNest
hlfir::genLoopNest(mlir::Location loc
,
858 fir::FirOpBuilder
&builder
,
859 mlir::ValueRange extents
, bool isUnordered
,
860 bool emitWorkshareLoop
) {
861 emitWorkshareLoop
= emitWorkshareLoop
&& isUnordered
;
862 hlfir::LoopNest loopNest
;
863 assert(!extents
.empty() && "must have at least one extent");
864 mlir::OpBuilder::InsertionGuard
guard(builder
);
865 loopNest
.oneBasedIndices
.assign(extents
.size(), mlir::Value
{});
866 // Build loop nest from column to row.
867 auto one
= builder
.create
<mlir::arith::ConstantIndexOp
>(loc
, 1);
868 mlir::Type indexType
= builder
.getIndexType();
869 if (emitWorkshareLoop
) {
870 auto wslw
= builder
.create
<mlir::omp::WorkshareLoopWrapperOp
>(loc
);
871 loopNest
.outerOp
= wslw
;
872 builder
.createBlock(&wslw
.getRegion());
873 mlir::omp::LoopNestOperands lnops
;
874 lnops
.loopInclusive
= builder
.getUnitAttr();
875 for (auto extent
: llvm::reverse(extents
)) {
876 lnops
.loopLowerBounds
.push_back(one
);
877 lnops
.loopUpperBounds
.push_back(extent
);
878 lnops
.loopSteps
.push_back(one
);
880 auto lnOp
= builder
.create
<mlir::omp::LoopNestOp
>(loc
, lnops
);
881 mlir::Block
*block
= builder
.createBlock(&lnOp
.getRegion());
882 for (auto extent
: llvm::reverse(extents
))
883 block
->addArgument(extent
.getType(), extent
.getLoc());
884 loopNest
.body
= block
;
885 builder
.create
<mlir::omp::YieldOp
>(loc
);
886 for (unsigned dim
= 0; dim
< extents
.size(); dim
++)
887 loopNest
.oneBasedIndices
[extents
.size() - dim
- 1] =
888 lnOp
.getRegion().front().getArgument(dim
);
890 unsigned dim
= extents
.size() - 1;
891 for (auto extent
: llvm::reverse(extents
)) {
892 auto ub
= builder
.createConvert(loc
, indexType
, extent
);
894 builder
.create
<fir::DoLoopOp
>(loc
, one
, ub
, one
, isUnordered
);
895 loopNest
.body
= doLoop
.getBody();
896 builder
.setInsertionPointToStart(loopNest
.body
);
897 // Reverse the indices so they are in column-major order.
898 loopNest
.oneBasedIndices
[dim
--] = doLoop
.getInductionVar();
899 if (!loopNest
.outerOp
)
900 loopNest
.outerOp
= doLoop
;
906 static fir::ExtendedValue
translateVariableToExtendedValue(
907 mlir::Location loc
, fir::FirOpBuilder
&builder
, hlfir::Entity variable
,
908 bool forceHlfirBase
= false, bool contiguousHint
= false) {
909 assert(variable
.isVariable() && "must be a variable");
910 // When going towards FIR, use the original base value to avoid
911 // introducing descriptors at runtime when they are not required.
912 // This is not done for assumed-rank since the fir::ExtendedValue cannot
913 // held the related lower bounds in an vector. The lower bounds of the
914 // descriptor must always be used instead.
916 mlir::Value base
= (forceHlfirBase
|| variable
.isAssumedRank())
918 : variable
.getFirBase();
919 if (variable
.isMutableBox())
920 return fir::MutableBoxValue(base
, getExplicitTypeParams(variable
),
921 fir::MutableProperties
{});
923 if (mlir::isa
<fir::BaseBoxType
>(base
.getType())) {
924 const bool contiguous
= variable
.isSimplyContiguous() || contiguousHint
;
925 const bool isAssumedRank
= variable
.isAssumedRank();
926 if (!contiguous
|| variable
.isPolymorphic() ||
927 variable
.isDerivedWithLengthParameters() || variable
.isOptional() ||
929 llvm::SmallVector
<mlir::Value
> nonDefaultLbounds
;
931 nonDefaultLbounds
= getNonDefaultLowerBounds(loc
, builder
, variable
);
932 return fir::BoxValue(base
, nonDefaultLbounds
,
933 getExplicitTypeParams(variable
));
935 // Otherwise, the variable can be represented in a fir::ExtendedValue
936 // without the overhead of a fir.box.
937 base
= genVariableRawAddress(loc
, builder
, variable
);
940 if (variable
.isScalar()) {
941 if (variable
.isCharacter()) {
942 if (mlir::isa
<fir::BoxCharType
>(base
.getType()))
943 return genUnboxChar(loc
, builder
, base
);
944 mlir::Value len
= genCharacterVariableLength(loc
, builder
, variable
);
945 return fir::CharBoxValue
{base
, len
};
949 llvm::SmallVector
<mlir::Value
> extents
;
950 llvm::SmallVector
<mlir::Value
> nonDefaultLbounds
;
951 if (mlir::isa
<fir::BaseBoxType
>(variable
.getType()) &&
952 !variable
.getIfVariableInterface() &&
953 variable
.mayHaveNonDefaultLowerBounds()) {
954 // This special case avoids generating two sets of identical
955 // fir.box_dim to get both the lower bounds and extents.
956 genLboundsAndExtentsFromBox(loc
, builder
, variable
, nonDefaultLbounds
,
959 extents
= getVariableExtents(loc
, builder
, variable
);
960 nonDefaultLbounds
= getNonDefaultLowerBounds(loc
, builder
, variable
);
962 if (variable
.isCharacter())
963 return fir::CharArrayBoxValue
{
964 base
, genCharacterVariableLength(loc
, builder
, variable
), extents
,
966 return fir::ArrayBoxValue
{base
, extents
, nonDefaultLbounds
};
970 hlfir::translateToExtendedValue(mlir::Location loc
, fir::FirOpBuilder
&builder
,
971 fir::FortranVariableOpInterface var
,
972 bool forceHlfirBase
) {
973 return translateVariableToExtendedValue(loc
, builder
, var
, forceHlfirBase
);
976 std::pair
<fir::ExtendedValue
, std::optional
<hlfir::CleanupFunction
>>
977 hlfir::translateToExtendedValue(mlir::Location loc
, fir::FirOpBuilder
&builder
,
978 hlfir::Entity entity
, bool contiguousHint
) {
979 if (entity
.isVariable())
980 return {translateVariableToExtendedValue(loc
, builder
, entity
, false,
984 if (entity
.isProcedure()) {
985 if (fir::isCharacterProcedureTuple(entity
.getType())) {
986 auto [boxProc
, len
] = fir::factory::extractCharacterProcedureTuple(
987 builder
, loc
, entity
, /*openBoxProc=*/false);
988 return {fir::CharBoxValue
{boxProc
, len
}, std::nullopt
};
990 return {static_cast<mlir::Value
>(entity
), std::nullopt
};
993 if (mlir::isa
<hlfir::ExprType
>(entity
.getType())) {
994 mlir::NamedAttribute byRefAttr
= fir::getAdaptToByRefAttr(builder
);
995 hlfir::AssociateOp associate
= hlfir::genAssociateExpr(
996 loc
, builder
, entity
, entity
.getType(), "", byRefAttr
);
997 auto *bldr
= &builder
;
998 hlfir::CleanupFunction cleanup
= [bldr
, loc
, associate
]() -> void {
999 bldr
->create
<hlfir::EndAssociateOp
>(loc
, associate
);
1001 hlfir::Entity temp
{associate
.getBase()};
1002 return {translateToExtendedValue(loc
, builder
, temp
).first
, cleanup
};
1004 return {{static_cast<mlir::Value
>(entity
)}, {}};
1007 std::pair
<fir::ExtendedValue
, std::optional
<hlfir::CleanupFunction
>>
1008 hlfir::convertToValue(mlir::Location loc
, fir::FirOpBuilder
&builder
,
1009 hlfir::Entity entity
) {
1010 // Load scalar references to integer, logical, real, or complex value
1011 // to an mlir value, dereference allocatable and pointers, and get rid
1012 // of fir.box that are not needed or create a copy into contiguous memory.
1013 auto derefedAndLoadedEntity
= loadTrivialScalar(loc
, builder
, entity
);
1014 return translateToExtendedValue(loc
, builder
, derefedAndLoadedEntity
);
1017 static fir::ExtendedValue
placeTrivialInMemory(mlir::Location loc
,
1018 fir::FirOpBuilder
&builder
,
1020 mlir::Type targetType
) {
1021 auto temp
= builder
.createTemporary(loc
, targetType
);
1022 if (targetType
!= val
.getType())
1023 builder
.createStoreWithConvert(loc
, val
, temp
);
1025 builder
.create
<fir::StoreOp
>(loc
, val
, temp
);
1029 std::pair
<fir::ExtendedValue
, std::optional
<hlfir::CleanupFunction
>>
1030 hlfir::convertToBox(mlir::Location loc
, fir::FirOpBuilder
&builder
,
1031 hlfir::Entity entity
, mlir::Type targetType
) {
1032 // fir::factory::createBoxValue is not meant to deal with procedures.
1033 // Dereference procedure pointers here.
1034 if (entity
.isProcedurePointer())
1035 entity
= hlfir::derefPointersAndAllocatables(loc
, builder
, entity
);
1037 auto [exv
, cleanup
] = translateToExtendedValue(loc
, builder
, entity
);
1038 // Procedure entities should not go through createBoxValue that embox
1039 // object entities. Return the fir.boxproc directly.
1040 if (entity
.isProcedure())
1041 return {exv
, cleanup
};
1042 mlir::Value base
= fir::getBase(exv
);
1043 if (fir::isa_trivial(base
.getType()))
1044 exv
= placeTrivialInMemory(loc
, builder
, base
, targetType
);
1045 fir::BoxValue box
= fir::factory::createBoxValue(builder
, loc
, exv
);
1046 return {box
, cleanup
};
1049 std::pair
<fir::ExtendedValue
, std::optional
<hlfir::CleanupFunction
>>
1050 hlfir::convertToAddress(mlir::Location loc
, fir::FirOpBuilder
&builder
,
1051 hlfir::Entity entity
, mlir::Type targetType
) {
1052 hlfir::Entity derefedEntity
=
1053 hlfir::derefPointersAndAllocatables(loc
, builder
, entity
);
1054 auto [exv
, cleanup
] =
1055 hlfir::translateToExtendedValue(loc
, builder
, derefedEntity
);
1056 mlir::Value base
= fir::getBase(exv
);
1057 if (fir::isa_trivial(base
.getType()))
1058 exv
= placeTrivialInMemory(loc
, builder
, base
, targetType
);
1059 return {exv
, cleanup
};
1064 /// hlfir.elemental_addr %shape : !fir.shape<1> {
1065 /// ^bb0(%i : index)
1067 /// %hlfir.yield %scalarAddress : fir.ref<T>
1074 /// %expr = hlfir.elemental %shape : (!fir.shape<1>) -> hlfir.expr<?xT> {
1075 /// ^bb0(%i : index)
1077 /// %value = fir.load %scalarAddress : fir.ref<T>
1078 /// %hlfir.yield_element %value : T
1082 hlfir::cloneToElementalOp(mlir::Location loc
, fir::FirOpBuilder
&builder
,
1083 hlfir::ElementalAddrOp elementalAddrOp
) {
1084 hlfir::Entity scalarAddress
=
1085 hlfir::Entity
{mlir::cast
<hlfir::YieldOp
>(
1086 elementalAddrOp
.getBody().back().getTerminator())
1088 llvm::SmallVector
<mlir::Value
, 1> typeParams
;
1089 hlfir::genLengthParameters(loc
, builder
, scalarAddress
, typeParams
);
1091 builder
.setInsertionPointAfter(elementalAddrOp
);
1092 auto genKernel
= [&](mlir::Location l
, fir::FirOpBuilder
&b
,
1093 mlir::ValueRange oneBasedIndices
) -> hlfir::Entity
{
1094 mlir::IRMapping mapper
;
1095 mapper
.map(elementalAddrOp
.getIndices(), oneBasedIndices
);
1096 mlir::Operation
*newOp
= nullptr;
1097 for (auto &op
: elementalAddrOp
.getBody().back().getOperations())
1098 newOp
= b
.clone(op
, mapper
);
1099 auto newYielOp
= mlir::dyn_cast_or_null
<hlfir::YieldOp
>(newOp
);
1100 assert(newYielOp
&& "hlfir.elemental_addr is ill formed");
1101 hlfir::Entity newAddr
{newYielOp
.getEntity()};
1103 return hlfir::loadTrivialScalar(l
, b
, newAddr
);
1105 mlir::Type elementType
= scalarAddress
.getFortranElementType();
1106 return hlfir::genElementalOp(
1107 loc
, builder
, elementType
, elementalAddrOp
.getShape(), typeParams
,
1108 genKernel
, !elementalAddrOp
.isOrdered(), elementalAddrOp
.getMold());
1111 bool hlfir::elementalOpMustProduceTemp(hlfir::ElementalOp elemental
) {
1112 for (mlir::Operation
*useOp
: elemental
->getUsers())
1113 if (auto destroy
= mlir::dyn_cast
<hlfir::DestroyOp
>(useOp
))
1114 if (destroy
.mustFinalizeExpr())
1120 std::pair
<hlfir::Entity
, mlir::Value
>
1121 hlfir::createTempFromMold(mlir::Location loc
, fir::FirOpBuilder
&builder
,
1122 hlfir::Entity mold
) {
1123 llvm::SmallVector
<mlir::Value
> lenParams
;
1124 hlfir::genLengthParameters(loc
, builder
, mold
, lenParams
);
1125 llvm::StringRef tmpName
{".tmp"};
1127 mlir::Value isHeapAlloc
;
1128 mlir::Value shape
{};
1129 fir::FortranVariableFlagsAttr declAttrs
;
1131 if (mold
.isPolymorphic()) {
1132 // Create unallocated polymorphic temporary using the dynamic type
1133 // of the mold. The static type of the temporary matches
1134 // the static type of the mold, but then the dynamic type
1135 // of the mold is applied to the temporary's descriptor.
1138 hlfir::genShape(loc
, builder
, mold
);
1140 // Create polymorphic allocatable box on the stack.
1141 mlir::Type boxHeapType
= fir::HeapType::get(fir::unwrapRefType(
1142 mlir::cast
<fir::BaseBoxType
>(mold
.getType()).getEleTy()));
1143 // The box must be initialized, because AllocatableApplyMold
1144 // may read its contents (e.g. for checking whether it is allocated).
1145 alloc
= fir::factory::genNullBoxStorage(builder
, loc
,
1146 fir::ClassType::get(boxHeapType
));
1147 // The temporary is unallocated even after AllocatableApplyMold below.
1148 // If the temporary is used as assignment LHS it will be automatically
1149 // allocated on the heap, as long as we use Assign family
1150 // runtime functions. So set MustFree to true.
1151 isHeapAlloc
= builder
.createBool(loc
, true);
1152 declAttrs
= fir::FortranVariableFlagsAttr::get(
1153 builder
.getContext(), fir::FortranVariableFlagsEnum::allocatable
);
1154 } else if (mold
.isArray()) {
1155 mlir::Type sequenceType
=
1156 hlfir::getFortranElementOrSequenceType(mold
.getType());
1157 shape
= hlfir::genShape(loc
, builder
, mold
);
1158 auto extents
= hlfir::getIndexExtents(loc
, builder
, shape
);
1159 alloc
= builder
.createHeapTemporary(loc
, sequenceType
, tmpName
, extents
,
1161 isHeapAlloc
= builder
.createBool(loc
, true);
1163 alloc
= builder
.createTemporary(loc
, mold
.getFortranElementType(), tmpName
,
1164 /*shape=*/std::nullopt
, lenParams
);
1165 isHeapAlloc
= builder
.createBool(loc
, false);
1168 builder
.create
<hlfir::DeclareOp
>(loc
, alloc
, tmpName
, shape
, lenParams
,
1169 /*dummy_scope=*/nullptr, declAttrs
);
1170 if (mold
.isPolymorphic()) {
1171 int rank
= mold
.getRank();
1172 // TODO: should probably read rank from the mold.
1174 TODO(loc
, "create temporary for assumed rank polymorphic");
1175 fir::runtime::genAllocatableApplyMold(builder
, loc
, alloc
,
1176 mold
.getFirBase(), rank
);
1179 return {hlfir::Entity
{declareOp
.getBase()}, isHeapAlloc
};
1182 hlfir::Entity
hlfir::createStackTempFromMold(mlir::Location loc
,
1183 fir::FirOpBuilder
&builder
,
1184 hlfir::Entity mold
) {
1185 llvm::SmallVector
<mlir::Value
> lenParams
;
1186 hlfir::genLengthParameters(loc
, builder
, mold
, lenParams
);
1187 llvm::StringRef tmpName
{".tmp"};
1189 mlir::Value shape
{};
1190 fir::FortranVariableFlagsAttr declAttrs
;
1192 if (mold
.isPolymorphic()) {
1193 // genAllocatableApplyMold does heap allocation
1194 TODO(loc
, "createStackTempFromMold for polymorphic type");
1195 } else if (mold
.isArray()) {
1196 mlir::Type sequenceType
=
1197 hlfir::getFortranElementOrSequenceType(mold
.getType());
1198 shape
= hlfir::genShape(loc
, builder
, mold
);
1199 auto extents
= hlfir::getIndexExtents(loc
, builder
, shape
);
1201 builder
.createTemporary(loc
, sequenceType
, tmpName
, extents
, lenParams
);
1203 alloc
= builder
.createTemporary(loc
, mold
.getFortranElementType(), tmpName
,
1204 /*shape=*/std::nullopt
, lenParams
);
1207 builder
.create
<hlfir::DeclareOp
>(loc
, alloc
, tmpName
, shape
, lenParams
,
1208 /*dummy_scope=*/nullptr, declAttrs
);
1209 return hlfir::Entity
{declareOp
.getBase()};
1212 hlfir::EntityWithAttributes
1213 hlfir::convertCharacterKind(mlir::Location loc
, fir::FirOpBuilder
&builder
,
1214 hlfir::Entity scalarChar
, int toKind
) {
1215 auto src
= hlfir::convertToAddress(loc
, builder
, scalarChar
,
1216 scalarChar
.getFortranElementType());
1217 assert(src
.first
.getCharBox() && "must be scalar character");
1218 fir::CharBoxValue res
= fir::factory::convertCharacterKind(
1219 builder
, loc
, *src
.first
.getCharBox(), toKind
);
1220 if (src
.second
.has_value())
1221 src
.second
.value()();
1223 return hlfir::EntityWithAttributes
{builder
.create
<hlfir::DeclareOp
>(
1224 loc
, res
.getAddr(), ".temp.kindconvert", /*shape=*/nullptr,
1225 /*typeparams=*/mlir::ValueRange
{res
.getLen()},
1226 /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr
{})};
1229 std::pair
<hlfir::Entity
, std::optional
<hlfir::CleanupFunction
>>
1230 hlfir::genTypeAndKindConvert(mlir::Location loc
, fir::FirOpBuilder
&builder
,
1231 hlfir::Entity source
, mlir::Type toType
,
1232 bool preserveLowerBounds
) {
1233 mlir::Type fromType
= source
.getFortranElementType();
1234 toType
= hlfir::getFortranElementType(toType
);
1235 if (!toType
|| fromType
== toType
||
1236 !(fir::isa_trivial(toType
) || mlir::isa
<fir::CharacterType
>(toType
)))
1237 return {source
, std::nullopt
};
1239 std::optional
<int> toKindCharConvert
;
1240 if (auto toCharTy
= mlir::dyn_cast
<fir::CharacterType
>(toType
)) {
1241 if (auto fromCharTy
= mlir::dyn_cast
<fir::CharacterType
>(fromType
))
1242 if (toCharTy
.getFKind() != fromCharTy
.getFKind()) {
1243 toKindCharConvert
= toCharTy
.getFKind();
1244 // Preserve source length (padding/truncation will occur in assignment
1246 toType
= fir::CharacterType::get(
1247 fromType
.getContext(), toCharTy
.getFKind(), fromCharTy
.getLen());
1249 // Do not convert in case of character length mismatch only, hlfir.assign
1251 if (!toKindCharConvert
)
1252 return {source
, std::nullopt
};
1255 if (source
.getRank() == 0) {
1256 mlir::Value cast
= toKindCharConvert
1257 ? mlir::Value
{hlfir::convertCharacterKind(
1258 loc
, builder
, source
, *toKindCharConvert
)}
1259 : builder
.convertWithSemantics(loc
, toType
, source
);
1260 return {hlfir::Entity
{cast
}, std::nullopt
};
1263 mlir::Value shape
= hlfir::genShape(loc
, builder
, source
);
1264 auto genKernel
= [source
, toType
, toKindCharConvert
](
1265 mlir::Location loc
, fir::FirOpBuilder
&builder
,
1266 mlir::ValueRange oneBasedIndices
) -> hlfir::Entity
{
1268 hlfir::getElementAt(loc
, builder
, source
, oneBasedIndices
);
1269 auto val
= hlfir::loadTrivialScalar(loc
, builder
, elementPtr
);
1270 if (toKindCharConvert
)
1271 return hlfir::convertCharacterKind(loc
, builder
, val
, *toKindCharConvert
);
1272 return hlfir::EntityWithAttributes
{
1273 builder
.convertWithSemantics(loc
, toType
, val
)};
1275 llvm::SmallVector
<mlir::Value
, 1> lenParams
;
1276 hlfir::genLengthParameters(loc
, builder
, source
, lenParams
);
1277 mlir::Value convertedRhs
=
1278 hlfir::genElementalOp(loc
, builder
, toType
, shape
, lenParams
, genKernel
,
1279 /*isUnordered=*/true);
1281 if (preserveLowerBounds
&& source
.mayHaveNonDefaultLowerBounds()) {
1282 hlfir::AssociateOp associate
=
1283 genAssociateExpr(loc
, builder
, hlfir::Entity
{convertedRhs
},
1284 convertedRhs
.getType(), ".tmp.keeplbounds");
1285 fir::ShapeOp shapeOp
= associate
.getShape().getDefiningOp
<fir::ShapeOp
>();
1286 assert(shapeOp
&& "associate shape must be a fir.shape");
1287 const unsigned rank
= shapeOp
.getExtents().size();
1288 llvm::SmallVector
<mlir::Value
> lbAndExtents
;
1289 for (unsigned dim
= 0; dim
< rank
; ++dim
) {
1290 lbAndExtents
.push_back(hlfir::genLBound(loc
, builder
, source
, dim
));
1291 lbAndExtents
.push_back(shapeOp
.getExtents()[dim
]);
1293 auto shapeShiftType
= fir::ShapeShiftType::get(builder
.getContext(), rank
);
1294 mlir::Value shapeShift
=
1295 builder
.create
<fir::ShapeShiftOp
>(loc
, shapeShiftType
, lbAndExtents
);
1296 auto declareOp
= builder
.create
<hlfir::DeclareOp
>(
1297 loc
, associate
.getFirBase(), *associate
.getUniqName(), shapeShift
,
1298 associate
.getTypeparams(), /*dummy_scope=*/nullptr,
1299 /*flags=*/fir::FortranVariableFlagsAttr
{});
1300 hlfir::Entity castWithLbounds
=
1301 mlir::cast
<fir::FortranVariableOpInterface
>(declareOp
.getOperation());
1302 fir::FirOpBuilder
*bldr
= &builder
;
1303 auto cleanup
= [loc
, bldr
, convertedRhs
, associate
]() {
1304 bldr
->create
<hlfir::EndAssociateOp
>(loc
, associate
);
1305 bldr
->create
<hlfir::DestroyOp
>(loc
, convertedRhs
);
1307 return {castWithLbounds
, cleanup
};
1310 fir::FirOpBuilder
*bldr
= &builder
;
1311 auto cleanup
= [loc
, bldr
, convertedRhs
]() {
1312 bldr
->create
<hlfir::DestroyOp
>(loc
, convertedRhs
);
1314 return {hlfir::Entity
{convertedRhs
}, cleanup
};