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 
prefix()20 inline std::string prefix() { return "_Q"; }
21 
doModules(llvm::ArrayRef<llvm::StringRef> mods)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.lower());
27     token = "S";
28   }
29   return result;
30 }
31 
doModulesHost(llvm::ArrayRef<llvm::StringRef> mods,llvm::Optional<llvm::StringRef> host)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->lower());
37   return result;
38 }
39 
40 inline llvm::SmallVector<llvm::StringRef, 2>
convertToStringRef(llvm::ArrayRef<std::string> from)41 convertToStringRef(llvm::ArrayRef<std::string> from) {
42   return {from.begin(), from.end()};
43 }
44 
45 inline llvm::Optional<llvm::StringRef>
convertToStringRef(const llvm::Optional<std::string> & from)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 
readName(llvm::StringRef uniq,std::size_t & i,std::size_t init,std::size_t end)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 - init).str();
59 }
60 
readInt(llvm::StringRef uniq,std::size_t & i,std::size_t init,std::size_t end)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 - init).getAsInteger(10, result))
68     return BAD_VALUE;
69   return result;
70 }
71 
toLower(llvm::StringRef name)72 std::string fir::NameUniquer::toLower(llvm::StringRef name) {
73   return name.lower();
74 }
75 
intAsString(std::int64_t i)76 std::string fir::NameUniquer::intAsString(std::int64_t i) {
77   assert(i >= 0);
78   return std::to_string(i);
79 }
80 
doKind(std::int64_t kind)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 
doKinds(llvm::ArrayRef<std::int64_t> kinds)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 
doCommonBlock(llvm::StringRef name)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
doConstant(llvm::ArrayRef<llvm::StringRef> modules,llvm::Optional<llvm::StringRef> host,llvm::StringRef name)101 fir::NameUniquer::doConstant(llvm::ArrayRef<llvm::StringRef> modules,
102                              llvm::Optional<llvm::StringRef> host,
103                              llvm::StringRef name) {
104   std::string result = prefix();
105   result.append(doModulesHost(modules, host)).append("EC");
106   return result.append(toLower(name));
107 }
108 
109 std::string
doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules,llvm::Optional<llvm::StringRef> host,llvm::StringRef name,llvm::ArrayRef<std::int64_t> kinds)110 fir::NameUniquer::doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules,
111                                   llvm::Optional<llvm::StringRef> host,
112                                   llvm::StringRef name,
113                                   llvm::ArrayRef<std::int64_t> kinds) {
114   std::string result = prefix();
115   result.append(doModulesHost(modules, host)).append("DT");
116   return result.append(toLower(name)).append(doKinds(kinds));
117 }
118 
doGenerated(llvm::StringRef name)119 std::string fir::NameUniquer::doGenerated(llvm::StringRef name) {
120   std::string result = prefix();
121   return result.append("Q").append(name);
122 }
123 
doIntrinsicTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,llvm::Optional<llvm::StringRef> host,IntrinsicType type,std::int64_t kind)124 std::string fir::NameUniquer::doIntrinsicTypeDescriptor(
125     llvm::ArrayRef<llvm::StringRef> modules,
126     llvm::Optional<llvm::StringRef> host, IntrinsicType type,
127     std::int64_t kind) {
128   const char *name = nullptr;
129   switch (type) {
130   case IntrinsicType::CHARACTER:
131     name = "character";
132     break;
133   case IntrinsicType::COMPLEX:
134     name = "complex";
135     break;
136   case IntrinsicType::INTEGER:
137     name = "integer";
138     break;
139   case IntrinsicType::LOGICAL:
140     name = "logical";
141     break;
142   case IntrinsicType::REAL:
143     name = "real";
144     break;
145   }
146   assert(name && "unknown intrinsic type");
147   std::string result = prefix();
148   result.append(doModulesHost(modules, host)).append("C");
149   return result.append(name).append(doKind(kind));
150 }
151 
152 std::string
doProcedure(llvm::ArrayRef<llvm::StringRef> modules,llvm::Optional<llvm::StringRef> host,llvm::StringRef name)153 fir::NameUniquer::doProcedure(llvm::ArrayRef<llvm::StringRef> modules,
154                               llvm::Optional<llvm::StringRef> host,
155                               llvm::StringRef name) {
156   std::string result = prefix();
157   result.append(doModulesHost(modules, host)).append("P");
158   return result.append(toLower(name));
159 }
160 
doType(llvm::ArrayRef<llvm::StringRef> modules,llvm::Optional<llvm::StringRef> host,llvm::StringRef name,llvm::ArrayRef<std::int64_t> kinds)161 std::string fir::NameUniquer::doType(llvm::ArrayRef<llvm::StringRef> modules,
162                                      llvm::Optional<llvm::StringRef> host,
163                                      llvm::StringRef name,
164                                      llvm::ArrayRef<std::int64_t> kinds) {
165   std::string result = prefix();
166   result.append(doModulesHost(modules, host)).append("T");
167   return result.append(toLower(name)).append(doKinds(kinds));
168 }
169 
170 std::string
doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,llvm::Optional<llvm::StringRef> host,llvm::StringRef name,llvm::ArrayRef<std::int64_t> kinds)171 fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
172                                    llvm::Optional<llvm::StringRef> host,
173                                    llvm::StringRef name,
174                                    llvm::ArrayRef<std::int64_t> kinds) {
175   std::string result = prefix();
176   result.append(doModulesHost(modules, host)).append("CT");
177   return result.append(toLower(name)).append(doKinds(kinds));
178 }
179 
doTypeDescriptor(llvm::ArrayRef<std::string> modules,llvm::Optional<std::string> host,llvm::StringRef name,llvm::ArrayRef<std::int64_t> kinds)180 std::string fir::NameUniquer::doTypeDescriptor(
181     llvm::ArrayRef<std::string> modules, llvm::Optional<std::string> host,
182     llvm::StringRef name, llvm::ArrayRef<std::int64_t> kinds) {
183   auto rmodules = convertToStringRef(modules);
184   auto rhost = convertToStringRef(host);
185   return doTypeDescriptor(rmodules, rhost, name, kinds);
186 }
187 
188 std::string
doVariable(llvm::ArrayRef<llvm::StringRef> modules,llvm::Optional<llvm::StringRef> host,llvm::StringRef name)189 fir::NameUniquer::doVariable(llvm::ArrayRef<llvm::StringRef> modules,
190                              llvm::Optional<llvm::StringRef> host,
191                              llvm::StringRef name) {
192   std::string result = prefix();
193   result.append(doModulesHost(modules, host)).append("E");
194   return result.append(toLower(name));
195 }
196 
doProgramEntry()197 llvm::StringRef fir::NameUniquer::doProgramEntry() {
198   if (mainEntryName.size())
199     return mainEntryName;
200   return "_QQmain";
201 }
202 
203 std::pair<fir::NameUniquer::NameKind, fir::NameUniquer::DeconstructedName>
deconstruct(llvm::StringRef uniq)204 fir::NameUniquer::deconstruct(llvm::StringRef uniq) {
205   if (uniq.startswith("_Q")) {
206     llvm::SmallVector<std::string, 4> modules;
207     llvm::Optional<std::string> host;
208     std::string name;
209     llvm::SmallVector<std::int64_t, 8> kinds;
210     NameKind nk = NameKind::NOT_UNIQUED;
211     for (std::size_t i = 2, end{uniq.size()}; i != end;) {
212       switch (uniq[i]) {
213       case 'B':
214         nk = NameKind::COMMON;
215         name = readName(uniq, i, i + 1, end);
216         break;
217       case 'C':
218         if (uniq[i + 1] == 'T') {
219           nk = NameKind::TYPE_DESC;
220           name = readName(uniq, i, i + 2, end);
221         } else {
222           nk = NameKind::INTRINSIC_TYPE_DESC;
223           name = readName(uniq, i, i + 1, end);
224         }
225         break;
226       case 'D':
227         nk = NameKind::DISPATCH_TABLE;
228         assert(uniq[i + 1] == 'T');
229         name = readName(uniq, i, i + 2, end);
230         break;
231       case 'E':
232         if (uniq[i + 1] == 'C') {
233           nk = NameKind::CONSTANT;
234           name = readName(uniq, i, i + 2, end);
235         } else {
236           nk = NameKind::VARIABLE;
237           name = readName(uniq, i, i + 1, end);
238         }
239         break;
240       case 'P':
241         nk = NameKind::PROCEDURE;
242         name = readName(uniq, i, i + 1, end);
243         break;
244       case 'Q':
245         nk = NameKind::GENERATED;
246         name = uniq;
247         i = end;
248         break;
249       case 'T':
250         nk = NameKind::DERIVED_TYPE;
251         name = readName(uniq, i, i + 1, end);
252         break;
253 
254       case 'M':
255       case 'S':
256         modules.push_back(readName(uniq, i, i + 1, end));
257         break;
258       case 'F':
259         host = readName(uniq, i, i + 1, end);
260         break;
261       case 'K':
262         if (uniq[i + 1] == 'N')
263           kinds.push_back(-readInt(uniq, i, i + 2, end));
264         else
265           kinds.push_back(readInt(uniq, i, i + 1, end));
266         break;
267 
268       default:
269         assert(false && "unknown uniquing code");
270         break;
271       }
272     }
273     return {nk, DeconstructedName(modules, host, name, kinds)};
274   }
275   return {NameKind::NOT_UNIQUED, DeconstructedName(uniq)};
276 }
277