1 //===- ClangOpenCLBuiltinEmitter.cpp - Generate Clang OpenCL Builtin handling 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 6 // See https://llvm.org/LICENSE.txt for license information. 7 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 8 // 9 //===----------------------------------------------------------------------===// 10 // 11 // These backends consume the definitions of OpenCL builtin functions in 12 // clang/lib/Sema/OpenCLBuiltins.td and produce builtin handling code for 13 // inclusion in SemaLookup.cpp, or a test file that calls all declared builtins. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "TableGenBackends.h" 18 #include "llvm/ADT/MapVector.h" 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/ADT/SmallString.h" 21 #include "llvm/ADT/StringExtras.h" 22 #include "llvm/ADT/StringMap.h" 23 #include "llvm/ADT/StringRef.h" 24 #include "llvm/ADT/StringSwitch.h" 25 #include "llvm/Support/ErrorHandling.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include "llvm/TableGen/Error.h" 28 #include "llvm/TableGen/Record.h" 29 #include "llvm/TableGen/StringMatcher.h" 30 #include "llvm/TableGen/TableGenBackend.h" 31 32 using namespace llvm; 33 34 namespace { 35 36 // A list of signatures that are shared by one or more builtin functions. 37 struct BuiltinTableEntries { 38 SmallVector<StringRef, 4> Names; 39 std::vector<std::pair<const Record *, unsigned>> Signatures; 40 }; 41 42 // This tablegen backend emits code for checking whether a function is an 43 // OpenCL builtin function. If so, all overloads of this function are 44 // added to the LookupResult. The generated include file is used by 45 // SemaLookup.cpp 46 // 47 // For a successful lookup of e.g. the "cos" builtin, isOpenCLBuiltin("cos") 48 // returns a pair <Index, Len>. 49 // BuiltinTable[Index] to BuiltinTable[Index + Len] contains the pairs 50 // <SigIndex, SigLen> of the overloads of "cos". 51 // SignatureTable[SigIndex] to SignatureTable[SigIndex + SigLen] contains 52 // one of the signatures of "cos". The SignatureTable entry can be 53 // referenced by other functions, e.g. "sin", to exploit the fact that 54 // many OpenCL builtins share the same signature. 55 // 56 // The file generated by this TableGen emitter contains the following: 57 // 58 // * Structs and enums to represent types and function signatures. 59 // 60 // * const char *FunctionExtensionTable[] 61 // List of space-separated OpenCL extensions. A builtin references an 62 // entry in this table when the builtin requires a particular (set of) 63 // extension(s) to be enabled. 64 // 65 // * OpenCLTypeStruct TypeTable[] 66 // Type information for return types and arguments. 67 // 68 // * unsigned SignatureTable[] 69 // A list of types representing function signatures. Each entry is an index 70 // into the above TypeTable. Multiple entries following each other form a 71 // signature, where the first entry is the return type and subsequent 72 // entries are the argument types. 73 // 74 // * OpenCLBuiltinStruct BuiltinTable[] 75 // Each entry represents one overload of an OpenCL builtin function and 76 // consists of an index into the SignatureTable and the number of arguments. 77 // 78 // * std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) 79 // Find out whether a string matches an existing OpenCL builtin function 80 // name and return an index into BuiltinTable and the number of overloads. 81 // 82 // * void OCL2Qual(Sema&, OpenCLTypeStruct, std::vector<QualType>&) 83 // Convert an OpenCLTypeStruct type to a list of QualType instances. 84 // One OpenCLTypeStruct can represent multiple types, primarily when using 85 // GenTypes. 86 // 87 class BuiltinNameEmitter { 88 public: 89 BuiltinNameEmitter(RecordKeeper &Records, raw_ostream &OS) 90 : Records(Records), OS(OS) {} 91 92 // Entrypoint to generate the functions and structures for checking 93 // whether a function is an OpenCL builtin function. 94 void Emit(); 95 96 private: 97 // A list of indices into the builtin function table. 98 using BuiltinIndexListTy = SmallVector<unsigned, 11>; 99 100 // Contains OpenCL builtin functions and related information, stored as 101 // Record instances. They are coming from the associated TableGen file. 102 RecordKeeper &Records; 103 104 // The output file. 105 raw_ostream &OS; 106 107 // Helper function for BuiltinNameEmitter::EmitDeclarations. Generate enum 108 // definitions in the Output string parameter, and save their Record instances 109 // in the List parameter. 110 // \param Types (in) List containing the Types to extract. 111 // \param TypesSeen (inout) List containing the Types already extracted. 112 // \param Output (out) String containing the enums to emit in the output file. 113 // \param List (out) List containing the extracted Types, except the Types in 114 // TypesSeen. 115 void ExtractEnumTypes(std::vector<Record *> &Types, 116 StringMap<bool> &TypesSeen, std::string &Output, 117 std::vector<const Record *> &List); 118 119 // Emit the enum or struct used in the generated file. 120 // Populate the TypeList at the same time. 121 void EmitDeclarations(); 122 123 // Parse the Records generated by TableGen to populate the SignaturesList, 124 // FctOverloadMap and TypeMap. 125 void GetOverloads(); 126 127 // Compare two lists of signatures and check that e.g. the OpenCL version, 128 // function attributes, and extension are equal for each signature. 129 // \param Candidate (in) Entry in the SignatureListMap to check. 130 // \param SignatureList (in) List of signatures of the considered function. 131 // \returns true if the two lists of signatures are identical. 132 bool CanReuseSignature( 133 BuiltinIndexListTy *Candidate, 134 std::vector<std::pair<const Record *, unsigned>> &SignatureList); 135 136 // Group functions with the same list of signatures by populating the 137 // SignatureListMap. 138 // Some builtin functions have the same list of signatures, for example the 139 // "sin" and "cos" functions. To save space in the BuiltinTable, the 140 // "isOpenCLBuiltin" function will have the same output for these two 141 // function names. 142 void GroupBySignature(); 143 144 // Emit the FunctionExtensionTable that lists all function extensions. 145 void EmitExtensionTable(); 146 147 // Emit the TypeTable containing all types used by OpenCL builtins. 148 void EmitTypeTable(); 149 150 // Emit the SignatureTable. This table contains all the possible signatures. 151 // A signature is stored as a list of indexes of the TypeTable. 152 // The first index references the return type (mandatory), and the followings 153 // reference its arguments. 154 // E.g.: 155 // 15, 2, 15 can represent a function with the signature: 156 // int func(float, int) 157 // The "int" type being at the index 15 in the TypeTable. 158 void EmitSignatureTable(); 159 160 // Emit the BuiltinTable table. This table contains all the overloads of 161 // each function, and is a struct OpenCLBuiltinDecl. 162 // E.g.: 163 // // 891 convert_float2_rtn 164 // { 58, 2, 3, 100, 0 }, 165 // This means that the signature of this convert_float2_rtn overload has 166 // 1 argument (+1 for the return type), stored at index 58 in 167 // the SignatureTable. This prototype requires extension "3" in the 168 // FunctionExtensionTable. The last two values represent the minimum (1.0) 169 // and maximum (0, meaning no max version) OpenCL version in which this 170 // overload is supported. 171 void EmitBuiltinTable(); 172 173 // Emit a StringMatcher function to check whether a function name is an 174 // OpenCL builtin function name. 175 void EmitStringMatcher(); 176 177 // Emit a function returning the clang QualType instance associated with 178 // the TableGen Record Type. 179 void EmitQualTypeFinder(); 180 181 // Contains a list of the available signatures, without the name of the 182 // function. Each pair consists of a signature and a cumulative index. 183 // E.g.: <<float, float>, 0>, 184 // <<float, int, int, 2>>, 185 // <<float>, 5>, 186 // ... 187 // <<double, double>, 35>. 188 std::vector<std::pair<std::vector<Record *>, unsigned>> SignaturesList; 189 190 // Map the name of a builtin function to its prototypes (instances of the 191 // TableGen "Builtin" class). 192 // Each prototype is registered as a pair of: 193 // <pointer to the "Builtin" instance, 194 // cumulative index of the associated signature in the SignaturesList> 195 // E.g.: The function cos: (float cos(float), double cos(double), ...) 196 // <"cos", <<ptrToPrototype0, 5>, 197 // <ptrToPrototype1, 35>, 198 // <ptrToPrototype2, 79>> 199 // ptrToPrototype1 has the following signature: <double, double> 200 MapVector<StringRef, std::vector<std::pair<const Record *, unsigned>>> 201 FctOverloadMap; 202 203 // Contains the map of OpenCL types to their index in the TypeTable. 204 MapVector<const Record *, unsigned> TypeMap; 205 206 // List of OpenCL function extensions mapping extension strings to 207 // an index into the FunctionExtensionTable. 208 StringMap<unsigned> FunctionExtensionIndex; 209 210 // List of OpenCL type names in the same order as in enum OpenCLTypeID. 211 // This list does not contain generic types. 212 std::vector<const Record *> TypeList; 213 214 // Same as TypeList, but for generic types only. 215 std::vector<const Record *> GenTypeList; 216 217 // Map an ordered vector of signatures to their original Record instances, 218 // and to a list of function names that share these signatures. 219 // 220 // For example, suppose the "cos" and "sin" functions have only three 221 // signatures, and these signatures are at index Ix in the SignatureTable: 222 // cos | sin | Signature | Index 223 // float cos(float) | float sin(float) | Signature1 | I1 224 // double cos(double) | double sin(double) | Signature2 | I2 225 // half cos(half) | half sin(half) | Signature3 | I3 226 // 227 // Then we will create a mapping of the vector of signatures: 228 // SignatureListMap[<I1, I2, I3>] = < 229 // <"cos", "sin">, 230 // <Signature1, Signature2, Signature3>> 231 // The function "tan", having the same signatures, would be mapped to the 232 // same entry (<I1, I2, I3>). 233 MapVector<BuiltinIndexListTy *, BuiltinTableEntries> SignatureListMap; 234 }; 235 236 /// Base class for emitting a file (e.g. header or test) from OpenCLBuiltins.td 237 class OpenCLBuiltinFileEmitterBase { 238 public: 239 OpenCLBuiltinFileEmitterBase(RecordKeeper &Records, raw_ostream &OS) 240 : Records(Records), OS(OS) {} 241 virtual ~OpenCLBuiltinFileEmitterBase() = default; 242 243 // Entrypoint to generate the functions for testing all OpenCL builtin 244 // functions. 245 virtual void emit() = 0; 246 247 protected: 248 struct TypeFlags { 249 TypeFlags() : IsConst(false), IsVolatile(false), IsPointer(false) {} 250 bool IsConst : 1; 251 bool IsVolatile : 1; 252 bool IsPointer : 1; 253 StringRef AddrSpace; 254 }; 255 256 // Return a string representation of the given type, such that it can be 257 // used as a type in OpenCL C code. 258 std::string getTypeString(const Record *Type, TypeFlags Flags, 259 int VectorSize) const; 260 261 // Return the type(s) and vector size(s) for the given type. For 262 // non-GenericTypes, the resulting vectors will contain 1 element. For 263 // GenericTypes, the resulting vectors typically contain multiple elements. 264 void getTypeLists(Record *Type, TypeFlags &Flags, 265 std::vector<Record *> &TypeList, 266 std::vector<int64_t> &VectorList) const; 267 268 // Expand the TableGen Records representing a builtin function signature into 269 // one or more function signatures. Return them as a vector of a vector of 270 // strings, with each string containing an OpenCL C type and optional 271 // qualifiers. 272 // 273 // The Records may contain GenericTypes, which expand into multiple 274 // signatures. Repeated occurrences of GenericType in a signature expand to 275 // the same types. For example [char, FGenType, FGenType] expands to: 276 // [char, float, float] 277 // [char, float2, float2] 278 // [char, float3, float3] 279 // ... 280 void 281 expandTypesInSignature(const std::vector<Record *> &Signature, 282 SmallVectorImpl<SmallVector<std::string, 2>> &Types); 283 284 // Emit extension enabling pragmas. 285 void emitExtensionSetup(); 286 287 // Emit an #if guard for a Builtin's extension. Return the corresponding 288 // closing #endif, or an empty string if no extension #if guard was emitted. 289 std::string emitExtensionGuard(const Record *Builtin); 290 291 // Emit an #if guard for a Builtin's language version. Return the 292 // corresponding closing #endif, or an empty string if no version #if guard 293 // was emitted. 294 std::string emitVersionGuard(const Record *Builtin); 295 296 // Contains OpenCL builtin functions and related information, stored as 297 // Record instances. They are coming from the associated TableGen file. 298 RecordKeeper &Records; 299 300 // The output file. 301 raw_ostream &OS; 302 }; 303 304 // OpenCL builtin test generator. This class processes the same TableGen input 305 // as BuiltinNameEmitter, but generates a .cl file that contains a call to each 306 // builtin function described in the .td input. 307 class OpenCLBuiltinTestEmitter : public OpenCLBuiltinFileEmitterBase { 308 public: 309 OpenCLBuiltinTestEmitter(RecordKeeper &Records, raw_ostream &OS) 310 : OpenCLBuiltinFileEmitterBase(Records, OS) {} 311 312 // Entrypoint to generate the functions for testing all OpenCL builtin 313 // functions. 314 void emit() override; 315 }; 316 317 } // namespace 318 319 void BuiltinNameEmitter::Emit() { 320 emitSourceFileHeader("OpenCL Builtin handling", OS); 321 322 OS << "#include \"llvm/ADT/StringRef.h\"\n"; 323 OS << "using namespace clang;\n\n"; 324 325 // Emit enums and structs. 326 EmitDeclarations(); 327 328 // Parse the Records to populate the internal lists. 329 GetOverloads(); 330 GroupBySignature(); 331 332 // Emit tables. 333 EmitExtensionTable(); 334 EmitTypeTable(); 335 EmitSignatureTable(); 336 EmitBuiltinTable(); 337 338 // Emit functions. 339 EmitStringMatcher(); 340 EmitQualTypeFinder(); 341 } 342 343 void BuiltinNameEmitter::ExtractEnumTypes(std::vector<Record *> &Types, 344 StringMap<bool> &TypesSeen, 345 std::string &Output, 346 std::vector<const Record *> &List) { 347 raw_string_ostream SS(Output); 348 349 for (const auto *T : Types) { 350 if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end()) { 351 SS << " OCLT_" + T->getValueAsString("Name") << ",\n"; 352 // Save the type names in the same order as their enum value. Note that 353 // the Record can be a VectorType or something else, only the name is 354 // important. 355 List.push_back(T); 356 TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true)); 357 } 358 } 359 SS.flush(); 360 } 361 362 void BuiltinNameEmitter::EmitDeclarations() { 363 // Enum of scalar type names (float, int, ...) and generic type sets. 364 OS << "enum OpenCLTypeID {\n"; 365 366 StringMap<bool> TypesSeen; 367 std::string GenTypeEnums; 368 std::string TypeEnums; 369 370 // Extract generic types and non-generic types separately, to keep 371 // gentypes at the end of the enum which simplifies the special handling 372 // for gentypes in SemaLookup. 373 std::vector<Record *> GenTypes = 374 Records.getAllDerivedDefinitions("GenericType"); 375 ExtractEnumTypes(GenTypes, TypesSeen, GenTypeEnums, GenTypeList); 376 377 std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); 378 ExtractEnumTypes(Types, TypesSeen, TypeEnums, TypeList); 379 380 OS << TypeEnums; 381 OS << GenTypeEnums; 382 OS << "};\n"; 383 384 // Structure definitions. 385 OS << R"( 386 // Image access qualifier. 387 enum OpenCLAccessQual : unsigned char { 388 OCLAQ_None, 389 OCLAQ_ReadOnly, 390 OCLAQ_WriteOnly, 391 OCLAQ_ReadWrite 392 }; 393 394 // Represents a return type or argument type. 395 struct OpenCLTypeStruct { 396 // A type (e.g. float, int, ...). 397 const OpenCLTypeID ID; 398 // Vector size (if applicable; 0 for scalars and generic types). 399 const unsigned VectorWidth; 400 // 0 if the type is not a pointer. 401 const bool IsPointer : 1; 402 // 0 if the type is not const. 403 const bool IsConst : 1; 404 // 0 if the type is not volatile. 405 const bool IsVolatile : 1; 406 // Access qualifier. 407 const OpenCLAccessQual AccessQualifier; 408 // Address space of the pointer (if applicable). 409 const LangAS AS; 410 }; 411 412 // One overload of an OpenCL builtin function. 413 struct OpenCLBuiltinStruct { 414 // Index of the signature in the OpenCLTypeStruct table. 415 const unsigned SigTableIndex; 416 // Entries between index SigTableIndex and (SigTableIndex + NumTypes - 1) in 417 // the SignatureTable represent the complete signature. The first type at 418 // index SigTableIndex is the return type. 419 const unsigned NumTypes; 420 // Function attribute __attribute__((pure)) 421 const bool IsPure : 1; 422 // Function attribute __attribute__((const)) 423 const bool IsConst : 1; 424 // Function attribute __attribute__((convergent)) 425 const bool IsConv : 1; 426 // OpenCL extension(s) required for this overload. 427 const unsigned short Extension; 428 // OpenCL versions in which this overload is available. 429 const unsigned short Versions; 430 }; 431 432 )"; 433 } 434 435 // Verify that the combination of GenTypes in a signature is supported. 436 // To simplify the logic for creating overloads in SemaLookup, only allow 437 // a signature to contain different GenTypes if these GenTypes represent 438 // the same number of actual scalar or vector types. 439 // 440 // Exit with a fatal error if an unsupported construct is encountered. 441 static void VerifySignature(const std::vector<Record *> &Signature, 442 const Record *BuiltinRec) { 443 unsigned GenTypeVecSizes = 1; 444 unsigned GenTypeTypes = 1; 445 446 for (const auto *T : Signature) { 447 // Check all GenericType arguments in this signature. 448 if (T->isSubClassOf("GenericType")) { 449 // Check number of vector sizes. 450 unsigned NVecSizes = 451 T->getValueAsDef("VectorList")->getValueAsListOfInts("List").size(); 452 if (NVecSizes != GenTypeVecSizes && NVecSizes != 1) { 453 if (GenTypeVecSizes > 1) { 454 // We already saw a gentype with a different number of vector sizes. 455 PrintFatalError(BuiltinRec->getLoc(), 456 "number of vector sizes should be equal or 1 for all gentypes " 457 "in a declaration"); 458 } 459 GenTypeVecSizes = NVecSizes; 460 } 461 462 // Check number of data types. 463 unsigned NTypes = 464 T->getValueAsDef("TypeList")->getValueAsListOfDefs("List").size(); 465 if (NTypes != GenTypeTypes && NTypes != 1) { 466 if (GenTypeTypes > 1) { 467 // We already saw a gentype with a different number of types. 468 PrintFatalError(BuiltinRec->getLoc(), 469 "number of types should be equal or 1 for all gentypes " 470 "in a declaration"); 471 } 472 GenTypeTypes = NTypes; 473 } 474 } 475 } 476 } 477 478 void BuiltinNameEmitter::GetOverloads() { 479 // Populate the TypeMap. 480 std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); 481 unsigned I = 0; 482 for (const auto &T : Types) { 483 TypeMap.insert(std::make_pair(T, I++)); 484 } 485 486 // Populate the SignaturesList and the FctOverloadMap. 487 unsigned CumulativeSignIndex = 0; 488 std::vector<Record *> Builtins = Records.getAllDerivedDefinitions("Builtin"); 489 for (const auto *B : Builtins) { 490 StringRef BName = B->getValueAsString("Name"); 491 if (FctOverloadMap.find(BName) == FctOverloadMap.end()) { 492 FctOverloadMap.insert(std::make_pair( 493 BName, std::vector<std::pair<const Record *, unsigned>>{})); 494 } 495 496 auto Signature = B->getValueAsListOfDefs("Signature"); 497 // Reuse signatures to avoid unnecessary duplicates. 498 auto it = 499 llvm::find_if(SignaturesList, 500 [&](const std::pair<std::vector<Record *>, unsigned> &a) { 501 return a.first == Signature; 502 }); 503 unsigned SignIndex; 504 if (it == SignaturesList.end()) { 505 VerifySignature(Signature, B); 506 SignaturesList.push_back(std::make_pair(Signature, CumulativeSignIndex)); 507 SignIndex = CumulativeSignIndex; 508 CumulativeSignIndex += Signature.size(); 509 } else { 510 SignIndex = it->second; 511 } 512 FctOverloadMap[BName].push_back(std::make_pair(B, SignIndex)); 513 } 514 } 515 516 void BuiltinNameEmitter::EmitExtensionTable() { 517 OS << "static const char *FunctionExtensionTable[] = {\n"; 518 unsigned Index = 0; 519 std::vector<Record *> FuncExtensions = 520 Records.getAllDerivedDefinitions("FunctionExtension"); 521 522 for (const auto &FE : FuncExtensions) { 523 // Emit OpenCL extension table entry. 524 OS << " // " << Index << ": " << FE->getName() << "\n" 525 << " \"" << FE->getValueAsString("ExtName") << "\",\n"; 526 527 // Record index of this extension. 528 FunctionExtensionIndex[FE->getName()] = Index++; 529 } 530 OS << "};\n\n"; 531 } 532 533 void BuiltinNameEmitter::EmitTypeTable() { 534 OS << "static const OpenCLTypeStruct TypeTable[] = {\n"; 535 for (const auto &T : TypeMap) { 536 const char *AccessQual = 537 StringSwitch<const char *>(T.first->getValueAsString("AccessQualifier")) 538 .Case("RO", "OCLAQ_ReadOnly") 539 .Case("WO", "OCLAQ_WriteOnly") 540 .Case("RW", "OCLAQ_ReadWrite") 541 .Default("OCLAQ_None"); 542 543 OS << " // " << T.second << "\n" 544 << " {OCLT_" << T.first->getValueAsString("Name") << ", " 545 << T.first->getValueAsInt("VecWidth") << ", " 546 << T.first->getValueAsBit("IsPointer") << ", " 547 << T.first->getValueAsBit("IsConst") << ", " 548 << T.first->getValueAsBit("IsVolatile") << ", " 549 << AccessQual << ", " 550 << T.first->getValueAsString("AddrSpace") << "},\n"; 551 } 552 OS << "};\n\n"; 553 } 554 555 void BuiltinNameEmitter::EmitSignatureTable() { 556 // Store a type (e.g. int, float, int2, ...). The type is stored as an index 557 // of a struct OpenCLType table. Multiple entries following each other form a 558 // signature. 559 OS << "static const unsigned short SignatureTable[] = {\n"; 560 for (const auto &P : SignaturesList) { 561 OS << " // " << P.second << "\n "; 562 for (const Record *R : P.first) { 563 unsigned Entry = TypeMap.find(R)->second; 564 if (Entry > USHRT_MAX) { 565 // Report an error when seeing an entry that is too large for the 566 // current index type (unsigned short). When hitting this, the type 567 // of SignatureTable will need to be changed. 568 PrintFatalError("Entry in SignatureTable exceeds limit."); 569 } 570 OS << Entry << ", "; 571 } 572 OS << "\n"; 573 } 574 OS << "};\n\n"; 575 } 576 577 // Encode a range MinVersion..MaxVersion into a single bit mask that can be 578 // checked against LangOpts using isOpenCLVersionContainedInMask(). 579 // This must be kept in sync with OpenCLVersionID in OpenCLOptions.h. 580 // (Including OpenCLOptions.h here would be a layering violation.) 581 static unsigned short EncodeVersions(unsigned int MinVersion, 582 unsigned int MaxVersion) { 583 unsigned short Encoded = 0; 584 585 // A maximum version of 0 means available in all later versions. 586 if (MaxVersion == 0) { 587 MaxVersion = UINT_MAX; 588 } 589 590 unsigned VersionIDs[] = {100, 110, 120, 200, 300}; 591 for (unsigned I = 0; I < sizeof(VersionIDs) / sizeof(VersionIDs[0]); I++) { 592 if (VersionIDs[I] >= MinVersion && VersionIDs[I] < MaxVersion) { 593 Encoded |= 1 << I; 594 } 595 } 596 597 return Encoded; 598 } 599 600 void BuiltinNameEmitter::EmitBuiltinTable() { 601 unsigned Index = 0; 602 603 OS << "static const OpenCLBuiltinStruct BuiltinTable[] = {\n"; 604 for (const auto &SLM : SignatureListMap) { 605 606 OS << " // " << (Index + 1) << ": "; 607 for (const auto &Name : SLM.second.Names) { 608 OS << Name << ", "; 609 } 610 OS << "\n"; 611 612 for (const auto &Overload : SLM.second.Signatures) { 613 StringRef ExtName = Overload.first->getValueAsDef("Extension")->getName(); 614 unsigned int MinVersion = 615 Overload.first->getValueAsDef("MinVersion")->getValueAsInt("ID"); 616 unsigned int MaxVersion = 617 Overload.first->getValueAsDef("MaxVersion")->getValueAsInt("ID"); 618 619 OS << " { " << Overload.second << ", " 620 << Overload.first->getValueAsListOfDefs("Signature").size() << ", " 621 << (Overload.first->getValueAsBit("IsPure")) << ", " 622 << (Overload.first->getValueAsBit("IsConst")) << ", " 623 << (Overload.first->getValueAsBit("IsConv")) << ", " 624 << FunctionExtensionIndex[ExtName] << ", " 625 << EncodeVersions(MinVersion, MaxVersion) << " },\n"; 626 Index++; 627 } 628 } 629 OS << "};\n\n"; 630 } 631 632 bool BuiltinNameEmitter::CanReuseSignature( 633 BuiltinIndexListTy *Candidate, 634 std::vector<std::pair<const Record *, unsigned>> &SignatureList) { 635 assert(Candidate->size() == SignatureList.size() && 636 "signature lists should have the same size"); 637 638 auto &CandidateSigs = 639 SignatureListMap.find(Candidate)->second.Signatures; 640 for (unsigned Index = 0; Index < Candidate->size(); Index++) { 641 const Record *Rec = SignatureList[Index].first; 642 const Record *Rec2 = CandidateSigs[Index].first; 643 if (Rec->getValueAsBit("IsPure") == Rec2->getValueAsBit("IsPure") && 644 Rec->getValueAsBit("IsConst") == Rec2->getValueAsBit("IsConst") && 645 Rec->getValueAsBit("IsConv") == Rec2->getValueAsBit("IsConv") && 646 Rec->getValueAsDef("MinVersion")->getValueAsInt("ID") == 647 Rec2->getValueAsDef("MinVersion")->getValueAsInt("ID") && 648 Rec->getValueAsDef("MaxVersion")->getValueAsInt("ID") == 649 Rec2->getValueAsDef("MaxVersion")->getValueAsInt("ID") && 650 Rec->getValueAsDef("Extension")->getName() == 651 Rec2->getValueAsDef("Extension")->getName()) { 652 return true; 653 } 654 } 655 return false; 656 } 657 658 void BuiltinNameEmitter::GroupBySignature() { 659 // List of signatures known to be emitted. 660 std::vector<BuiltinIndexListTy *> KnownSignatures; 661 662 for (auto &Fct : FctOverloadMap) { 663 bool FoundReusableSig = false; 664 665 // Gather all signatures for the current function. 666 auto *CurSignatureList = new BuiltinIndexListTy(); 667 for (const auto &Signature : Fct.second) { 668 CurSignatureList->push_back(Signature.second); 669 } 670 // Sort the list to facilitate future comparisons. 671 llvm::sort(*CurSignatureList); 672 673 // Check if we have already seen another function with the same list of 674 // signatures. If so, just add the name of the function. 675 for (auto *Candidate : KnownSignatures) { 676 if (Candidate->size() == CurSignatureList->size() && 677 *Candidate == *CurSignatureList) { 678 if (CanReuseSignature(Candidate, Fct.second)) { 679 SignatureListMap.find(Candidate)->second.Names.push_back(Fct.first); 680 FoundReusableSig = true; 681 } 682 } 683 } 684 685 if (FoundReusableSig) { 686 delete CurSignatureList; 687 } else { 688 // Add a new entry. 689 SignatureListMap[CurSignatureList] = { 690 SmallVector<StringRef, 4>(1, Fct.first), Fct.second}; 691 KnownSignatures.push_back(CurSignatureList); 692 } 693 } 694 695 for (auto *I : KnownSignatures) { 696 delete I; 697 } 698 } 699 700 void BuiltinNameEmitter::EmitStringMatcher() { 701 std::vector<StringMatcher::StringPair> ValidBuiltins; 702 unsigned CumulativeIndex = 1; 703 704 for (const auto &SLM : SignatureListMap) { 705 const auto &Ovl = SLM.second.Signatures; 706 707 // A single signature list may be used by different builtins. Return the 708 // same <index, length> pair for each of those builtins. 709 for (const auto &FctName : SLM.second.Names) { 710 std::string RetStmt; 711 raw_string_ostream SS(RetStmt); 712 SS << "return std::make_pair(" << CumulativeIndex << ", " << Ovl.size() 713 << ");"; 714 SS.flush(); 715 ValidBuiltins.push_back( 716 StringMatcher::StringPair(std::string(FctName), RetStmt)); 717 } 718 CumulativeIndex += Ovl.size(); 719 } 720 721 OS << R"( 722 // Find out whether a string matches an existing OpenCL builtin function name. 723 // Returns: A pair <0, 0> if no name matches. 724 // A pair <Index, Len> indexing the BuiltinTable if the name is 725 // matching an OpenCL builtin function. 726 static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) { 727 728 )"; 729 730 StringMatcher("Name", ValidBuiltins, OS).Emit(0, true); 731 732 OS << " return std::make_pair(0, 0);\n"; 733 OS << "} // isOpenCLBuiltin\n"; 734 } 735 736 void BuiltinNameEmitter::EmitQualTypeFinder() { 737 OS << R"( 738 739 static QualType getOpenCLEnumType(Sema &S, llvm::StringRef Name); 740 static QualType getOpenCLTypedefType(Sema &S, llvm::StringRef Name); 741 742 // Convert an OpenCLTypeStruct type to a list of QualTypes. 743 // Generic types represent multiple types and vector sizes, thus a vector 744 // is returned. The conversion is done in two steps: 745 // Step 1: A switch statement fills a vector with scalar base types for the 746 // Cartesian product of (vector sizes) x (types) for generic types, 747 // or a single scalar type for non generic types. 748 // Step 2: Qualifiers and other type properties such as vector size are 749 // applied. 750 static void OCL2Qual(Sema &S, const OpenCLTypeStruct &Ty, 751 llvm::SmallVectorImpl<QualType> &QT) { 752 ASTContext &Context = S.Context; 753 // Number of scalar types in the GenType. 754 unsigned GenTypeNumTypes; 755 // Pointer to the list of vector sizes for the GenType. 756 llvm::ArrayRef<unsigned> GenVectorSizes; 757 )"; 758 759 // Generate list of vector sizes for each generic type. 760 for (const auto *VectList : Records.getAllDerivedDefinitions("IntList")) { 761 OS << " constexpr unsigned List" 762 << VectList->getValueAsString("Name") << "[] = {"; 763 for (const auto V : VectList->getValueAsListOfInts("List")) { 764 OS << V << ", "; 765 } 766 OS << "};\n"; 767 } 768 769 // Step 1. 770 // Start of switch statement over all types. 771 OS << "\n switch (Ty.ID) {\n"; 772 773 // Switch cases for image types (Image2d, Image3d, ...) 774 std::vector<Record *> ImageTypes = 775 Records.getAllDerivedDefinitions("ImageType"); 776 777 // Map an image type name to its 3 access-qualified types (RO, WO, RW). 778 StringMap<SmallVector<Record *, 3>> ImageTypesMap; 779 for (auto *IT : ImageTypes) { 780 auto Entry = ImageTypesMap.find(IT->getValueAsString("Name")); 781 if (Entry == ImageTypesMap.end()) { 782 SmallVector<Record *, 3> ImageList; 783 ImageList.push_back(IT); 784 ImageTypesMap.insert( 785 std::make_pair(IT->getValueAsString("Name"), ImageList)); 786 } else { 787 Entry->second.push_back(IT); 788 } 789 } 790 791 // Emit the cases for the image types. For an image type name, there are 3 792 // corresponding QualTypes ("RO", "WO", "RW"). The "AccessQualifier" field 793 // tells which one is needed. Emit a switch statement that puts the 794 // corresponding QualType into "QT". 795 for (const auto &ITE : ImageTypesMap) { 796 OS << " case OCLT_" << ITE.getKey() << ":\n" 797 << " switch (Ty.AccessQualifier) {\n" 798 << " case OCLAQ_None:\n" 799 << " llvm_unreachable(\"Image without access qualifier\");\n"; 800 for (const auto &Image : ITE.getValue()) { 801 OS << StringSwitch<const char *>( 802 Image->getValueAsString("AccessQualifier")) 803 .Case("RO", " case OCLAQ_ReadOnly:\n") 804 .Case("WO", " case OCLAQ_WriteOnly:\n") 805 .Case("RW", " case OCLAQ_ReadWrite:\n") 806 << " QT.push_back(" 807 << Image->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") 808 << ");\n" 809 << " break;\n"; 810 } 811 OS << " }\n" 812 << " break;\n"; 813 } 814 815 // Switch cases for generic types. 816 for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) { 817 OS << " case OCLT_" << GenType->getValueAsString("Name") << ": {\n"; 818 819 // Build the Cartesian product of (vector sizes) x (types). Only insert 820 // the plain scalar types for now; other type information such as vector 821 // size and type qualifiers will be added after the switch statement. 822 std::vector<Record *> BaseTypes = 823 GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List"); 824 825 // Collect all QualTypes for a single vector size into TypeList. 826 OS << " SmallVector<QualType, " << BaseTypes.size() << "> TypeList;\n"; 827 for (const auto *T : BaseTypes) { 828 StringRef Ext = 829 T->getValueAsDef("Extension")->getValueAsString("ExtName"); 830 if (!Ext.empty()) { 831 OS << " if (S.getPreprocessor().isMacroDefined(\"" << Ext 832 << "\")) {\n "; 833 } 834 OS << " TypeList.push_back(" 835 << T->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") << ");\n"; 836 if (!Ext.empty()) { 837 OS << " }\n"; 838 } 839 } 840 OS << " GenTypeNumTypes = TypeList.size();\n"; 841 842 // Duplicate the TypeList for every vector size. 843 std::vector<int64_t> VectorList = 844 GenType->getValueAsDef("VectorList")->getValueAsListOfInts("List"); 845 OS << " QT.reserve(" << VectorList.size() * BaseTypes.size() << ");\n" 846 << " for (unsigned I = 0; I < " << VectorList.size() << "; I++) {\n" 847 << " QT.append(TypeList);\n" 848 << " }\n"; 849 850 // GenVectorSizes is the list of vector sizes for this GenType. 851 OS << " GenVectorSizes = List" 852 << GenType->getValueAsDef("VectorList")->getValueAsString("Name") 853 << ";\n" 854 << " break;\n" 855 << " }\n"; 856 } 857 858 // Switch cases for non generic, non image types (int, int4, float, ...). 859 // Only insert the plain scalar type; vector information and type qualifiers 860 // are added in step 2. 861 std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); 862 StringMap<bool> TypesSeen; 863 864 for (const auto *T : Types) { 865 // Check this is not an image type 866 if (ImageTypesMap.find(T->getValueAsString("Name")) != ImageTypesMap.end()) 867 continue; 868 // Check we have not seen this Type 869 if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end()) 870 continue; 871 TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true)); 872 873 // Check the Type does not have an "abstract" QualType 874 auto QT = T->getValueAsDef("QTExpr"); 875 if (QT->getValueAsBit("IsAbstract") == 1) 876 continue; 877 // Emit the cases for non generic, non image types. 878 OS << " case OCLT_" << T->getValueAsString("Name") << ":\n"; 879 880 StringRef Ext = T->getValueAsDef("Extension")->getValueAsString("ExtName"); 881 // If this type depends on an extension, ensure the extension macro is 882 // defined. 883 if (!Ext.empty()) { 884 OS << " if (S.getPreprocessor().isMacroDefined(\"" << Ext 885 << "\")) {\n "; 886 } 887 OS << " QT.push_back(" << QT->getValueAsString("TypeExpr") << ");\n"; 888 if (!Ext.empty()) { 889 OS << " }\n"; 890 } 891 OS << " break;\n"; 892 } 893 894 // End of switch statement. 895 OS << " } // end of switch (Ty.ID)\n\n"; 896 897 // Step 2. 898 // Add ExtVector types if this was a generic type, as the switch statement 899 // above only populated the list with scalar types. This completes the 900 // construction of the Cartesian product of (vector sizes) x (types). 901 OS << " // Construct the different vector types for each generic type.\n"; 902 OS << " if (Ty.ID >= " << TypeList.size() << ") {"; 903 OS << R"( 904 for (unsigned I = 0; I < QT.size(); I++) { 905 // For scalars, size is 1. 906 if (GenVectorSizes[I / GenTypeNumTypes] != 1) { 907 QT[I] = Context.getExtVectorType(QT[I], 908 GenVectorSizes[I / GenTypeNumTypes]); 909 } 910 } 911 } 912 )"; 913 914 // Assign the right attributes to the types (e.g. vector size). 915 OS << R"( 916 // Set vector size for non-generic vector types. 917 if (Ty.VectorWidth > 1) { 918 for (unsigned Index = 0; Index < QT.size(); Index++) { 919 QT[Index] = Context.getExtVectorType(QT[Index], Ty.VectorWidth); 920 } 921 } 922 923 if (Ty.IsVolatile != 0) { 924 for (unsigned Index = 0; Index < QT.size(); Index++) { 925 QT[Index] = Context.getVolatileType(QT[Index]); 926 } 927 } 928 929 if (Ty.IsConst != 0) { 930 for (unsigned Index = 0; Index < QT.size(); Index++) { 931 QT[Index] = Context.getConstType(QT[Index]); 932 } 933 } 934 935 // Transform the type to a pointer as the last step, if necessary. 936 // Builtin functions only have pointers on [const|volatile], no 937 // [const|volatile] pointers, so this is ok to do it as a last step. 938 if (Ty.IsPointer != 0) { 939 for (unsigned Index = 0; Index < QT.size(); Index++) { 940 QT[Index] = Context.getAddrSpaceQualType(QT[Index], Ty.AS); 941 QT[Index] = Context.getPointerType(QT[Index]); 942 } 943 } 944 )"; 945 946 // End of the "OCL2Qual" function. 947 OS << "\n} // OCL2Qual\n"; 948 } 949 950 std::string OpenCLBuiltinFileEmitterBase::getTypeString(const Record *Type, 951 TypeFlags Flags, 952 int VectorSize) const { 953 std::string S; 954 if (Type->getValueAsBit("IsConst") || Flags.IsConst) { 955 S += "const "; 956 } 957 if (Type->getValueAsBit("IsVolatile") || Flags.IsVolatile) { 958 S += "volatile "; 959 } 960 961 auto PrintAddrSpace = [&S](StringRef AddrSpace) { 962 S += StringSwitch<const char *>(AddrSpace) 963 .Case("clang::LangAS::opencl_private", "__private") 964 .Case("clang::LangAS::opencl_global", "__global") 965 .Case("clang::LangAS::opencl_constant", "__constant") 966 .Case("clang::LangAS::opencl_local", "__local") 967 .Case("clang::LangAS::opencl_generic", "__generic") 968 .Default("__private"); 969 S += " "; 970 }; 971 if (Flags.IsPointer) { 972 PrintAddrSpace(Flags.AddrSpace); 973 } else if (Type->getValueAsBit("IsPointer")) { 974 PrintAddrSpace(Type->getValueAsString("AddrSpace")); 975 } 976 977 StringRef Acc = Type->getValueAsString("AccessQualifier"); 978 if (Acc != "") { 979 S += StringSwitch<const char *>(Acc) 980 .Case("RO", "__read_only ") 981 .Case("WO", "__write_only ") 982 .Case("RW", "__read_write "); 983 } 984 985 S += Type->getValueAsString("Name").str(); 986 if (VectorSize > 1) { 987 S += std::to_string(VectorSize); 988 } 989 990 if (Type->getValueAsBit("IsPointer") || Flags.IsPointer) { 991 S += " *"; 992 } 993 994 return S; 995 } 996 997 void OpenCLBuiltinFileEmitterBase::getTypeLists( 998 Record *Type, TypeFlags &Flags, std::vector<Record *> &TypeList, 999 std::vector<int64_t> &VectorList) const { 1000 bool isGenType = Type->isSubClassOf("GenericType"); 1001 if (isGenType) { 1002 TypeList = Type->getValueAsDef("TypeList")->getValueAsListOfDefs("List"); 1003 VectorList = 1004 Type->getValueAsDef("VectorList")->getValueAsListOfInts("List"); 1005 return; 1006 } 1007 1008 if (Type->isSubClassOf("PointerType") || Type->isSubClassOf("ConstType") || 1009 Type->isSubClassOf("VolatileType")) { 1010 StringRef SubTypeName = Type->getValueAsString("Name"); 1011 Record *PossibleGenType = Records.getDef(SubTypeName); 1012 if (PossibleGenType && PossibleGenType->isSubClassOf("GenericType")) { 1013 // When PointerType, ConstType, or VolatileType is applied to a 1014 // GenericType, the flags need to be taken from the subtype, not from the 1015 // GenericType. 1016 Flags.IsPointer = Type->getValueAsBit("IsPointer"); 1017 Flags.IsConst = Type->getValueAsBit("IsConst"); 1018 Flags.IsVolatile = Type->getValueAsBit("IsVolatile"); 1019 Flags.AddrSpace = Type->getValueAsString("AddrSpace"); 1020 getTypeLists(PossibleGenType, Flags, TypeList, VectorList); 1021 return; 1022 } 1023 } 1024 1025 // Not a GenericType, so just insert the single type. 1026 TypeList.push_back(Type); 1027 VectorList.push_back(Type->getValueAsInt("VecWidth")); 1028 } 1029 1030 void OpenCLBuiltinFileEmitterBase::expandTypesInSignature( 1031 const std::vector<Record *> &Signature, 1032 SmallVectorImpl<SmallVector<std::string, 2>> &Types) { 1033 // Find out if there are any GenTypes in this signature, and if so, calculate 1034 // into how many signatures they will expand. 1035 unsigned NumSignatures = 1; 1036 SmallVector<SmallVector<std::string, 4>, 4> ExpandedGenTypes; 1037 for (const auto &Arg : Signature) { 1038 SmallVector<std::string, 4> ExpandedArg; 1039 std::vector<Record *> TypeList; 1040 std::vector<int64_t> VectorList; 1041 TypeFlags Flags; 1042 1043 getTypeLists(Arg, Flags, TypeList, VectorList); 1044 1045 // Insert the Cartesian product of the types and vector sizes. 1046 for (const auto &Vector : VectorList) { 1047 for (const auto &Type : TypeList) { 1048 ExpandedArg.push_back(getTypeString(Type, Flags, Vector)); 1049 } 1050 } 1051 NumSignatures = std::max<unsigned>(NumSignatures, ExpandedArg.size()); 1052 ExpandedGenTypes.push_back(ExpandedArg); 1053 } 1054 1055 // Now the total number of signatures is known. Populate the return list with 1056 // all signatures. 1057 for (unsigned I = 0; I < NumSignatures; I++) { 1058 SmallVector<std::string, 2> Args; 1059 1060 // Process a single signature. 1061 for (unsigned ArgNum = 0; ArgNum < Signature.size(); ArgNum++) { 1062 // For differently-sized GenTypes in a parameter list, the smaller 1063 // GenTypes just repeat, so index modulo the number of expanded types. 1064 size_t TypeIndex = I % ExpandedGenTypes[ArgNum].size(); 1065 Args.push_back(ExpandedGenTypes[ArgNum][TypeIndex]); 1066 } 1067 Types.push_back(Args); 1068 } 1069 } 1070 1071 void OpenCLBuiltinFileEmitterBase::emitExtensionSetup() { 1072 OS << R"( 1073 #pragma OPENCL EXTENSION cl_khr_fp16 : enable 1074 #pragma OPENCL EXTENSION cl_khr_fp64 : enable 1075 #pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable 1076 #pragma OPENCL EXTENSION cl_khr_int64_extended_atomics : enable 1077 #pragma OPENCL EXTENSION cl_khr_gl_msaa_sharing : enable 1078 #pragma OPENCL EXTENSION cl_khr_mipmap_image_writes : enable 1079 #pragma OPENCL EXTENSION cl_khr_3d_image_writes : enable 1080 1081 )"; 1082 } 1083 1084 std::string 1085 OpenCLBuiltinFileEmitterBase::emitExtensionGuard(const Record *Builtin) { 1086 StringRef Extensions = 1087 Builtin->getValueAsDef("Extension")->getValueAsString("ExtName"); 1088 if (Extensions.empty()) 1089 return ""; 1090 1091 OS << "#if"; 1092 1093 SmallVector<StringRef, 2> ExtVec; 1094 Extensions.split(ExtVec, " "); 1095 bool isFirst = true; 1096 for (StringRef Ext : ExtVec) { 1097 if (!isFirst) { 1098 OS << " &&"; 1099 } 1100 OS << " defined(" << Ext << ")"; 1101 isFirst = false; 1102 } 1103 OS << "\n"; 1104 1105 return "#endif // Extension\n"; 1106 } 1107 1108 std::string 1109 OpenCLBuiltinFileEmitterBase::emitVersionGuard(const Record *Builtin) { 1110 std::string OptionalEndif; 1111 auto PrintOpenCLVersion = [this](int Version) { 1112 OS << "CL_VERSION_" << (Version / 100) << "_" << ((Version % 100) / 10); 1113 }; 1114 int MinVersion = Builtin->getValueAsDef("MinVersion")->getValueAsInt("ID"); 1115 if (MinVersion != 100) { 1116 // OpenCL 1.0 is the default minimum version. 1117 OS << "#if __OPENCL_C_VERSION__ >= "; 1118 PrintOpenCLVersion(MinVersion); 1119 OS << "\n"; 1120 OptionalEndif = "#endif // MinVersion\n" + OptionalEndif; 1121 } 1122 int MaxVersion = Builtin->getValueAsDef("MaxVersion")->getValueAsInt("ID"); 1123 if (MaxVersion) { 1124 OS << "#if __OPENCL_C_VERSION__ < "; 1125 PrintOpenCLVersion(MaxVersion); 1126 OS << "\n"; 1127 OptionalEndif = "#endif // MaxVersion\n" + OptionalEndif; 1128 } 1129 return OptionalEndif; 1130 } 1131 1132 void OpenCLBuiltinTestEmitter::emit() { 1133 emitSourceFileHeader("OpenCL Builtin exhaustive testing", OS); 1134 1135 emitExtensionSetup(); 1136 1137 // Ensure each test has a unique name by numbering them. 1138 unsigned TestID = 0; 1139 1140 // Iterate over all builtins. 1141 std::vector<Record *> Builtins = Records.getAllDerivedDefinitions("Builtin"); 1142 for (const auto *B : Builtins) { 1143 StringRef Name = B->getValueAsString("Name"); 1144 1145 SmallVector<SmallVector<std::string, 2>, 4> FTypes; 1146 expandTypesInSignature(B->getValueAsListOfDefs("Signature"), FTypes); 1147 1148 OS << "// Test " << Name << "\n"; 1149 1150 std::string OptionalExtensionEndif = emitExtensionGuard(B); 1151 std::string OptionalVersionEndif = emitVersionGuard(B); 1152 1153 for (const auto &Signature : FTypes) { 1154 // Emit function declaration. 1155 OS << Signature[0] << " test" << TestID++ << "_" << Name << "("; 1156 if (Signature.size() > 1) { 1157 for (unsigned I = 1; I < Signature.size(); I++) { 1158 if (I != 1) 1159 OS << ", "; 1160 OS << Signature[I] << " arg" << I; 1161 } 1162 } 1163 OS << ") {\n"; 1164 1165 // Emit function body. 1166 OS << " "; 1167 if (Signature[0] != "void") { 1168 OS << "return "; 1169 } 1170 OS << Name << "("; 1171 for (unsigned I = 1; I < Signature.size(); I++) { 1172 if (I != 1) 1173 OS << ", "; 1174 OS << "arg" << I; 1175 } 1176 OS << ");\n"; 1177 1178 // End of function body. 1179 OS << "}\n"; 1180 } 1181 1182 OS << OptionalVersionEndif; 1183 OS << OptionalExtensionEndif; 1184 } 1185 } 1186 1187 void clang::EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) { 1188 BuiltinNameEmitter NameChecker(Records, OS); 1189 NameChecker.Emit(); 1190 } 1191 1192 void clang::EmitClangOpenCLBuiltinTests(RecordKeeper &Records, 1193 raw_ostream &OS) { 1194 OpenCLBuiltinTestEmitter TestFileGenerator(Records, OS); 1195 TestFileGenerator.emit(); 1196 } 1197