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 /// Generate a mangling prefix from module, submodule, procedure, and 30 /// statement function names, plus an (innermost) block scope id. 31 static std::string doAncestors(llvm::ArrayRef<llvm::StringRef> modules, 32 llvm::ArrayRef<llvm::StringRef> procs, 33 std::int64_t blockId = 0) { 34 std::string prefix; 35 const char *tag = "M"; 36 for (auto mod : modules) { 37 prefix.append(tag).append(mod.lower()); 38 tag = "S"; 39 } 40 for (auto proc : procs) 41 prefix.append("F").append(proc.lower()); 42 if (blockId) 43 prefix.append("B").append(std::to_string(blockId)); 44 return prefix; 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 return prefix().append("C").append(toLower(name)); 104 } 105 106 std::string 107 fir::NameUniquer::doConstant(llvm::ArrayRef<llvm::StringRef> modules, 108 llvm::ArrayRef<llvm::StringRef> procs, 109 std::int64_t blockId, llvm::StringRef name) { 110 return prefix() 111 .append(doAncestors(modules, procs, blockId)) 112 .append("EC") 113 .append(toLower(name)); 114 } 115 116 std::string 117 fir::NameUniquer::doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules, 118 llvm::ArrayRef<llvm::StringRef> procs, 119 std::int64_t blockId, llvm::StringRef name, 120 llvm::ArrayRef<std::int64_t> kinds) { 121 return prefix() 122 .append(doAncestors(modules, procs, blockId)) 123 .append("DT") 124 .append(toLower(name)) 125 .append(doKinds(kinds)); 126 } 127 128 std::string fir::NameUniquer::doGenerated(llvm::StringRef name) { 129 return prefix().append("Q").append(name); 130 } 131 132 std::string 133 fir::NameUniquer::doGenerated(llvm::ArrayRef<llvm::StringRef> modules, 134 llvm::ArrayRef<llvm::StringRef> procs, 135 std::int64_t blockId, llvm::StringRef name) { 136 return prefix() 137 .append("Q") 138 .append(doAncestors(modules, procs, blockId)) 139 .append(name); 140 } 141 142 std::string fir::NameUniquer::doIntrinsicTypeDescriptor( 143 llvm::ArrayRef<llvm::StringRef> modules, 144 llvm::ArrayRef<llvm::StringRef> procs, std::int64_t blockId, 145 IntrinsicType type, std::int64_t kind) { 146 const char *name = nullptr; 147 switch (type) { 148 case IntrinsicType::CHARACTER: 149 name = "character"; 150 break; 151 case IntrinsicType::COMPLEX: 152 name = "complex"; 153 break; 154 case IntrinsicType::INTEGER: 155 name = "integer"; 156 break; 157 case IntrinsicType::LOGICAL: 158 name = "logical"; 159 break; 160 case IntrinsicType::REAL: 161 name = "real"; 162 break; 163 } 164 assert(name && "unknown intrinsic type"); 165 return prefix() 166 .append(doAncestors(modules, procs, blockId)) 167 .append("YI") 168 .append(name) 169 .append(doKind(kind)); 170 } 171 172 std::string 173 fir::NameUniquer::doProcedure(llvm::ArrayRef<llvm::StringRef> modules, 174 llvm::ArrayRef<llvm::StringRef> procs, 175 llvm::StringRef name) { 176 return prefix() 177 .append(doAncestors(modules, procs)) 178 .append("P") 179 .append(toLower(name)); 180 } 181 182 std::string fir::NameUniquer::doType(llvm::ArrayRef<llvm::StringRef> modules, 183 llvm::ArrayRef<llvm::StringRef> procs, 184 std::int64_t blockId, llvm::StringRef name, 185 llvm::ArrayRef<std::int64_t> kinds) { 186 return prefix() 187 .append(doAncestors(modules, procs, blockId)) 188 .append("T") 189 .append(toLower(name)) 190 .append(doKinds(kinds)); 191 } 192 193 std::string 194 fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules, 195 llvm::ArrayRef<llvm::StringRef> procs, 196 std::int64_t blockId, llvm::StringRef name, 197 llvm::ArrayRef<std::int64_t> kinds) { 198 return prefix() 199 .append(doAncestors(modules, procs, blockId)) 200 .append("CT") 201 .append(toLower(name)) 202 .append(doKinds(kinds)); 203 } 204 205 std::string 206 fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef<std::string> modules, 207 llvm::ArrayRef<std::string> procs, 208 std::int64_t blockId, llvm::StringRef name, 209 llvm::ArrayRef<std::int64_t> kinds) { 210 auto rmodules = convertToStringRef(modules); 211 auto rprocs = convertToStringRef(procs); 212 return doTypeDescriptor(rmodules, rprocs, blockId, name, kinds); 213 } 214 215 std::string 216 fir::NameUniquer::doVariable(llvm::ArrayRef<llvm::StringRef> modules, 217 llvm::ArrayRef<llvm::StringRef> procs, 218 std::int64_t blockId, llvm::StringRef name) { 219 return prefix() 220 .append(doAncestors(modules, procs, blockId)) 221 .append("E") 222 .append(toLower(name)); 223 } 224 225 std::string 226 fir::NameUniquer::doNamelistGroup(llvm::ArrayRef<llvm::StringRef> modules, 227 llvm::ArrayRef<llvm::StringRef> procs, 228 llvm::StringRef name) { 229 return prefix() 230 .append(doAncestors(modules, procs)) 231 .append("N") 232 .append(toLower(name)); 233 } 234 235 llvm::StringRef fir::NameUniquer::doProgramEntry() { 236 if (mainEntryName.size()) 237 return mainEntryName; 238 return "_QQmain"; 239 } 240 241 std::pair<fir::NameUniquer::NameKind, fir::NameUniquer::DeconstructedName> 242 fir::NameUniquer::deconstruct(llvm::StringRef uniq) { 243 uniq = fir::NameUniquer::dropTypeConversionMarkers(uniq); 244 if (uniq.starts_with("_Q")) { 245 llvm::SmallVector<std::string> modules; 246 llvm::SmallVector<std::string> procs; 247 std::int64_t blockId = 0; 248 std::string name; 249 llvm::SmallVector<std::int64_t> kinds; 250 NameKind nk = NameKind::NOT_UNIQUED; 251 for (std::size_t i = 2, end{uniq.size()}; i != end;) { 252 switch (uniq[i]) { 253 case 'B': // Block 254 blockId = readInt(uniq, i, i + 1, end); 255 break; 256 case 'C': // Common block 257 nk = NameKind::COMMON; 258 name = readName(uniq, i, i + 1, end); 259 break; 260 case 'D': // Dispatch table 261 nk = NameKind::DISPATCH_TABLE; 262 assert(uniq[i + 1] == 'T'); 263 name = readName(uniq, i, i + 2, end); 264 break; 265 case 'E': 266 if (uniq[i + 1] == 'C') { // Constant Entity 267 nk = NameKind::CONSTANT; 268 name = readName(uniq, i, i + 2, end); 269 } else { // variable Entity 270 nk = NameKind::VARIABLE; 271 name = readName(uniq, i, i + 1, end); 272 } 273 break; 274 case 'F': // procedure/Function ancestor component of a mangled prefix 275 procs.push_back(readName(uniq, i, i + 1, end)); 276 break; 277 case 'K': 278 if (uniq[i + 1] == 'N') // Negative Kind 279 kinds.push_back(-readInt(uniq, i, i + 2, end)); 280 else // [positive] Kind 281 kinds.push_back(readInt(uniq, i, i + 1, end)); 282 break; 283 case 'M': // Module 284 case 'S': // Submodule 285 modules.push_back(readName(uniq, i, i + 1, end)); 286 break; 287 case 'N': // Namelist group 288 nk = NameKind::NAMELIST_GROUP; 289 name = readName(uniq, i, i + 1, end); 290 break; 291 case 'P': // Procedure/function (itself) 292 nk = NameKind::PROCEDURE; 293 name = readName(uniq, i, i + 1, end); 294 break; 295 case 'Q': // UniQue mangle name tag 296 nk = NameKind::GENERATED; 297 name = uniq; 298 i = end; 299 break; 300 case 'T': // derived Type 301 nk = NameKind::DERIVED_TYPE; 302 name = readName(uniq, i, i + 1, end); 303 break; 304 case 'Y': 305 if (uniq[i + 1] == 'I') { // tYpe descriptor for an Intrinsic type 306 nk = NameKind::INTRINSIC_TYPE_DESC; 307 name = readName(uniq, i, i + 1, end); 308 } else { // tYpe descriptor 309 nk = NameKind::TYPE_DESC; 310 name = readName(uniq, i, i + 2, end); 311 } 312 break; 313 default: 314 assert(false && "unknown uniquing code"); 315 break; 316 } 317 } 318 return {nk, DeconstructedName(modules, procs, blockId, name, kinds)}; 319 } 320 return {NameKind::NOT_UNIQUED, DeconstructedName(uniq)}; 321 } 322 323 bool fir::NameUniquer::isExternalFacingUniquedName( 324 const std::pair<fir::NameUniquer::NameKind, 325 fir::NameUniquer::DeconstructedName> &deconstructResult) { 326 return (deconstructResult.first == NameKind::PROCEDURE || 327 deconstructResult.first == NameKind::COMMON) && 328 deconstructResult.second.modules.empty() && 329 deconstructResult.second.procs.empty(); 330 } 331 332 bool fir::NameUniquer::needExternalNameMangling(llvm::StringRef uniquedName) { 333 auto result = fir::NameUniquer::deconstruct(uniquedName); 334 return result.first != fir::NameUniquer::NameKind::NOT_UNIQUED && 335 fir::NameUniquer::isExternalFacingUniquedName(result); 336 } 337 338 bool fir::NameUniquer::belongsToModule(llvm::StringRef uniquedName, 339 llvm::StringRef moduleName) { 340 auto result = fir::NameUniquer::deconstruct(uniquedName); 341 return !result.second.modules.empty() && 342 result.second.modules[0] == moduleName; 343 } 344 345 static std::string 346 mangleTypeDescriptorKinds(llvm::ArrayRef<std::int64_t> kinds) { 347 if (kinds.empty()) 348 return ""; 349 std::string result; 350 for (std::int64_t kind : kinds) 351 result += "." + std::to_string(kind); 352 return result; 353 } 354 355 static std::string getDerivedTypeObjectName(llvm::StringRef mangledTypeName, 356 const llvm::StringRef separator) { 357 mangledTypeName = 358 fir::NameUniquer::dropTypeConversionMarkers(mangledTypeName); 359 auto result = fir::NameUniquer::deconstruct(mangledTypeName); 360 if (result.first != fir::NameUniquer::NameKind::DERIVED_TYPE) 361 return ""; 362 std::string varName = separator.str() + result.second.name + 363 mangleTypeDescriptorKinds(result.second.kinds); 364 llvm::SmallVector<llvm::StringRef> modules; 365 for (const std::string &mod : result.second.modules) 366 modules.push_back(mod); 367 llvm::SmallVector<llvm::StringRef> procs; 368 for (const std::string &proc : result.second.procs) 369 procs.push_back(proc); 370 return fir::NameUniquer::doVariable(modules, procs, result.second.blockId, 371 varName); 372 } 373 374 std::string 375 fir::NameUniquer::getTypeDescriptorName(llvm::StringRef mangledTypeName) { 376 return getDerivedTypeObjectName(mangledTypeName, typeDescriptorSeparator); 377 } 378 379 std::string fir::NameUniquer::getTypeDescriptorBindingTableName( 380 llvm::StringRef mangledTypeName) { 381 return getDerivedTypeObjectName(mangledTypeName, bindingTableSeparator); 382 } 383 384 std::string 385 fir::NameUniquer::getComponentInitName(llvm::StringRef mangledTypeName, 386 llvm::StringRef componentName) { 387 388 std::string prefix = 389 getDerivedTypeObjectName(mangledTypeName, componentInitSeparator); 390 return prefix + "." + componentName.str(); 391 } 392 393 llvm::StringRef 394 fir::NameUniquer::dropTypeConversionMarkers(llvm::StringRef mangledTypeName) { 395 if (mangledTypeName.ends_with(boxprocSuffix)) 396 return mangledTypeName.drop_back(boxprocSuffix.size()); 397 return mangledTypeName; 398 } 399