1 //===-- ClangBuiltinsEmitter.cpp - Generate Clang builtins tables ---------===// 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 // This tablegen backend emits Clang's builtins tables. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "TableGenBackends.h" 14 #include "llvm/ADT/StringExtras.h" 15 #include "llvm/ADT/StringSwitch.h" 16 #include "llvm/TableGen/Error.h" 17 #include "llvm/TableGen/Record.h" 18 #include "llvm/TableGen/StringToOffsetTable.h" 19 #include "llvm/TableGen/TableGenBackend.h" 20 #include <sstream> 21 22 using namespace llvm; 23 24 namespace { 25 enum class BuiltinType { 26 Builtin, 27 AtomicBuiltin, 28 LibBuiltin, 29 LangBuiltin, 30 TargetBuiltin, 31 TargetLibBuiltin, 32 }; 33 34 class HeaderNameParser { 35 public: 36 HeaderNameParser(const Record *Builtin) { 37 for (char c : Builtin->getValueAsString("Header")) { 38 if (std::islower(c)) 39 HeaderName += static_cast<char>(std::toupper(c)); 40 else if (c == '.' || c == '_' || c == '/' || c == '-') 41 HeaderName += '_'; 42 else 43 PrintFatalError(Builtin->getLoc(), "Unexpected header name"); 44 } 45 } 46 47 void Print(raw_ostream &OS) const { OS << HeaderName; } 48 49 private: 50 std::string HeaderName; 51 }; 52 53 struct Builtin { 54 BuiltinType BT; 55 std::string Name; 56 std::string Type; 57 std::string Attributes; 58 59 const Record *BuiltinRecord; 60 61 void EmitEnumerator(llvm::raw_ostream &OS) const { 62 OS << " BI"; 63 // If there is a required name prefix, include its spelling in the 64 // enumerator. 65 if (auto *PrefixRecord = 66 BuiltinRecord->getValueAsOptionalDef("RequiredNamePrefix")) 67 OS << PrefixRecord->getValueAsString("Spelling"); 68 OS << Name << ",\n"; 69 } 70 71 void EmitInfo(llvm::raw_ostream &OS, const StringToOffsetTable &Table) const { 72 OS << " Builtin::Info{Builtin::Info::StrOffsets{" 73 << Table.GetStringOffset(Name) << " /* " << Name << " */, " 74 << Table.GetStringOffset(Type) << " /* " << Type << " */, " 75 << Table.GetStringOffset(Attributes) << " /* " << Attributes << " */, "; 76 if (BT == BuiltinType::TargetBuiltin) { 77 const auto &Features = BuiltinRecord->getValueAsString("Features"); 78 OS << Table.GetStringOffset(Features) << " /* " << Features << " */"; 79 } else { 80 OS << "0"; 81 } 82 OS << "}, "; 83 if (BT == BuiltinType::LibBuiltin || BT == BuiltinType::TargetLibBuiltin) { 84 OS << "HeaderDesc::"; 85 HeaderNameParser{BuiltinRecord}.Print(OS); 86 } else { 87 OS << "HeaderDesc::NO_HEADER"; 88 } 89 OS << ", "; 90 if (BT == BuiltinType::LibBuiltin || BT == BuiltinType::LangBuiltin || 91 BT == BuiltinType::TargetLibBuiltin) { 92 OS << BuiltinRecord->getValueAsString("Languages"); 93 } else { 94 OS << "ALL_LANGUAGES"; 95 } 96 OS << "},\n"; 97 } 98 99 void EmitXMacro(llvm::raw_ostream &OS) const { 100 if (BuiltinRecord->getValueAsBit("RequiresUndef")) 101 OS << "#undef " << Name << '\n'; 102 switch (BT) { 103 case BuiltinType::LibBuiltin: 104 OS << "LIBBUILTIN"; 105 break; 106 case BuiltinType::LangBuiltin: 107 OS << "LANGBUILTIN"; 108 break; 109 case BuiltinType::Builtin: 110 OS << "BUILTIN"; 111 break; 112 case BuiltinType::AtomicBuiltin: 113 OS << "ATOMIC_BUILTIN"; 114 break; 115 case BuiltinType::TargetBuiltin: 116 OS << "TARGET_BUILTIN"; 117 break; 118 case BuiltinType::TargetLibBuiltin: 119 OS << "TARGET_HEADER_BUILTIN"; 120 break; 121 } 122 123 OS << "(" << Name << ", \"" << Type << "\", \"" << Attributes << "\""; 124 125 switch (BT) { 126 case BuiltinType::LibBuiltin: { 127 OS << ", "; 128 HeaderNameParser{BuiltinRecord}.Print(OS); 129 [[fallthrough]]; 130 } 131 case BuiltinType::LangBuiltin: { 132 OS << ", " << BuiltinRecord->getValueAsString("Languages"); 133 break; 134 } 135 case BuiltinType::TargetLibBuiltin: { 136 OS << ", "; 137 HeaderNameParser{BuiltinRecord}.Print(OS); 138 OS << ", " << BuiltinRecord->getValueAsString("Languages"); 139 [[fallthrough]]; 140 } 141 case BuiltinType::TargetBuiltin: { 142 OS << ", \"" << BuiltinRecord->getValueAsString("Features") << "\""; 143 break; 144 } 145 case BuiltinType::AtomicBuiltin: 146 case BuiltinType::Builtin: 147 break; 148 } 149 OS << ")\n"; 150 } 151 }; 152 153 class PrototypeParser { 154 public: 155 PrototypeParser(StringRef Substitution, const Record *Builtin) 156 : Loc(Builtin->getFieldLoc("Prototype")), Substitution(Substitution), 157 EnableOpenCLLong(Builtin->getValueAsBit("EnableOpenCLLong")) { 158 ParsePrototype(Builtin->getValueAsString("Prototype")); 159 } 160 161 std::string takeTypeString() && { return std::move(Type); } 162 163 private: 164 void ParsePrototype(StringRef Prototype) { 165 Prototype = Prototype.trim(); 166 167 // Some builtins don't have an expressible prototype, simply emit an empty 168 // string for them. 169 if (Prototype.empty()) { 170 Type = ""; 171 return; 172 } 173 174 ParseTypes(Prototype); 175 } 176 177 void ParseTypes(StringRef &Prototype) { 178 auto ReturnType = Prototype.take_until([](char c) { return c == '('; }); 179 ParseType(ReturnType); 180 Prototype = Prototype.drop_front(ReturnType.size() + 1); 181 if (!Prototype.ends_with(")")) 182 PrintFatalError(Loc, "Expected closing brace at end of prototype"); 183 Prototype = Prototype.drop_back(); 184 185 // Look through the input parameters. 186 const size_t end = Prototype.size(); 187 for (size_t I = 0; I != end;) { 188 const StringRef Current = Prototype.substr(I, end); 189 // Skip any leading space or commas 190 if (Current.starts_with(" ") || Current.starts_with(",")) { 191 ++I; 192 continue; 193 } 194 195 // Check if we are in _ExtVector. We do this first because 196 // extended vectors are written in template form with the syntax 197 // _ExtVector< ..., ...>, so we need to make sure we are not 198 // detecting the comma of the template class as a separator for 199 // the parameters of the prototype. Note: the assumption is that 200 // we cannot have nested _ExtVector. 201 if (Current.starts_with("_ExtVector<") || 202 Current.starts_with("_Vector<")) { 203 const size_t EndTemplate = Current.find('>', 0); 204 ParseType(Current.substr(0, EndTemplate + 1)); 205 // Move the prototype beyond _ExtVector<...> 206 I += EndTemplate + 1; 207 continue; 208 } 209 210 // We know that we are past _ExtVector, therefore the first seen 211 // comma is the boundary of a parameter in the prototype. 212 if (size_t CommaPos = Current.find(',', 0)) { 213 if (CommaPos != StringRef::npos) { 214 StringRef T = Current.substr(0, CommaPos); 215 ParseType(T); 216 // Move the prototype beyond the comma. 217 I += CommaPos + 1; 218 continue; 219 } 220 } 221 222 // No more commas, parse final parameter. 223 ParseType(Current); 224 I = end; 225 } 226 } 227 228 void ParseType(StringRef T) { 229 T = T.trim(); 230 231 auto ConsumeAddrSpace = [&]() -> std::optional<unsigned> { 232 T = T.trim(); 233 if (!T.consume_back(">")) 234 return std::nullopt; 235 236 auto Open = T.find_last_of('<'); 237 if (Open == StringRef::npos) 238 PrintFatalError(Loc, "Mismatched angle-brackets in type"); 239 240 StringRef ArgStr = T.substr(Open + 1); 241 T = T.slice(0, Open); 242 if (!T.consume_back("address_space")) 243 PrintFatalError(Loc, 244 "Only `address_space<N>` supported as a parameterized " 245 "pointer or reference type qualifier"); 246 247 unsigned Number = 0; 248 if (ArgStr.getAsInteger(10, Number)) 249 PrintFatalError( 250 Loc, "Expected an integer argument to the address_space qualifier"); 251 if (Number == 0) 252 PrintFatalError(Loc, "No need for a qualifier for address space `0`"); 253 return Number; 254 }; 255 256 if (T.consume_back("*")) { 257 // Pointers may have an address space qualifier immediately before them. 258 std::optional<unsigned> AS = ConsumeAddrSpace(); 259 ParseType(T); 260 Type += "*"; 261 if (AS) 262 Type += std::to_string(*AS); 263 } else if (T.consume_back("const")) { 264 ParseType(T); 265 Type += "C"; 266 } else if (T.consume_back("volatile")) { 267 ParseType(T); 268 Type += "D"; 269 } else if (T.consume_back("restrict")) { 270 ParseType(T); 271 Type += "R"; 272 } else if (T.consume_back("&")) { 273 // References may have an address space qualifier immediately before them. 274 std::optional<unsigned> AS = ConsumeAddrSpace(); 275 ParseType(T); 276 Type += "&"; 277 if (AS) 278 Type += std::to_string(*AS); 279 } else if (T.consume_back(")")) { 280 ParseType(T); 281 Type += "&"; 282 } else if (EnableOpenCLLong && T.consume_front("long long")) { 283 Type += "O"; 284 ParseType(T); 285 } else if (T.consume_front("long")) { 286 Type += "L"; 287 ParseType(T); 288 } else if (T.consume_front("signed")) { 289 Type += "S"; 290 ParseType(T); 291 } else if (T.consume_front("unsigned")) { 292 Type += "U"; 293 ParseType(T); 294 } else if (T.consume_front("_Complex")) { 295 Type += "X"; 296 ParseType(T); 297 } else if (T.consume_front("_Constant")) { 298 Type += "I"; 299 ParseType(T); 300 } else if (T.consume_front("T")) { 301 if (Substitution.empty()) 302 PrintFatalError(Loc, "Not a template"); 303 ParseType(Substitution); 304 } else if (auto IsExt = T.consume_front("_ExtVector"); 305 IsExt || T.consume_front("_Vector")) { 306 // Clang extended vector types are mangled as follows: 307 // 308 // '_ExtVector<' <lanes> ',' <scalar type> '>' 309 310 // Before parsing T(=<scalar type>), make sure the syntax of 311 // `_ExtVector<N, T>` is correct... 312 if (!T.consume_front("<")) 313 PrintFatalError(Loc, "Expected '<' after '_ExtVector'"); 314 unsigned long long Lanes; 315 if (consumeUnsignedInteger(T, 10, Lanes)) 316 PrintFatalError(Loc, "Expected number of lanes after '_ExtVector<'"); 317 Type += (IsExt ? "E" : "V") + std::to_string(Lanes); 318 if (!T.consume_front(",")) 319 PrintFatalError(Loc, 320 "Expected ',' after number of lanes in '_ExtVector<'"); 321 if (!T.consume_back(">")) 322 PrintFatalError( 323 Loc, "Expected '>' after scalar type in '_ExtVector<N, type>'"); 324 325 // ...all good, we can check if we have a valid `<scalar type>`. 326 ParseType(T); 327 } else { 328 auto ReturnTypeVal = StringSwitch<std::string>(T) 329 .Case("__builtin_va_list_ref", "A") 330 .Case("__builtin_va_list", "a") 331 .Case("__float128", "LLd") 332 .Case("__fp16", "h") 333 .Case("__int128_t", "LLLi") 334 .Case("_Float16", "x") 335 .Case("__bf16", "y") 336 .Case("bool", "b") 337 .Case("char", "c") 338 .Case("constant_CFString", "F") 339 .Case("double", "d") 340 .Case("FILE", "P") 341 .Case("float", "f") 342 .Case("id", "G") 343 .Case("int", "i") 344 .Case("int32_t", "Zi") 345 .Case("int64_t", "Wi") 346 .Case("jmp_buf", "J") 347 .Case("msint32_t", "Ni") 348 .Case("msuint32_t", "UNi") 349 .Case("objc_super", "M") 350 .Case("pid_t", "p") 351 .Case("ptrdiff_t", "Y") 352 .Case("SEL", "H") 353 .Case("short", "s") 354 .Case("sigjmp_buf", "SJ") 355 .Case("size_t", "z") 356 .Case("ucontext_t", "K") 357 .Case("uint32_t", "UZi") 358 .Case("uint64_t", "UWi") 359 .Case("void", "v") 360 .Case("wchar_t", "w") 361 .Case("...", ".") 362 .Default("error"); 363 if (ReturnTypeVal == "error") 364 PrintFatalError(Loc, "Unknown Type: " + T); 365 Type += ReturnTypeVal; 366 } 367 } 368 369 SMLoc Loc; 370 StringRef Substitution; 371 bool EnableOpenCLLong; 372 std::string Type; 373 }; 374 375 std::string renderAttributes(const Record *Builtin, BuiltinType BT) { 376 std::string Attributes; 377 raw_string_ostream OS(Attributes); 378 if (Builtin->isSubClassOf("LibBuiltin")) { 379 if (BT == BuiltinType::LibBuiltin) { 380 OS << 'f'; 381 } else { 382 OS << 'F'; 383 if (Builtin->getValueAsBit("OnlyBuiltinPrefixedAliasIsConstexpr")) 384 OS << 'E'; 385 } 386 } 387 388 if (auto NS = Builtin->getValueAsOptionalString("Namespace")) { 389 if (NS != "std") 390 PrintFatalError(Builtin->getFieldLoc("Namespace"), "Unknown namespace: "); 391 OS << "z"; 392 } 393 394 for (const auto *Attr : Builtin->getValueAsListOfDefs("Attributes")) { 395 OS << Attr->getValueAsString("Mangling"); 396 if (Attr->isSubClassOf("IndexedAttribute")) { 397 OS << ':' << Attr->getValueAsInt("Index") << ':'; 398 } else if (Attr->isSubClassOf("MultiIndexAttribute")) { 399 OS << '<'; 400 llvm::ListSeparator Sep(","); 401 for (int64_t Index : Attr->getValueAsListOfInts("Indices")) 402 OS << Sep << Index; 403 OS << '>'; 404 } 405 } 406 return Attributes; 407 } 408 409 Builtin buildBuiltin(StringRef Substitution, const Record *BuiltinRecord, 410 Twine Spelling, BuiltinType BT) { 411 Builtin B; 412 B.BT = BT; 413 B.Name = Spelling.str(); 414 B.Type = PrototypeParser(Substitution, BuiltinRecord).takeTypeString(); 415 B.Attributes = renderAttributes(BuiltinRecord, BT); 416 B.BuiltinRecord = BuiltinRecord; 417 return B; 418 } 419 420 struct TemplateInsts { 421 std::vector<std::string> Substitution; 422 std::vector<std::string> Affix; 423 bool IsPrefix; 424 }; 425 426 TemplateInsts getTemplateInsts(const Record *R) { 427 TemplateInsts temp; 428 auto Substitutions = R->getValueAsListOfStrings("Substitutions"); 429 auto Affixes = R->getValueAsListOfStrings("Affixes"); 430 temp.IsPrefix = R->getValueAsBit("AsPrefix"); 431 432 if (Substitutions.size() != Affixes.size()) 433 PrintFatalError(R->getLoc(), "Substitutions and affixes " 434 "don't have the same lengths"); 435 436 for (auto [Affix, Substitution] : zip(Affixes, Substitutions)) { 437 temp.Substitution.emplace_back(Substitution); 438 temp.Affix.emplace_back(Affix); 439 } 440 return temp; 441 } 442 443 void collectBuiltins(const Record *BuiltinRecord, 444 SmallVectorImpl<Builtin> &Builtins) { 445 TemplateInsts Templates = {}; 446 if (BuiltinRecord->isSubClassOf("Template")) { 447 Templates = getTemplateInsts(BuiltinRecord); 448 } else { 449 Templates.Affix.emplace_back(); 450 Templates.Substitution.emplace_back(); 451 } 452 453 for (auto [Substitution, Affix] : 454 zip(Templates.Substitution, Templates.Affix)) { 455 for (StringRef Spelling : 456 BuiltinRecord->getValueAsListOfStrings("Spellings")) { 457 auto FullSpelling = 458 (Templates.IsPrefix ? Affix + Spelling : Spelling + Affix).str(); 459 BuiltinType BT = BuiltinType::Builtin; 460 if (BuiltinRecord->isSubClassOf("AtomicBuiltin")) { 461 BT = BuiltinType::AtomicBuiltin; 462 } else if (BuiltinRecord->isSubClassOf("LangBuiltin")) { 463 BT = BuiltinType::LangBuiltin; 464 } else if (BuiltinRecord->isSubClassOf("TargetLibBuiltin")) { 465 BT = BuiltinType::TargetLibBuiltin; 466 } else if (BuiltinRecord->isSubClassOf("TargetBuiltin")) { 467 BT = BuiltinType::TargetBuiltin; 468 } else if (BuiltinRecord->isSubClassOf("LibBuiltin")) { 469 BT = BuiltinType::LibBuiltin; 470 if (BuiltinRecord->getValueAsBit("AddBuiltinPrefixedAlias")) 471 Builtins.push_back(buildBuiltin( 472 Substitution, BuiltinRecord, 473 std::string("__builtin_") + FullSpelling, BuiltinType::Builtin)); 474 } 475 Builtins.push_back( 476 buildBuiltin(Substitution, BuiltinRecord, FullSpelling, BT)); 477 } 478 } 479 } 480 } // namespace 481 482 void clang::EmitClangBuiltins(const RecordKeeper &Records, raw_ostream &OS) { 483 emitSourceFileHeader("List of builtins that Clang recognizes", OS); 484 485 SmallVector<Builtin> Builtins; 486 // AtomicBuiltins are order dependent. Emit them first to make manual checking 487 // easier and so we can build a special atomic builtin X-macro. 488 for (const auto *BuiltinRecord : 489 Records.getAllDerivedDefinitions("AtomicBuiltin")) 490 collectBuiltins(BuiltinRecord, Builtins); 491 unsigned NumAtomicBuiltins = Builtins.size(); 492 493 for (const auto *BuiltinRecord : 494 Records.getAllDerivedDefinitions("Builtin")) { 495 if (BuiltinRecord->isSubClassOf("AtomicBuiltin")) 496 continue; 497 // Prefixed builtins are also special and we emit them last so they can have 498 // their own representation that skips the prefix. 499 if (BuiltinRecord->getValueAsOptionalDef("RequiredNamePrefix")) 500 continue; 501 502 collectBuiltins(BuiltinRecord, Builtins); 503 } 504 505 // Now collect (and count) the prefixed builtins. 506 unsigned NumPrefixedBuiltins = Builtins.size(); 507 const Record *FirstPrefix = nullptr; 508 for (const auto *BuiltinRecord : 509 Records.getAllDerivedDefinitions("Builtin")) { 510 auto *Prefix = BuiltinRecord->getValueAsOptionalDef("RequiredNamePrefix"); 511 if (!Prefix) 512 continue; 513 514 if (!FirstPrefix) 515 FirstPrefix = Prefix; 516 assert(Prefix == FirstPrefix && 517 "Multiple distinct prefixes which is not currently supported!"); 518 assert(!BuiltinRecord->isSubClassOf("AtomicBuiltin") && 519 "Cannot require a name prefix for an atomic builtin."); 520 collectBuiltins(BuiltinRecord, Builtins); 521 } 522 NumPrefixedBuiltins = Builtins.size() - NumPrefixedBuiltins; 523 524 auto AtomicBuiltins = ArrayRef(Builtins).slice(0, NumAtomicBuiltins); 525 auto UnprefixedBuiltins = ArrayRef(Builtins).drop_back(NumPrefixedBuiltins); 526 auto PrefixedBuiltins = ArrayRef(Builtins).take_back(NumPrefixedBuiltins); 527 528 // Collect strings into a table. 529 StringToOffsetTable Table; 530 Table.GetOrAddStringOffset(""); 531 for (const auto &B : Builtins) { 532 Table.GetOrAddStringOffset(B.Name); 533 Table.GetOrAddStringOffset(B.Type); 534 Table.GetOrAddStringOffset(B.Attributes); 535 if (B.BT == BuiltinType::TargetBuiltin) 536 Table.GetOrAddStringOffset(B.BuiltinRecord->getValueAsString("Features")); 537 } 538 539 // Emit enumerators. 540 OS << R"c++( 541 #ifdef GET_BUILTIN_ENUMERATORS 542 )c++"; 543 for (const auto &B : Builtins) 544 B.EmitEnumerator(OS); 545 OS << R"c++( 546 #endif // GET_BUILTIN_ENUMERATORS 547 )c++"; 548 549 // Emit a string table that can be referenced for these builtins. 550 OS << R"c++( 551 #ifdef GET_BUILTIN_STR_TABLE 552 )c++"; 553 Table.EmitStringTableDef(OS, "BuiltinStrings"); 554 OS << R"c++( 555 #endif // GET_BUILTIN_STR_TABLE 556 )c++"; 557 558 // Emit a direct set of `Builtin::Info` initializers, first for the unprefixed 559 // builtins and then for the prefixed builtins. 560 OS << R"c++( 561 #ifdef GET_BUILTIN_INFOS 562 )c++"; 563 for (const auto &B : UnprefixedBuiltins) 564 B.EmitInfo(OS, Table); 565 OS << R"c++( 566 #endif // GET_BUILTIN_INFOS 567 )c++"; 568 569 OS << R"c++( 570 #ifdef GET_BUILTIN_PREFIXED_INFOS 571 )c++"; 572 for (const auto &B : PrefixedBuiltins) 573 B.EmitInfo(OS, Table); 574 OS << R"c++( 575 #endif // GET_BUILTIN_PREFIXED_INFOS 576 )c++"; 577 578 // Emit X-macros for the atomic builtins to support various custome patterns 579 // used exclusively with those builtins. 580 // 581 // FIXME: We should eventually move this to a separate file so that users 582 // don't need to include the full set of builtins. 583 OS << R"c++( 584 #ifdef ATOMIC_BUILTIN 585 )c++"; 586 for (const auto &Builtin : AtomicBuiltins) { 587 Builtin.EmitXMacro(OS); 588 } 589 OS << R"c++( 590 #endif // ATOMIC_BUILTIN 591 #undef ATOMIC_BUILTIN 592 )c++"; 593 } 594