diff options
Diffstat (limited to 'utils/TableGen/ClangOpenCLBuiltinEmitter.cpp')
-rw-r--r-- | utils/TableGen/ClangOpenCLBuiltinEmitter.cpp | 540 |
1 files changed, 434 insertions, 106 deletions
diff --git a/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp index 8d83b1c7fa6b9..c8975d7bf615d 100644 --- a/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ b/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -15,20 +15,49 @@ // // For a successful lookup of e.g. the "cos" builtin, isOpenCLBuiltin("cos") // returns a pair <Index, Len>. -// OpenCLBuiltins[Index] to OpenCLBuiltins[Index + Len] contains the pairs +// BuiltinTable[Index] to BuiltinTable[Index + Len] contains the pairs // <SigIndex, SigLen> of the overloads of "cos". -// OpenCLSignature[SigIndex] to OpenCLSignature[SigIndex + SigLen] contains -// one of the signatures of "cos". The OpenCLSignature entry can be -// referenced by other functions, i.e. "sin", since multiple OpenCL builtins -// share the same signature. +// SignatureTable[SigIndex] to SignatureTable[SigIndex + SigLen] contains +// one of the signatures of "cos". The SignatureTable entry can be +// referenced by other functions, e.g. "sin", to exploit the fact that +// many OpenCL builtins share the same signature. +// +// The file generated by this TableGen emitter contains the following: +// +// * Structs and enums to represent types and function signatures. +// +// * OpenCLTypeStruct TypeTable[] +// Type information for return types and arguments. +// +// * unsigned SignatureTable[] +// A list of types representing function signatures. Each entry is an index +// into the above TypeTable. Multiple entries following each other form a +// signature, where the first entry is the return type and subsequent +// entries are the argument types. +// +// * OpenCLBuiltinStruct BuiltinTable[] +// Each entry represents one overload of an OpenCL builtin function and +// consists of an index into the SignatureTable and the number of arguments. +// +// * std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) +// Find out whether a string matches an existing OpenCL builtin function +// name and return an index into BuiltinTable and the number of overloads. +// +// * void OCL2Qual(ASTContext&, OpenCLTypeStruct, std::vector<QualType>&) +// Convert an OpenCLTypeStruct type to a list of QualType instances. +// One OpenCLTypeStruct can represent multiple types, primarily when using +// GenTypes. +// //===----------------------------------------------------------------------===// +#include "TableGenBackends.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" @@ -57,34 +86,49 @@ private: // The output file. raw_ostream &OS; - // Emit the enums and structs. + // Helper function for BuiltinNameEmitter::EmitDeclarations. Generate enum + // definitions in the Output string parameter, and save their Record instances + // in the List parameter. + // \param Types (in) List containing the Types to extract. + // \param TypesSeen (inout) List containing the Types already extracted. + // \param Output (out) String containing the enums to emit in the output file. + // \param List (out) List containing the extracted Types, except the Types in + // TypesSeen. + void ExtractEnumTypes(std::vector<Record *> &Types, + StringMap<bool> &TypesSeen, std::string &Output, + std::vector<const Record *> &List); + + // Emit the enum or struct used in the generated file. + // Populate the TypeList at the same time. void EmitDeclarations(); - // Parse the Records generated by TableGen and populate OverloadInfo and - // SignatureSet. + // Parse the Records generated by TableGen to populate the SignaturesList, + // FctOverloadMap and TypeMap. void GetOverloads(); - // Emit the OpenCLSignature table. This table contains all possible - // signatures, and is a struct OpenCLType. A signature is composed of a - // return type (mandatory), followed by zero or more argument types. + // Emit the TypeTable containing all types used by OpenCL builtins. + void EmitTypeTable(); + + // Emit the SignatureTable. This table contains all the possible signatures. + // A signature is stored as a list of indexes of the TypeTable. + // The first index references the return type (mandatory), and the followings + // reference its arguments. // E.g.: - // // 12 - // { OCLT_uchar, 4, clang::LangAS::Default, false }, - // { OCLT_float, 4, clang::LangAS::Default, false }, - // This means that index 12 represents a signature - // - returning a uchar vector of 4 elements, and - // - taking as first argument a float vector of 4 elements. + // 15, 2, 15 can represent a function with the signature: + // int func(float, int) + // The "int" type being at the index 15 in the TypeTable. void EmitSignatureTable(); - // Emit the OpenCLBuiltins table. This table contains all overloads of + // Emit the BuiltinTable table. This table contains all the overloads of // each function, and is a struct OpenCLBuiltinDecl. // E.g.: - // // acos - // { 2, 0, "", 100 }, - // This means that the signature of this acos overload is defined in OpenCL - // version 1.0 (100) and does not belong to any extension (""). It has a - // 1 argument (+1 for the return type), stored at index 0 in the - // OpenCLSignature table. + // // 891 convert_float2_rtn + // { 58, 2, 100, 0 }, + // This means that the signature of this convert_float2_rtn overload has + // 1 argument (+1 for the return type), stored at index 58 in + // the SignatureTable. The last two values represent the minimum (1.0) and + // maximum (0, meaning no max version) OpenCL version in which this overload + // is supported. void EmitBuiltinTable(); // Emit a StringMatcher function to check whether a function name is an @@ -102,20 +146,30 @@ private: // <<float>, 5>, // ... // <<double, double>, 35>. - std::vector<std::pair<std::vector<Record *>, unsigned>> SignatureSet; + std::vector<std::pair<std::vector<Record *>, unsigned>> SignaturesList; // Map the name of a builtin function to its prototypes (instances of the // TableGen "Builtin" class). // Each prototype is registered as a pair of: // <pointer to the "Builtin" instance, - // cumulative index of the associated signature in the SignatureSet> + // cumulative index of the associated signature in the SignaturesList> // E.g.: The function cos: (float cos(float), double cos(double), ...) // <"cos", <<ptrToPrototype0, 5>, - // <ptrToPrototype1, 35>> - // <ptrToPrototype2, 79>> + // <ptrToPrototype1, 35>, + // <ptrToPrototype2, 79>> // ptrToPrototype1 has the following signature: <double, double> MapVector<StringRef, std::vector<std::pair<const Record *, unsigned>>> - OverloadInfo; + FctOverloadMap; + + // Contains the map of OpenCL types to their index in the TypeTable. + MapVector<const Record *, unsigned> TypeMap; + + // List of OpenCL type names in the same order as in enum OpenCLTypeID. + // This list does not contain generic types. + std::vector<const Record *> TypeList; + + // Same as TypeList, but for generic types only. + std::vector<const Record *> GenTypeList; }; } // namespace @@ -125,12 +179,14 @@ void BuiltinNameEmitter::Emit() { OS << "#include \"llvm/ADT/StringRef.h\"\n"; OS << "using namespace clang;\n\n"; + // Emit enums and structs. EmitDeclarations(); GetOverloads(); + // Emit tables. + EmitTypeTable(); EmitSignatureTable(); - EmitBuiltinTable(); EmitStringMatcher(); @@ -138,100 +194,226 @@ void BuiltinNameEmitter::Emit() { EmitQualTypeFinder(); } +void BuiltinNameEmitter::ExtractEnumTypes(std::vector<Record *> &Types, + StringMap<bool> &TypesSeen, + std::string &Output, + std::vector<const Record *> &List) { + raw_string_ostream SS(Output); + + for (const auto *T : Types) { + if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end()) { + SS << " OCLT_" + T->getValueAsString("Name") << ",\n"; + // Save the type names in the same order as their enum value. Note that + // the Record can be a VectorType or something else, only the name is + // important. + List.push_back(T); + TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true)); + } + } + SS.flush(); +} + void BuiltinNameEmitter::EmitDeclarations() { + // Enum of scalar type names (float, int, ...) and generic type sets. OS << "enum OpenCLTypeID {\n"; - std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); + StringMap<bool> TypesSeen; - for (const auto *T : Types) { - if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end()) - OS << " OCLT_" + T->getValueAsString("Name") << ",\n"; - TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true)); - } + std::string GenTypeEnums; + std::string TypeEnums; + + // Extract generic types and non-generic types separately, to keep + // gentypes at the end of the enum which simplifies the special handling + // for gentypes in SemaLookup. + std::vector<Record *> GenTypes = + Records.getAllDerivedDefinitions("GenericType"); + ExtractEnumTypes(GenTypes, TypesSeen, GenTypeEnums, GenTypeList); + + std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); + ExtractEnumTypes(Types, TypesSeen, TypeEnums, TypeList); + + OS << TypeEnums; + OS << GenTypeEnums; OS << "};\n"; + // Structure definitions. OS << R"( +// Image access qualifier. +enum OpenCLAccessQual : unsigned char { + OCLAQ_None, + OCLAQ_ReadOnly, + OCLAQ_WriteOnly, + OCLAQ_ReadWrite +}; -// Type used in a prototype of an OpenCL builtin function. -struct OpenCLType { - // A type (e.g.: float, int, ...) - OpenCLTypeID ID; - // Size of vector (if applicable) - unsigned VectorWidth; - // Address space of the pointer (if applicable) - LangAS AS; - // Whether the type is a pointer - bool isPointer; +// Represents a return type or argument type. +struct OpenCLTypeStruct { + // A type (e.g. float, int, ...). + const OpenCLTypeID ID; + // Vector size (if applicable; 0 for scalars and generic types). + const unsigned VectorWidth; + // 0 if the type is not a pointer. + const bool IsPointer; + // 0 if the type is not const. + const bool IsConst; + // 0 if the type is not volatile. + const bool IsVolatile; + // Access qualifier. + const OpenCLAccessQual AccessQualifier; + // Address space of the pointer (if applicable). + const LangAS AS; }; // One overload of an OpenCL builtin function. -struct OpenCLBuiltinDecl { - // Number of arguments for the signature - unsigned NumArgs; - // Index in the OpenCLSignature table to get the required types - unsigned ArgTableIndex; - // Extension to which it belongs (e.g. cl_khr_subgroups) - const char *Extension; - // Version in which it was introduced (e.g. CL20) - unsigned Version; +struct OpenCLBuiltinStruct { + // Index of the signature in the OpenCLTypeStruct table. + const unsigned SigTableIndex; + // Entries between index SigTableIndex and (SigTableIndex + NumTypes - 1) in + // the SignatureTable represent the complete signature. The first type at + // index SigTableIndex is the return type. + const unsigned NumTypes; + // First OpenCL version in which this overload was introduced (e.g. CL20). + const unsigned short MinVersion; + // First OpenCL version in which this overload was removed (e.g. CL20). + const unsigned short MaxVersion; }; )"; } +// Verify that the combination of GenTypes in a signature is supported. +// To simplify the logic for creating overloads in SemaLookup, only allow +// a signature to contain different GenTypes if these GenTypes represent +// the same number of actual scalar or vector types. +// +// Exit with a fatal error if an unsupported construct is encountered. +static void VerifySignature(const std::vector<Record *> &Signature, + const Record *BuiltinRec) { + unsigned GenTypeVecSizes = 1; + unsigned GenTypeTypes = 1; + + for (const auto *T : Signature) { + // Check all GenericType arguments in this signature. + if (T->isSubClassOf("GenericType")) { + // Check number of vector sizes. + unsigned NVecSizes = + T->getValueAsDef("VectorList")->getValueAsListOfInts("List").size(); + if (NVecSizes != GenTypeVecSizes && NVecSizes != 1) { + if (GenTypeVecSizes > 1) { + // We already saw a gentype with a different number of vector sizes. + PrintFatalError(BuiltinRec->getLoc(), + "number of vector sizes should be equal or 1 for all gentypes " + "in a declaration"); + } + GenTypeVecSizes = NVecSizes; + } + + // Check number of data types. + unsigned NTypes = + T->getValueAsDef("TypeList")->getValueAsListOfDefs("List").size(); + if (NTypes != GenTypeTypes && NTypes != 1) { + if (GenTypeTypes > 1) { + // We already saw a gentype with a different number of types. + PrintFatalError(BuiltinRec->getLoc(), + "number of types should be equal or 1 for all gentypes " + "in a declaration"); + } + GenTypeTypes = NTypes; + } + } + } +} + void BuiltinNameEmitter::GetOverloads() { + // Populate the TypeMap. + std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); + unsigned I = 0; + for (const auto &T : Types) { + TypeMap.insert(std::make_pair(T, I++)); + } + + // Populate the SignaturesList and the FctOverloadMap. unsigned CumulativeSignIndex = 0; std::vector<Record *> Builtins = Records.getAllDerivedDefinitions("Builtin"); for (const auto *B : Builtins) { StringRef BName = B->getValueAsString("Name"); - if (OverloadInfo.find(BName) == OverloadInfo.end()) { - OverloadInfo.insert(std::make_pair( + if (FctOverloadMap.find(BName) == FctOverloadMap.end()) { + FctOverloadMap.insert(std::make_pair( BName, std::vector<std::pair<const Record *, unsigned>>{})); } auto Signature = B->getValueAsListOfDefs("Signature"); + // Reuse signatures to avoid unnecessary duplicates. auto it = - std::find_if(SignatureSet.begin(), SignatureSet.end(), + std::find_if(SignaturesList.begin(), SignaturesList.end(), [&](const std::pair<std::vector<Record *>, unsigned> &a) { return a.first == Signature; }); unsigned SignIndex; - if (it == SignatureSet.end()) { - SignatureSet.push_back(std::make_pair(Signature, CumulativeSignIndex)); + if (it == SignaturesList.end()) { + VerifySignature(Signature, B); + SignaturesList.push_back(std::make_pair(Signature, CumulativeSignIndex)); SignIndex = CumulativeSignIndex; CumulativeSignIndex += Signature.size(); } else { SignIndex = it->second; } - OverloadInfo[BName].push_back(std::make_pair(B, SignIndex)); + FctOverloadMap[BName].push_back(std::make_pair(B, SignIndex)); } } +void BuiltinNameEmitter::EmitTypeTable() { + OS << "static const OpenCLTypeStruct TypeTable[] = {\n"; + for (const auto &T : TypeMap) { + const char *AccessQual = + StringSwitch<const char *>(T.first->getValueAsString("AccessQualifier")) + .Case("RO", "OCLAQ_ReadOnly") + .Case("WO", "OCLAQ_WriteOnly") + .Case("RW", "OCLAQ_ReadWrite") + .Default("OCLAQ_None"); + + OS << " // " << T.second << "\n" + << " {OCLT_" << T.first->getValueAsString("Name") << ", " + << T.first->getValueAsInt("VecWidth") << ", " + << T.first->getValueAsBit("IsPointer") << ", " + << T.first->getValueAsBit("IsConst") << ", " + << T.first->getValueAsBit("IsVolatile") << ", " + << AccessQual << ", " + << T.first->getValueAsString("AddrSpace") << "},\n"; + } + OS << "};\n\n"; +} + void BuiltinNameEmitter::EmitSignatureTable() { - OS << "static const OpenCLType OpenCLSignature[] = {\n"; - for (auto &P : SignatureSet) { - OS << "// " << P.second << "\n"; - for (Record *R : P.first) { - OS << "{ OCLT_" << R->getValueAsString("Name") << ", " - << R->getValueAsInt("VecWidth") << ", " - << R->getValueAsString("AddrSpace") << ", " - << R->getValueAsBit("IsPointer") << "},"; - OS << "\n"; + // Store a type (e.g. int, float, int2, ...). The type is stored as an index + // of a struct OpenCLType table. Multiple entries following each other form a + // signature. + OS << "static const unsigned SignatureTable[] = {\n"; + for (const auto &P : SignaturesList) { + OS << " // " << P.second << "\n "; + for (const Record *R : P.first) { + OS << TypeMap.find(R)->second << ", "; } + OS << "\n"; } OS << "};\n\n"; } void BuiltinNameEmitter::EmitBuiltinTable() { - OS << "static const OpenCLBuiltinDecl OpenCLBuiltins[] = {\n"; - for (auto &i : OverloadInfo) { - StringRef Name = i.first; - OS << "// " << Name << "\n"; - for (auto &Overload : i.second) { - OS << " { " << Overload.first->getValueAsListOfDefs("Signature").size() - << ", " << Overload.second << ", " << '"' - << Overload.first->getValueAsString("Extension") << "\", " - << Overload.first->getValueAsDef("Version")->getValueAsInt("Version") + unsigned Index = 0; + + OS << "static const OpenCLBuiltinStruct BuiltinTable[] = {\n"; + for (const auto &FOM : FctOverloadMap) { + + OS << " // " << (Index + 1) << ": " << FOM.first << "\n"; + + for (const auto &Overload : FOM.second) { + OS << " { " << Overload.second << ", " + << Overload.first->getValueAsListOfDefs("Signature").size() << ", " + << Overload.first->getValueAsDef("MinVersion")->getValueAsInt("ID") + << ", " + << Overload.first->getValueAsDef("MaxVersion")->getValueAsInt("ID") << " },\n"; + Index++; } } OS << "};\n\n"; @@ -240,7 +422,7 @@ void BuiltinNameEmitter::EmitBuiltinTable() { void BuiltinNameEmitter::EmitStringMatcher() { std::vector<StringMatcher::StringPair> ValidBuiltins; unsigned CumulativeIndex = 1; - for (auto &i : OverloadInfo) { + for (auto &i : FctOverloadMap) { auto &Ov = i.second; std::string RetStmt; raw_string_ostream SS(RetStmt); @@ -253,30 +435,137 @@ void BuiltinNameEmitter::EmitStringMatcher() { } OS << R"( -// Return 0 if name is not a recognized OpenCL builtin, or an index -// into a table of declarations if it is an OpenCL builtin. -static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef name) { +// Find out whether a string matches an existing OpenCL builtin function name. +// Returns: A pair <0, 0> if no name matches. +// A pair <Index, Len> indexing the BuiltinTable if the name is +// matching an OpenCL builtin function. +static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) { )"; - StringMatcher("name", ValidBuiltins, OS).Emit(0, true); + StringMatcher("Name", ValidBuiltins, OS).Emit(0, true); OS << " return std::make_pair(0, 0);\n"; - OS << "}\n"; + OS << "} // isOpenCLBuiltin\n"; } void BuiltinNameEmitter::EmitQualTypeFinder() { OS << R"( -static QualType OCL2Qual(ASTContext &Context, OpenCLType Ty) { - QualType RT = Context.VoidTy; - switch (Ty.ID) { +// Convert an OpenCLTypeStruct type to a list of QualTypes. +// Generic types represent multiple types and vector sizes, thus a vector +// is returned. The conversion is done in two steps: +// Step 1: A switch statement fills a vector with scalar base types for the +// Cartesian product of (vector sizes) x (types) for generic types, +// or a single scalar type for non generic types. +// Step 2: Qualifiers and other type properties such as vector size are +// applied. +static void OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty, + llvm::SmallVectorImpl<QualType> &QT) { + // Number of scalar types in the GenType. + unsigned GenTypeNumTypes; + // Pointer to the list of vector sizes for the GenType. + llvm::ArrayRef<unsigned> GenVectorSizes; )"; + // Generate list of vector sizes for each generic type. + for (const auto *VectList : Records.getAllDerivedDefinitions("IntList")) { + OS << " constexpr unsigned List" + << VectList->getValueAsString("Name") << "[] = {"; + for (const auto V : VectList->getValueAsListOfInts("List")) { + OS << V << ", "; + } + OS << "};\n"; + } + + // Step 1. + // Start of switch statement over all types. + OS << "\n switch (Ty.ID) {\n"; + + // Switch cases for image types (Image2d, Image3d, ...) + std::vector<Record *> ImageTypes = + Records.getAllDerivedDefinitions("ImageType"); + + // Map an image type name to its 3 access-qualified types (RO, WO, RW). + std::map<StringRef, SmallVector<Record *, 3>> ImageTypesMap; + for (auto *IT : ImageTypes) { + auto Entry = ImageTypesMap.find(IT->getValueAsString("Name")); + if (Entry == ImageTypesMap.end()) { + SmallVector<Record *, 3> ImageList; + ImageList.push_back(IT); + ImageTypesMap.insert( + std::make_pair(IT->getValueAsString("Name"), ImageList)); + } else { + Entry->second.push_back(IT); + } + } + + // Emit the cases for the image types. For an image type name, there are 3 + // corresponding QualTypes ("RO", "WO", "RW"). The "AccessQualifier" field + // tells which one is needed. Emit a switch statement that puts the + // corresponding QualType into "QT". + for (const auto &ITE : ImageTypesMap) { + OS << " case OCLT_" << ITE.first.str() << ":\n" + << " switch (Ty.AccessQualifier) {\n" + << " case OCLAQ_None:\n" + << " llvm_unreachable(\"Image without access qualifier\");\n"; + for (const auto &Image : ITE.second) { + OS << StringSwitch<const char *>( + Image->getValueAsString("AccessQualifier")) + .Case("RO", " case OCLAQ_ReadOnly:\n") + .Case("WO", " case OCLAQ_WriteOnly:\n") + .Case("RW", " case OCLAQ_ReadWrite:\n") + << " QT.push_back(Context." + << Image->getValueAsDef("QTName")->getValueAsString("Name") << ");\n" + << " break;\n"; + } + OS << " }\n" + << " break;\n"; + } + + // Switch cases for generic types. + for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) { + OS << " case OCLT_" << GenType->getValueAsString("Name") << ":\n"; + OS << " QT.append({"; + + // Build the Cartesian product of (vector sizes) x (types). Only insert + // the plain scalar types for now; other type information such as vector + // size and type qualifiers will be added after the switch statement. + for (unsigned I = 0; I < GenType->getValueAsDef("VectorList") + ->getValueAsListOfInts("List") + .size(); + I++) { + for (const auto *T : + GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")) { + OS << "Context." + << T->getValueAsDef("QTName")->getValueAsString("Name") << ", "; + } + } + OS << "});\n"; + // GenTypeNumTypes is the number of types in the GenType + // (e.g. float/double/half). + OS << " GenTypeNumTypes = " + << GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List") + .size() + << ";\n"; + // GenVectorSizes is the list of vector sizes for this GenType. + // QT contains GenTypeNumTypes * #GenVectorSizes elements. + OS << " GenVectorSizes = List" + << GenType->getValueAsDef("VectorList")->getValueAsString("Name") + << ";\n"; + OS << " break;\n"; + } + + // Switch cases for non generic, non image types (int, int4, float, ...). + // Only insert the plain scalar type; vector information and type qualifiers + // are added in step 2. std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type"); StringMap<bool> TypesSeen; for (const auto *T : Types) { + // Check this is not an image type + if (ImageTypesMap.find(T->getValueAsString("Name")) != ImageTypesMap.end()) + continue; // Check we have not seen this Type if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end()) continue; @@ -284,35 +573,74 @@ static QualType OCL2Qual(ASTContext &Context, OpenCLType Ty) { // Check the Type does not have an "abstract" QualType auto QT = T->getValueAsDef("QTName"); - if (QT->getValueAsString("Name") == "null") + if (QT->getValueAsBit("IsAbstract") == 1) continue; + // Emit the cases for non generic, non image types. + OS << " case OCLT_" << T->getValueAsString("Name") << ":\n"; + OS << " QT.push_back(Context." << QT->getValueAsString("Name") + << ");\n"; + OS << " break;\n"; + } - OS << " case OCLT_" << T->getValueAsString("Name") << ":\n"; - OS << " RT = Context." << QT->getValueAsString("Name") << ";\n"; - OS << " break;\n"; + // End of switch statement. + OS << " default:\n" + << " llvm_unreachable(\"OpenCL builtin type not handled yet\");\n" + << " } // end of switch (Ty.ID)\n\n"; + + // Step 2. + // Add ExtVector types if this was a generic type, as the switch statement + // above only populated the list with scalar types. This completes the + // construction of the Cartesian product of (vector sizes) x (types). + OS << " // Construct the different vector types for each generic type.\n"; + OS << " if (Ty.ID >= " << TypeList.size() << ") {"; + OS << R"( + for (unsigned I = 0; I < QT.size(); I++) { + // For scalars, size is 1. + if (GenVectorSizes[I / GenTypeNumTypes] != 1) { + QT[I] = Context.getExtVectorType(QT[I], + GenVectorSizes[I / GenTypeNumTypes]); + } + } } - OS << " }\n"; +)"; - // Special cases + // Assign the right attributes to the types (e.g. vector size). OS << R"( - if (Ty.VectorWidth > 0) - RT = Context.getExtVectorType(RT, Ty.VectorWidth); + // Set vector size for non-generic vector types. + if (Ty.VectorWidth > 1) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getExtVectorType(QT[Index], Ty.VectorWidth); + } + } + + if (Ty.IsVolatile != 0) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getVolatileType(QT[Index]); + } + } - if (Ty.isPointer) { - RT = Context.getAddrSpaceQualType(RT, Ty.AS); - RT = Context.getPointerType(RT); + if (Ty.IsConst != 0) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getConstType(QT[Index]); + } } - return RT; -} + // Transform the type to a pointer as the last step, if necessary. + // Builtin functions only have pointers on [const|volatile], no + // [const|volatile] pointers, so this is ok to do it as a last step. + if (Ty.IsPointer != 0) { + for (unsigned Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getAddrSpaceQualType(QT[Index], Ty.AS); + QT[Index] = Context.getPointerType(QT[Index]); + } + } )"; -} -namespace clang { + // End of the "OCL2Qual" function. + OS << "\n} // OCL2Qual\n"; +} -void EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) { +void clang::EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) { BuiltinNameEmitter NameChecker(Records, OS); NameChecker.Emit(); } - -} // end namespace clang |