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