diff --git a/flang/include/flang/Lower/CallInterface.h b/flang/include/flang/Lower/CallInterface.h --- a/flang/include/flang/Lower/CallInterface.h +++ b/flang/include/flang/Lower/CallInterface.h @@ -29,6 +29,7 @@ #include "flang/Common/reference.h" #include "flang/Evaluate/characteristics.h" +#include "flang/Semantics/symbol.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/IR/BuiltinOps.h" #include @@ -388,6 +389,9 @@ mlir::FunctionType translateSignature(const Fortran::evaluate::ProcedureDesignator &, Fortran::lower::AbstractConverter &); +mlir::FunctionType +translateSignature(const semantics::Symbol &procedure, + Fortran::lower::AbstractConverter &converter); /// Declare or find the mlir::func::FuncOp named \p name. If the /// mlir::func::FuncOp does not exist yet, declare it with the signature diff --git a/flang/include/flang/Lower/ConvertExpr.h b/flang/include/flang/Lower/ConvertExpr.h --- a/flang/include/flang/Lower/ConvertExpr.h +++ b/flang/include/flang/Lower/ConvertExpr.h @@ -95,6 +95,10 @@ const SomeExpr &expr, SymMap &symMap, StatementContext &stmtCtx); +fir::ProcBoxValue createProcBoxValue(mlir::Location loc, + AbstractConverter &converter, + const SomeExpr &expr, SymMap &symMap); + /// Lower an array assignment expression. /// /// 1. Evaluate the lhs to determine the rank and how to form the ArrayLoad diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -2085,8 +2085,6 @@ // [3] Pointer assignment with possibly empty bounds-spec. R1035: a // bounds-spec is a lower bound value. [&](const Fortran::evaluate::Assignment::BoundsSpec &lbExprs) { - if (Fortran::evaluate::IsProcedure(assign.rhs)) - TODO(loc, "procedure pointer assignment"); std::optional lhsType = assign.lhs.GetType(); std::optional rhsType = @@ -2106,9 +2104,17 @@ genArrayAssignment(assign, stmtCtx, lbounds); return; } - fir::MutableBoxValue lhs = genExprMutableBox(loc, assign.lhs); - Fortran::lower::associateMutableBox(*this, loc, lhs, assign.rhs, - lbounds, stmtCtx); + if (Fortran::evaluate::IsProcedure(assign.rhs)) { + fir::ProcBoxValue lhs = Fortran::lower::createProcBoxValue(loc, *this, assign.lhs, localSymbols); + auto rhs = Fortran::lower::createProcBoxValue(loc, *this, assign.rhs, localSymbols); + auto& builder = getFirOpBuilder(); + + builder.create(loc, getBase(rhs), lhs.getAddr()); + } else { + fir::MutableBoxValue lhs = genExprMutableBox(loc, assign.lhs); + Fortran::lower::associateMutableBox(*this, loc, lhs, assign.rhs, + lbounds, stmtCtx); + } }, // [4] Pointer assignment with bounds-remapping. R1036: a diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp --- a/flang/lib/Lower/CallInterface.cpp +++ b/flang/lib/Lower/CallInterface.cpp @@ -1154,18 +1154,33 @@ const Fortran::evaluate::characteristics::Procedure &proc; }; +template +mlir::FunctionType +translateSignatureImpl(const T &proc, + Fortran::lower::AbstractConverter &converter, + bool forceImplicit = false) { + using Fortran::evaluate::characteristics::Procedure; + std::optional characteristics = + Procedure::Characterize(proc, converter.getFoldingContext()); + return SignatureBuilder{characteristics.value(), converter, forceImplicit} + .getFunctionType(); +} + +mlir::FunctionType Fortran::lower::translateSignature( + const semantics::Symbol &proc, + Fortran::lower::AbstractConverter &converter) { + assert(IsProcedure(proc)); + return translateSignatureImpl(proc, converter); +} + mlir::FunctionType Fortran::lower::translateSignature( const Fortran::evaluate::ProcedureDesignator &proc, Fortran::lower::AbstractConverter &converter) { - std::optional characteristics = - Fortran::evaluate::characteristics::Procedure::Characterize( - proc, converter.getFoldingContext()); // Most unrestricted intrinsic characteristic has the Elemental attribute // which triggers CanBeCalledViaImplicitInterface to return false. However, // using implicit interface rules is just fine here. bool forceImplicit = proc.GetSpecificIntrinsic(); - return SignatureBuilder{characteristics.value(), converter, forceImplicit} - .getFunctionType(); + return translateSignatureImpl(proc, converter, forceImplicit); } mlir::func::FuncOp Fortran::lower::getOrDeclareFunction( diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -13,8 +13,10 @@ #include "flang/Lower/ConvertExpr.h" #include "flang/Common/default-kinds.h" #include "flang/Common/unwrap.h" +#include "flang/Evaluate/call.h" #include "flang/Evaluate/fold.h" #include "flang/Evaluate/real.h" +#include "flang/Evaluate/tools.h" #include "flang/Evaluate/traverse.h" #include "flang/Lower/Allocatable.h" #include "flang/Lower/Bridge.h" @@ -31,6 +33,7 @@ #include "flang/Lower/Runtime.h" #include "flang/Lower/Support/Utils.h" #include "flang/Lower/Todo.h" +#include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Builder/Character.h" #include "flang/Optimizer/Builder/Complex.h" #include "flang/Optimizer/Builder/Factory.h" @@ -39,6 +42,7 @@ #include "flang/Optimizer/Builder/Runtime/Ragged.h" #include "flang/Optimizer/Dialect/FIRAttr.h" #include "flang/Optimizer/Dialect/FIRDialect.h" +#include "flang/Optimizer/Dialect/FIROps.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Optimizer/Support/FatalError.h" #include "flang/Semantics/expression.h" @@ -584,6 +588,25 @@ return genval(expr); } + fir::ProcBoxValue genProcBoxValue(const Fortran::lower::SomeExpr &expr) { + const auto &proc = DEREF( + Fortran::evaluate::UnwrapExpr( + expr)); + if (const auto *component = proc.GetComponent()) { + return DEREF(genComponent(*component).getBoxOf()); + } + const auto symbol = symMap.lookupSymbol(proc.GetSymbol()); + std::string name = converter.mangleName(*proc.GetSymbol()); + mlir::func::FuncOp func = + Fortran::lower::getOrDeclareFunction(name, proc, converter); + const auto funcTy = func.getFunctionType(); + const mlir::Value address = builder.create( + getLoc(), funcTy, builder.getSymbolRefAttr(name)); + const auto emboxed = builder.create( + getLoc(), builder.getBoxProcType(funcTy), address); + return fir::ProcBoxValue{emboxed->getResult(0), emboxed->getResult(1)}; + } + /// Lower an expression that is a pointer or an allocatable to a /// MutableBoxValue. fir::MutableBoxValue @@ -7433,6 +7456,14 @@ stmtCtx, expr); } +fir::ProcBoxValue Fortran::lower::createProcBoxValue( + mlir::Location loc, Fortran::lower::AbstractConverter &converter, + const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) { + Fortran::lower::StatementContext dummyStmtCtx; + return ScalarExprLowering{loc, converter, symMap, dummyStmtCtx} + .genProcBoxValue(expr); +} + fir::MutableBoxValue Fortran::lower::createMutableBox( mlir::Location loc, Fortran::lower::AbstractConverter &converter, const Fortran::lower::SomeExpr &expr, Fortran::lower::SymMap &symMap) { diff --git a/flang/lib/Lower/ConvertType.cpp b/flang/lib/Lower/ConvertType.cpp --- a/flang/lib/Lower/ConvertType.cpp +++ b/flang/lib/Lower/ConvertType.cpp @@ -303,9 +303,13 @@ if (componentHasNonDefaultLowerBounds(field)) TODO(converter.genLocation(field.name()), "lowering derived type components with non default lower bounds"); - if (IsProcedure(field)) - TODO(converter.genLocation(field.name()), "procedure components"); - mlir::Type ty = genSymbolType(field); + mlir::Type ty; + if (IsProcedure(field)) { + ty = translateSignature(field, converter); + ty = fir::BoxProcType::get(context, ty); + } else { + ty = genSymbolType(field); + } // Do not add the parent component (component of the parents are // added and should be sufficient, the parent component would // duplicate the fields). diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -907,6 +907,10 @@ return fir::MutableBoxValue(component, nonDeferredTypeParams, /*mutableProperties=*/{}); } + if (auto funTy = fieldTy.dyn_cast()) { + // TODO: host-assoc pointer + return fir::ProcBoxValue{component, {}}; + } llvm::SmallVector extents; if (auto seqTy = fieldTy.dyn_cast()) { fieldTy = seqTy.getEleTy();