1 //===-- Mangler.cpp -------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "flang/Lower/Mangler.h"
10 #include "flang/Common/reference.h"
11 #include "flang/Lower/Support/Utils.h"
12 #include "flang/Optimizer/Builder/Todo.h"
13 #include "flang/Optimizer/Dialect/FIRType.h"
14 #include "flang/Optimizer/Support/InternalNames.h"
15 #include "flang/Semantics/tools.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/MD5.h"
21 /// Return all ancestor module and submodule scope names; all host procedure
22 /// and statement function scope names; and the innermost blockId containing
23 /// \p scope, including scope itself.
24 static std::tuple
<llvm::SmallVector
<llvm::StringRef
>,
25 llvm::SmallVector
<llvm::StringRef
>, std::int64_t>
26 ancestors(const Fortran::semantics::Scope
&scope
,
27 Fortran::lower::mangle::ScopeBlockIdMap
&scopeBlockIdMap
) {
28 llvm::SmallVector
<const Fortran::semantics::Scope
*> scopes
;
29 for (auto *scp
= &scope
; !scp
->IsGlobal(); scp
= &scp
->parent())
30 scopes
.push_back(scp
);
31 llvm::SmallVector
<llvm::StringRef
> modules
;
32 llvm::SmallVector
<llvm::StringRef
> procs
;
33 std::int64_t blockId
= 0;
34 for (auto iter
= scopes
.rbegin(), rend
= scopes
.rend(); iter
!= rend
;
37 switch (scp
->kind()) {
38 case Fortran::semantics::Scope::Kind::Module
:
39 modules
.emplace_back(toStringRef(scp
->symbol()->name()));
41 case Fortran::semantics::Scope::Kind::Subprogram
:
42 procs
.emplace_back(toStringRef(scp
->symbol()->name()));
44 case Fortran::semantics::Scope::Kind::MainProgram
:
45 // Do not use the main program name, if any, because it may collide
46 // with a procedure of the same name in another compilation unit.
47 // This is nonconformant, but universally allowed.
48 procs
.emplace_back(llvm::StringRef(""));
50 case Fortran::semantics::Scope::Kind::BlockConstruct
: {
51 auto it
= scopeBlockIdMap
.find(scp
);
52 assert(it
!= scopeBlockIdMap
.end() && it
->second
&&
53 "invalid block identifier");
60 return {modules
, procs
, blockId
};
63 /// Return all ancestor module and submodule scope names; all host procedure
64 /// and statement function scope names; and the innermost blockId containing
66 static std::tuple
<llvm::SmallVector
<llvm::StringRef
>,
67 llvm::SmallVector
<llvm::StringRef
>, std::int64_t>
68 ancestors(const Fortran::semantics::Symbol
&symbol
,
69 Fortran::lower::mangle::ScopeBlockIdMap
&scopeBlockIdMap
) {
70 return ancestors(symbol
.owner(), scopeBlockIdMap
);
73 /// Return a globally unique string for a compiler generated \p name.
75 Fortran::lower::mangle::mangleName(std::string
&name
,
76 const Fortran::semantics::Scope
&scope
,
77 ScopeBlockIdMap
&scopeBlockIdMap
) {
78 llvm::SmallVector
<llvm::StringRef
> modules
;
79 llvm::SmallVector
<llvm::StringRef
> procs
;
81 std::tie(modules
, procs
, blockId
) = ancestors(scope
, scopeBlockIdMap
);
82 return fir::NameUniquer::doGenerated(modules
, procs
, blockId
, name
);
85 // Mangle the name of \p symbol to make it globally unique.
86 std::string
Fortran::lower::mangle::mangleName(
87 const Fortran::semantics::Symbol
&symbol
, ScopeBlockIdMap
&scopeBlockIdMap
,
88 bool keepExternalInScope
, bool underscoring
) {
89 // Resolve module and host associations before mangling.
90 const auto &ultimateSymbol
= symbol
.GetUltimate();
92 // The Fortran and BIND(C) namespaces are counterintuitive. A BIND(C) name is
93 // substituted early, and has precedence over the Fortran name. This allows
94 // multiple procedures or objects with identical Fortran names to legally
95 // coexist. The BIND(C) name is unique.
96 if (auto *overrideName
= ultimateSymbol
.GetBindName())
99 llvm::StringRef symbolName
= toStringRef(ultimateSymbol
.name());
100 llvm::SmallVector
<llvm::StringRef
> modules
;
101 llvm::SmallVector
<llvm::StringRef
> procs
;
102 std::int64_t blockId
;
104 // mangle ObjectEntityDetails or AssocEntityDetails symbols.
105 auto mangleObject
= [&]() -> std::string
{
106 std::tie(modules
, procs
, blockId
) =
107 ancestors(ultimateSymbol
, scopeBlockIdMap
);
108 if (Fortran::semantics::IsNamedConstant(ultimateSymbol
))
109 return fir::NameUniquer::doConstant(modules
, procs
, blockId
, symbolName
);
110 return fir::NameUniquer::doVariable(modules
, procs
, blockId
, symbolName
);
114 Fortran::common::visitors
{
115 [&](const Fortran::semantics::MainProgramDetails
&) {
116 return fir::NameUniquer::doProgramEntry().str();
118 [&](const Fortran::semantics::SubprogramDetails
&subpDetails
) {
119 // Mangle external procedure without any scope prefix.
120 if (!keepExternalInScope
&&
121 Fortran::semantics::IsExternal(ultimateSymbol
))
122 return fir::NameUniquer::doProcedure(std::nullopt
, std::nullopt
,
124 // A separate module procedure must be mangled according to its
125 // declaration scope, not its definition scope.
126 const Fortran::semantics::Symbol
*interface
= &ultimateSymbol
;
127 if (interface
->attrs().test(Fortran::semantics::Attr::MODULE
) &&
128 interface
->owner().IsSubmodule() && !subpDetails
.isInterface())
129 interface
= subpDetails
.moduleInterface();
130 std::tie(modules
, procs
, blockId
) = ancestors(
131 interface
? *interface
: ultimateSymbol
, scopeBlockIdMap
);
132 return fir::NameUniquer::doProcedure(modules
, procs
, symbolName
);
134 [&](const Fortran::semantics::ProcEntityDetails
&) {
135 // Mangle procedure pointers and dummy procedures as variables.
136 if (Fortran::semantics::IsPointer(ultimateSymbol
) ||
137 Fortran::semantics::IsDummy(ultimateSymbol
)) {
138 std::tie(modules
, procs
, blockId
) =
139 ancestors(ultimateSymbol
, scopeBlockIdMap
);
140 return fir::NameUniquer::doVariable(modules
, procs
, blockId
,
143 // Otherwise, this is an external procedure, with or without an
144 // explicit EXTERNAL attribute. Mangle it without any prefix.
145 return fir::NameUniquer::doProcedure(std::nullopt
, std::nullopt
,
148 [&](const Fortran::semantics::ObjectEntityDetails
&) {
149 return mangleObject();
151 [&](const Fortran::semantics::AssocEntityDetails
&) {
152 return mangleObject();
154 [&](const Fortran::semantics::NamelistDetails
&) {
155 std::tie(modules
, procs
, blockId
) =
156 ancestors(ultimateSymbol
, scopeBlockIdMap
);
157 return fir::NameUniquer::doNamelistGroup(modules
, procs
,
160 [&](const Fortran::semantics::CommonBlockDetails
&) {
161 return Fortran::semantics::GetCommonBlockObjectName(ultimateSymbol
,
164 [&](const Fortran::semantics::ProcBindingDetails
&procBinding
) {
165 return mangleName(procBinding
.symbol(), scopeBlockIdMap
,
166 keepExternalInScope
, underscoring
);
168 [&](const Fortran::semantics::DerivedTypeDetails
&) -> std::string
{
169 // Derived type mangling must use mangleName(DerivedTypeSpec) so
170 // that kind type parameter values can be mangled.
171 llvm::report_fatal_error(
172 "only derived type instances can be mangled");
174 [](const auto &) -> std::string
{ TODO_NOLOC("symbol mangling"); },
176 ultimateSymbol
.details());
180 Fortran::lower::mangle::mangleName(const Fortran::semantics::Symbol
&symbol
,
181 bool keepExternalInScope
,
183 assert((symbol
.owner().kind() !=
184 Fortran::semantics::Scope::Kind::BlockConstruct
||
185 symbol
.has
<Fortran::semantics::SubprogramDetails
>()) &&
186 "block object mangling must specify a scopeBlockIdMap");
187 ScopeBlockIdMap scopeBlockIdMap
;
188 return mangleName(symbol
, scopeBlockIdMap
, keepExternalInScope
, underscoring
);
191 std::string
Fortran::lower::mangle::mangleName(
192 const Fortran::semantics::DerivedTypeSpec
&derivedType
,
193 ScopeBlockIdMap
&scopeBlockIdMap
) {
194 // Resolve module and host associations before mangling.
195 const Fortran::semantics::Symbol
&ultimateSymbol
=
196 derivedType
.typeSymbol().GetUltimate();
198 llvm::StringRef symbolName
= toStringRef(ultimateSymbol
.name());
199 llvm::SmallVector
<llvm::StringRef
> modules
;
200 llvm::SmallVector
<llvm::StringRef
> procs
;
201 std::int64_t blockId
;
202 std::tie(modules
, procs
, blockId
) =
203 ancestors(ultimateSymbol
, scopeBlockIdMap
);
204 llvm::SmallVector
<std::int64_t> kinds
;
205 for (const auto ¶m
:
206 Fortran::semantics::OrderParameterDeclarations(ultimateSymbol
)) {
207 const auto ¶mDetails
=
208 param
->get
<Fortran::semantics::TypeParamDetails
>();
209 if (paramDetails
.attr() == Fortran::common::TypeParamAttr::Kind
) {
210 const Fortran::semantics::ParamValue
*paramValue
=
211 derivedType
.FindParameter(param
->name());
212 assert(paramValue
&& "derived type kind parameter value not found");
213 const Fortran::semantics::MaybeIntExpr paramExpr
=
214 paramValue
->GetExplicit();
215 assert(paramExpr
&& "derived type kind param not explicit");
216 std::optional
<int64_t> init
=
217 Fortran::evaluate::ToInt64(paramValue
->GetExplicit());
218 assert(init
&& "derived type kind param is not constant");
219 kinds
.emplace_back(*init
);
222 return fir::NameUniquer::doType(modules
, procs
, blockId
, symbolName
, kinds
);
225 std::string
Fortran::lower::mangle::getRecordTypeFieldName(
226 const Fortran::semantics::Symbol
&component
,
227 ScopeBlockIdMap
&scopeBlockIdMap
) {
228 if (!component
.attrs().test(Fortran::semantics::Attr::PRIVATE
))
229 return component
.name().ToString();
230 const Fortran::semantics::DerivedTypeSpec
*componentParentType
=
231 component
.owner().derivedTypeSpec();
232 assert(componentParentType
&&
233 "failed to retrieve private component parent type");
234 // Do not mangle Iso C C_PTR and C_FUNPTR components. This type cannot be
235 // extended as per Fortran 2018 7.5.7.1, mangling them makes the IR unreadable
236 // when using ISO C modules, and lowering needs to know the component way
237 // without access to semantics::Symbol.
238 if (Fortran::semantics::IsIsoCType(componentParentType
))
239 return component
.name().ToString();
240 return mangleName(*componentParentType
, scopeBlockIdMap
) + "." +
241 component
.name().ToString();
244 std::string
Fortran::lower::mangle::demangleName(llvm::StringRef name
) {
245 auto result
= fir::NameUniquer::deconstruct(name
);
246 return result
.second
.name
;
249 //===----------------------------------------------------------------------===//
250 // Array Literals Mangling
251 //===----------------------------------------------------------------------===//
253 static std::string
typeToString(Fortran::common::TypeCategory cat
, int kind
,
254 llvm::StringRef derivedName
) {
256 case Fortran::common::TypeCategory::Integer
:
257 return "i" + std::to_string(kind
);
258 case Fortran::common::TypeCategory::Real
:
259 return "r" + std::to_string(kind
);
260 case Fortran::common::TypeCategory::Complex
:
261 return "z" + std::to_string(kind
);
262 case Fortran::common::TypeCategory::Logical
:
263 return "l" + std::to_string(kind
);
264 case Fortran::common::TypeCategory::Character
:
265 return "c" + std::to_string(kind
);
266 case Fortran::common::TypeCategory::Derived
:
267 return derivedName
.str();
269 llvm_unreachable("bad TypeCategory");
272 std::string
Fortran::lower::mangle::mangleArrayLiteral(
273 size_t size
, const Fortran::evaluate::ConstantSubscripts
&shape
,
274 Fortran::common::TypeCategory cat
, int kind
,
275 Fortran::common::ConstantSubscript charLen
, llvm::StringRef derivedName
) {
277 for (Fortran::evaluate::ConstantSubscript extent
: shape
)
278 typeId
.append(std::to_string(extent
)).append("x");
280 typeId
.append(std::to_string(charLen
)).append("x");
281 typeId
.append(typeToString(cat
, kind
, derivedName
));
283 fir::NameUniquer::doGenerated("ro."s
.append(typeId
).append("."));
289 std::string
Fortran::lower::mangle::globalNamelistDescriptorName(
290 const Fortran::semantics::Symbol
&sym
) {
291 std::string name
= mangleName(sym
);
292 return IsAllocatableOrObjectPointer(&sym
) ? name
: name
+ ".desc"s
;