diff --git a/flang/include/flang/Lower/Bridge.h b/flang/include/flang/Lower/Bridge.h --- a/flang/include/flang/Lower/Bridge.h +++ b/flang/include/flang/Lower/Bridge.h @@ -22,10 +22,6 @@ #include "flang/Optimizer/Support/KindMapping.h" #include "mlir/IR/BuiltinOps.h" -namespace fir { -struct NameUniquer; -} - namespace Fortran { namespace common { class IntrinsicTypeDefaultKinds; @@ -92,7 +88,7 @@ void parseSourceFile(llvm::SourceMgr &); /// Cross the bridge from the Fortran parse-tree, etc. to MLIR dialects - void lower(const Fortran::parser::Program &program, fir::NameUniquer &uniquer, + void lower(const Fortran::parser::Program &program, const Fortran::semantics::SemanticsContext &semanticsContext); private: diff --git a/flang/include/flang/Lower/Mangler.h b/flang/include/flang/Lower/Mangler.h --- a/flang/include/flang/Lower/Mangler.h +++ b/flang/include/flang/Lower/Mangler.h @@ -18,7 +18,6 @@ #include namespace fir { -struct NameUniquer; /// Returns a name suitable to define mlir functions for Fortran intrinsic /// Procedure. These names are guaranteed to not conflict with user defined @@ -40,18 +39,26 @@ namespace semantics { class Symbol; -} +class DerivedTypeSpec; +} // namespace semantics + +namespace lower::mangle { -namespace lower { -namespace mangle { +/// Convert a front-end Symbol to an internal name. +/// If \p keepExternalInScope is true, the mangling of external symbols +/// retains the scope of the symbol declaring externals. Otherwise, +/// external symbols are mangled outside of any scope. Keeping the scope is +/// useful in attributes where all the Fortran context is to be maintained. +std::string mangleName(const semantics::Symbol &, + bool keepExternalInScope = false); -/// Convert a front-end Symbol to an internal name -std::string mangleName(fir::NameUniquer &uniquer, const semantics::Symbol &); +/// Convert a derived type instance to an internal name. +std::string mangleName(const semantics::DerivedTypeSpec &); +/// Recover the bare name of the original symbol from an internal name. std::string demangleName(llvm::StringRef name); -} // namespace mangle -} // namespace lower +} // namespace lower::mangle } // namespace Fortran #endif // FORTRAN_LOWER_MANGLER_H diff --git a/flang/include/flang/Optimizer/CodeGen/CodeGen.h b/flang/include/flang/Optimizer/CodeGen/CodeGen.h --- a/flang/include/flang/Optimizer/CodeGen/CodeGen.h +++ b/flang/include/flang/Optimizer/CodeGen/CodeGen.h @@ -23,7 +23,7 @@ std::unique_ptr createFirCodeGenRewritePass(); /// Convert FIR to the LLVM IR dialect -std::unique_ptr createFIRToLLVMPass(NameUniquer &uniquer); +std::unique_ptr createFIRToLLVMPass(); /// Convert the LLVM IR dialect to LLVM-IR proper std::unique_ptr diff --git a/flang/lib/Lower/Mangler.cpp b/flang/lib/Lower/Mangler.cpp --- a/flang/lib/Lower/Mangler.cpp +++ b/flang/lib/Lower/Mangler.cpp @@ -8,6 +8,7 @@ #include "flang/Lower/Mangler.h" #include "flang/Common/reference.h" +#include "flang/Lower/Todo.h" #include "flang/Lower/Utils.h" #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Support/InternalNames.h" @@ -65,8 +66,8 @@ // Mangle the name of `symbol` to make it unique within FIR's symbol table using // the FIR name mangler, `mangler` std::string -Fortran::lower::mangle::mangleName(fir::NameUniquer &uniquer, - const Fortran::semantics::Symbol &symbol) { +Fortran::lower::mangle::mangleName(const Fortran::semantics::Symbol &symbol, + bool keepExternalInScope) { // Resolve host and module association before mangling const auto &ultimateSymbol = symbol.GetUltimate(); auto symbolName = toStringRef(ultimateSymbol.name()); @@ -74,12 +75,14 @@ return std::visit( Fortran::common::visitors{ [&](const Fortran::semantics::MainProgramDetails &) { - return uniquer.doProgramEntry().str(); + return fir::NameUniquer::doProgramEntry().str(); }, [&](const Fortran::semantics::SubprogramDetails &) { // Mangle external procedure without any scope prefix. - if (Fortran::semantics::IsExternal(ultimateSymbol)) - return uniquer.doProcedure(llvm::None, llvm::None, symbolName); + if (!keepExternalInScope && + Fortran::semantics::IsExternal(ultimateSymbol)) + return fir::NameUniquer::doProcedure(llvm::None, llvm::None, + symbolName); // Separate module subprograms must be mangled according to the // scope where they were declared (the symbol we have is the // definition). @@ -87,35 +90,69 @@ if (const auto *mpIface = findInterfaceIfSeperateMP(ultimateSymbol)) interface = mpIface; auto modNames = moduleNames(*interface); - return uniquer.doProcedure(modNames, hostName(*interface), - symbolName); + return fir::NameUniquer::doProcedure(modNames, hostName(*interface), + symbolName); }, [&](const Fortran::semantics::ProcEntityDetails &) { // Mangle procedure pointers and dummy procedures as variables if (Fortran::semantics::IsPointer(ultimateSymbol) || Fortran::semantics::IsDummy(ultimateSymbol)) - return uniquer.doVariable(moduleNames(ultimateSymbol), - hostName(ultimateSymbol), symbolName); + return fir::NameUniquer::doVariable(moduleNames(ultimateSymbol), + hostName(ultimateSymbol), + symbolName); // Otherwise, this is an external procedure, even if it does not // have an explicit EXTERNAL attribute. Mangle it without any // prefix. - return uniquer.doProcedure(llvm::None, llvm::None, symbolName); + return fir::NameUniquer::doProcedure(llvm::None, llvm::None, + symbolName); }, [&](const Fortran::semantics::ObjectEntityDetails &) { auto modNames = moduleNames(ultimateSymbol); auto optHost = hostName(ultimateSymbol); if (Fortran::semantics::IsNamedConstant(ultimateSymbol)) - return uniquer.doConstant(modNames, optHost, symbolName); - return uniquer.doVariable(modNames, optHost, symbolName); + return fir::NameUniquer::doConstant(modNames, optHost, + symbolName); + return fir::NameUniquer::doVariable(modNames, optHost, symbolName); }, - [](const auto &) -> std::string { - assert(false); - return {}; + [&](const Fortran::semantics::CommonBlockDetails &) { + return fir::NameUniquer::doCommonBlock(symbolName); }, + [&](const Fortran::semantics::DerivedTypeDetails &) -> std::string { + // Derived type mangling must used mangleName(DerivedTypeSpec&) so + // that kind type parameter values can be mangled. + llvm::report_fatal_error( + "only derived type instances can be mangled"); + }, + [](const auto &) -> std::string { TODO_NOLOC("symbol mangling"); }, }, ultimateSymbol.details()); } +std::string Fortran::lower::mangle::mangleName( + const Fortran::semantics::DerivedTypeSpec &derivedType) { + // Resolve host and module association before mangling + const auto &ultimateSymbol = derivedType.typeSymbol().GetUltimate(); + auto symbolName = toStringRef(ultimateSymbol.name()); + auto modNames = moduleNames(ultimateSymbol); + auto optHost = hostName(ultimateSymbol); + llvm::SmallVector kinds; + for (const auto ¶m : + Fortran::semantics::OrderParameterDeclarations(ultimateSymbol)) { + const auto ¶mDetails = + param->get(); + if (paramDetails.attr() == Fortran::common::TypeParamAttr::Kind) { + const auto *paramValue = derivedType.FindParameter(param->name()); + assert(paramValue && "derived type kind parameter value not found"); + auto paramExpr = paramValue->GetExplicit(); + assert(paramExpr && "derived type kind param not explicit"); + auto init = Fortran::evaluate::ToInt64(paramValue->GetExplicit()); + assert(init && "derived type kind param is not constant"); + kinds.emplace_back(*init); + } + } + return fir::NameUniquer::doType(modNames, optHost, symbolName, kinds); +} + std::string Fortran::lower::mangle::demangleName(llvm::StringRef name) { auto result = fir::NameUniquer::deconstruct(name); return result.second.name;