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 #include "flang/Optimizer/Support/InternalNames.h"
10 #include "mlir/IR/Diagnostics.h"
11 #include "llvm/Support/CommandLine.h"
12 
13 static llvm::cl::opt<std::string> mainEntryName(
14     "main-entry-name",
15     llvm::cl::desc("override the name of the default PROGRAM entry (may be "
16                    "helpful for using other runtimes)"));
17 
18 constexpr std::int64_t BAD_VALUE = -1;
19 
20 inline std::string prefix() { return "_Q"; }
21 
22 static std::string doModules(llvm::ArrayRef<llvm::StringRef> mods) {
23   std::string result;
24   auto *token = "M";
25   for (auto mod : mods) {
26     result.append(token).append(mod);
27     token = "S";
28   }
29   return result;
30 }
31 
32 static std::string doModulesHost(llvm::ArrayRef<llvm::StringRef> mods,
33                                  llvm::Optional<llvm::StringRef> host) {
34   std::string result = doModules(mods);
35   if (host.hasValue())
36     result.append("F").append(*host);
37   return result;
38 }
39 
40 inline llvm::SmallVector<llvm::StringRef, 2>
41 convertToStringRef(llvm::ArrayRef<std::string> from) {
42   return {from.begin(), from.end()};
43 }
44 
45 inline llvm::Optional<llvm::StringRef>
46 convertToStringRef(const llvm::Optional<std::string> &from) {
47   llvm::Optional<llvm::StringRef> to;
48   if (from.hasValue())
49     to = from.getValue();
50   return to;
51 }
52 
53 static std::string readName(llvm::StringRef uniq, std::size_t &i,
54                             std::size_t init, std::size_t end) {
55   for (i = init; i < end && uniq[i] >= 'a' && uniq[i] <= 'z'; ++i) {
56     // do nothing
57   }
58   return uniq.substr(init, i).str();
59 }
60 
61 static std::int64_t readInt(llvm::StringRef uniq, std::size_t &i,
62                             std::size_t init, std::size_t end) {
63   for (i = init; i < end && uniq[i] >= '0' && uniq[i] <= '9'; ++i) {
64     // do nothing
65   }
66   std::int64_t result = BAD_VALUE;
67   if (uniq.substr(init, i).getAsInteger(10, result))
68     return BAD_VALUE;
69   return result;
70 }
71 
72 std::string fir::NameUniquer::toLower(llvm::StringRef name) {
73   return name.lower();
74 }
75 
76 std::string fir::NameUniquer::intAsString(std::int64_t i) {
77   assert(i >= 0);
78   return std::to_string(i);
79 }
80 
81 std::string fir::NameUniquer::doKind(std::int64_t kind) {
82   std::string result = "K";
83   if (kind < 0)
84     return result.append("N").append(intAsString(-kind));
85   return result.append(intAsString(kind));
86 }
87 
88 std::string fir::NameUniquer::doKinds(llvm::ArrayRef<std::int64_t> kinds) {
89   std::string result;
90   for (auto i : kinds)
91     result.append(doKind(i));
92   return result;
93 }
94 
95 std::string fir::NameUniquer::doCommonBlock(llvm::StringRef name) {
96   std::string result = prefix();
97   return result.append("B").append(toLower(name));
98 }
99 
100 std::string
101 fir::NameUniquer::doConstant(llvm::ArrayRef<llvm::StringRef> modules,
102                              llvm::StringRef name) {
103   std::string result = prefix();
104   return result.append(doModules(modules)).append("EC").append(toLower(name));
105 }
106 
107 std::string
108 fir::NameUniquer::doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules,
109                                   llvm::Optional<llvm::StringRef> host,
110                                   llvm::StringRef name,
111                                   llvm::ArrayRef<std::int64_t> kinds) {
112   std::string result = prefix();
113   result.append(doModulesHost(modules, host)).append("DT");
114   return result.append(toLower(name)).append(doKinds(kinds));
115 }
116 
117 std::string fir::NameUniquer::doGenerated(llvm::StringRef name) {
118   std::string result = prefix();
119   return result.append("Q").append(name);
120 }
121 
122 std::string fir::NameUniquer::doIntrinsicTypeDescriptor(
123     llvm::ArrayRef<llvm::StringRef> modules,
124     llvm::Optional<llvm::StringRef> host, IntrinsicType type,
125     std::int64_t kind) {
126   const char *name = nullptr;
127   switch (type) {
128   case IntrinsicType::CHARACTER:
129     name = "character";
130     break;
131   case IntrinsicType::COMPLEX:
132     name = "complex";
133     break;
134   case IntrinsicType::INTEGER:
135     name = "integer";
136     break;
137   case IntrinsicType::LOGICAL:
138     name = "logical";
139     break;
140   case IntrinsicType::REAL:
141     name = "real";
142     break;
143   }
144   assert(name && "unknown intrinsic type");
145   std::string result = prefix();
146   result.append(doModulesHost(modules, host)).append("C");
147   return result.append(name).append(doKind(kind));
148 }
149 
150 std::string
151 fir::NameUniquer::doProcedure(llvm::ArrayRef<llvm::StringRef> modules,
152                               llvm::Optional<llvm::StringRef> host,
153                               llvm::StringRef name) {
154   std::string result = prefix();
155   result.append(doModulesHost(modules, host)).append("P");
156   return result.append(toLower(name));
157 }
158 
159 std::string fir::NameUniquer::doType(llvm::ArrayRef<llvm::StringRef> modules,
160                                      llvm::Optional<llvm::StringRef> host,
161                                      llvm::StringRef name,
162                                      llvm::ArrayRef<std::int64_t> kinds) {
163   std::string result = prefix();
164   result.append(doModulesHost(modules, host)).append("T");
165   return result.append(toLower(name)).append(doKinds(kinds));
166 }
167 
168 std::string
169 fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
170                                    llvm::Optional<llvm::StringRef> host,
171                                    llvm::StringRef name,
172                                    llvm::ArrayRef<std::int64_t> kinds) {
173   std::string result = prefix();
174   result.append(doModulesHost(modules, host)).append("CT");
175   return result.append(toLower(name)).append(doKinds(kinds));
176 }
177 
178 std::string fir::NameUniquer::doTypeDescriptor(
179     llvm::ArrayRef<std::string> modules, llvm::Optional<std::string> host,
180     llvm::StringRef name, llvm::ArrayRef<std::int64_t> kinds) {
181   auto rmodules = convertToStringRef(modules);
182   auto rhost = convertToStringRef(host);
183   return doTypeDescriptor(rmodules, rhost, name, kinds);
184 }
185 
186 std::string
187 fir::NameUniquer::doVariable(llvm::ArrayRef<llvm::StringRef> modules,
188                              llvm::Optional<llvm::StringRef> host,
189                              llvm::StringRef name) {
190   std::string result = prefix();
191   result.append(doModulesHost(modules, host)).append("E");
192   return result.append(toLower(name));
193 }
194 
195 llvm::StringRef fir::NameUniquer::doProgramEntry() {
196   if (mainEntryName.size())
197     return mainEntryName;
198   return "_QQmain";
199 }
200 
201 std::pair<fir::NameUniquer::NameKind, fir::NameUniquer::DeconstructedName>
202 fir::NameUniquer::deconstruct(llvm::StringRef uniq) {
203   if (uniq.startswith("_Q")) {
204     llvm::SmallVector<std::string, 4> modules;
205     llvm::Optional<std::string> host;
206     std::string name;
207     llvm::SmallVector<std::int64_t, 8> kinds;
208     NameKind nk = NameKind::NOT_UNIQUED;
209     for (std::size_t i = 2, end{uniq.size()}; i != end;) {
210       switch (uniq[i]) {
211       case 'B':
212         nk = NameKind::COMMON;
213         name = readName(uniq, i, i + 1, end);
214         break;
215       case 'C':
216         if (uniq[i + 1] == 'T') {
217           nk = NameKind::TYPE_DESC;
218           name = readName(uniq, i, i + 2, end);
219         } else {
220           nk = NameKind::INTRINSIC_TYPE_DESC;
221           name = readName(uniq, i, i + 1, end);
222         }
223         break;
224       case 'D':
225         nk = NameKind::DISPATCH_TABLE;
226         assert(uniq[i + 1] == 'T');
227         name = readName(uniq, i, i + 2, end);
228         break;
229       case 'E':
230         if (uniq[i + 1] == 'C') {
231           nk = NameKind::CONSTANT;
232           name = readName(uniq, i, i + 2, end);
233         } else {
234           nk = NameKind::VARIABLE;
235           name = readName(uniq, i, i + 1, end);
236         }
237         break;
238       case 'P':
239         nk = NameKind::PROCEDURE;
240         name = readName(uniq, i, i + 1, end);
241         break;
242       case 'Q':
243         nk = NameKind::GENERATED;
244         name = uniq;
245         i = end;
246         break;
247       case 'T':
248         nk = NameKind::DERIVED_TYPE;
249         name = readName(uniq, i, i + 1, end);
250         break;
251 
252       case 'M':
253       case 'S':
254         modules.push_back(readName(uniq, i, i + 1, end));
255         break;
256       case 'F':
257         host = readName(uniq, i, i + 1, end);
258         break;
259       case 'K':
260         if (uniq[i + 1] == 'N')
261           kinds.push_back(-readInt(uniq, i, i + 2, end));
262         else
263           kinds.push_back(readInt(uniq, i, i + 1, end));
264         break;
265 
266       default:
267         assert(false && "unknown uniquing code");
268         break;
269       }
270     }
271     return {nk, DeconstructedName(modules, host, name, kinds)};
272   }
273   return {NameKind::NOT_UNIQUED, DeconstructedName(uniq)};
274 }
275