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