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