[Flang] Changes to mangling code

Call static functions using the class name (fir::NameUniquer).
Add function for mangling derivedTypes.

All the name mangling functions that are ultimately called are
tested in unittests/Optimizer/InternalNamesTest.cpp.

Differential Revision: https://reviews.llvm.org/D99967

GitOrigin-RevId: 9da35814e5fb71d8610ed7888d1f05703bfa8b54
diff --git a/include/flang/Lower/Bridge.h b/include/flang/Lower/Bridge.h
index eafa16d..28ce992 100644
--- a/include/flang/Lower/Bridge.h
+++ b/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/include/flang/Lower/Mangler.h b/include/flang/Lower/Mangler.h
index 0029772..d82fdb0 100644
--- a/include/flang/Lower/Mangler.h
+++ b/include/flang/Lower/Mangler.h
@@ -18,7 +18,6 @@
 #include <string>
 
 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 {
-namespace mangle {
+namespace lower::mangle {
 
-/// Convert a front-end Symbol to an internal name
-std::string mangleName(fir::NameUniquer &uniquer, const semantics::Symbol &);
+/// 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 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/include/flang/Optimizer/CodeGen/CodeGen.h b/include/flang/Optimizer/CodeGen/CodeGen.h
index 7623c59..d863545 100644
--- a/include/flang/Optimizer/CodeGen/CodeGen.h
+++ b/include/flang/Optimizer/CodeGen/CodeGen.h
@@ -23,7 +23,7 @@
 std::unique_ptr<mlir::Pass> createFirCodeGenRewritePass();
 
 /// Convert FIR to the LLVM IR dialect
-std::unique_ptr<mlir::Pass> createFIRToLLVMPass(NameUniquer &uniquer);
+std::unique_ptr<mlir::Pass> createFIRToLLVMPass();
 
 /// Convert the LLVM IR dialect to LLVM-IR proper
 std::unique_ptr<mlir::Pass>
diff --git a/lib/Lower/Mangler.cpp b/lib/Lower/Mangler.cpp
index b590fc9..07d9e63 100644
--- a/lib/Lower/Mangler.cpp
+++ b/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<std::int64_t> kinds;
+  for (const auto &param :
+       Fortran::semantics::OrderParameterDeclarations(ultimateSymbol)) {
+    const auto &paramDetails =
+        param->get<Fortran::semantics::TypeParamDetails>();
+    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;