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 #include <regex> 20 21 static llvm::cl::opt<std::string> mainEntryName( 22 "main-entry-name", 23 llvm::cl::desc("override the name of the default PROGRAM entry (may be " 24 "helpful for using other runtimes)")); 25 26 constexpr std::int64_t badValue = -1; 27 28 inline std::string prefix() { return "_Q"; } 29 30 /// Generate a mangling prefix from module, submodule, procedure, and 31 /// statement function names, plus an (innermost) block scope id. 32 static std::string doAncestors(llvm::ArrayRef<llvm::StringRef> modules, 33 llvm::ArrayRef<llvm::StringRef> procs, 34 std::int64_t blockId = 0) { 35 std::string prefix; 36 const char *tag = "M"; 37 for (auto mod : modules) { 38 prefix.append(tag).append(mod.lower()); 39 tag = "S"; 40 } 41 for (auto proc : procs) 42 prefix.append("F").append(proc.lower()); 43 if (blockId) 44 prefix.append("B").append(std::to_string(blockId)); 45 return prefix; 46 } 47 48 inline llvm::SmallVector<llvm::StringRef> 49 convertToStringRef(llvm::ArrayRef<std::string> from) { 50 return {from.begin(), from.end()}; 51 } 52 53 inline std::optional<llvm::StringRef> 54 convertToStringRef(const std::optional<std::string> &from) { 55 std::optional<llvm::StringRef> to; 56 if (from) 57 to = *from; 58 return to; 59 } 60 61 static std::string readName(llvm::StringRef uniq, std::size_t &i, 62 std::size_t init, std::size_t end) { 63 // Allow 'X' to be part of the mangled name, which 64 // can happen after the special symbols are replaced 65 // in the mangled names by CompilerGeneratedNamesConversionPass. 66 for (i = init; i < end && (uniq[i] < 'A' || uniq[i] > 'Z' || uniq[i] == 'X'); 67 ++i) { 68 // do nothing 69 } 70 return uniq.substr(init, i - init).str(); 71 } 72 73 static std::int64_t readInt(llvm::StringRef uniq, std::size_t &i, 74 std::size_t init, std::size_t end) { 75 for (i = init; i < end && uniq[i] >= '0' && uniq[i] <= '9'; ++i) { 76 // do nothing 77 } 78 std::int64_t result = badValue; 79 if (uniq.substr(init, i - init).getAsInteger(10, result)) 80 return badValue; 81 return result; 82 } 83 84 std::string fir::NameUniquer::toLower(llvm::StringRef name) { 85 return name.lower(); 86 } 87 88 std::string fir::NameUniquer::intAsString(std::int64_t i) { 89 assert(i >= 0); 90 return std::to_string(i); 91 } 92 93 std::string fir::NameUniquer::doKind(std::int64_t kind) { 94 std::string result = "K"; 95 if (kind < 0) 96 return result.append("N").append(intAsString(-kind)); 97 return result.append(intAsString(kind)); 98 } 99 100 std::string fir::NameUniquer::doKinds(llvm::ArrayRef<std::int64_t> kinds) { 101 std::string result; 102 for (auto i : kinds) 103 result.append(doKind(i)); 104 return result; 105 } 106 107 std::string fir::NameUniquer::doCommonBlock(llvm::StringRef name) { 108 return prefix().append("C").append(toLower(name)); 109 } 110 111 std::string 112 fir::NameUniquer::doConstant(llvm::ArrayRef<llvm::StringRef> modules, 113 llvm::ArrayRef<llvm::StringRef> procs, 114 std::int64_t blockId, llvm::StringRef name) { 115 return prefix() 116 .append(doAncestors(modules, procs, blockId)) 117 .append("EC") 118 .append(toLower(name)); 119 } 120 121 std::string 122 fir::NameUniquer::doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules, 123 llvm::ArrayRef<llvm::StringRef> procs, 124 std::int64_t blockId, llvm::StringRef name, 125 llvm::ArrayRef<std::int64_t> kinds) { 126 return prefix() 127 .append(doAncestors(modules, procs, blockId)) 128 .append("DT") 129 .append(toLower(name)) 130 .append(doKinds(kinds)); 131 } 132 133 std::string fir::NameUniquer::doGenerated(llvm::StringRef name) { 134 return prefix().append("Q").append(name); 135 } 136 137 std::string 138 fir::NameUniquer::doGenerated(llvm::ArrayRef<llvm::StringRef> modules, 139 llvm::ArrayRef<llvm::StringRef> procs, 140 std::int64_t blockId, llvm::StringRef name) { 141 return prefix() 142 .append("Q") 143 .append(doAncestors(modules, procs, blockId)) 144 .append(name); 145 } 146 147 std::string fir::NameUniquer::doIntrinsicTypeDescriptor( 148 llvm::ArrayRef<llvm::StringRef> modules, 149 llvm::ArrayRef<llvm::StringRef> procs, std::int64_t blockId, 150 IntrinsicType type, std::int64_t kind) { 151 const char *name = nullptr; 152 switch (type) { 153 case IntrinsicType::CHARACTER: 154 name = "character"; 155 break; 156 case IntrinsicType::COMPLEX: 157 name = "complex"; 158 break; 159 case IntrinsicType::INTEGER: 160 name = "integer"; 161 break; 162 case IntrinsicType::LOGICAL: 163 name = "logical"; 164 break; 165 case IntrinsicType::REAL: 166 name = "real"; 167 break; 168 } 169 assert(name && "unknown intrinsic type"); 170 return prefix() 171 .append(doAncestors(modules, procs, blockId)) 172 .append("YI") 173 .append(name) 174 .append(doKind(kind)); 175 } 176 177 std::string 178 fir::NameUniquer::doProcedure(llvm::ArrayRef<llvm::StringRef> modules, 179 llvm::ArrayRef<llvm::StringRef> procs, 180 llvm::StringRef name) { 181 return prefix() 182 .append(doAncestors(modules, procs)) 183 .append("P") 184 .append(toLower(name)); 185 } 186 187 std::string fir::NameUniquer::doType(llvm::ArrayRef<llvm::StringRef> modules, 188 llvm::ArrayRef<llvm::StringRef> procs, 189 std::int64_t blockId, llvm::StringRef name, 190 llvm::ArrayRef<std::int64_t> kinds) { 191 return prefix() 192 .append(doAncestors(modules, procs, blockId)) 193 .append("T") 194 .append(toLower(name)) 195 .append(doKinds(kinds)); 196 } 197 198 std::string 199 fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules, 200 llvm::ArrayRef<llvm::StringRef> procs, 201 std::int64_t blockId, llvm::StringRef name, 202 llvm::ArrayRef<std::int64_t> kinds) { 203 return prefix() 204 .append(doAncestors(modules, procs, blockId)) 205 .append("CT") 206 .append(toLower(name)) 207 .append(doKinds(kinds)); 208 } 209 210 std::string 211 fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef<std::string> modules, 212 llvm::ArrayRef<std::string> procs, 213 std::int64_t blockId, llvm::StringRef name, 214 llvm::ArrayRef<std::int64_t> kinds) { 215 auto rmodules = convertToStringRef(modules); 216 auto rprocs = convertToStringRef(procs); 217 return doTypeDescriptor(rmodules, rprocs, blockId, name, kinds); 218 } 219 220 std::string 221 fir::NameUniquer::doVariable(llvm::ArrayRef<llvm::StringRef> modules, 222 llvm::ArrayRef<llvm::StringRef> procs, 223 std::int64_t blockId, llvm::StringRef name) { 224 return prefix() 225 .append(doAncestors(modules, procs, blockId)) 226 .append("E") 227 .append(toLower(name)); 228 } 229 230 std::string 231 fir::NameUniquer::doNamelistGroup(llvm::ArrayRef<llvm::StringRef> modules, 232 llvm::ArrayRef<llvm::StringRef> procs, 233 llvm::StringRef name) { 234 return prefix() 235 .append(doAncestors(modules, procs)) 236 .append("N") 237 .append(toLower(name)); 238 } 239 240 llvm::StringRef fir::NameUniquer::doProgramEntry() { 241 if (mainEntryName.size()) 242 return mainEntryName; 243 return "_QQmain"; 244 } 245 246 std::pair<fir::NameUniquer::NameKind, fir::NameUniquer::DeconstructedName> 247 fir::NameUniquer::deconstruct(llvm::StringRef uniq) { 248 uniq = fir::NameUniquer::dropTypeConversionMarkers(uniq); 249 if (uniq.starts_with("_Q")) { 250 llvm::SmallVector<std::string> modules; 251 llvm::SmallVector<std::string> procs; 252 std::int64_t blockId = 0; 253 std::string name; 254 llvm::SmallVector<std::int64_t> kinds; 255 NameKind nk = NameKind::NOT_UNIQUED; 256 for (std::size_t i = 2, end{uniq.size()}; i != end;) { 257 switch (uniq[i]) { 258 case 'B': // Block 259 blockId = readInt(uniq, i, i + 1, end); 260 break; 261 case 'C': // Common block 262 nk = NameKind::COMMON; 263 name = readName(uniq, i, i + 1, end); 264 break; 265 case 'D': // Dispatch table 266 nk = NameKind::DISPATCH_TABLE; 267 assert(uniq[i + 1] == 'T'); 268 name = readName(uniq, i, i + 2, end); 269 break; 270 case 'E': 271 if (uniq[i + 1] == 'C') { // Constant Entity 272 nk = NameKind::CONSTANT; 273 name = readName(uniq, i, i + 2, end); 274 } else { // variable Entity 275 nk = NameKind::VARIABLE; 276 name = readName(uniq, i, i + 1, end); 277 } 278 break; 279 case 'F': // procedure/Function ancestor component of a mangled prefix 280 procs.push_back(readName(uniq, i, i + 1, end)); 281 break; 282 case 'K': 283 if (uniq[i + 1] == 'N') // Negative Kind 284 kinds.push_back(-readInt(uniq, i, i + 2, end)); 285 else // [positive] Kind 286 kinds.push_back(readInt(uniq, i, i + 1, end)); 287 break; 288 case 'M': // Module 289 case 'S': // Submodule 290 modules.push_back(readName(uniq, i, i + 1, end)); 291 break; 292 case 'N': // Namelist group 293 nk = NameKind::NAMELIST_GROUP; 294 name = readName(uniq, i, i + 1, end); 295 break; 296 case 'P': // Procedure/function (itself) 297 nk = NameKind::PROCEDURE; 298 name = readName(uniq, i, i + 1, end); 299 break; 300 case 'Q': // UniQue mangle name tag 301 nk = NameKind::GENERATED; 302 name = uniq; 303 i = end; 304 break; 305 case 'T': // derived Type 306 nk = NameKind::DERIVED_TYPE; 307 name = readName(uniq, i, i + 1, end); 308 break; 309 case 'Y': 310 if (uniq[i + 1] == 'I') { // tYpe descriptor for an Intrinsic type 311 nk = NameKind::INTRINSIC_TYPE_DESC; 312 name = readName(uniq, i, i + 1, end); 313 } else { // tYpe descriptor 314 nk = NameKind::TYPE_DESC; 315 name = readName(uniq, i, i + 2, end); 316 } 317 break; 318 default: 319 assert(false && "unknown uniquing code"); 320 break; 321 } 322 } 323 return {nk, DeconstructedName(modules, procs, blockId, name, kinds)}; 324 } 325 return {NameKind::NOT_UNIQUED, DeconstructedName(uniq)}; 326 } 327 328 bool fir::NameUniquer::isExternalFacingUniquedName( 329 const std::pair<fir::NameUniquer::NameKind, 330 fir::NameUniquer::DeconstructedName> &deconstructResult) { 331 return (deconstructResult.first == NameKind::PROCEDURE || 332 deconstructResult.first == NameKind::COMMON) && 333 deconstructResult.second.modules.empty() && 334 deconstructResult.second.procs.empty(); 335 } 336 337 bool fir::NameUniquer::needExternalNameMangling(llvm::StringRef uniquedName) { 338 auto result = fir::NameUniquer::deconstruct(uniquedName); 339 return result.first != fir::NameUniquer::NameKind::NOT_UNIQUED && 340 fir::NameUniquer::isExternalFacingUniquedName(result); 341 } 342 343 bool fir::NameUniquer::belongsToModule(llvm::StringRef uniquedName, 344 llvm::StringRef moduleName) { 345 auto result = fir::NameUniquer::deconstruct(uniquedName); 346 return !result.second.modules.empty() && 347 result.second.modules[0] == moduleName; 348 } 349 350 static std::string 351 mangleTypeDescriptorKinds(llvm::ArrayRef<std::int64_t> kinds) { 352 if (kinds.empty()) 353 return ""; 354 std::string result; 355 for (std::int64_t kind : kinds) 356 result += (fir::kNameSeparator + std::to_string(kind)).str(); 357 return result; 358 } 359 360 static std::string getDerivedTypeObjectName(llvm::StringRef mangledTypeName, 361 const llvm::StringRef separator) { 362 mangledTypeName = 363 fir::NameUniquer::dropTypeConversionMarkers(mangledTypeName); 364 auto result = fir::NameUniquer::deconstruct(mangledTypeName); 365 if (result.first != fir::NameUniquer::NameKind::DERIVED_TYPE) 366 return ""; 367 std::string varName = separator.str() + result.second.name + 368 mangleTypeDescriptorKinds(result.second.kinds); 369 llvm::SmallVector<llvm::StringRef> modules; 370 for (const std::string &mod : result.second.modules) 371 modules.push_back(mod); 372 llvm::SmallVector<llvm::StringRef> procs; 373 for (const std::string &proc : result.second.procs) 374 procs.push_back(proc); 375 return fir::NameUniquer::doVariable(modules, procs, result.second.blockId, 376 varName); 377 } 378 379 std::string 380 fir::NameUniquer::getTypeDescriptorName(llvm::StringRef mangledTypeName) { 381 return getDerivedTypeObjectName(mangledTypeName, 382 fir::kTypeDescriptorSeparator); 383 } 384 385 std::string fir::NameUniquer::getTypeDescriptorAssemblyName( 386 llvm::StringRef mangledTypeName) { 387 return replaceSpecialSymbols(getTypeDescriptorName(mangledTypeName)); 388 } 389 390 std::string fir::NameUniquer::getTypeDescriptorBindingTableName( 391 llvm::StringRef mangledTypeName) { 392 return getDerivedTypeObjectName(mangledTypeName, fir::kBindingTableSeparator); 393 } 394 395 std::string 396 fir::NameUniquer::getComponentInitName(llvm::StringRef mangledTypeName, 397 llvm::StringRef componentName) { 398 399 std::string prefix = 400 getDerivedTypeObjectName(mangledTypeName, fir::kComponentInitSeparator); 401 return (prefix + fir::kNameSeparator + componentName).str(); 402 } 403 404 llvm::StringRef 405 fir::NameUniquer::dropTypeConversionMarkers(llvm::StringRef mangledTypeName) { 406 if (mangledTypeName.ends_with(fir::boxprocSuffix)) 407 return mangledTypeName.drop_back(fir::boxprocSuffix.size()); 408 return mangledTypeName; 409 } 410 411 std::string fir::NameUniquer::replaceSpecialSymbols(const std::string &name) { 412 return std::regex_replace(name, std::regex{"\\."}, "X"); 413 } 414 415 bool fir::NameUniquer::isSpecialSymbol(llvm::StringRef name) { 416 return !name.empty() && (name[0] == '.' || name[0] == 'X'); 417 } 418