1334 lines · cpp
1//===-- ClangOpenCLBuiltinEmitter.cpp - Generate OpenCL Builtin handling --===//2//3// The LLVM Compiler Infrastructure4//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-exception8//9//===----------------------------------------------------------------------===//10//11// These backends consume the definitions of OpenCL builtin functions in12// clang/lib/Sema/OpenCLBuiltins.td and produce builtin handling code for13// 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 32using namespace llvm;33 34namespace {35 36// A list of signatures that are shared by one or more builtin functions.37struct 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 an43// OpenCL builtin function. If so, all overloads of this function are44// added to the LookupResult. The generated include file is used by45// SemaLookup.cpp46//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 pairs50// <SigIndex, SigLen> of the overloads of "cos".51// SignatureTable[SigIndex] to SignatureTable[SigIndex + SigLen] contains52// one of the signatures of "cos". The SignatureTable entry can be53// referenced by other functions, e.g. "sin", to exploit the fact that54// 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 an62// 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 index70// into the above TypeTable. Multiple entries following each other form a71// signature, where the first entry is the return type and subsequent72// entries are the argument types.73//74// * OpenCLBuiltinStruct BuiltinTable[]75// Each entry represents one overload of an OpenCL builtin function and76// 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 function80// 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 using85// GenTypes.86//87class BuiltinNameEmitter {88public:89 BuiltinNameEmitter(const RecordKeeper &Records, raw_ostream &OS)90 : Records(Records), OS(OS) {}91 92 // Entrypoint to generate the functions and structures for checking93 // whether a function is an OpenCL builtin function.94 void Emit();95 96private: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 as101 // 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 enum108 // definitions in the Output string parameter, and save their Record instances109 // 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 in114 // 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 the136 // SignatureListMap.137 // Some builtin functions have the same list of signatures, for example the138 // "sin" and "cos" functions. To save space in the BuiltinTable, the139 // "isOpenCLBuiltin" function will have the same output for these two140 // 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 followings152 // 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 of160 // each function, and is a struct OpenCLBuiltinDecl.161 // E.g.:162 // // 891 convert_float2_rtn163 // { 58, 2, 3, 100, 0 },164 // This means that the signature of this convert_float2_rtn overload has165 // 1 argument (+1 for the return type), stored at index 58 in166 // the SignatureTable. This prototype requires extension "3" in the167 // FunctionExtensionTable. The last two values represent the minimum (1.0)168 // and maximum (0, meaning no max version) OpenCL version in which this169 // overload is supported.170 void EmitBuiltinTable();171 172 // Emit a StringMatcher function to check whether a function name is an173 // OpenCL builtin function name.174 void EmitStringMatcher();175 176 // Emit a function returning the clang QualType instance associated with177 // the TableGen Record Type.178 void EmitQualTypeFinder();179 180 // Contains a list of the available signatures, without the name of the181 // 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 the190 // 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 to206 // 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 three220 // signatures, and these signatures are at index Ix in the SignatureTable:221 // cos | sin | Signature | Index222 // float cos(float) | float sin(float) | Signature1 | I1223 // double cos(double) | double sin(double) | Signature2 | I2224 // half cos(half) | half sin(half) | Signature3 | I3225 //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 the231 // 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.td236class OpenCLBuiltinFileEmitterBase {237public: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 builtin243 // functions.244 virtual void emit() = 0;245 246protected: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 be256 // 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. For261 // non-GenericTypes, the resulting vectors will contain 1 element. For262 // 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 into268 // one or more function signatures. Return them as a vector of a vector of269 // strings, with each string containing an OpenCL C type and optional270 // qualifiers.271 //272 // The Records may contain GenericTypes, which expand into multiple273 // signatures. Repeated occurrences of GenericType in a signature expand to274 // the same types. For example [char, FGenType, FGenType] expands to:275 // [char, float, float]276 // [char, float2, float2]277 // [char, float3, float3]278 // ...279 void280 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 corresponding287 // 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 the291 // corresponding closing #endif, or an empty string if no version #if guard292 // was emitted.293 std::string emitVersionGuard(const Record *Builtin);294 295 // Emit an #if guard for all type extensions required for the given type296 // strings. Return the corresponding closing #endif, or an empty string297 // if no extension #if guard was emitted.298 StringRef299 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 as305 // 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 input313// as BuiltinNameEmitter, but generates a .cl file that contains a call to each314// builtin function described in the .td input.315class OpenCLBuiltinTestEmitter : public OpenCLBuiltinFileEmitterBase {316public:317 OpenCLBuiltinTestEmitter(const RecordKeeper &Records, raw_ostream &OS)318 : OpenCLBuiltinFileEmitterBase(Records, OS) {}319 320 // Entrypoint to generate the functions for testing all OpenCL builtin321 // functions.322 void emit() override;323};324 325// OpenCL builtin header generator. This class processes the same TableGen326// input as BuiltinNameEmitter, but generates a .h file that contains a327// prototype for each builtin function described in the .td input.328class OpenCLBuiltinHeaderEmitter : public OpenCLBuiltinFileEmitterBase {329public: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} // namespace338 339void 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 363void 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 that373 // the Record can be a VectorType or something else, only the name is374 // important.375 List.push_back(T);376 TypesSeen.insert(T->getValueAsString("Name"));377 }378 }379}380 381void 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 keep390 // gentypes at the end of the enum which simplifies the special handling391 // 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.406enum OpenCLAccessQual : unsigned char {407 OCLAQ_None,408 OCLAQ_ReadOnly,409 OCLAQ_WriteOnly,410 OCLAQ_ReadWrite411};412 413// Represents a return type or argument type.414struct 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.432struct OpenCLBuiltinStruct {433 // Index of the signature in the OpenCLTypeStruct table.434 const unsigned SigTableIndex;435 // Entries between index SigTableIndex and (SigTableIndex + NumTypes - 1) in436 // the SignatureTable represent the complete signature. The first type at437 // 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 allow456// a signature to contain different GenTypes if these GenTypes represent457// the same number of actual scalar or vector types.458//459// Exit with a fatal error if an unsupported construct is encountered.460static 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 497void 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 533void 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 550void 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 572void BuiltinNameEmitter::EmitSignatureTable() {573 // Store a type (e.g. int, float, int2, ...). The type is stored as an index574 // of a struct OpenCLType table. Multiple entries following each other form a575 // 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 the583 // current index type (unsigned short). When hitting this, the type584 // 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 be595// 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.)598static 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 617void 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 649bool 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 675void 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 of691 // 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 717void 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 the725 // 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 is741// matching an OpenCL builtin function.742static 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 in753// the space-separated list of extensions.754static 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 766void BuiltinNameEmitter::EmitQualTypeFinder() {767 OS << R"(768 769static QualType getOpenCLEnumType(Sema &S, llvm::StringRef Name);770static 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 vector774// is returned. The conversion is done in two steps:775// Step 1: A switch statement fills a vector with scalar base types for the776// 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 are779// applied.780static 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 3813 // corresponding QualTypes ("RO", "WO", "RW"). The "AccessQualifier" field814 // tells which one is needed. Emit a switch statement that puts the815 // 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 insert850 // the plain scalar types for now; other type information such as vector851 // 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 qualifiers889 // 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 type895 if (ImageTypesMap.contains(T->getValueAsString("Name")))896 continue;897 // Check we have not seen this Type898 if (!TypesSeen.insert(T->getValueAsString("Name")).second)899 continue;900 901 // Check the Type does not have an "abstract" QualType902 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 are910 // 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 statement926 // above only populated the list with scalar types. This completes the927 // 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], no964 // [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 977std::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 1024void 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 a1041 // GenericType, the flags need to be taken from the subtype, not from the1042 // 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 1057void 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, calculate1061 // 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 mapping1079 // 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 with1091 // 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 smaller1098 // 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 1106void OpenCLBuiltinFileEmitterBase::emitExtensionSetup() {1107 OS << R"(1108#pragma OPENCL EXTENSION cl_khr_fp16 : enable1109#pragma OPENCL EXTENSION cl_khr_fp64 : enable1110#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable1111#pragma OPENCL EXTENSION cl_khr_int64_extended_atomics : enable1112#pragma OPENCL EXTENSION cl_khr_gl_msaa_sharing : enable1113#pragma OPENCL EXTENSION cl_khr_mipmap_image_writes : enable1114#pragma OPENCL EXTENSION cl_khr_3d_image_writes : enable1115 1116)";1117}1118 1119std::string1120OpenCLBuiltinFileEmitterBase::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 1143std::string1144OpenCLBuiltinFileEmitterBase::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 1167StringRef 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 ExtSet.insert_range(ExtVec);1179 }1180 }1181 1182 // Emit the #if only when at least one extension is required.1183 if (ExtSet.empty())1184 return "";1185 1186 OS << "#if ";1187 bool isFirst = true;1188 for (const auto Ext : ExtSet) {1189 if (!isFirst)1190 OS << " && ";1191 OS << "defined(" << Ext << ")";1192 isFirst = false;1193 }1194 OS << "\n";1195 return "#endif // TypeExtension\n";1196}1197 1198void OpenCLBuiltinTestEmitter::emit() {1199 emitSourceFileHeader("OpenCL Builtin exhaustive testing", OS, Records);1200 1201 emitExtensionSetup();1202 1203 // Ensure each test has a unique name by numbering them.1204 unsigned TestID = 0;1205 1206 // Iterate over all builtins.1207 ArrayRef<const Record *> Builtins =1208 Records.getAllDerivedDefinitions("Builtin");1209 for (const auto *B : Builtins) {1210 StringRef Name = B->getValueAsString("Name");1211 1212 SmallVector<SmallVector<std::string, 2>, 4> FTypes;1213 expandTypesInSignature(B->getValueAsListOfDefs("Signature"), FTypes);1214 1215 OS << "// Test " << Name << "\n";1216 1217 std::string OptionalExtensionEndif = emitExtensionGuard(B);1218 std::string OptionalVersionEndif = emitVersionGuard(B);1219 1220 for (const auto &Signature : FTypes) {1221 StringRef OptionalTypeExtEndif = emitTypeExtensionGuards(Signature);1222 1223 // Emit function declaration.1224 OS << Signature[0] << " test" << TestID++ << "_" << Name << "(";1225 if (Signature.size() > 1) {1226 for (unsigned I = 1; I < Signature.size(); I++) {1227 if (I != 1)1228 OS << ", ";1229 OS << Signature[I] << " arg" << I;1230 }1231 }1232 OS << ") {\n";1233 1234 // Emit function body.1235 OS << " ";1236 if (Signature[0] != "void") {1237 OS << "return ";1238 }1239 OS << Name << "(";1240 for (unsigned I = 1; I < Signature.size(); I++) {1241 if (I != 1)1242 OS << ", ";1243 OS << "arg" << I;1244 }1245 OS << ");\n";1246 1247 // End of function body.1248 OS << "}\n";1249 OS << OptionalTypeExtEndif;1250 }1251 1252 OS << OptionalVersionEndif;1253 OS << OptionalExtensionEndif;1254 }1255}1256 1257void OpenCLBuiltinHeaderEmitter::emit() {1258 emitSourceFileHeader("OpenCL Builtin declarations", OS, Records);1259 1260 emitExtensionSetup();1261 1262 OS << R"(1263#define __ovld __attribute__((overloadable))1264#define __conv __attribute__((convergent))1265#define __purefn __attribute__((pure))1266#define __cnfn __attribute__((const))1267 1268)";1269 1270 // Iterate over all builtins; sort to follow order of definition in .td file.1271 std::vector<const Record *> Builtins =1272 Records.getAllDerivedDefinitions("Builtin");1273 sort(Builtins, LessRecord());1274 1275 for (const auto *B : Builtins) {1276 StringRef Name = B->getValueAsString("Name");1277 1278 std::string OptionalExtensionEndif = emitExtensionGuard(B);1279 std::string OptionalVersionEndif = emitVersionGuard(B);1280 1281 SmallVector<SmallVector<std::string, 2>, 4> FTypes;1282 expandTypesInSignature(B->getValueAsListOfDefs("Signature"), FTypes);1283 1284 for (const auto &Signature : FTypes) {1285 StringRef OptionalTypeExtEndif = emitTypeExtensionGuards(Signature);1286 1287 // Emit function declaration.1288 OS << Signature[0] << " __ovld ";1289 if (B->getValueAsBit("IsConst"))1290 OS << "__cnfn ";1291 if (B->getValueAsBit("IsPure"))1292 OS << "__purefn ";1293 if (B->getValueAsBit("IsConv"))1294 OS << "__conv ";1295 1296 OS << Name << "(";1297 if (Signature.size() > 1) {1298 for (unsigned I = 1; I < Signature.size(); I++) {1299 if (I != 1)1300 OS << ", ";1301 OS << Signature[I];1302 }1303 }1304 OS << ");\n";1305 1306 OS << OptionalTypeExtEndif;1307 }1308 1309 OS << OptionalVersionEndif;1310 OS << OptionalExtensionEndif;1311 }1312 1313 OS << "\n// Disable any extensions we may have enabled previously.\n"1314 "#pragma OPENCL EXTENSION all : disable\n";1315}1316 1317void clang::EmitClangOpenCLBuiltins(const RecordKeeper &Records,1318 raw_ostream &OS) {1319 BuiltinNameEmitter NameChecker(Records, OS);1320 NameChecker.Emit();1321}1322 1323void clang::EmitClangOpenCLBuiltinHeader(const RecordKeeper &Records,1324 raw_ostream &OS) {1325 OpenCLBuiltinHeaderEmitter HeaderFileGenerator(Records, OS);1326 HeaderFileGenerator.emit();1327}1328 1329void clang::EmitClangOpenCLBuiltinTests(const RecordKeeper &Records,1330 raw_ostream &OS) {1331 OpenCLBuiltinTestEmitter TestFileGenerator(Records, OS);1332 TestFileGenerator.emit();1333}1334