@@ -183,6 +183,29 @@ static mlir::Value genRuntimeAllocate(fir::FirOpBuilder &builder,
183
183
return builder.create <fir::CallOp>(loc, callee, operands).getResult (0 );
184
184
}
185
185
186
+ // / Generate a sequence of runtime calls to allocate memory and assign with the
187
+ // / \p source.
188
+ static mlir::Value genRuntimeAllocateSource (fir::FirOpBuilder &builder,
189
+ mlir::Location loc,
190
+ const fir::MutableBoxValue &box,
191
+ fir::ExtendedValue source,
192
+ ErrorManager &errorManager) {
193
+ mlir::func::FuncOp callee =
194
+ box.isPointer ()
195
+ ? fir::runtime::getRuntimeFunc<mkRTKey (PointerAllocateSource)>(
196
+ loc, builder)
197
+ : fir::runtime::getRuntimeFunc<mkRTKey (AllocatableAllocateSource)>(
198
+ loc, builder);
199
+ llvm::SmallVector<mlir::Value> args{
200
+ box.getAddr (), fir::getBase (source),
201
+ errorManager.hasStat , errorManager.errMsgAddr ,
202
+ errorManager.sourceFile , errorManager.sourceLine };
203
+ llvm::SmallVector<mlir::Value> operands;
204
+ for (auto [fst, snd] : llvm::zip (args, callee.getFunctionType ().getInputs ()))
205
+ operands.emplace_back (builder.createConvert (loc, snd, fst));
206
+ return builder.create <fir::CallOp>(loc, callee, operands).getResult (0 );
207
+ }
208
+
186
209
// / Generate a runtime call to deallocate memory.
187
210
static mlir::Value genRuntimeDeallocate (fir::FirOpBuilder &builder,
188
211
mlir::Location loc,
@@ -255,8 +278,11 @@ class AllocateStmtHelper {
255
278
visitAllocateOptions ();
256
279
lowerAllocateLengthParameters ();
257
280
errorManager.init (converter, loc, statExpr, errMsgExpr);
258
- if (sourceExpr || moldExpr)
259
- TODO (loc, " lower MOLD/SOURCE expr in allocate" );
281
+ Fortran::lower::StatementContext stmtCtx;
282
+ if (sourceExpr)
283
+ sourceExv = converter.genExprBox (loc, *sourceExpr, stmtCtx);
284
+ if (moldExpr)
285
+ TODO (loc, " lower MOLD expr in allocate" );
260
286
mlir::OpBuilder::InsertPoint insertPt = builder.saveInsertionPoint ();
261
287
for (const auto &allocation :
262
288
std::get<std::list<Fortran::parser::Allocation>>(stmt.t ))
@@ -393,45 +419,13 @@ class AllocateStmtHelper {
393
419
}
394
420
// Generate a sequence of runtime calls.
395
421
errorManager.genStatCheck (builder, loc);
396
- if (box.isPointer ()) {
397
- // For pointers, the descriptor may still be uninitialized (see Fortran
398
- // 2018 19.5.2.2). The allocation runtime needs to be given a descriptor
399
- // with initialized rank, types and attributes. Initialize the descriptor
400
- // here to ensure these constraints are fulfilled.
401
- mlir::Value nullPointer = fir::factory::createUnallocatedBox (
402
- builder, loc, box.getBoxTy (), box.nonDeferredLenParams ());
403
- builder.create <fir::StoreOp>(loc, nullPointer, box.getAddr ());
404
- } else {
405
- assert (box.isAllocatable () && " must be an allocatable" );
406
- // For allocatables, sync the MutableBoxValue and descriptor before the
407
- // calls in case it is tracked locally by a set of variables.
408
- fir::factory::getMutableIRBox (builder, loc, box);
409
- }
422
+ genAllocateObjectInit (box);
410
423
if (alloc.hasCoarraySpec ())
411
424
TODO (loc, " coarray allocation" );
412
425
if (alloc.type .IsPolymorphic ())
413
426
genSetType (alloc, box, loc);
414
427
genSetDeferredLengthParameters (alloc, box);
415
- // Set bounds for arrays
416
- mlir::Type idxTy = builder.getIndexType ();
417
- mlir::Type i32Ty = builder.getIntegerType (32 );
418
- Fortran::lower::StatementContext stmtCtx;
419
- for (const auto &iter : llvm::enumerate (alloc.getShapeSpecs ())) {
420
- mlir::Value lb;
421
- const auto &bounds = iter.value ().t ;
422
- if (const std::optional<Fortran::parser::BoundExpr> &lbExpr =
423
- std::get<0 >(bounds))
424
- lb = fir::getBase (converter.genExprValue (
425
- loc, Fortran::semantics::GetExpr (*lbExpr), stmtCtx));
426
- else
427
- lb = builder.createIntegerConstant (loc, idxTy, 1 );
428
- mlir::Value ub = fir::getBase (converter.genExprValue (
429
- loc, Fortran::semantics::GetExpr (std::get<1 >(bounds)), stmtCtx));
430
- mlir::Value dimIndex =
431
- builder.createIntegerConstant (loc, i32Ty, iter.index ());
432
- // Runtime call
433
- genRuntimeSetBounds (builder, loc, box, dimIndex, lb, ub);
434
- }
428
+ genAllocateObjectBounds (alloc, box);
435
429
mlir::Value stat = genRuntimeAllocate (builder, loc, box, errorManager);
436
430
fir::factory::syncMutableBoxFromIRBox (builder, loc, box);
437
431
errorManager.assignStat (builder, loc, stat);
@@ -478,8 +472,87 @@ class AllocateStmtHelper {
478
472
TODO (loc, " derived type length parameters in allocate" );
479
473
}
480
474
481
- void genSourceAllocation (const Allocation &, const fir::MutableBoxValue &) {
482
- TODO (loc, " SOURCE allocation" );
475
+ void genAllocateObjectInit (const fir::MutableBoxValue &box) {
476
+ if (box.isPointer ()) {
477
+ // For pointers, the descriptor may still be uninitialized (see Fortran
478
+ // 2018 19.5.2.2). The allocation runtime needs to be given a descriptor
479
+ // with initialized rank, types and attributes. Initialize the descriptor
480
+ // here to ensure these constraints are fulfilled.
481
+ mlir::Value nullPointer = fir::factory::createUnallocatedBox (
482
+ builder, loc, box.getBoxTy (), box.nonDeferredLenParams ());
483
+ builder.create <fir::StoreOp>(loc, nullPointer, box.getAddr ());
484
+ } else {
485
+ assert (box.isAllocatable () && " must be an allocatable" );
486
+ // For allocatables, sync the MutableBoxValue and descriptor before the
487
+ // calls in case it is tracked locally by a set of variables.
488
+ fir::factory::getMutableIRBox (builder, loc, box);
489
+ }
490
+ }
491
+
492
+ void genAllocateObjectBounds (const Allocation &alloc,
493
+ const fir::MutableBoxValue &box) {
494
+ // Set bounds for arrays
495
+ mlir::Type idxTy = builder.getIndexType ();
496
+ mlir::Type i32Ty = builder.getIntegerType (32 );
497
+ Fortran::lower::StatementContext stmtCtx;
498
+ for (const auto &iter : llvm::enumerate (alloc.getShapeSpecs ())) {
499
+ mlir::Value lb;
500
+ const auto &bounds = iter.value ().t ;
501
+ if (const std::optional<Fortran::parser::BoundExpr> &lbExpr =
502
+ std::get<0 >(bounds))
503
+ lb = fir::getBase (converter.genExprValue (
504
+ loc, Fortran::semantics::GetExpr (*lbExpr), stmtCtx));
505
+ else
506
+ lb = builder.createIntegerConstant (loc, idxTy, 1 );
507
+ mlir::Value ub = fir::getBase (converter.genExprValue (
508
+ loc, Fortran::semantics::GetExpr (std::get<1 >(bounds)), stmtCtx));
509
+ mlir::Value dimIndex =
510
+ builder.createIntegerConstant (loc, i32Ty, iter.index ());
511
+ // Runtime call
512
+ genRuntimeSetBounds (builder, loc, box, dimIndex, lb, ub);
513
+ }
514
+ if (sourceExpr && sourceExpr->Rank () > 0 &&
515
+ alloc.getShapeSpecs ().size () == 0 ) {
516
+ // If the alloc object does not have shape list, get the bounds from the
517
+ // source expression.
518
+ mlir::Value one = builder.createIntegerConstant (loc, idxTy, 1 );
519
+ const auto *sourceBox = sourceExv.getBoxOf <fir::BoxValue>();
520
+ assert (sourceBox && " source expression should be lowered to one box" );
521
+ for (int i = 0 ; i < sourceExpr->Rank (); ++i) {
522
+ auto dimVal = builder.createIntegerConstant (loc, idxTy, i);
523
+ auto dimInfo = builder.create <fir::BoxDimsOp>(
524
+ loc, idxTy, idxTy, idxTy, sourceBox->getAddr (), dimVal);
525
+ mlir::Value lb =
526
+ fir::factory::readLowerBound (builder, loc, sourceExv, i, one);
527
+ mlir::Value extent = dimInfo.getResult (1 );
528
+ mlir::Value ub = builder.create <mlir::arith::SubIOp>(
529
+ loc, builder.create <mlir::arith::AddIOp>(loc, extent, lb), one);
530
+ mlir::Value dimIndex = builder.createIntegerConstant (loc, i32Ty, i);
531
+ genRuntimeSetBounds (builder, loc, box, dimIndex, lb, ub);
532
+ }
533
+ }
534
+ }
535
+
536
+ void genSourceAllocation (const Allocation &alloc,
537
+ const fir::MutableBoxValue &box) {
538
+ // Generate a sequence of runtime calls.
539
+ errorManager.genStatCheck (builder, loc);
540
+ genAllocateObjectInit (box);
541
+ if (alloc.hasCoarraySpec ())
542
+ TODO (loc, " coarray allocation" );
543
+ if (alloc.type .IsPolymorphic ())
544
+ TODO (loc, " polymorphic allocation with SOURCE specifier" );
545
+ // Set length of the allocate object if it has. Otherwise, get the length
546
+ // from source for the deferred length parameter.
547
+ if (lenParams.empty () && box.isCharacter () &&
548
+ !box.hasNonDeferredLenParams ())
549
+ lenParams.push_back (fir::factory::readCharLen (builder, loc, sourceExv));
550
+ genSetDeferredLengthParameters (alloc, box);
551
+ genAllocateObjectBounds (alloc, box);
552
+ mlir::Value stat =
553
+ genRuntimeAllocateSource (builder, loc, box, sourceExv, errorManager);
554
+ fir::factory::syncMutableBoxFromIRBox (builder, loc, box);
555
+ errorManager.assignStat (builder, loc, stat);
483
556
}
484
557
void genMoldAllocation (const Allocation &, const fir::MutableBoxValue &) {
485
558
TODO (loc, " MOLD allocation" );
@@ -576,6 +649,8 @@ class AllocateStmtHelper {
576
649
// value of the length parameters that were specified inside.
577
650
llvm::SmallVector<mlir::Value> lenParams;
578
651
ErrorManager errorManager;
652
+ // 9.7.1.2(7) The source-expr is evaluated exactly once for each AllocateStmt.
653
+ fir::ExtendedValue sourceExv;
579
654
580
655
mlir::Location loc;
581
656
};
0 commit comments