xref: /llvm-project/flang/lib/Optimizer/Support/InternalNames.cpp (revision c09215860fd5c32012ef4fdc5a001485a04fe85a)
1 //===-- InternalNames.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 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10 //
11 //===----------------------------------------------------------------------===//
12 
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"
18 #include <optional>
19 
20 static llvm::cl::opt<std::string> mainEntryName(
21     "main-entry-name",
22     llvm::cl::desc("override the name of the default PROGRAM entry (may be "
23                    "helpful for using other runtimes)"));
24 
25 constexpr std::int64_t badValue = -1;
26 
27 inline std::string prefix() { return "_Q"; }
28 
29 static std::string doModules(llvm::ArrayRef<llvm::StringRef> mods) {
30   std::string result;
31   auto *token = "M";
32   for (auto mod : mods) {
33     result.append(token).append(mod.lower());
34     token = "S";
35   }
36   return result;
37 }
38 
39 static std::string doModulesHost(llvm::ArrayRef<llvm::StringRef> mods,
40                                  std::optional<llvm::StringRef> host) {
41   std::string result = doModules(mods);
42   if (host)
43     result.append("F").append(host->lower());
44   return result;
45 }
46 
47 inline llvm::SmallVector<llvm::StringRef>
48 convertToStringRef(llvm::ArrayRef<std::string> from) {
49   return {from.begin(), from.end()};
50 }
51 
52 inline std::optional<llvm::StringRef>
53 convertToStringRef(const std::optional<std::string> &from) {
54   std::optional<llvm::StringRef> to;
55   if (from)
56     to = *from;
57   return to;
58 }
59 
60 static std::string readName(llvm::StringRef uniq, std::size_t &i,
61                             std::size_t init, std::size_t end) {
62   for (i = init; i < end && (uniq[i] < 'A' || uniq[i] > 'Z'); ++i) {
63     // do nothing
64   }
65   return uniq.substr(init, i - init).str();
66 }
67 
68 static std::int64_t readInt(llvm::StringRef uniq, std::size_t &i,
69                             std::size_t init, std::size_t end) {
70   for (i = init; i < end && uniq[i] >= '0' && uniq[i] <= '9'; ++i) {
71     // do nothing
72   }
73   std::int64_t result = badValue;
74   if (uniq.substr(init, i - init).getAsInteger(10, result))
75     return badValue;
76   return result;
77 }
78 
79 std::string fir::NameUniquer::toLower(llvm::StringRef name) {
80   return name.lower();
81 }
82 
83 std::string fir::NameUniquer::intAsString(std::int64_t i) {
84   assert(i >= 0);
85   return std::to_string(i);
86 }
87 
88 std::string fir::NameUniquer::doKind(std::int64_t kind) {
89   std::string result = "K";
90   if (kind < 0)
91     return result.append("N").append(intAsString(-kind));
92   return result.append(intAsString(kind));
93 }
94 
95 std::string fir::NameUniquer::doKinds(llvm::ArrayRef<std::int64_t> kinds) {
96   std::string result;
97   for (auto i : kinds)
98     result.append(doKind(i));
99   return result;
100 }
101 
102 std::string fir::NameUniquer::doCommonBlock(llvm::StringRef name) {
103   std::string result = prefix();
104   return result.append("B").append(toLower(name));
105 }
106 
107 std::string fir::NameUniquer::doBlockData(llvm::StringRef name) {
108   std::string result = prefix();
109   return result.append("L").append(toLower(name));
110 }
111 
112 std::string
113 fir::NameUniquer::doConstant(llvm::ArrayRef<llvm::StringRef> modules,
114                              std::optional<llvm::StringRef> host,
115                              llvm::StringRef name) {
116   std::string result = prefix();
117   result.append(doModulesHost(modules, host)).append("EC");
118   return result.append(toLower(name));
119 }
120 
121 std::string
122 fir::NameUniquer::doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules,
123                                   std::optional<llvm::StringRef> host,
124                                   llvm::StringRef name,
125                                   llvm::ArrayRef<std::int64_t> kinds) {
126   std::string result = prefix();
127   result.append(doModulesHost(modules, host)).append("DT");
128   return result.append(toLower(name)).append(doKinds(kinds));
129 }
130 
131 std::string fir::NameUniquer::doGenerated(llvm::StringRef name) {
132   std::string result = prefix();
133   return result.append("Q").append(name);
134 }
135 
136 std::string fir::NameUniquer::doIntrinsicTypeDescriptor(
137     llvm::ArrayRef<llvm::StringRef> modules,
138     std::optional<llvm::StringRef> host, IntrinsicType type,
139     std::int64_t kind) {
140   const char *name = nullptr;
141   switch (type) {
142   case IntrinsicType::CHARACTER:
143     name = "character";
144     break;
145   case IntrinsicType::COMPLEX:
146     name = "complex";
147     break;
148   case IntrinsicType::INTEGER:
149     name = "integer";
150     break;
151   case IntrinsicType::LOGICAL:
152     name = "logical";
153     break;
154   case IntrinsicType::REAL:
155     name = "real";
156     break;
157   }
158   assert(name && "unknown intrinsic type");
159   std::string result = prefix();
160   result.append(doModulesHost(modules, host)).append("C");
161   return result.append(name).append(doKind(kind));
162 }
163 
164 std::string
165 fir::NameUniquer::doProcedure(llvm::ArrayRef<llvm::StringRef> modules,
166                               std::optional<llvm::StringRef> host,
167                               llvm::StringRef name) {
168   std::string result = prefix();
169   result.append(doModulesHost(modules, host)).append("P");
170   return result.append(toLower(name));
171 }
172 
173 std::string fir::NameUniquer::doType(llvm::ArrayRef<llvm::StringRef> modules,
174                                      std::optional<llvm::StringRef> host,
175                                      llvm::StringRef name,
176                                      llvm::ArrayRef<std::int64_t> kinds) {
177   std::string result = prefix();
178   result.append(doModulesHost(modules, host)).append("T");
179   return result.append(toLower(name)).append(doKinds(kinds));
180 }
181 
182 std::string
183 fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
184                                    std::optional<llvm::StringRef> host,
185                                    llvm::StringRef name,
186                                    llvm::ArrayRef<std::int64_t> kinds) {
187   std::string result = prefix();
188   result.append(doModulesHost(modules, host)).append("CT");
189   return result.append(toLower(name)).append(doKinds(kinds));
190 }
191 
192 std::string fir::NameUniquer::doTypeDescriptor(
193     llvm::ArrayRef<std::string> modules, std::optional<std::string> host,
194     llvm::StringRef name, llvm::ArrayRef<std::int64_t> kinds) {
195   auto rmodules = convertToStringRef(modules);
196   auto rhost = convertToStringRef(host);
197   return doTypeDescriptor(rmodules, rhost, name, kinds);
198 }
199 
200 std::string
201 fir::NameUniquer::doVariable(llvm::ArrayRef<llvm::StringRef> modules,
202                              std::optional<llvm::StringRef> host,
203                              llvm::StringRef name) {
204   std::string result = prefix();
205   result.append(doModulesHost(modules, host)).append("E");
206   return result.append(toLower(name));
207 }
208 
209 std::string
210 fir::NameUniquer::doNamelistGroup(llvm::ArrayRef<llvm::StringRef> modules,
211                                   std::optional<llvm::StringRef> host,
212                                   llvm::StringRef name) {
213   std::string result = prefix();
214   result.append(doModulesHost(modules, host)).append("G");
215   return result.append(toLower(name));
216 }
217 
218 llvm::StringRef fir::NameUniquer::doProgramEntry() {
219   if (mainEntryName.size())
220     return mainEntryName;
221   return "_QQmain";
222 }
223 
224 std::pair<fir::NameUniquer::NameKind, fir::NameUniquer::DeconstructedName>
225 fir::NameUniquer::deconstruct(llvm::StringRef uniq) {
226   if (uniq.startswith("_Q")) {
227     llvm::SmallVector<std::string> modules;
228     std::optional<std::string> host;
229     std::string name;
230     llvm::SmallVector<std::int64_t> kinds;
231     NameKind nk = NameKind::NOT_UNIQUED;
232     for (std::size_t i = 2, end{uniq.size()}; i != end;) {
233       switch (uniq[i]) {
234       case 'B':
235         nk = NameKind::COMMON;
236         name = readName(uniq, i, i + 1, end);
237         break;
238       case 'C':
239         if (uniq[i + 1] == 'T') {
240           nk = NameKind::TYPE_DESC;
241           name = readName(uniq, i, i + 2, end);
242         } else {
243           nk = NameKind::INTRINSIC_TYPE_DESC;
244           name = readName(uniq, i, i + 1, end);
245         }
246         break;
247       case 'D':
248         nk = NameKind::DISPATCH_TABLE;
249         assert(uniq[i + 1] == 'T');
250         name = readName(uniq, i, i + 2, end);
251         break;
252       case 'E':
253         if (uniq[i + 1] == 'C') {
254           nk = NameKind::CONSTANT;
255           name = readName(uniq, i, i + 2, end);
256         } else {
257           nk = NameKind::VARIABLE;
258           name = readName(uniq, i, i + 1, end);
259         }
260         break;
261       case 'L':
262         nk = NameKind::BLOCK_DATA_NAME;
263         name = readName(uniq, i, i + 1, end);
264         break;
265       case 'P':
266         nk = NameKind::PROCEDURE;
267         name = readName(uniq, i, i + 1, end);
268         break;
269       case 'Q':
270         nk = NameKind::GENERATED;
271         name = uniq;
272         i = end;
273         break;
274       case 'T':
275         nk = NameKind::DERIVED_TYPE;
276         name = readName(uniq, i, i + 1, end);
277         break;
278 
279       case 'M':
280       case 'S':
281         modules.push_back(readName(uniq, i, i + 1, end));
282         break;
283       case 'F':
284         host = readName(uniq, i, i + 1, end);
285         break;
286       case 'K':
287         if (uniq[i + 1] == 'N')
288           kinds.push_back(-readInt(uniq, i, i + 2, end));
289         else
290           kinds.push_back(readInt(uniq, i, i + 1, end));
291         break;
292       case 'G':
293         nk = NameKind::NAMELIST_GROUP;
294         name = readName(uniq, i, i + 1, end);
295         break;
296 
297       default:
298         assert(false && "unknown uniquing code");
299         break;
300       }
301     }
302     return {nk, DeconstructedName(modules, host, name, kinds)};
303   }
304   return {NameKind::NOT_UNIQUED, DeconstructedName(uniq)};
305 }
306 
307 bool fir::NameUniquer::isExternalFacingUniquedName(
308     const std::pair<fir::NameUniquer::NameKind,
309                     fir::NameUniquer::DeconstructedName> &deconstructResult) {
310   return (deconstructResult.first == NameKind::PROCEDURE ||
311           deconstructResult.first == NameKind::COMMON) &&
312          deconstructResult.second.modules.empty() &&
313          !deconstructResult.second.host;
314 }
315 
316 bool fir::NameUniquer::needExternalNameMangling(llvm::StringRef uniquedName) {
317   auto result = fir::NameUniquer::deconstruct(uniquedName);
318   return result.first != fir::NameUniquer::NameKind::NOT_UNIQUED &&
319          fir::NameUniquer::isExternalFacingUniquedName(result);
320 }
321 
322 bool fir::NameUniquer::belongsToModule(llvm::StringRef uniquedName,
323                                        llvm::StringRef moduleName) {
324   auto result = fir::NameUniquer::deconstruct(uniquedName);
325   return !result.second.modules.empty() &&
326          result.second.modules[0] == moduleName;
327 }
328 
329 static std::string
330 mangleTypeDescriptorKinds(llvm::ArrayRef<std::int64_t> kinds) {
331   if (kinds.empty())
332     return "";
333   std::string result;
334   for (std::int64_t kind : kinds)
335     result += "." + std::to_string(kind);
336   return result;
337 }
338 
339 static std::string getDerivedTypeObjectName(llvm::StringRef mangledTypeName,
340                                             const llvm::StringRef separator) {
341   if (mangledTypeName.ends_with(boxprocSuffix))
342     mangledTypeName = mangledTypeName.drop_back(boxprocSuffix.size());
343   auto result = fir::NameUniquer::deconstruct(mangledTypeName);
344   if (result.first != fir::NameUniquer::NameKind::DERIVED_TYPE)
345     return "";
346   std::string varName = separator.str() + result.second.name +
347                         mangleTypeDescriptorKinds(result.second.kinds);
348   llvm::SmallVector<llvm::StringRef> modules;
349   for (const std::string &mod : result.second.modules)
350     modules.push_back(mod);
351   std::optional<llvm::StringRef> host;
352   if (result.second.host)
353     host = *result.second.host;
354   return fir::NameUniquer::doVariable(modules, host, varName);
355 }
356 
357 std::string
358 fir::NameUniquer::getTypeDescriptorName(llvm::StringRef mangledTypeName) {
359   return getDerivedTypeObjectName(mangledTypeName, typeDescriptorSeparator);
360 }
361 
362 std::string fir::NameUniquer::getTypeDescriptorBindingTableName(
363     llvm::StringRef mangledTypeName) {
364   return getDerivedTypeObjectName(mangledTypeName, bindingTableSeparator);
365 }
366