Skip to content

Commit 6a41f53

Browse files
authored
[flang][hlfir] do not propagate polymorphic temporary as allocatables (#142609)
Polymorphic temporary are currently propagated as fir.ref<fir.class<fir.heap<>>> because their allocation may be delayed to the hlfir.assign copy (using realloc). This patch moves away from this and directly allocate the temp and propagate it as a fir.class. The polymorphic temporaries creating is also simplified by avoiding the need to call the runtime to setup the descriptor altogether (the runtime is still call for the allocation currently because alloca/allocmem do not support polymorphism).
1 parent 3f7b885 commit 6a41f53

33 files changed

+516
-680
lines changed

flang/include/flang/Optimizer/Builder/FIRBuilder.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,14 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
271271
/// Sample genDeclare callback for createArrayTemp() below.
272272
/// It creates fir.declare operation using the given operands.
273273
/// \p memref is the base of the allocated temporary,
274-
/// which may be !fir.ref<!fir.array<>> or !fir.ref<!fir.box/class<>>.
274+
/// which may be !fir.ref<!fir.array<>> or !fir.box/class<>.
275275
static mlir::Value genTempDeclareOp(fir::FirOpBuilder &builder,
276276
mlir::Location loc, mlir::Value memref,
277277
llvm::StringRef name, mlir::Value shape,
278278
llvm::ArrayRef<mlir::Value> typeParams,
279279
fir::FortranVariableFlagsAttr attrs);
280280

281-
/// Create a temporary array with the given \p arrayType,
281+
/// Create a temporary with the given \p baseType,
282282
/// \p shape, \p extents and \p typeParams. An optional
283283
/// \p polymorphicMold specifies the entity which dynamic type
284284
/// has to be used for the allocation.
@@ -291,16 +291,26 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
291291
/// If \p useStack is true, the function will try to do the allocation
292292
/// in stack memory (which is not always possible currently).
293293
/// The first return value is the base of the temporary object,
294-
/// which may be !fir.ref<!fir.array<>> or !fir.ref<!fir.box/class<>>.
294+
/// which may be !fir.ref<!fir.array<>> or !fir.box/class<>.
295295
/// The second return value is true, if the actual allocation
296296
/// was done in heap memory.
297+
std::pair<mlir::Value, bool> createAndDeclareTemp(
298+
mlir::Location loc, mlir::Type baseType, mlir::Value shape,
299+
llvm::ArrayRef<mlir::Value> extents,
300+
llvm::ArrayRef<mlir::Value> typeParams,
301+
const std::function<decltype(genTempDeclareOp)> &genDeclare,
302+
mlir::Value polymorphicMold, bool useStack, llvm::StringRef tmpName);
303+
/// Create and declare an array temporary.
297304
std::pair<mlir::Value, bool>
298305
createArrayTemp(mlir::Location loc, fir::SequenceType arrayType,
299306
mlir::Value shape, llvm::ArrayRef<mlir::Value> extents,
300307
llvm::ArrayRef<mlir::Value> typeParams,
301308
const std::function<decltype(genTempDeclareOp)> &genDeclare,
302309
mlir::Value polymorphicMold, bool useStack = false,
303-
llvm::StringRef tmpName = ".tmp.array");
310+
llvm::StringRef tmpName = ".tmp.array") {
311+
return createAndDeclareTemp(loc, arrayType, shape, extents, typeParams,
312+
genDeclare, polymorphicMold, useStack, tmpName);
313+
}
304314

305315
/// Create an LLVM stack save intrinsic op. Returns the saved stack pointer.
306316
/// The stack address space is fetched from the data layout of the current

flang/include/flang/Optimizer/Builder/MutableBox.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,18 @@ mlir::Value genIsNotAllocatedOrAssociatedTest(fir::FirOpBuilder &builder,
181181
mlir::Value genNullBoxStorage(fir::FirOpBuilder &builder, mlir::Location loc,
182182
mlir::Type boxTy);
183183

184+
/// Generate an unallocated box of the given \p boxTy with the
185+
/// bounds, type parameters, and dynamic type set according to the
186+
/// parameters.
187+
/// \p shape may be null for scalars, and \p polymorphicMold may be null for
188+
/// statically typed entities. This box can then be directly passed to the
189+
/// runtime for allocation.
190+
mlir::Value getAndEstablishBoxStorage(fir::FirOpBuilder &builder,
191+
mlir::Location loc,
192+
fir::BaseBoxType boxTy, mlir::Value shape,
193+
llvm::ArrayRef<mlir::Value> typeParams,
194+
mlir::Value polymorphicMold);
195+
184196
} // namespace fir::factory
185197

186198
#endif // FORTRAN_OPTIMIZER_BUILDER_MUTABLEBOX_H

flang/include/flang/Optimizer/Dialect/FIRType.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ class BaseBoxType : public mlir::Type {
4747
/// Returns the element type of this box type.
4848
mlir::Type getEleTy() const;
4949

50+
/// Get the raw address type of the memory described by the box.
51+
mlir::Type getBaseAddressType() const;
52+
5053
/// Unwrap element type from fir.heap, fir.ptr and fir.array.
5154
mlir::Type unwrapInnerType() const;
5255

@@ -56,6 +59,9 @@ class BaseBoxType : public mlir::Type {
5659
/// Is this a box for a pointer?
5760
bool isPointer() const;
5861

62+
/// Is this a box describing volatile memory?
63+
bool isVolatile() const;
64+
5965
/// Return the same type, except for the shape, that is taken the shape
6066
/// of shapeMold.
6167
BaseBoxType getBoxTypeWithNewShape(mlir::Type shapeMold) const;

flang/lib/Optimizer/Builder/FIRBuilder.cpp

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -366,55 +366,29 @@ mlir::Value fir::FirOpBuilder::createHeapTemporary(
366366
name, dynamicLength, dynamicShape, attrs);
367367
}
368368

369-
std::pair<mlir::Value, bool> fir::FirOpBuilder::createArrayTemp(
370-
mlir::Location loc, fir::SequenceType arrayType, mlir::Value shape,
369+
std::pair<mlir::Value, bool> fir::FirOpBuilder::createAndDeclareTemp(
370+
mlir::Location loc, mlir::Type baseType, mlir::Value shape,
371371
llvm::ArrayRef<mlir::Value> extents, llvm::ArrayRef<mlir::Value> typeParams,
372372
const std::function<decltype(FirOpBuilder::genTempDeclareOp)> &genDeclare,
373373
mlir::Value polymorphicMold, bool useStack, llvm::StringRef tmpName) {
374374
if (polymorphicMold) {
375375
// Create *allocated* polymorphic temporary using the dynamic type
376-
// of the mold and the provided shape/extents. The created temporary
377-
// array will be written element per element, that is why it has to be
378-
// allocated.
379-
mlir::Type boxHeapType = fir::HeapType::get(arrayType);
380-
mlir::Value alloc = fir::factory::genNullBoxStorage(
381-
*this, loc, fir::ClassType::get(boxHeapType));
382-
fir::FortranVariableFlagsAttr declAttrs =
383-
fir::FortranVariableFlagsAttr::get(
384-
getContext(), fir::FortranVariableFlagsEnum::allocatable);
385-
386-
mlir::Value base = genDeclare(*this, loc, alloc, tmpName,
387-
/*shape=*/nullptr, typeParams, declAttrs);
388-
389-
int rank = extents.size();
390-
fir::runtime::genAllocatableApplyMold(*this, loc, alloc, polymorphicMold,
391-
rank);
392-
if (!extents.empty()) {
393-
mlir::Type idxTy = getIndexType();
394-
mlir::Value one = createIntegerConstant(loc, idxTy, 1);
395-
unsigned dim = 0;
396-
for (mlir::Value extent : extents) {
397-
mlir::Value dimIndex = createIntegerConstant(loc, idxTy, dim++);
398-
fir::runtime::genAllocatableSetBounds(*this, loc, alloc, dimIndex, one,
399-
extent);
400-
}
401-
}
402-
if (!typeParams.empty()) {
403-
// We should call AllocatableSetDerivedLength() here.
404-
// TODO: does the mold provide the length parameters or
405-
// the operation itself or should they be in sync?
406-
TODO(loc, "polymorphic type with length parameters");
407-
}
408-
fir::runtime::genAllocatableAllocate(*this, loc, alloc);
409-
376+
// of the mold and the provided shape/extents.
377+
auto boxType = fir::ClassType::get(fir::HeapType::get(baseType));
378+
mlir::Value boxAddress = fir::factory::getAndEstablishBoxStorage(
379+
*this, loc, boxType, shape, typeParams, polymorphicMold);
380+
fir::runtime::genAllocatableAllocate(*this, loc, boxAddress);
381+
mlir::Value box = create<fir::LoadOp>(loc, boxAddress);
382+
mlir::Value base =
383+
genDeclare(*this, loc, box, tmpName, /*shape=*/mlir::Value{},
384+
typeParams, fir::FortranVariableFlagsAttr{});
410385
return {base, /*isHeapAllocation=*/true};
411386
}
412387
mlir::Value allocmem;
413388
if (useStack)
414-
allocmem = createTemporary(loc, arrayType, tmpName, extents, typeParams);
389+
allocmem = createTemporary(loc, baseType, tmpName, extents, typeParams);
415390
else
416-
allocmem =
417-
createHeapTemporary(loc, arrayType, tmpName, extents, typeParams);
391+
allocmem = createHeapTemporary(loc, baseType, tmpName, extents, typeParams);
418392
mlir::Value base = genDeclare(*this, loc, allocmem, tmpName, shape,
419393
typeParams, fir::FortranVariableFlagsAttr{});
420394
return {base, !useStack};

flang/lib/Optimizer/Builder/HLFIRTools.cpp

Lines changed: 23 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,63 +1331,36 @@ bool hlfir::elementalOpMustProduceTemp(hlfir::ElementalOp elemental) {
13311331
std::pair<hlfir::Entity, mlir::Value>
13321332
hlfir::createTempFromMold(mlir::Location loc, fir::FirOpBuilder &builder,
13331333
hlfir::Entity mold) {
1334+
assert(!mold.isAssumedRank() &&
1335+
"cannot create temporary from assumed-rank mold");
13341336
llvm::SmallVector<mlir::Value> lenParams;
13351337
hlfir::genLengthParameters(loc, builder, mold, lenParams);
13361338
llvm::StringRef tmpName{".tmp"};
1337-
mlir::Value alloc;
1338-
mlir::Value isHeapAlloc;
1339-
mlir::Value shape{};
1340-
fir::FortranVariableFlagsAttr declAttrs;
13411339

1342-
if (mold.isPolymorphic()) {
1343-
// Create unallocated polymorphic temporary using the dynamic type
1344-
// of the mold. The static type of the temporary matches
1345-
// the static type of the mold, but then the dynamic type
1346-
// of the mold is applied to the temporary's descriptor.
1347-
1348-
if (mold.isArray())
1349-
hlfir::genShape(loc, builder, mold);
1350-
1351-
// Create polymorphic allocatable box on the stack.
1352-
mlir::Type boxHeapType = fir::HeapType::get(fir::unwrapRefType(
1353-
mlir::cast<fir::BaseBoxType>(mold.getType()).getEleTy()));
1354-
// The box must be initialized, because AllocatableApplyMold
1355-
// may read its contents (e.g. for checking whether it is allocated).
1356-
alloc = fir::factory::genNullBoxStorage(builder, loc,
1357-
fir::ClassType::get(boxHeapType));
1358-
// The temporary is unallocated even after AllocatableApplyMold below.
1359-
// If the temporary is used as assignment LHS it will be automatically
1360-
// allocated on the heap, as long as we use Assign family
1361-
// runtime functions. So set MustFree to true.
1362-
isHeapAlloc = builder.createBool(loc, true);
1363-
declAttrs = fir::FortranVariableFlagsAttr::get(
1364-
builder.getContext(), fir::FortranVariableFlagsEnum::allocatable);
1365-
} else if (mold.isArray()) {
1366-
mlir::Type sequenceType =
1367-
hlfir::getFortranElementOrSequenceType(mold.getType());
1340+
mlir::Value shape{};
1341+
llvm::SmallVector<mlir::Value> extents;
1342+
if (mold.isArray()) {
13681343
shape = hlfir::genShape(loc, builder, mold);
1369-
auto extents = hlfir::getIndexExtents(loc, builder, shape);
1370-
alloc = builder.createHeapTemporary(loc, sequenceType, tmpName, extents,
1371-
lenParams);
1372-
isHeapAlloc = builder.createBool(loc, true);
1373-
} else {
1374-
alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName,
1375-
/*shape=*/std::nullopt, lenParams);
1376-
isHeapAlloc = builder.createBool(loc, false);
1377-
}
1378-
auto declareOp =
1379-
builder.create<hlfir::DeclareOp>(loc, alloc, tmpName, shape, lenParams,
1380-
/*dummy_scope=*/nullptr, declAttrs);
1381-
if (mold.isPolymorphic()) {
1382-
int rank = mold.getRank();
1383-
// TODO: should probably read rank from the mold.
1384-
if (rank < 0)
1385-
TODO(loc, "create temporary for assumed rank polymorphic");
1386-
fir::runtime::genAllocatableApplyMold(builder, loc, alloc,
1387-
mold.getFirBase(), rank);
1344+
extents = hlfir::getExplicitExtentsFromShape(shape, builder);
13881345
}
13891346

1390-
return {hlfir::Entity{declareOp.getBase()}, isHeapAlloc};
1347+
bool useStack = !mold.isArray() && !mold.isPolymorphic();
1348+
auto genTempDeclareOp =
1349+
[](fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value memref,
1350+
llvm::StringRef name, mlir::Value shape,
1351+
llvm::ArrayRef<mlir::Value> typeParams,
1352+
fir::FortranVariableFlagsAttr attrs) -> mlir::Value {
1353+
auto declareOp =
1354+
builder.create<hlfir::DeclareOp>(loc, memref, name, shape, typeParams,
1355+
/*dummy_scope=*/nullptr, attrs);
1356+
return declareOp.getBase();
1357+
};
1358+
1359+
auto [base, isHeapAlloc] = builder.createAndDeclareTemp(
1360+
loc, mold.getElementOrSequenceType(), shape, extents, lenParams,
1361+
genTempDeclareOp, mold.isPolymorphic() ? mold.getBase() : nullptr,
1362+
useStack, tmpName);
1363+
return {hlfir::Entity{base}, builder.createBool(loc, isHeapAlloc)};
13911364
}
13921365

13931366
hlfir::Entity hlfir::createStackTempFromMold(mlir::Location loc,

flang/lib/Optimizer/Builder/MutableBox.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,7 @@ mlir::Value fir::factory::createUnallocatedBox(
349349
const bool isAssumedRank = baseBoxType.isAssumedRank();
350350
if (isAssumedRank)
351351
baseBoxType = baseBoxType.getBoxTypeWithNewShape(/*rank=*/0);
352-
auto baseAddrType = baseBoxType.getEleTy();
353-
if (!fir::isa_ref_type(baseAddrType))
354-
baseAddrType =
355-
builder.getRefType(baseAddrType, fir::isa_volatile_type(baseBoxType));
352+
auto baseAddrType = baseBoxType.getBaseAddressType();
356353
auto type = fir::unwrapRefType(baseAddrType);
357354
auto eleTy = fir::unwrapSequenceType(type);
358355
if (auto recTy = mlir::dyn_cast<fir::RecordType>(eleTy))
@@ -982,3 +979,20 @@ mlir::Value fir::factory::genNullBoxStorage(fir::FirOpBuilder &builder,
982979
builder.create<fir::StoreOp>(loc, nullBox, boxStorage);
983980
return boxStorage;
984981
}
982+
983+
mlir::Value fir::factory::getAndEstablishBoxStorage(
984+
fir::FirOpBuilder &builder, mlir::Location loc, fir::BaseBoxType boxTy,
985+
mlir::Value shape, llvm::ArrayRef<mlir::Value> typeParams,
986+
mlir::Value polymorphicMold) {
987+
mlir::Value boxStorage = builder.createTemporary(loc, boxTy);
988+
mlir::Value nullAddr =
989+
builder.createNullConstant(loc, boxTy.getBaseAddressType());
990+
mlir::Value box =
991+
builder.create<fir::EmboxOp>(loc, boxTy, nullAddr, shape,
992+
/*emptySlice=*/mlir::Value{},
993+
fir::factory::elideLengthsAlreadyInType(
994+
boxTy.unwrapInnerType(), typeParams),
995+
polymorphicMold);
996+
builder.create<fir::StoreOp>(loc, box, boxStorage);
997+
return boxStorage;
998+
}

flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,10 @@ mlir::Value PackArrayConversion::allocateTempBuffer(
190190
if (useStack && canAllocateTempOnStack(origBox))
191191
assert(!isHeapAllocation && "temp must have been allocated on the stack");
192192

193-
if (isHeapAllocation)
194-
if (auto baseType = mlir::dyn_cast<fir::ReferenceType>(base.getType()))
195-
if (mlir::isa<fir::BaseBoxType>(baseType.getEleTy()))
196-
return builder.create<fir::LoadOp>(loc, base);
197-
198193
mlir::Type ptrType = base.getType();
194+
if (llvm::isa<fir::BaseBoxType>(ptrType))
195+
return base;
196+
199197
mlir::Type tempBoxType = fir::BoxType::get(mlir::isa<fir::HeapType>(ptrType)
200198
? ptrType
201199
: fir::unwrapRefType(ptrType));

flang/lib/Optimizer/Dialect/FIRType.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,13 @@ mlir::Type BaseBoxType::getEleTy() const {
14071407
[](auto type) { return type.getEleTy(); });
14081408
}
14091409

1410+
mlir::Type BaseBoxType::getBaseAddressType() const {
1411+
mlir::Type eleTy = getEleTy();
1412+
if (fir::isa_ref_type(eleTy))
1413+
return eleTy;
1414+
return fir::ReferenceType::get(eleTy, isVolatile());
1415+
}
1416+
14101417
mlir::Type BaseBoxType::unwrapInnerType() const {
14111418
return fir::unwrapInnerType(getEleTy());
14121419
}
@@ -1492,6 +1499,7 @@ bool fir::BaseBoxType::isPointer() const {
14921499
return llvm::isa<fir::PointerType>(getEleTy());
14931500
}
14941501

1502+
bool BaseBoxType::isVolatile() const { return fir::isa_volatile_type(*this); }
14951503
//===----------------------------------------------------------------------===//
14961504
// FIROpsDialect
14971505
//===----------------------------------------------------------------------===//

flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1586,7 +1586,7 @@ void hlfir::AssociateOp::build(mlir::OpBuilder &builder,
15861586
mlir::Type firVarType;
15871587
auto sourceExprType = mlir::dyn_cast<hlfir::ExprType>(source.getType());
15881588
if (sourceExprType && sourceExprType.isPolymorphic())
1589-
firVarType = fir::ClassType::get(fir::HeapType::get(dataType));
1589+
firVarType = fir::ClassType::get(dataType);
15901590
else
15911591
firVarType = fir::ReferenceType::get(dataType);
15921592

0 commit comments

Comments
 (0)