1414#include " flang/Lower/StatementContext.h"
1515#include " flang/Lower/SymbolMap.h"
1616#include " flang/Optimizer/Builder/HLFIRTools.h"
17+ #include " flang/Optimizer/Builder/Runtime/ArrayConstructor.h"
1718#include " flang/Optimizer/Builder/Runtime/RTBuilder.h"
1819#include " flang/Optimizer/Builder/Todo.h"
1920#include " flang/Optimizer/HLFIR/HLFIROps.h"
20- #include " flang/Runtime/array-constructor.h"
2121
2222// Array constructors are lowered with three different strategies.
2323// All strategies are not possible with all array constructors.
@@ -287,7 +287,150 @@ class AsElementalStrategy {
287287 hlfir::ElementalOp elementalOp{};
288288};
289289
290- // TODO: add and implement RuntimeTempStrategy.
290+ // / Class that implements the "runtime temp strategy" to lower array
291+ // / constructors.
292+ class RuntimeTempStrategy {
293+ // / Name that will be given to the temporary allocation and hlfir.declare in
294+ // / the IR.
295+ static constexpr char tempName[] = " .tmp.arrayctor" ;
296+
297+ public:
298+ // / Start lowering an array constructor according to the runtime strategy.
299+ // / The temporary is only created if the extents and length parameters are
300+ // / already known. Otherwise, the handling of the allocation (and
301+ // / reallocation) is left up to the runtime.
302+ // / \p extent is the pre-computed extent of the array constructor, if it could
303+ // / be pre-computed. It is std::nullopt otherwise.
304+ // / \p lengths are the pre-computed length parameters of the array
305+ // / constructor, if they could be precomputed. \p missingLengthParameters is
306+ // / set to true if the length parameters could not be precomputed.
307+ RuntimeTempStrategy (mlir::Location loc, fir::FirOpBuilder &builder,
308+ fir::SequenceType declaredType,
309+ std::optional<mlir::Value> extent,
310+ llvm::ArrayRef<mlir::Value> lengths,
311+ bool missingLengthParameters)
312+ : arrayConstructorElementType{declaredType.getEleTy ()} {
313+ mlir::Type heapType = fir::HeapType::get (declaredType);
314+ mlir::Type boxType = fir::BoxType::get (heapType);
315+ allocatableTemp = builder.createTemporary (loc, boxType, tempName);
316+ mlir::Value initialBoxValue;
317+ if (extent && !missingLengthParameters) {
318+ llvm::SmallVector<mlir::Value, 1 > extents{*extent};
319+ mlir::Value tempStorage = builder.createHeapTemporary (
320+ loc, declaredType, tempName, extents, lengths);
321+ mlir::Value shape = builder.genShape (loc, extents);
322+ declare = builder.create <hlfir::DeclareOp>(
323+ loc, tempStorage, tempName, shape, lengths,
324+ fir::FortranVariableFlagsAttr{});
325+ initialBoxValue =
326+ builder.createBox (loc, boxType, declare->getOriginalBase (), shape,
327+ /* slice=*/ mlir::Value{}, lengths, /* tdesc=*/ {});
328+ } else {
329+ // The runtime will have to do the initial allocation.
330+ // The declare operation cannot be emitted in this case since the final
331+ // array constructor has not yet been allocated. Instead, the resulting
332+ // temporary variable will be extracted from the allocatable descriptor
333+ // after all the API calls.
334+ // Prepare the initial state of the allocatable descriptor with a
335+ // deallocated status and all the available knowledge about the extent
336+ // and length parameters.
337+ llvm::SmallVector<mlir::Value> emboxLengths (lengths.begin (),
338+ lengths.end ());
339+ if (!extent)
340+ extent = builder.createIntegerConstant (loc, builder.getIndexType (), 0 );
341+ if (missingLengthParameters) {
342+ if (declaredType.getEleTy ().isa <fir::CharacterType>())
343+ emboxLengths.push_back (builder.createIntegerConstant (
344+ loc, builder.getCharacterLengthType (), 0 ));
345+ else
346+ TODO (loc,
347+ " parametrized derived type array constructor without type-spec" );
348+ }
349+ mlir::Value nullAddr = builder.createNullConstant (loc, heapType);
350+ mlir::Value shape = builder.genShape (loc, {*extent});
351+ initialBoxValue = builder.createBox (loc, boxType, nullAddr, shape,
352+ /* slice=*/ mlir::Value{}, emboxLengths,
353+ /* tdesc=*/ {});
354+ }
355+ builder.create <fir::StoreOp>(loc, initialBoxValue, allocatableTemp);
356+ arrayConstructorVector = fir::runtime::genInitArrayConstructorVector (
357+ loc, builder, allocatableTemp,
358+ builder.createBool (loc, missingLengthParameters));
359+ }
360+
361+ bool useSimplePushRuntime (hlfir::Entity value) {
362+ return value.isScalar () &&
363+ !arrayConstructorElementType.isa <fir::CharacterType>() &&
364+ !fir::isRecordWithAllocatableMember (arrayConstructorElementType) &&
365+ !fir::isRecordWithTypeParameters (arrayConstructorElementType);
366+ }
367+
368+ // / Push a lowered ac-value into the array constructor vector using
369+ // / the runtime API.
370+ void pushValue (mlir::Location loc, fir::FirOpBuilder &builder,
371+ hlfir::Entity value) {
372+ if (useSimplePushRuntime (value)) {
373+ auto [addrExv, cleanUp] = hlfir::convertToAddress (
374+ loc, builder, value, arrayConstructorElementType);
375+ mlir::Value addr = fir::getBase (addrExv);
376+ if (addr.getType ().isa <fir::BaseBoxType>())
377+ addr = builder.create <fir::BoxAddrOp>(loc, addr);
378+ fir::runtime::genPushArrayConstructorSimpleScalar (
379+ loc, builder, arrayConstructorVector, addr);
380+ if (cleanUp)
381+ (*cleanUp)();
382+ return ;
383+ }
384+ auto [boxExv, cleanUp] =
385+ hlfir::convertToBox (loc, builder, value, arrayConstructorElementType);
386+ fir::runtime::genPushArrayConstructorValue (
387+ loc, builder, arrayConstructorVector, fir::getBase (boxExv));
388+ if (cleanUp)
389+ (*cleanUp)();
390+ }
391+
392+ // / Start a fir.do_loop with the control from an implied-do and return
393+ // / the loop induction variable that is the ac-do-variable value.
394+ mlir::Value startImpliedDo (mlir::Location loc, fir::FirOpBuilder &builder,
395+ mlir::Value lower, mlir::Value upper,
396+ mlir::Value stride) {
397+ auto loop = builder.create <fir::DoLoopOp>(loc, lower, upper, stride,
398+ /* unordered=*/ false ,
399+ /* finalCount=*/ false );
400+ builder.setInsertionPointToStart (loop.getBody ());
401+ return loop.getInductionVar ();
402+ }
403+
404+ // / Move the temporary to an hlfir.expr value (array constructors are not
405+ // / variables and cannot be further modified).
406+ hlfir::Entity finishArrayCtorLowering (mlir::Location loc,
407+ fir::FirOpBuilder &builder) {
408+ // Temp is created using createHeapTemporary, or allocated on the heap
409+ // by the runtime.
410+ mlir::Value mustFree = builder.createBool (loc, true );
411+ mlir::Value temp;
412+ if (declare)
413+ temp = declare->getBase ();
414+ else
415+ temp = hlfir::derefPointersAndAllocatables (
416+ loc, builder, hlfir::Entity{allocatableTemp});
417+ auto hlfirExpr = builder.create <hlfir::AsExprOp>(loc, temp, mustFree);
418+ return hlfir::Entity{hlfirExpr};
419+ }
420+
421+ private:
422+ // / Element type of the array constructor being built.
423+ mlir::Type arrayConstructorElementType;
424+ // / Allocatable descriptor for the storage of the array constructor being
425+ // / built.
426+ mlir::Value allocatableTemp;
427+ // / Structure that allows the runtime API to maintain the status of
428+ // / of the array constructor being built between two API calls.
429+ mlir::Value arrayConstructorVector;
430+ // / DeclareOp for the array constructor storage, if it was possible to
431+ // / allocate it before any API calls.
432+ std::optional<hlfir::DeclareOp> declare;
433+ };
291434
292435// / Wrapper class that dispatch to the selected array constructor lowering
293436// / strategy and does nothing else.
@@ -322,7 +465,7 @@ class ArrayCtorLoweringStrategy {
322465
323466private:
324467 std::variant<InlinedTempStrategy, LooplessInlinedTempStrategy,
325- AsElementalStrategy>
468+ AsElementalStrategy, RuntimeTempStrategy >
326469 implVariant;
327470};
328471} // namespace
@@ -382,9 +525,8 @@ struct LengthAndTypeCollector<Character<Kind>> {
382525// / Does the array constructor have length parameters that
383526// / LengthAndTypeCollector::collect could not lower because this requires
384527// / lowering an ac-value and must be delayed?
385- static bool
386- failedToGatherLengthParameters (mlir::Type elementType,
387- llvm::ArrayRef<mlir::Value> lengths) {
528+ static bool missingLengthParameters (mlir::Type elementType,
529+ llvm::ArrayRef<mlir::Value> lengths) {
388530 return (elementType.isa <fir::CharacterType>() ||
389531 fir::isRecordWithTypeParameters (elementType)) &&
390532 lengths.empty ();
@@ -505,8 +647,8 @@ static ArrayCtorLoweringStrategy selectArrayCtorLoweringStrategy(
505647 // Try to gather the array constructor extent.
506648 mlir::Value extent;
507649 fir::SequenceType::Extent typeExtent = fir::SequenceType::getUnknownExtent ();
508- auto shapeExpr =
509- Fortran::evaluate::GetShape ( converter.getFoldingContext (), arrayCtorExpr);
650+ auto shapeExpr = Fortran::evaluate::GetContextFreeShape (
651+ converter.getFoldingContext (), arrayCtorExpr);
510652 if (shapeExpr && shapeExpr->size () == 1 && (*shapeExpr)[0 ]) {
511653 const Fortran::evaluate::ExtentExpr &extentExpr = *(*shapeExpr)[0 ];
512654 if (auto constantExtent = Fortran::evaluate::ToInt64 (extentExpr)) {
@@ -531,15 +673,17 @@ static ArrayCtorLoweringStrategy selectArrayCtorLoweringStrategy(
531673 // Run an analysis of the array constructor ac-value.
532674 ArrayCtorAnalysis analysis (converter.getFoldingContext (), arrayCtorExpr);
533675 bool needToEvaluateOneExprToGetLengthParameters =
534- failedToGatherLengthParameters (elementType, lengths);
676+ missingLengthParameters (elementType, lengths);
677+ auto declaredType = fir::SequenceType::get ({typeExtent}, elementType);
535678
536679 // Based on what was gathered and the result of the analysis, select and
537680 // instantiate the right lowering strategy for the array constructor.
538681 if (!extent || needToEvaluateOneExprToGetLengthParameters ||
539682 analysis.anyArrayExpr )
540- TODO (loc, " Lowering of array constructor requiring the runtime" );
541-
542- auto declaredType = fir::SequenceType::get ({typeExtent}, elementType);
683+ return RuntimeTempStrategy (
684+ loc, builder, declaredType,
685+ extent ? std::optional<mlir::Value>(extent) : std::nullopt , lengths,
686+ needToEvaluateOneExprToGetLengthParameters);
543687 // Note: array constructors containing impure ac-value expr are currently not
544688 // rewritten to hlfir.elemental because impure expressions should be evaluated
545689 // in order, and hlfir.elemental currently misses a way to indicate that.
@@ -562,8 +706,6 @@ static void genAcValue(mlir::Location loc,
562706 Fortran::lower::SymMap &symMap,
563707 Fortran::lower::StatementContext &stmtCtx,
564708 ArrayCtorLoweringStrategy &arrayBuilder) {
565- if (expr.Rank () != 0 )
566- TODO (loc, " array constructor with array ac-value in HLFIR" );
567709 // TODO: get rid of the toEvExpr indirection.
568710 fir::FirOpBuilder &builder = converter.getFirOpBuilder ();
569711 hlfir::Entity value = Fortran::lower::convertExprToHLFIR (
0 commit comments