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/TableGenBackend.h" 19 20 using namespace llvm; 21 22 namespace { 23 enum class BuiltinType { 24 Builtin, 25 AtomicBuiltin, 26 LibBuiltin, 27 LangBuiltin, 28 TargetBuiltin, 29 TargetLibBuiltin, 30 }; 31 32 class PrototypeParser { 33 public: 34 PrototypeParser(StringRef Substitution, const Record *Builtin) 35 : Loc(Builtin->getFieldLoc("Prototype")), Substitution(Substitution), 36 EnableOpenCLLong(Builtin->getValueAsBit("EnableOpenCLLong")) { 37 ParsePrototype(Builtin->getValueAsString("Prototype")); 38 } 39 40 private: 41 void ParsePrototype(StringRef Prototype) { 42 Prototype = Prototype.trim(); 43 44 // Some builtins don't have an expressible prototype, simply emit an empty 45 // string for them. 46 if (Prototype.empty()) { 47 Type = ""; 48 return; 49 } 50 51 ParseTypes(Prototype); 52 } 53 54 void ParseTypes(StringRef &Prototype) { 55 auto ReturnType = Prototype.take_until([](char c) { return c == '('; }); 56 ParseType(ReturnType); 57 Prototype = Prototype.drop_front(ReturnType.size() + 1); 58 if (!Prototype.ends_with(")")) 59 PrintFatalError(Loc, "Expected closing brace at end of prototype"); 60 Prototype = Prototype.drop_back(); 61 62 // Look through the input parameters. 63 const size_t end = Prototype.size(); 64 for (size_t I = 0; I != end;) { 65 const StringRef Current = Prototype.substr(I, end); 66 // Skip any leading space or commas 67 if (Current.starts_with(" ") || Current.starts_with(",")) { 68 ++I; 69 continue; 70 } 71 72 // Check if we are in _ExtVector. We do this first because 73 // extended vectors are written in template form with the syntax 74 // _ExtVector< ..., ...>, so we need to make sure we are not 75 // detecting the comma of the template class as a separator for 76 // the parameters of the prototype. Note: the assumption is that 77 // we cannot have nested _ExtVector. 78 if (Current.starts_with("_ExtVector<") || 79 Current.starts_with("_Vector<")) { 80 const size_t EndTemplate = Current.find('>', 0); 81 ParseType(Current.substr(0, EndTemplate + 1)); 82 // Move the prototype beyond _ExtVector<...> 83 I += EndTemplate + 1; 84 continue; 85 } 86 87 // We know that we are past _ExtVector, therefore the first seen 88 // comma is the boundary of a parameter in the prototype. 89 if (size_t CommaPos = Current.find(',', 0)) { 90 if (CommaPos != StringRef::npos) { 91 StringRef T = Current.substr(0, CommaPos); 92 ParseType(T); 93 // Move the prototype beyond the comma. 94 I += CommaPos + 1; 95 continue; 96 } 97 } 98 99 // No more commas, parse final parameter. 100 ParseType(Current); 101 I = end; 102 } 103 } 104 105 void ParseType(StringRef T) { 106 T = T.trim(); 107 108 auto ConsumeAddrSpace = [&]() -> std::optional<unsigned> { 109 T = T.trim(); 110 if (!T.consume_back(">")) 111 return std::nullopt; 112 113 auto Open = T.find_last_of('<'); 114 if (Open == StringRef::npos) 115 PrintFatalError(Loc, "Mismatched angle-brackets in type"); 116 117 StringRef ArgStr = T.substr(Open + 1); 118 T = T.slice(0, Open); 119 if (!T.consume_back("address_space")) 120 PrintFatalError(Loc, 121 "Only `address_space<N>` supported as a parameterized " 122 "pointer or reference type qualifier"); 123 124 unsigned Number = 0; 125 if (ArgStr.getAsInteger(10, Number)) 126 PrintFatalError( 127 Loc, "Expected an integer argument to the address_space qualifier"); 128 if (Number == 0) 129 PrintFatalError(Loc, "No need for a qualifier for address space `0`"); 130 return Number; 131 }; 132 133 if (T.consume_back("*")) { 134 // Pointers may have an address space qualifier immediately before them. 135 std::optional<unsigned> AS = ConsumeAddrSpace(); 136 ParseType(T); 137 Type += "*"; 138 if (AS) 139 Type += std::to_string(*AS); 140 } else if (T.consume_back("const")) { 141 ParseType(T); 142 Type += "C"; 143 } else if (T.consume_back("volatile")) { 144 ParseType(T); 145 Type += "D"; 146 } else if (T.consume_back("restrict")) { 147 ParseType(T); 148 Type += "R"; 149 } else if (T.consume_back("&")) { 150 // References may have an address space qualifier immediately before them. 151 std::optional<unsigned> AS = ConsumeAddrSpace(); 152 ParseType(T); 153 Type += "&"; 154 if (AS) 155 Type += std::to_string(*AS); 156 } else if (T.consume_back(")")) { 157 ParseType(T); 158 Type += "&"; 159 } else if (EnableOpenCLLong && T.consume_front("long long")) { 160 Type += "O"; 161 ParseType(T); 162 } else if (T.consume_front("long")) { 163 Type += "L"; 164 ParseType(T); 165 } else if (T.consume_front("signed")) { 166 Type += "S"; 167 ParseType(T); 168 } else if (T.consume_front("unsigned")) { 169 Type += "U"; 170 ParseType(T); 171 } else if (T.consume_front("_Complex")) { 172 Type += "X"; 173 ParseType(T); 174 } else if (T.consume_front("_Constant")) { 175 Type += "I"; 176 ParseType(T); 177 } else if (T.consume_front("T")) { 178 if (Substitution.empty()) 179 PrintFatalError(Loc, "Not a template"); 180 ParseType(Substitution); 181 } else if (auto IsExt = T.consume_front("_ExtVector"); 182 IsExt || T.consume_front("_Vector")) { 183 // Clang extended vector types are mangled as follows: 184 // 185 // '_ExtVector<' <lanes> ',' <scalar type> '>' 186 187 // Before parsing T(=<scalar type>), make sure the syntax of 188 // `_ExtVector<N, T>` is correct... 189 if (!T.consume_front("<")) 190 PrintFatalError(Loc, "Expected '<' after '_ExtVector'"); 191 unsigned long long Lanes; 192 if (consumeUnsignedInteger(T, 10, Lanes)) 193 PrintFatalError(Loc, "Expected number of lanes after '_ExtVector<'"); 194 Type += (IsExt ? "E" : "V") + std::to_string(Lanes); 195 if (!T.consume_front(",")) 196 PrintFatalError(Loc, 197 "Expected ',' after number of lanes in '_ExtVector<'"); 198 if (!T.consume_back(">")) 199 PrintFatalError( 200 Loc, "Expected '>' after scalar type in '_ExtVector<N, type>'"); 201 202 // ...all good, we can check if we have a valid `<scalar type>`. 203 ParseType(T); 204 } else { 205 auto ReturnTypeVal = StringSwitch<std::string>(T) 206 .Case("__builtin_va_list_ref", "A") 207 .Case("__builtin_va_list", "a") 208 .Case("__float128", "LLd") 209 .Case("__fp16", "h") 210 .Case("__int128_t", "LLLi") 211 .Case("_Float16", "x") 212 .Case("__bf16", "y") 213 .Case("bool", "b") 214 .Case("char", "c") 215 .Case("constant_CFString", "F") 216 .Case("double", "d") 217 .Case("FILE", "P") 218 .Case("float", "f") 219 .Case("id", "G") 220 .Case("int", "i") 221 .Case("int32_t", "Zi") 222 .Case("int64_t", "Wi") 223 .Case("jmp_buf", "J") 224 .Case("msint32_t", "Ni") 225 .Case("msuint32_t", "UNi") 226 .Case("objc_super", "M") 227 .Case("pid_t", "p") 228 .Case("ptrdiff_t", "Y") 229 .Case("SEL", "H") 230 .Case("short", "s") 231 .Case("sigjmp_buf", "SJ") 232 .Case("size_t", "z") 233 .Case("ucontext_t", "K") 234 .Case("uint32_t", "UZi") 235 .Case("uint64_t", "UWi") 236 .Case("void", "v") 237 .Case("wchar_t", "w") 238 .Case("...", ".") 239 .Default("error"); 240 if (ReturnTypeVal == "error") 241 PrintFatalError(Loc, "Unknown Type: " + T); 242 Type += ReturnTypeVal; 243 } 244 } 245 246 public: 247 void Print(raw_ostream &OS) const { OS << ", \"" << Type << '\"'; } 248 249 private: 250 SMLoc Loc; 251 StringRef Substitution; 252 bool EnableOpenCLLong; 253 std::string Type; 254 }; 255 256 class HeaderNameParser { 257 public: 258 HeaderNameParser(const Record *Builtin) { 259 for (char c : Builtin->getValueAsString("Header")) { 260 if (std::islower(c)) 261 HeaderName += static_cast<char>(std::toupper(c)); 262 else if (c == '.' || c == '_' || c == '/' || c == '-') 263 HeaderName += '_'; 264 else 265 PrintFatalError(Builtin->getLoc(), "Unexpected header name"); 266 } 267 } 268 269 void Print(raw_ostream &OS) const { OS << HeaderName; } 270 271 private: 272 std::string HeaderName; 273 }; 274 275 void PrintAttributes(const Record *Builtin, BuiltinType BT, raw_ostream &OS) { 276 OS << '\"'; 277 if (Builtin->isSubClassOf("LibBuiltin")) { 278 if (BT == BuiltinType::LibBuiltin) { 279 OS << 'f'; 280 } else { 281 OS << 'F'; 282 if (Builtin->getValueAsBit("OnlyBuiltinPrefixedAliasIsConstexpr")) 283 OS << 'E'; 284 } 285 } 286 287 if (auto NS = Builtin->getValueAsOptionalString("Namespace")) { 288 if (NS != "std") 289 PrintFatalError(Builtin->getFieldLoc("Namespace"), "Unknown namespace: "); 290 OS << "z"; 291 } 292 293 for (const auto *Attr : Builtin->getValueAsListOfDefs("Attributes")) { 294 OS << Attr->getValueAsString("Mangling"); 295 if (Attr->isSubClassOf("IndexedAttribute")) { 296 OS << ':' << Attr->getValueAsInt("Index") << ':'; 297 } else if (Attr->isSubClassOf("MultiIndexAttribute")) { 298 OS << '<'; 299 llvm::ListSeparator Sep(","); 300 for (int64_t Index : Attr->getValueAsListOfInts("Indices")) 301 OS << Sep << Index; 302 OS << '>'; 303 } 304 } 305 OS << '\"'; 306 } 307 308 void EmitBuiltinDef(raw_ostream &OS, StringRef Substitution, 309 const Record *Builtin, Twine Spelling, BuiltinType BT) { 310 if (Builtin->getValueAsBit("RequiresUndef")) 311 OS << "#undef " << Spelling << '\n'; 312 switch (BT) { 313 case BuiltinType::LibBuiltin: 314 OS << "LIBBUILTIN"; 315 break; 316 case BuiltinType::LangBuiltin: 317 OS << "LANGBUILTIN"; 318 break; 319 case BuiltinType::Builtin: 320 OS << "BUILTIN"; 321 break; 322 case BuiltinType::AtomicBuiltin: 323 OS << "ATOMIC_BUILTIN"; 324 break; 325 case BuiltinType::TargetBuiltin: 326 OS << "TARGET_BUILTIN"; 327 break; 328 case BuiltinType::TargetLibBuiltin: 329 OS << "TARGET_HEADER_BUILTIN"; 330 break; 331 } 332 333 OS << "(" << Spelling; 334 PrototypeParser{Substitution, Builtin}.Print(OS); 335 OS << ", "; 336 PrintAttributes(Builtin, BT, OS); 337 338 switch (BT) { 339 case BuiltinType::LibBuiltin: { 340 OS << ", "; 341 HeaderNameParser{Builtin}.Print(OS); 342 [[fallthrough]]; 343 } 344 case BuiltinType::LangBuiltin: { 345 OS << ", " << Builtin->getValueAsString("Languages"); 346 break; 347 } 348 case BuiltinType::TargetLibBuiltin: { 349 OS << ", "; 350 HeaderNameParser{Builtin}.Print(OS); 351 OS << ", " << Builtin->getValueAsString("Languages"); 352 [[fallthrough]]; 353 } 354 case BuiltinType::TargetBuiltin: 355 OS << ", \"" << Builtin->getValueAsString("Features") << "\""; 356 break; 357 case BuiltinType::AtomicBuiltin: 358 case BuiltinType::Builtin: 359 break; 360 } 361 OS << ")\n"; 362 } 363 364 struct TemplateInsts { 365 std::vector<std::string> Substitution; 366 std::vector<std::string> Affix; 367 bool IsPrefix; 368 }; 369 370 TemplateInsts getTemplateInsts(const Record *R) { 371 TemplateInsts temp; 372 auto Substitutions = R->getValueAsListOfStrings("Substitutions"); 373 auto Affixes = R->getValueAsListOfStrings("Affixes"); 374 temp.IsPrefix = R->getValueAsBit("AsPrefix"); 375 376 if (Substitutions.size() != Affixes.size()) 377 PrintFatalError(R->getLoc(), "Substitutions and affixes " 378 "don't have the same lengths"); 379 380 for (auto [Affix, Substitution] : zip(Affixes, Substitutions)) { 381 temp.Substitution.emplace_back(Substitution); 382 temp.Affix.emplace_back(Affix); 383 } 384 return temp; 385 } 386 387 void EmitBuiltin(raw_ostream &OS, const Record *Builtin) { 388 TemplateInsts Templates = {}; 389 if (Builtin->isSubClassOf("Template")) { 390 Templates = getTemplateInsts(Builtin); 391 } else { 392 Templates.Affix.emplace_back(); 393 Templates.Substitution.emplace_back(); 394 } 395 396 for (auto [Substitution, Affix] : 397 zip(Templates.Substitution, Templates.Affix)) { 398 for (StringRef Spelling : Builtin->getValueAsListOfStrings("Spellings")) { 399 auto FullSpelling = 400 (Templates.IsPrefix ? Affix + Spelling : Spelling + Affix).str(); 401 BuiltinType BT = BuiltinType::Builtin; 402 if (Builtin->isSubClassOf("AtomicBuiltin")) { 403 BT = BuiltinType::AtomicBuiltin; 404 } else if (Builtin->isSubClassOf("LangBuiltin")) { 405 BT = BuiltinType::LangBuiltin; 406 } else if (Builtin->isSubClassOf("TargetLibBuiltin")) { 407 BT = BuiltinType::TargetLibBuiltin; 408 } else if (Builtin->isSubClassOf("TargetBuiltin")) { 409 BT = BuiltinType::TargetBuiltin; 410 } else if (Builtin->isSubClassOf("LibBuiltin")) { 411 BT = BuiltinType::LibBuiltin; 412 if (Builtin->getValueAsBit("AddBuiltinPrefixedAlias")) 413 EmitBuiltinDef(OS, Substitution, Builtin, 414 std::string("__builtin_") + FullSpelling, 415 BuiltinType::Builtin); 416 } 417 EmitBuiltinDef(OS, Substitution, Builtin, FullSpelling, BT); 418 } 419 } 420 } 421 } // namespace 422 423 void clang::EmitClangBuiltins(const RecordKeeper &Records, raw_ostream &OS) { 424 emitSourceFileHeader("List of builtins that Clang recognizes", OS); 425 426 OS << R"c++( 427 #if defined(BUILTIN) && !defined(LIBBUILTIN) 428 # define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS) 429 #endif 430 431 #if defined(BUILTIN) && !defined(LANGBUILTIN) 432 # define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS) 433 #endif 434 435 // Some of our atomics builtins are handled by AtomicExpr rather than 436 // as normal builtin CallExprs. This macro is used for such builtins. 437 #ifndef ATOMIC_BUILTIN 438 # define ATOMIC_BUILTIN(ID, TYPE, ATTRS) BUILTIN(ID, TYPE, ATTRS) 439 #endif 440 441 #if defined(BUILTIN) && !defined(TARGET_BUILTIN) 442 # define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) 443 #endif 444 445 #if defined(BUILTIN) && !defined(TARGET_HEADER_BUILTIN) 446 # define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS) 447 #endif 448 )c++"; 449 450 // AtomicBuiltins are order dependent 451 // emit them first to make manual checking easier 452 for (const auto *Builtin : Records.getAllDerivedDefinitions("AtomicBuiltin")) 453 EmitBuiltin(OS, Builtin); 454 455 for (const auto *Builtin : Records.getAllDerivedDefinitions("Builtin")) { 456 if (Builtin->isSubClassOf("AtomicBuiltin")) 457 continue; 458 EmitBuiltin(OS, Builtin); 459 } 460 461 OS << R"c++( 462 #undef ATOMIC_BUILTIN 463 #undef BUILTIN 464 #undef LIBBUILTIN 465 #undef LANGBUILTIN 466 #undef TARGET_BUILTIN 467 #undef TARGET_HEADER_BUILTIN 468 )c++"; 469 } 470