1 //===-- Mangler.cpp -------------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
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/Optional.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/ADT/Twine.h"
21 #include "llvm/Support/MD5.h"
22
23 // recursively build the vector of module scopes
moduleNames(const Fortran::semantics::Scope & scope,llvm::SmallVector<llvm::StringRef> & result)24 static void moduleNames(const Fortran::semantics::Scope &scope,
25 llvm::SmallVector<llvm::StringRef> &result) {
26 if (scope.IsTopLevel())
27 return;
28 moduleNames(scope.parent(), result);
29 if (scope.kind() == Fortran::semantics::Scope::Kind::Module)
30 if (const Fortran::semantics::Symbol *symbol = scope.symbol())
31 result.emplace_back(toStringRef(symbol->name()));
32 }
33
34 static llvm::SmallVector<llvm::StringRef>
moduleNames(const Fortran::semantics::Symbol & symbol)35 moduleNames(const Fortran::semantics::Symbol &symbol) {
36 const Fortran::semantics::Scope &scope = symbol.owner();
37 llvm::SmallVector<llvm::StringRef> result;
38 moduleNames(scope, result);
39 return result;
40 }
41
42 static llvm::Optional<llvm::StringRef>
hostName(const Fortran::semantics::Symbol & symbol)43 hostName(const Fortran::semantics::Symbol &symbol) {
44 const Fortran::semantics::Scope &scope = symbol.owner();
45 if (scope.kind() == Fortran::semantics::Scope::Kind::Subprogram) {
46 assert(scope.symbol() && "subprogram scope must have a symbol");
47 return toStringRef(scope.symbol()->name());
48 }
49 if (scope.kind() == Fortran::semantics::Scope::Kind::MainProgram)
50 // Do not use the main program name, if any, because it may lead to name
51 // collision with procedures with the same name in other compilation units
52 // (technically illegal, but all compilers are able to compile and link
53 // properly these programs).
54 return llvm::StringRef("");
55 return {};
56 }
57
58 static const Fortran::semantics::Symbol *
findInterfaceIfSeperateMP(const Fortran::semantics::Symbol & symbol)59 findInterfaceIfSeperateMP(const Fortran::semantics::Symbol &symbol) {
60 const Fortran::semantics::Scope &scope = symbol.owner();
61 if (symbol.attrs().test(Fortran::semantics::Attr::MODULE) &&
62 scope.IsSubmodule()) {
63 // FIXME symbol from MpSubprogramStmt do not seem to have
64 // Attr::MODULE set.
65 const Fortran::semantics::Symbol *iface =
66 scope.parent().FindSymbol(symbol.name());
67 assert(iface && "Separate module procedure must be declared");
68 return iface;
69 }
70 return nullptr;
71 }
72
73 // Mangle the name of `symbol` to make it unique within FIR's symbol table using
74 // the FIR name mangler, `mangler`
75 std::string
mangleName(const Fortran::semantics::Symbol & symbol,bool keepExternalInScope)76 Fortran::lower::mangle::mangleName(const Fortran::semantics::Symbol &symbol,
77 bool keepExternalInScope) {
78 // Resolve host and module association before mangling
79 const auto &ultimateSymbol = symbol.GetUltimate();
80 auto symbolName = toStringRef(ultimateSymbol.name());
81
82 // The Fortran and BIND(C) namespaces are counterintuitive. A
83 // BIND(C) name is substituted early having precedence over the
84 // Fortran name of the subprogram. By side-effect, this allows
85 // multiple subprocedures with identical Fortran names to be legally
86 // present in the program. Assume the BIND(C) name is unique.
87 if (auto *overrideName = ultimateSymbol.GetBindName())
88 return *overrideName;
89 // TODO: the case of procedure that inherits the BIND(C) through another
90 // interface (procedure(iface)), should be dealt within GetBindName()
91 // directly, or some semantics wrapper.
92 if (!Fortran::semantics::IsPointer(ultimateSymbol) &&
93 Fortran::semantics::IsBindCProcedure(ultimateSymbol) &&
94 Fortran::semantics::ClassifyProcedure(symbol) !=
95 Fortran::semantics::ProcedureDefinitionClass::Internal)
96 return ultimateSymbol.name().ToString();
97
98 return std::visit(
99 Fortran::common::visitors{
100 [&](const Fortran::semantics::MainProgramDetails &) {
101 return fir::NameUniquer::doProgramEntry().str();
102 },
103 [&](const Fortran::semantics::SubprogramDetails &) {
104 // Mangle external procedure without any scope prefix.
105 if (!keepExternalInScope &&
106 Fortran::semantics::IsExternal(ultimateSymbol))
107 return fir::NameUniquer::doProcedure(llvm::None, llvm::None,
108 symbolName);
109 // Separate module subprograms must be mangled according to the
110 // scope where they were declared (the symbol we have is the
111 // definition).
112 const Fortran::semantics::Symbol *interface = &ultimateSymbol;
113 if (const auto *mpIface = findInterfaceIfSeperateMP(ultimateSymbol))
114 interface = mpIface;
115 llvm::SmallVector<llvm::StringRef> modNames =
116 moduleNames(*interface);
117 return fir::NameUniquer::doProcedure(modNames, hostName(*interface),
118 symbolName);
119 },
120 [&](const Fortran::semantics::ProcEntityDetails &) {
121 // Mangle procedure pointers and dummy procedures as variables
122 if (Fortran::semantics::IsPointer(ultimateSymbol) ||
123 Fortran::semantics::IsDummy(ultimateSymbol))
124 return fir::NameUniquer::doVariable(moduleNames(ultimateSymbol),
125 hostName(ultimateSymbol),
126 symbolName);
127 // Otherwise, this is an external procedure, even if it does not
128 // have an explicit EXTERNAL attribute. Mangle it without any
129 // prefix.
130 return fir::NameUniquer::doProcedure(llvm::None, llvm::None,
131 symbolName);
132 },
133 [&](const Fortran::semantics::ObjectEntityDetails &) {
134 llvm::SmallVector<llvm::StringRef> modNames =
135 moduleNames(ultimateSymbol);
136 llvm::Optional<llvm::StringRef> optHost = hostName(ultimateSymbol);
137 if (Fortran::semantics::IsNamedConstant(ultimateSymbol))
138 return fir::NameUniquer::doConstant(modNames, optHost,
139 symbolName);
140 return fir::NameUniquer::doVariable(modNames, optHost, symbolName);
141 },
142 [&](const Fortran::semantics::NamelistDetails &) {
143 llvm::SmallVector<llvm::StringRef> modNames =
144 moduleNames(ultimateSymbol);
145 llvm::Optional<llvm::StringRef> optHost = hostName(ultimateSymbol);
146 return fir::NameUniquer::doNamelistGroup(modNames, optHost,
147 symbolName);
148 },
149 [&](const Fortran::semantics::CommonBlockDetails &) {
150 return fir::NameUniquer::doCommonBlock(symbolName);
151 },
152 [&](const Fortran::semantics::DerivedTypeDetails &) -> std::string {
153 // Derived type mangling must used mangleName(DerivedTypeSpec&) so
154 // that kind type parameter values can be mangled.
155 llvm::report_fatal_error(
156 "only derived type instances can be mangled");
157 },
158 [](const auto &) -> std::string { TODO_NOLOC("symbol mangling"); },
159 },
160 ultimateSymbol.details());
161 }
162
mangleName(const Fortran::semantics::DerivedTypeSpec & derivedType)163 std::string Fortran::lower::mangle::mangleName(
164 const Fortran::semantics::DerivedTypeSpec &derivedType) {
165 // Resolve host and module association before mangling
166 const Fortran::semantics::Symbol &ultimateSymbol =
167 derivedType.typeSymbol().GetUltimate();
168 llvm::StringRef symbolName = toStringRef(ultimateSymbol.name());
169 llvm::SmallVector<llvm::StringRef> modNames = moduleNames(ultimateSymbol);
170 llvm::Optional<llvm::StringRef> optHost = hostName(ultimateSymbol);
171 llvm::SmallVector<std::int64_t> kinds;
172 for (const auto ¶m :
173 Fortran::semantics::OrderParameterDeclarations(ultimateSymbol)) {
174 const auto ¶mDetails =
175 param->get<Fortran::semantics::TypeParamDetails>();
176 if (paramDetails.attr() == Fortran::common::TypeParamAttr::Kind) {
177 const Fortran::semantics::ParamValue *paramValue =
178 derivedType.FindParameter(param->name());
179 assert(paramValue && "derived type kind parameter value not found");
180 const Fortran::semantics::MaybeIntExpr paramExpr =
181 paramValue->GetExplicit();
182 assert(paramExpr && "derived type kind param not explicit");
183 std::optional<int64_t> init =
184 Fortran::evaluate::ToInt64(paramValue->GetExplicit());
185 assert(init && "derived type kind param is not constant");
186 kinds.emplace_back(*init);
187 }
188 }
189 return fir::NameUniquer::doType(modNames, optHost, symbolName, kinds);
190 }
191
demangleName(llvm::StringRef name)192 std::string Fortran::lower::mangle::demangleName(llvm::StringRef name) {
193 auto result = fir::NameUniquer::deconstruct(name);
194 return result.second.name;
195 }
196
197 //===----------------------------------------------------------------------===//
198 // Array Literals Mangling
199 //===----------------------------------------------------------------------===//
200
typeToString(Fortran::common::TypeCategory cat,int kind)201 static std::string typeToString(Fortran::common::TypeCategory cat, int kind) {
202 switch (cat) {
203 case Fortran::common::TypeCategory::Integer:
204 return "i" + std::to_string(kind);
205 case Fortran::common::TypeCategory::Real:
206 return "r" + std::to_string(kind);
207 case Fortran::common::TypeCategory::Complex:
208 return "z" + std::to_string(kind);
209 case Fortran::common::TypeCategory::Logical:
210 return "l" + std::to_string(kind);
211 case Fortran::common::TypeCategory::Character:
212 return "c" + std::to_string(kind);
213 case Fortran::common::TypeCategory::Derived:
214 // FIXME: Replace "DT" with the (fully qualified) type name.
215 return "dt.DT";
216 }
217 llvm_unreachable("bad TypeCategory");
218 }
219
mangleArrayLiteral(const uint8_t * addr,size_t size,const Fortran::evaluate::ConstantSubscripts & shape,Fortran::common::TypeCategory cat,int kind,Fortran::common::ConstantSubscript charLen)220 std::string Fortran::lower::mangle::mangleArrayLiteral(
221 const uint8_t *addr, size_t size,
222 const Fortran::evaluate::ConstantSubscripts &shape,
223 Fortran::common::TypeCategory cat, int kind,
224 Fortran::common::ConstantSubscript charLen) {
225 std::string typeId = "";
226 for (Fortran::evaluate::ConstantSubscript extent : shape)
227 typeId.append(std::to_string(extent)).append("x");
228 if (charLen >= 0)
229 typeId.append(std::to_string(charLen)).append("x");
230 typeId.append(typeToString(cat, kind));
231 std::string name =
232 fir::NameUniquer::doGenerated("ro."s.append(typeId).append("."));
233 if (!size)
234 return name += "null";
235 llvm::MD5 hashValue{};
236 hashValue.update(llvm::ArrayRef<uint8_t>{addr, size});
237 llvm::MD5::MD5Result hashResult;
238 hashValue.final(hashResult);
239 llvm::SmallString<32> hashString;
240 llvm::MD5::stringifyResult(hashResult, hashString);
241 return name += hashString.c_str();
242 }
243
244 //===----------------------------------------------------------------------===//
245 // Intrinsic Procedure Mangling
246 //===----------------------------------------------------------------------===//
247
248 /// Helper to encode type into string for intrinsic procedure names.
249 /// Note: mlir has Type::dump(ostream) methods but it may add "!" that is not
250 /// suitable for function names.
typeToString(mlir::Type t)251 static std::string typeToString(mlir::Type t) {
252 if (auto refT{t.dyn_cast<fir::ReferenceType>()})
253 return "ref_" + typeToString(refT.getEleTy());
254 if (auto i{t.dyn_cast<mlir::IntegerType>()}) {
255 return "i" + std::to_string(i.getWidth());
256 }
257 if (auto cplx{t.dyn_cast<fir::ComplexType>()}) {
258 return "z" + std::to_string(cplx.getFKind());
259 }
260 if (auto real{t.dyn_cast<fir::RealType>()}) {
261 return "r" + std::to_string(real.getFKind());
262 }
263 if (auto f{t.dyn_cast<mlir::FloatType>()}) {
264 return "f" + std::to_string(f.getWidth());
265 }
266 if (auto logical{t.dyn_cast<fir::LogicalType>()}) {
267 return "l" + std::to_string(logical.getFKind());
268 }
269 if (auto character{t.dyn_cast<fir::CharacterType>()}) {
270 return "c" + std::to_string(character.getFKind());
271 }
272 if (auto boxCharacter{t.dyn_cast<fir::BoxCharType>()}) {
273 return "bc" + std::to_string(boxCharacter.getEleTy().getFKind());
274 }
275 llvm_unreachable("no mangling for type");
276 }
277
mangleIntrinsicProcedure(llvm::StringRef intrinsic,mlir::FunctionType funTy)278 std::string fir::mangleIntrinsicProcedure(llvm::StringRef intrinsic,
279 mlir::FunctionType funTy) {
280 std::string name = "fir.";
281 name.append(intrinsic.str()).append(".");
282 assert(funTy.getNumResults() == 1 && "only function mangling supported");
283 name.append(typeToString(funTy.getResult(0)));
284 unsigned e = funTy.getNumInputs();
285 for (decltype(e) i = 0; i < e; ++i)
286 name.append(".").append(typeToString(funTy.getInput(i)));
287 return name;
288 }
289