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