@@ -4353,30 +4353,12 @@ class FirConverter : public Fortran::lower::AbstractConverter {
43534353 stmtCtx);
43544354 }
43554355
4356- void genForallPointerAssignment (
4357- mlir::Location loc, const Fortran::evaluate::Assignment &assign,
4358- const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
4359- std::optional<Fortran::evaluate::DynamicType> lhsType =
4360- assign.lhs .GetType ();
4361- // Polymorphic pointer assignment is delegated to the runtime, and
4362- // PointerAssociateLowerBounds needs the lower bounds as arguments, so they
4363- // must be preserved.
4364- if (lhsType && lhsType->IsPolymorphic ())
4365- TODO (loc, " polymorphic pointer assignment in FORALL" );
4366- // Nullification is special, there is no RHS that can be prepared,
4367- // need to encode it in HLFIR.
4368- if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4369- assign.rhs ))
4370- TODO (loc, " NULL pointer assignment in FORALL" );
4371- // Lower bounds could be "applied" when preparing RHS, but in order
4372- // to deal with the polymorphic case and to reuse existing pointer
4373- // assignment helpers in HLFIR codegen, it is better to keep them
4374- // separate.
4375- if (!lbExprs.empty ())
4376- TODO (loc, " Pointer assignment with new lower bounds inside FORALL" );
4377- // Otherwise, this is a "dumb" pointer assignment that can be represented
4378- // with hlfir.region_assign with descriptor address/value and later
4379- // implemented with a store.
4356+ void genForallPointerAssignment (mlir::Location loc,
4357+ const Fortran::evaluate::Assignment &assign) {
4358+ // Lower pointer assignment inside forall with hlfir.region_assign with
4359+ // descriptor address/value and later implemented with a store.
4360+ // The RHS is fully prepared in lowering, so that all that is left
4361+ // in hlfir.region_assign code generation is the store.
43804362 auto regionAssignOp = builder->create <hlfir::RegionAssignOp>(loc);
43814363
43824364 // Lower LHS in its own region.
@@ -4400,22 +4382,73 @@ class FirConverter : public Fortran::lower::AbstractConverter {
44004382 builder->setInsertionPointAfter (regionAssignOp);
44014383 }
44024384
4385+ mlir::Value lowerToIndexValue (mlir::Location loc,
4386+ const Fortran::evaluate::ExtentExpr &expr,
4387+ Fortran::lower::StatementContext &stmtCtx) {
4388+ mlir::Value val = fir::getBase (genExprValue (toEvExpr (expr), stmtCtx));
4389+ return builder->createConvert (loc, builder->getIndexType (), val);
4390+ }
4391+
44034392 mlir::Value
44044393 genForallPointerAssignmentRhs (mlir::Location loc, mlir::Value lhs,
44054394 const Fortran::evaluate::Assignment &assign,
44064395 Fortran::lower::StatementContext &rhsContext) {
4407- if (Fortran::evaluate::IsProcedureDesignator (assign.rhs ))
4396+ if (Fortran::evaluate::IsProcedureDesignator (assign.lhs )) {
4397+ if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4398+ assign.rhs ))
4399+ return fir::factory::createNullBoxProc (
4400+ *builder, loc, fir::unwrapRefType (lhs.getType ()));
44084401 return fir::getBase (Fortran::lower::convertExprToAddress (
44094402 loc, *this , assign.rhs , localSymbols, rhsContext));
4403+ }
44104404 // Data target.
4405+ auto lhsBoxType =
4406+ llvm::cast<fir::BaseBoxType>(fir::unwrapRefType (lhs.getType ()));
4407+ // For NULL, create disassociated descriptor whose dynamic type is
4408+ // the static type of the LHS.
4409+ if (Fortran::evaluate::UnwrapExpr<Fortran::evaluate::NullPointer>(
4410+ assign.rhs ))
4411+ return fir::factory::createUnallocatedBox (*builder, loc, lhsBoxType,
4412+ std::nullopt );
44114413 hlfir::Entity rhs = Fortran::lower::convertExprToHLFIR (
44124414 loc, *this , assign.rhs , localSymbols, rhsContext);
44134415 // Create pointer descriptor value from the RHS.
44144416 if (rhs.isMutableBox ())
44154417 rhs = hlfir::Entity{builder->create <fir::LoadOp>(loc, rhs)};
4416- auto lhsBoxType =
4417- llvm::cast<fir::BaseBoxType>(fir::unwrapRefType (lhs.getType ()));
4418- return hlfir::genVariableBox (loc, *builder, rhs, lhsBoxType);
4418+ mlir::Value rhsBox = hlfir::genVariableBox (
4419+ loc, *builder, rhs, lhsBoxType.getBoxTypeWithNewShape (rhs.getRank ()));
4420+ // Apply lower bounds or reshaping if any.
4421+ if (const auto *lbExprs =
4422+ std::get_if<Fortran::evaluate::Assignment::BoundsSpec>(&assign.u );
4423+ lbExprs && !lbExprs->empty ()) {
4424+ // Override target lower bounds with the LHS bounds spec.
4425+ llvm::SmallVector<mlir::Value> lbounds;
4426+ for (const Fortran::evaluate::ExtentExpr &lbExpr : *lbExprs)
4427+ lbounds.push_back (lowerToIndexValue (loc, lbExpr, rhsContext));
4428+ mlir::Value shift = builder->genShift (loc, lbounds);
4429+ rhsBox = builder->create <fir::ReboxOp>(loc, lhsBoxType, rhsBox, shift,
4430+ /* slice=*/ mlir::Value{});
4431+ } else if (const auto *boundExprs =
4432+ std::get_if<Fortran::evaluate::Assignment::BoundsRemapping>(
4433+ &assign.u );
4434+ boundExprs && !boundExprs->empty ()) {
4435+ // Reshape the target according to the LHS bounds remapping.
4436+ llvm::SmallVector<mlir::Value> lbounds;
4437+ llvm::SmallVector<mlir::Value> extents;
4438+ mlir::Type indexTy = builder->getIndexType ();
4439+ mlir::Value zero = builder->createIntegerConstant (loc, indexTy, 0 );
4440+ mlir::Value one = builder->createIntegerConstant (loc, indexTy, 1 );
4441+ for (const auto &[lbExpr, ubExpr] : *boundExprs) {
4442+ lbounds.push_back (lowerToIndexValue (loc, lbExpr, rhsContext));
4443+ mlir::Value ub = lowerToIndexValue (loc, ubExpr, rhsContext);
4444+ extents.push_back (fir::factory::computeExtent (
4445+ *builder, loc, lbounds.back (), ub, zero, one));
4446+ }
4447+ mlir::Value shape = builder->genShape (loc, lbounds, extents);
4448+ rhsBox = builder->create <fir::ReboxOp>(loc, lhsBoxType, rhsBox, shape,
4449+ /* slice=*/ mlir::Value{});
4450+ }
4451+ return rhsBox;
44194452 }
44204453
44214454 // Create the 2 x newRank array with the bounds to be passed to the runtime as
@@ -4856,17 +4889,16 @@ class FirConverter : public Fortran::lower::AbstractConverter {
48564889 },
48574890 [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) {
48584891 if (isInsideHlfirForallOrWhere ())
4859- genForallPointerAssignment (loc, assign, lbExprs );
4892+ genForallPointerAssignment (loc, assign);
48604893 else
48614894 genPointerAssignment (loc, assign, lbExprs);
48624895 },
48634896 [&](const Fortran::evaluate::Assignment::BoundsRemapping
48644897 &boundExprs) {
48654898 if (isInsideHlfirForallOrWhere ())
4866- TODO (
4867- loc,
4868- " pointer assignment with bounds remapping inside FORALL" );
4869- genPointerAssignment (loc, assign, boundExprs);
4899+ genForallPointerAssignment (loc, assign);
4900+ else
4901+ genPointerAssignment (loc, assign, boundExprs);
48704902 },
48714903 },
48724904 assign.u );
0 commit comments