[MemProf] Templatize CallStackRadixTreeBuilder (NFC) (#117014)
[llvm-project.git] / flang / lib / Optimizer / Builder / HLFIRTools.cpp
blob7425ccf7fc0e30c20f662fdf41c19c72529c49e5
1 //===-- HLFIRTools.cpp ----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // 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>
24 #include <optional>
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)) {
40 return {};
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();
53 } else {
54 extentVal =
55 builder.createIntegerConstant(shape.getLoc(), indexTy, extent);
57 result.emplace_back(extentVal);
59 } else {
60 TODO(shape.getLoc(), "read fir.shape to get extents");
62 return result;
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);
69 return {};
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)) {
79 return {};
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());
86 } else {
87 TODO(shape.getLoc(), "read fir.shape to get lower bounds");
89 return result;
91 static llvm::SmallVector<mlir::Value>
92 getExplicitLbounds(fir::FortranVariableOpInterface var) {
93 if (mlir::Value shape = var.getShape())
94 return getExplicitLboundsFromShape(shape);
95 return {};
98 static void
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,
109 boxEntity, dim);
110 lbounds.push_back(dimInfo.getLowerBound());
111 if (extents)
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())
122 return {};
123 if (auto varIface = entity.getIfVariableInterface()) {
124 llvm::SmallVector<mlir::Value> lbounds = getExplicitLbounds(varIface);
125 if (!lbounds.empty())
126 return lbounds;
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);
133 return lowerBounds;
136 static llvm::SmallVector<mlir::Value> toSmallVector(mlir::ValueRange range) {
137 llvm::SmallVector<mlir::Value> res;
138 res.append(range.begin(), range.end());
139 return res;
142 static llvm::SmallVector<mlir::Value> getExplicitTypeParams(hlfir::Entity var) {
143 if (auto varIface = var.getMaybeDereferencedVariableInterface())
144 return toSmallVector(varIface.getExplicitTypeParams());
145 return {};
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,
157 hlfir::Entity var) {
158 if (mlir::Value len = tryGettingNonDeferredCharLen(var))
159 return len;
160 auto charType = mlir::cast<fir::CharacterType>(var.getFortranElementType());
161 if (charType.hasConstantLen())
162 return builder.createIntegerConstant(loc, builder.getIndexType(),
163 charType.getLen());
164 if (var.isMutableBox())
165 var = hlfir::Entity{builder.create<fir::LoadOp>(loc, var)};
166 mlir::Value len = fir::factory::CharacterExprHelper{builder, loc}.getLength(
167 var.getFirBase());
168 assert(len && "failed to retrieve length");
169 return len;
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())
185 len = explicitlen;
186 return {addr, len};
189 mlir::Value hlfir::Entity::getFirBase() const {
190 if (fir::FortranVariableOpInterface variable = getIfVariableInterface()) {
191 if (auto declareOp =
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();
198 return getBase();
201 static bool isShapeWithLowerBounds(mlir::Value shape) {
202 if (!shape)
203 return false;
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())
211 return false;
212 if (isMutableBox())
213 return true;
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.
221 return true;
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;
235 exv.match(
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());
262 hlfir::AssociateOp
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");
268 mlir::Value shape{};
269 if (value.isArray())
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),
285 value);
287 llvm::SmallVector<mlir::Value> lenParams;
288 genLengthParameters(loc, builder, value, lenParams);
289 if (attr) {
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,
301 hlfir::Entity var) {
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);
306 // Get raw address.
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);
311 return baseAddr;
314 mlir::Value hlfir::genVariableBoxChar(mlir::Location loc,
315 fir::FirOpBuilder &builder,
316 hlfir::Entity var) {
317 assert(var.isVariable() && "only address of variables can be taken");
318 if (mlir::isa<fir::BoxCharType>(var.getType()))
319 return var;
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());
325 auto boxCharType =
326 fir::BoxCharType::get(builder.getContext(), charType.getFKind());
327 auto scalarAddr =
328 builder.createConvert(loc, fir::ReferenceType::get(charType), addr);
329 return builder.create<fir::EmboxCharOp>(loc, boxCharType, scalarAddr,
330 lengths[0]);
333 hlfir::Entity hlfir::genVariableBox(mlir::Location loc,
334 fir::FirOpBuilder &builder,
335 hlfir::Entity var) {
336 assert(var.isVariable() && "must be a variable");
337 var = hlfir::derefPointersAndAllocatables(loc, builder, var);
338 if (mlir::isa<fir::BaseBoxType>(var.getType()))
339 return var;
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.
342 mlir::Value shape =
343 var.isArray() ? hlfir::genShape(loc, builder, var) : mlir::Value{};
344 llvm::SmallVector<mlir::Value> typeParams;
345 auto maybeCharType =
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());
353 auto embox =
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,
361 Entity entity) {
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)};
367 return entity;
370 hlfir::Entity hlfir::getElementAt(mlir::Location loc,
371 fir::FirOpBuilder &builder, Entity entity,
372 mlir::ValueRange oneBasedIndices) {
373 if (entity.isScalar())
374 return entity;
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);
395 mlir::Value index =
396 builder.create<mlir::arith::AddIOp>(loc, oneBasedIdx, shift);
397 indices.push_back(index);
399 designate = builder.create<hlfir::DesignateOp>(loc, resultType, entity,
400 indices, lenParams);
401 } else {
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,
410 mlir::Value one) {
411 if (auto constantLb = fir::getIntIfConstant(lb))
412 if (*constantLb == 1)
413 return extent;
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,
422 Entity entity) {
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});
438 return result;
441 llvm::SmallVector<std::pair<mlir::Value, mlir::Value>>
442 hlfir::genBounds(mlir::Location loc, fir::FirOpBuilder &builder,
443 mlir::Value shape) {
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()
456 ? extent.value()
457 : genUBound(loc, builder, lb, extent.value(), one);
458 result.push_back({lb, ub});
460 return result;
463 llvm::SmallVector<mlir::Value> hlfir::genLowerbounds(mlir::Location loc,
464 fir::FirOpBuilder &builder,
465 mlir::Value shape,
466 unsigned rank) {
467 llvm::SmallVector<mlir::Value> lbounds;
468 if (shape)
469 lbounds = getExplicitLboundsFromShape(shape);
470 if (!lbounds.empty())
471 return lbounds;
472 mlir::Value one =
473 builder.createIntegerConstant(loc, builder.getIndexType(), 1);
474 return llvm::SmallVector<mlir::Value>(rank, one);
477 static hlfir::Entity followShapeInducingSource(hlfir::Entity entity) {
478 while (true) {
479 if (auto reassoc = entity.getDefiningOp<hlfir::NoReassocOp>()) {
480 entity = hlfir::Entity{reassoc.getVal()};
481 continue;
483 if (auto asExpr = entity.getDefiningOp<hlfir::AsExprOp>()) {
484 entity = hlfir::Entity{asExpr.getVar()};
485 continue;
487 break;
489 return entity;
492 static mlir::Value computeVariableExtent(mlir::Location loc,
493 fir::FirOpBuilder &builder,
494 hlfir::Entity variable,
495 fir::SequenceType seqTy,
496 unsigned dim) {
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,
507 variable, dimVal);
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())
518 return extents;
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)
529 extents.push_back(
530 computeVariableExtent(loc, builder, variable, seqTy, dim));
531 return extents;
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();
542 return {};
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()))
552 return shape;
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,
567 mlir::Value shape) {
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);
573 return extents;
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");
583 return extents[dim];
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");
606 return lbounds[dim];
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);
614 auto dimInfo =
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,
620 Entity entity,
621 llvm::SmallVectorImpl<mlir::Value> &result) {
622 if (!entity.hasLengthParameters())
623 return;
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());
633 return;
634 } else if (auto concat = expr.getDefiningOp<hlfir::SetLengthOp>()) {
635 result.push_back(concat.getLength());
636 return;
637 } else if (auto asExpr = expr.getDefiningOp<hlfir::AsExprOp>()) {
638 hlfir::genLengthParameters(loc, builder, hlfir::Entity{asExpr.getVar()},
639 result);
640 return;
641 } else if (auto elemental = expr.getDefiningOp<hlfir::ElementalOp>()) {
642 result.append(elemental.getTypeparams().begin(),
643 elemental.getTypeparams().end());
644 return;
645 } else if (auto apply = expr.getDefiningOp<hlfir::ApplyOp>()) {
646 result.append(apply.getTypeparams().begin(), apply.getTypeparams().end());
647 return;
649 if (entity.isCharacter()) {
650 result.push_back(builder.create<hlfir::GetLengthOp>(loc, expr));
651 return;
653 TODO(loc, "inquire PDTs length parameters of hlfir.expr");
656 if (entity.isCharacter()) {
657 result.push_back(genCharacterVariableLength(loc, builder, entity));
658 return;
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");
668 return lenParams[0];
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,
683 mlir::Value shape) {
684 if (!shape)
685 return shape;
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
689 // in the fir.box.
690 if (mlir::isa<fir::BaseBoxType>(fir::getBase(exv).getType()) &&
691 !mlir::isa<fir::ShiftType>(shape.getType()))
692 return builder.createShape(loc, exv);
693 return shape;
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,
715 Entity entity) {
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);
727 auto boxCharType =
728 fir::BoxCharType::get(builder.getContext(), charType.getFKind());
729 return hlfir::Entity{
730 builder.create<fir::EmboxCharOp>(loc, boxCharType, base, len)
731 .getResult()};
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.
738 return boxLoad;
739 } else if (entity.isProcedurePointer()) {
740 return hlfir::Entity{builder.create<fir::LoadOp>(loc, entity)};
742 return 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,
780 isPolymorphic);
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) {
788 if (!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
798 // here.
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);
803 return elementalOp;
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");
823 return yield;
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 &region = 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);
850 continue;
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);
889 } else {
890 unsigned dim = extents.size() - 1;
891 for (auto extent : llvm::reverse(extents)) {
892 auto ub = builder.createConvert(loc, indexType, extent);
893 auto doLoop =
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;
903 return loopNest;
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())
917 ? variable.getBase()
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() ||
928 isAssumedRank) {
929 llvm::SmallVector<mlir::Value> nonDefaultLbounds;
930 if (!isAssumedRank)
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};
947 return base;
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,
957 &extents);
958 } else {
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,
965 nonDefaultLbounds};
966 return fir::ArrayBoxValue{base, extents, nonDefaultLbounds};
969 fir::ExtendedValue
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,
981 contiguousHint),
982 std::nullopt};
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,
1019 mlir::Value val,
1020 mlir::Type targetType) {
1021 auto temp = builder.createTemporary(loc, targetType);
1022 if (targetType != val.getType())
1023 builder.createStoreWithConvert(loc, val, temp);
1024 else
1025 builder.create<fir::StoreOp>(loc, val, temp);
1026 return 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};
1062 /// Clone:
1063 /// ```
1064 /// hlfir.elemental_addr %shape : !fir.shape<1> {
1065 /// ^bb0(%i : index)
1066 /// .....
1067 /// %hlfir.yield %scalarAddress : fir.ref<T>
1068 /// }
1069 /// ```
1071 /// into
1073 /// ```
1074 /// %expr = hlfir.elemental %shape : (!fir.shape<1>) -> hlfir.expr<?xT> {
1075 /// ^bb0(%i : index)
1076 /// .....
1077 /// %value = fir.load %scalarAddress : fir.ref<T>
1078 /// %hlfir.yield_element %value : T
1079 /// }
1080 /// ```
1081 hlfir::ElementalOp
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())
1087 .getEntity()};
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()};
1102 newYielOp->erase();
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())
1115 return true;
1117 return false;
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"};
1126 mlir::Value alloc;
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.
1137 if (mold.isArray())
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,
1160 lenParams);
1161 isHeapAlloc = builder.createBool(loc, true);
1162 } else {
1163 alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName,
1164 /*shape=*/std::nullopt, lenParams);
1165 isHeapAlloc = builder.createBool(loc, false);
1167 auto declareOp =
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.
1173 if (rank < 0)
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"};
1188 mlir::Value alloc;
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);
1200 alloc =
1201 builder.createTemporary(loc, sequenceType, tmpName, extents, lenParams);
1202 } else {
1203 alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName,
1204 /*shape=*/std::nullopt, lenParams);
1206 auto declareOp =
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
1245 // if needed).
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
1250 // deals with it.
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 {
1267 auto elementPtr =
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};