Skip to content

Commit bcee18a

Browse files
authored
[flang] Handle SEQUENCE derived types for array repacking. (#148777)
It is possible that a non-polymorphic dummy argument has a dynamic type that does not match its static type in a valid Fortran program, e.g. when the actual and the dummy arguments have different compatible derived SEQUENCE types: module mod type t sequence integer x end type contains subroutine test(x) type t sequence integer x end type type(t) :: x(:) end subroutine end module 'test' may be called with an actual argument of type 'mod::t', which is the dynamic type of 'x' on entry to 'test'. If we create the repacking temporary based on the static type of 'x' ('test::t'), then the runtime will report the types mismatch as an error. Thus, we have to create the temporary using the dynamic type of 'x'. The fact that the dummy's type has SEQUENCE or BIND attribute is not easily computable at this stage, so we use the dynamic type for all derived type cases. As long as this is done only when the repacking actually happens, the overhead should not be noticeable.
1 parent c4d4e76 commit bcee18a

File tree

2 files changed

+98
-86
lines changed

2 files changed

+98
-86
lines changed

flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,14 @@ class PackArrayConversion : public mlir::OpRewritePattern<fir::PackArrayOp> {
6363
static constexpr llvm::StringRef bufferName = ".repacked";
6464

6565
// Return value of fir::BaseBoxType that represents a temporary
66-
// array created for the original box with given extents and
67-
// type parameters. The new box has the default lower bounds.
68-
// If useStack is true, then the temporary will be allocated
66+
// array created for the original box with given lbounds/extents and
67+
// type parameters. The new box has the same shape as the original
68+
// array. If useStack is true, then the temporary will be allocated
6969
// in stack memory (when possible).
7070
static mlir::Value allocateTempBuffer(fir::FirOpBuilder &builder,
7171
mlir::Location loc, bool useStack,
7272
mlir::Value origBox,
73+
llvm::ArrayRef<mlir::Value> lbounds,
7374
llvm::ArrayRef<mlir::Value> extents,
7475
llvm::ArrayRef<mlir::Value> typeParams);
7576

@@ -99,7 +100,9 @@ class UnpackArrayConversion
99100
// the presence of the stack attribute does not automatically
100101
// mean that the allocation is actually done in stack memory.
101102
// For example, we always do the heap allocation for polymorphic
102-
// types using Fortran runtime.
103+
// types using Fortran runtime. Currently, we allocate all
104+
// repack temporaries of derived types as polymorphic,
105+
// so that we can preserve the dynamic type of the original.
103106
// Adding the polymorpic mold to fir.alloca and then using
104107
// Fortran runtime to compute the allocation size could probably
105108
// resolve this limitation.
@@ -170,7 +173,8 @@ PackArrayConversion::matchAndRewrite(fir::PackArrayOp op,
170173

171174
mlir::Value PackArrayConversion::allocateTempBuffer(
172175
fir::FirOpBuilder &builder, mlir::Location loc, bool useStack,
173-
mlir::Value origBox, llvm::ArrayRef<mlir::Value> extents,
176+
mlir::Value origBox, llvm::ArrayRef<mlir::Value> lbounds,
177+
llvm::ArrayRef<mlir::Value> extents,
174178
llvm::ArrayRef<mlir::Value> typeParams) {
175179
auto tempType = mlir::cast<fir::SequenceType>(
176180
fir::extractSequenceType(origBox.getType()));
@@ -191,16 +195,35 @@ mlir::Value PackArrayConversion::allocateTempBuffer(
191195
assert(!isHeapAllocation && "temp must have been allocated on the stack");
192196

193197
mlir::Type ptrType = base.getType();
194-
if (llvm::isa<fir::BaseBoxType>(ptrType))
195-
return base;
198+
if (auto tempBoxType = mlir::dyn_cast<fir::BaseBoxType>(ptrType)) {
199+
// We need to reset the CFI_attribute_allocatable before
200+
// returning the temporary box to avoid any mishandling
201+
// of the temporary box in Fortran runtime.
202+
base = builder.create<fir::BoxAddrOp>(loc, fir::boxMemRefType(tempBoxType),
203+
base);
204+
ptrType = base.getType();
205+
}
196206

197-
mlir::Type tempBoxType = fir::BoxType::get(mlir::isa<fir::HeapType>(ptrType)
198-
? ptrType
199-
: fir::unwrapRefType(ptrType));
207+
// Create the temporary using dynamic type of the original,
208+
// if it is polymorphic, or it has a derived type with SEQUENCE
209+
// or BIND attribute (such dummy arguments may have their dynamic
210+
// type not exactly matching their static type).
211+
// Note that for the latter case, the allocation can still be done
212+
// without the mold, because the dynamic and static types
213+
// must be storage compatible.
214+
bool useDynamicType = fir::isBoxedRecordType(origBox.getType()) ||
215+
fir::isPolymorphicType(origBox.getType());
216+
mlir::Type tempBoxType =
217+
fir::wrapInClassOrBoxType(fir::unwrapRefType(ptrType),
218+
/*isPolymorphic=*/useDynamicType);
219+
// Use the shape with proper lower bounds for the final box.
220+
shape = builder.genShape(loc, lbounds, extents);
200221
mlir::Value newBox =
201222
builder.createBox(loc, tempBoxType, base, shape, /*slice=*/nullptr,
202-
typeParams, /*tdesc=*/nullptr);
203-
return newBox;
223+
typeParams, useDynamicType ? origBox : nullptr);
224+
// The new box might be !fir.class, while the original might be
225+
// !fir.box - we have to add a conversion.
226+
return builder.createConvert(loc, origBox.getType(), newBox);
204227
}
205228

206229
mlir::FailureOr<mlir::Value>
@@ -280,16 +303,11 @@ PackArrayConversion::genRepackedBox(fir::FirOpBuilder &builder,
280303
<< op.getOperation() << '\n';
281304
}
282305

283-
mlir::Value tempBox =
284-
allocateTempBuffer(builder, loc, op.getStack(), box, extents, typeParams);
306+
mlir::Value tempBox = allocateTempBuffer(builder, loc, op.getStack(), box,
307+
lbounds, extents, typeParams);
285308
if (!op.getNoCopy())
286309
fir::runtime::genShallowCopy(builder, loc, tempBox, box,
287310
/*resultIsAllocated=*/true);
288-
289-
// Set lower bounds after the original box.
290-
mlir::Value shift = builder.genShift(loc, lbounds);
291-
tempBox = builder.create<fir::ReboxOp>(loc, boxType, tempBox, shift,
292-
/*slice=*/nullptr);
293311
builder.create<fir::ResultOp>(loc, tempBox);
294312

295313
return ifOp.getResult(0);

0 commit comments

Comments
 (0)