1 //===-- InternalNames.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 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
11 //===----------------------------------------------------------------------===//
13 #include "flang/Optimizer/Support/InternalNames.h"
14 #include "flang/Optimizer/Dialect/FIRType.h"
15 #include "mlir/IR/BuiltinTypes.h"
16 #include "mlir/IR/Diagnostics.h"
17 #include "llvm/Support/CommandLine.h"
21 static llvm::cl::opt
<std::string
> mainEntryName(
23 llvm::cl::desc("override the name of the default PROGRAM entry (may be "
24 "helpful for using other runtimes)"));
26 constexpr std::int64_t badValue
= -1;
28 inline std::string
prefix() { return "_Q"; }
30 /// Generate a mangling prefix from module, submodule, procedure, and
31 /// statement function names, plus an (innermost) block scope id.
32 static std::string
doAncestors(llvm::ArrayRef
<llvm::StringRef
> modules
,
33 llvm::ArrayRef
<llvm::StringRef
> procs
,
34 std::int64_t blockId
= 0) {
36 const char *tag
= "M";
37 for (auto mod
: modules
) {
38 prefix
.append(tag
).append(mod
.lower());
41 for (auto proc
: procs
)
42 prefix
.append("F").append(proc
.lower());
44 prefix
.append("B").append(std::to_string(blockId
));
48 inline llvm::SmallVector
<llvm::StringRef
>
49 convertToStringRef(llvm::ArrayRef
<std::string
> from
) {
50 return {from
.begin(), from
.end()};
53 inline std::optional
<llvm::StringRef
>
54 convertToStringRef(const std::optional
<std::string
> &from
) {
55 std::optional
<llvm::StringRef
> to
;
61 static std::string
readName(llvm::StringRef uniq
, std::size_t &i
,
62 std::size_t init
, std::size_t end
) {
63 // Allow 'X' to be part of the mangled name, which
64 // can happen after the special symbols are replaced
65 // in the mangled names by CompilerGeneratedNamesConversionPass.
66 for (i
= init
; i
< end
&& (uniq
[i
] < 'A' || uniq
[i
] > 'Z' || uniq
[i
] == 'X');
70 return uniq
.substr(init
, i
- init
).str();
73 static std::int64_t readInt(llvm::StringRef uniq
, std::size_t &i
,
74 std::size_t init
, std::size_t end
) {
75 for (i
= init
; i
< end
&& uniq
[i
] >= '0' && uniq
[i
] <= '9'; ++i
) {
78 std::int64_t result
= badValue
;
79 if (uniq
.substr(init
, i
- init
).getAsInteger(10, result
))
84 std::string
fir::NameUniquer::toLower(llvm::StringRef name
) {
88 std::string
fir::NameUniquer::intAsString(std::int64_t i
) {
90 return std::to_string(i
);
93 std::string
fir::NameUniquer::doKind(std::int64_t kind
) {
94 std::string result
= "K";
96 return result
.append("N").append(intAsString(-kind
));
97 return result
.append(intAsString(kind
));
100 std::string
fir::NameUniquer::doKinds(llvm::ArrayRef
<std::int64_t> kinds
) {
103 result
.append(doKind(i
));
107 std::string
fir::NameUniquer::doCommonBlock(llvm::StringRef name
) {
108 return prefix().append("C").append(toLower(name
));
112 fir::NameUniquer::doConstant(llvm::ArrayRef
<llvm::StringRef
> modules
,
113 llvm::ArrayRef
<llvm::StringRef
> procs
,
114 std::int64_t blockId
, llvm::StringRef name
) {
116 .append(doAncestors(modules
, procs
, blockId
))
118 .append(toLower(name
));
122 fir::NameUniquer::doDispatchTable(llvm::ArrayRef
<llvm::StringRef
> modules
,
123 llvm::ArrayRef
<llvm::StringRef
> procs
,
124 std::int64_t blockId
, llvm::StringRef name
,
125 llvm::ArrayRef
<std::int64_t> kinds
) {
127 .append(doAncestors(modules
, procs
, blockId
))
129 .append(toLower(name
))
130 .append(doKinds(kinds
));
133 std::string
fir::NameUniquer::doGenerated(llvm::StringRef name
) {
134 return prefix().append("Q").append(name
);
138 fir::NameUniquer::doGenerated(llvm::ArrayRef
<llvm::StringRef
> modules
,
139 llvm::ArrayRef
<llvm::StringRef
> procs
,
140 std::int64_t blockId
, llvm::StringRef name
) {
143 .append(doAncestors(modules
, procs
, blockId
))
147 std::string
fir::NameUniquer::doIntrinsicTypeDescriptor(
148 llvm::ArrayRef
<llvm::StringRef
> modules
,
149 llvm::ArrayRef
<llvm::StringRef
> procs
, std::int64_t blockId
,
150 IntrinsicType type
, std::int64_t kind
) {
151 const char *name
= nullptr;
153 case IntrinsicType::CHARACTER
:
156 case IntrinsicType::COMPLEX
:
159 case IntrinsicType::INTEGER
:
162 case IntrinsicType::LOGICAL
:
165 case IntrinsicType::REAL
:
169 assert(name
&& "unknown intrinsic type");
171 .append(doAncestors(modules
, procs
, blockId
))
174 .append(doKind(kind
));
178 fir::NameUniquer::doProcedure(llvm::ArrayRef
<llvm::StringRef
> modules
,
179 llvm::ArrayRef
<llvm::StringRef
> procs
,
180 llvm::StringRef name
) {
182 .append(doAncestors(modules
, procs
))
184 .append(toLower(name
));
187 std::string
fir::NameUniquer::doType(llvm::ArrayRef
<llvm::StringRef
> modules
,
188 llvm::ArrayRef
<llvm::StringRef
> procs
,
189 std::int64_t blockId
, llvm::StringRef name
,
190 llvm::ArrayRef
<std::int64_t> kinds
) {
192 .append(doAncestors(modules
, procs
, blockId
))
194 .append(toLower(name
))
195 .append(doKinds(kinds
));
199 fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef
<llvm::StringRef
> modules
,
200 llvm::ArrayRef
<llvm::StringRef
> procs
,
201 std::int64_t blockId
, llvm::StringRef name
,
202 llvm::ArrayRef
<std::int64_t> kinds
) {
204 .append(doAncestors(modules
, procs
, blockId
))
206 .append(toLower(name
))
207 .append(doKinds(kinds
));
211 fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef
<std::string
> modules
,
212 llvm::ArrayRef
<std::string
> procs
,
213 std::int64_t blockId
, llvm::StringRef name
,
214 llvm::ArrayRef
<std::int64_t> kinds
) {
215 auto rmodules
= convertToStringRef(modules
);
216 auto rprocs
= convertToStringRef(procs
);
217 return doTypeDescriptor(rmodules
, rprocs
, blockId
, name
, kinds
);
221 fir::NameUniquer::doVariable(llvm::ArrayRef
<llvm::StringRef
> modules
,
222 llvm::ArrayRef
<llvm::StringRef
> procs
,
223 std::int64_t blockId
, llvm::StringRef name
) {
225 .append(doAncestors(modules
, procs
, blockId
))
227 .append(toLower(name
));
231 fir::NameUniquer::doNamelistGroup(llvm::ArrayRef
<llvm::StringRef
> modules
,
232 llvm::ArrayRef
<llvm::StringRef
> procs
,
233 llvm::StringRef name
) {
235 .append(doAncestors(modules
, procs
))
237 .append(toLower(name
));
240 llvm::StringRef
fir::NameUniquer::doProgramEntry() {
241 if (mainEntryName
.size())
242 return mainEntryName
;
246 std::pair
<fir::NameUniquer::NameKind
, fir::NameUniquer::DeconstructedName
>
247 fir::NameUniquer::deconstruct(llvm::StringRef uniq
) {
248 uniq
= fir::NameUniquer::dropTypeConversionMarkers(uniq
);
249 if (uniq
.starts_with("_Q")) {
250 llvm::SmallVector
<std::string
> modules
;
251 llvm::SmallVector
<std::string
> procs
;
252 std::int64_t blockId
= 0;
254 llvm::SmallVector
<std::int64_t> kinds
;
255 NameKind nk
= NameKind::NOT_UNIQUED
;
256 for (std::size_t i
= 2, end
{uniq
.size()}; i
!= end
;) {
259 blockId
= readInt(uniq
, i
, i
+ 1, end
);
261 case 'C': // Common block
262 nk
= NameKind::COMMON
;
263 name
= readName(uniq
, i
, i
+ 1, end
);
265 case 'D': // Dispatch table
266 nk
= NameKind::DISPATCH_TABLE
;
267 assert(uniq
[i
+ 1] == 'T');
268 name
= readName(uniq
, i
, i
+ 2, end
);
271 if (uniq
[i
+ 1] == 'C') { // Constant Entity
272 nk
= NameKind::CONSTANT
;
273 name
= readName(uniq
, i
, i
+ 2, end
);
274 } else { // variable Entity
275 nk
= NameKind::VARIABLE
;
276 name
= readName(uniq
, i
, i
+ 1, end
);
279 case 'F': // procedure/Function ancestor component of a mangled prefix
280 procs
.push_back(readName(uniq
, i
, i
+ 1, end
));
283 if (uniq
[i
+ 1] == 'N') // Negative Kind
284 kinds
.push_back(-readInt(uniq
, i
, i
+ 2, end
));
285 else // [positive] Kind
286 kinds
.push_back(readInt(uniq
, i
, i
+ 1, end
));
289 case 'S': // Submodule
290 modules
.push_back(readName(uniq
, i
, i
+ 1, end
));
292 case 'N': // Namelist group
293 nk
= NameKind::NAMELIST_GROUP
;
294 name
= readName(uniq
, i
, i
+ 1, end
);
296 case 'P': // Procedure/function (itself)
297 nk
= NameKind::PROCEDURE
;
298 name
= readName(uniq
, i
, i
+ 1, end
);
300 case 'Q': // UniQue mangle name tag
301 nk
= NameKind::GENERATED
;
305 case 'T': // derived Type
306 nk
= NameKind::DERIVED_TYPE
;
307 name
= readName(uniq
, i
, i
+ 1, end
);
310 if (uniq
[i
+ 1] == 'I') { // tYpe descriptor for an Intrinsic type
311 nk
= NameKind::INTRINSIC_TYPE_DESC
;
312 name
= readName(uniq
, i
, i
+ 1, end
);
313 } else { // tYpe descriptor
314 nk
= NameKind::TYPE_DESC
;
315 name
= readName(uniq
, i
, i
+ 2, end
);
319 assert(false && "unknown uniquing code");
323 return {nk
, DeconstructedName(modules
, procs
, blockId
, name
, kinds
)};
325 return {NameKind::NOT_UNIQUED
, DeconstructedName(uniq
)};
328 bool fir::NameUniquer::isExternalFacingUniquedName(
329 const std::pair
<fir::NameUniquer::NameKind
,
330 fir::NameUniquer::DeconstructedName
> &deconstructResult
) {
331 return (deconstructResult
.first
== NameKind::PROCEDURE
||
332 deconstructResult
.first
== NameKind::COMMON
) &&
333 deconstructResult
.second
.modules
.empty() &&
334 deconstructResult
.second
.procs
.empty();
337 bool fir::NameUniquer::needExternalNameMangling(llvm::StringRef uniquedName
) {
338 auto result
= fir::NameUniquer::deconstruct(uniquedName
);
339 return result
.first
!= fir::NameUniquer::NameKind::NOT_UNIQUED
&&
340 fir::NameUniquer::isExternalFacingUniquedName(result
);
343 bool fir::NameUniquer::belongsToModule(llvm::StringRef uniquedName
,
344 llvm::StringRef moduleName
) {
345 auto result
= fir::NameUniquer::deconstruct(uniquedName
);
346 return !result
.second
.modules
.empty() &&
347 result
.second
.modules
[0] == moduleName
;
351 mangleTypeDescriptorKinds(llvm::ArrayRef
<std::int64_t> kinds
) {
355 for (std::int64_t kind
: kinds
)
356 result
+= (fir::kNameSeparator
+ std::to_string(kind
)).str();
360 static std::string
getDerivedTypeObjectName(llvm::StringRef mangledTypeName
,
361 const llvm::StringRef separator
) {
363 fir::NameUniquer::dropTypeConversionMarkers(mangledTypeName
);
364 auto result
= fir::NameUniquer::deconstruct(mangledTypeName
);
365 if (result
.first
!= fir::NameUniquer::NameKind::DERIVED_TYPE
)
367 std::string varName
= separator
.str() + result
.second
.name
+
368 mangleTypeDescriptorKinds(result
.second
.kinds
);
369 llvm::SmallVector
<llvm::StringRef
> modules
;
370 for (const std::string
&mod
: result
.second
.modules
)
371 modules
.push_back(mod
);
372 llvm::SmallVector
<llvm::StringRef
> procs
;
373 for (const std::string
&proc
: result
.second
.procs
)
374 procs
.push_back(proc
);
375 return fir::NameUniquer::doVariable(modules
, procs
, result
.second
.blockId
,
380 fir::NameUniquer::getTypeDescriptorName(llvm::StringRef mangledTypeName
) {
381 return getDerivedTypeObjectName(mangledTypeName
,
382 fir::kTypeDescriptorSeparator
);
385 std::string
fir::NameUniquer::getTypeDescriptorAssemblyName(
386 llvm::StringRef mangledTypeName
) {
387 return replaceSpecialSymbols(getTypeDescriptorName(mangledTypeName
));
390 std::string
fir::NameUniquer::getTypeDescriptorBindingTableName(
391 llvm::StringRef mangledTypeName
) {
392 return getDerivedTypeObjectName(mangledTypeName
, fir::kBindingTableSeparator
);
396 fir::NameUniquer::getComponentInitName(llvm::StringRef mangledTypeName
,
397 llvm::StringRef componentName
) {
400 getDerivedTypeObjectName(mangledTypeName
, fir::kComponentInitSeparator
);
401 return (prefix
+ fir::kNameSeparator
+ componentName
).str();
405 fir::NameUniquer::dropTypeConversionMarkers(llvm::StringRef mangledTypeName
) {
406 if (mangledTypeName
.ends_with(fir::boxprocSuffix
))
407 return mangledTypeName
.drop_back(fir::boxprocSuffix
.size());
408 return mangledTypeName
;
411 std::string
fir::NameUniquer::replaceSpecialSymbols(const std::string
&name
) {
412 return std::regex_replace(name
, std::regex
{"\\."}, "X");
415 bool fir::NameUniquer::isSpecialSymbol(llvm::StringRef name
) {
416 return !name
.empty() && (name
[0] == '.' || name
[0] == 'X');