https://github.com/dzbarsky updated https://github.com/llvm/llvm-project/pull/202651
>From bfc5e15b01c71abed77a63ce1518b2f41f480d0b Mon Sep 17 00:00:00 2001 From: David Zbarsky <[email protected]> Date: Thu, 11 Jun 2026 22:03:42 -0400 Subject: [PATCH] [clang][OpenCL] Compact builtin metadata tables OpenCLTypeStruct and OpenCLBuiltinStruct contain scalar fields whose values fit in 32 bits. Store each record as bit-fields and retain the existing signature and extension tables. Compile-time assertions protect every packed field and both four-byte record layouts. The generated table payload decreases by 40,812 bytes. SemaLookup.cpp.o decreases from 419,992 to 379,128 bytes, with __TEXT,__const decreasing from 76,800 to 35,984 bytes and relocations decreasing from 4,077 to 4,075. Standalone clang decreases from 117,159,208 to 117,126,200 bytes, saving 33,008 bytes; its stripped size has the same reduction and linked fixups are unchanged. Build clang and generate and compile OpenCLBuiltins.inc. --- .../TableGen/ClangOpenCLBuiltinEmitter.cpp | 109 +++++++++++++----- 1 file changed, 79 insertions(+), 30 deletions(-) diff --git a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp index 720afea8b0965..41ec58abd1130 100644 --- a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -398,7 +398,7 @@ void BuiltinNameEmitter::EmitDeclarations() { OS << TypeEnums; OS << GenTypeEnums; - OS << "};\n"; + OS << " OCLT_Count\n};\n"; // Structure definitions. OS << R"( @@ -410,43 +410,64 @@ enum OpenCLAccessQual : unsigned char { OCLAQ_ReadWrite }; +static constexpr unsigned OpenCLTypeIDBits = 7; +static constexpr unsigned OpenCLTypeVectorWidthBits = 5; +static constexpr unsigned OpenCLTypeAccessQualifierBits = 2; +static constexpr unsigned OpenCLTypeAddressSpaceBits = 3; +static constexpr unsigned OpenCLBuiltinSigTableIndexBits = 14; +static constexpr unsigned OpenCLBuiltinNumTypesBits = 3; +static constexpr unsigned OpenCLBuiltinExtensionBits = 7; +static constexpr unsigned OpenCLBuiltinVersionsBits = 5; + // Represents a return type or argument type. struct OpenCLTypeStruct { // A type (e.g. float, int, ...). - const OpenCLTypeID ID; + const unsigned ID : OpenCLTypeIDBits; // Vector size (if applicable; 0 for scalars and generic types). - const unsigned VectorWidth; + const unsigned VectorWidth : OpenCLTypeVectorWidthBits; // 0 if the type is not a pointer. - const bool IsPointer : 1; + const unsigned IsPointer : 1; // 0 if the type is not const. - const bool IsConst : 1; + const unsigned IsConst : 1; // 0 if the type is not volatile. - const bool IsVolatile : 1; + const unsigned IsVolatile : 1; // Access qualifier. - const OpenCLAccessQual AccessQualifier; + const unsigned AccessQualifier : OpenCLTypeAccessQualifierBits; // Address space of the pointer (if applicable). - const LangAS AS; + const unsigned AS : OpenCLTypeAddressSpaceBits; }; +static_assert(sizeof(OpenCLTypeStruct) == 4, + "OpenCLTypeStruct must remain compact"); // One overload of an OpenCL builtin function. struct OpenCLBuiltinStruct { // Index of the signature in the OpenCLTypeStruct table. - const unsigned SigTableIndex; + const unsigned SigTableIndex : OpenCLBuiltinSigTableIndexBits; // 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; + const unsigned NumTypes : OpenCLBuiltinNumTypesBits; // Function attribute __attribute__((pure)) - const bool IsPure : 1; + const unsigned IsPure : 1; // Function attribute __attribute__((const)) - const bool IsConst : 1; + const unsigned IsConst : 1; // Function attribute __attribute__((convergent)) - const bool IsConv : 1; + const unsigned IsConv : 1; // OpenCL extension(s) required for this overload. - const unsigned short Extension; + const unsigned Extension : OpenCLBuiltinExtensionBits; // OpenCL versions in which this overload is available. - const unsigned short Versions; + const unsigned Versions : OpenCLBuiltinVersionsBits; }; +static_assert(sizeof(OpenCLBuiltinStruct) == 4, + "OpenCLBuiltinStruct must remain compact"); + +static_assert(OCLT_Count <= (1u << OpenCLTypeIDBits), + "OpenCLTypeStruct::ID is too narrow"); +static_assert(OCLAQ_ReadWrite < (1u << OpenCLTypeAccessQualifierBits), + "OpenCLTypeStruct::AccessQualifier is too narrow"); +static_assert(static_cast<unsigned>(LangAS::opencl_global_host) < + (1u << OpenCLTypeAddressSpaceBits), + "OpenCLTypeStruct::AS is too narrow"); )"; } @@ -544,10 +565,14 @@ void BuiltinNameEmitter::EmitExtensionTable() { // Record index of this extension. FunctionExtensionIndex[FE->getName()] = Index++; } - OS << "};\n\n"; + OS << "};\n\n" + << "static_assert(" << FuncExtensions.size() + << " <= (1u << OpenCLBuiltinExtensionBits),\n" + << " \"OpenCLBuiltinStruct::Extension is too narrow\");\n\n"; } void BuiltinNameEmitter::EmitTypeTable() { + unsigned MaxVectorWidth = 0; OS << "static const OpenCLTypeStruct TypeTable[] = {\n"; for (const auto &T : TypeMap) { const char *AccessQual = @@ -556,17 +581,21 @@ void BuiltinNameEmitter::EmitTypeTable() { .Case("WO", "OCLAQ_WriteOnly") .Case("RW", "OCLAQ_ReadWrite") .Default("OCLAQ_None"); + unsigned VectorWidth = T.first->getValueAsInt("VecWidth"); + MaxVectorWidth = std::max(MaxVectorWidth, VectorWidth); OS << " // " << T.second << "\n" - << " {OCLT_" << T.first->getValueAsString("Name") << ", " - << T.first->getValueAsInt("VecWidth") << ", " - << T.first->getValueAsBit("IsPointer") << ", " + << " {OCLT_" << T.first->getValueAsString("Name") << ", " << VectorWidth + << ", " << T.first->getValueAsBit("IsPointer") << ", " << T.first->getValueAsBit("IsConst") << ", " - << T.first->getValueAsBit("IsVolatile") << ", " - << AccessQual << ", " - << T.first->getValueAsString("AddrSpace") << "},\n"; + << T.first->getValueAsBit("IsVolatile") << ", " << AccessQual << ", " + << "static_cast<unsigned>(" << T.first->getValueAsString("AddrSpace") + << ")},\n"; } - OS << "};\n\n"; + OS << "};\n\n" + << "static_assert(" << MaxVectorWidth + << " < (1u << OpenCLTypeVectorWidthBits),\n" + << " \"OpenCLTypeStruct::VectorWidth is too narrow\");\n\n"; } void BuiltinNameEmitter::EmitSignatureTable() { @@ -588,7 +617,15 @@ void BuiltinNameEmitter::EmitSignatureTable() { } OS << "\n"; } - OS << "};\n\n"; + unsigned SignatureTableSize = + SignaturesList.empty() + ? 0 + : SignaturesList.back().second + SignaturesList.back().first.size(); + OS << "};\n\n" + << "static_assert(" << SignatureTableSize + << " <= (1u << OpenCLBuiltinSigTableIndexBits),\n" + << " \"OpenCLBuiltinStruct::SigTableIndex is too " + "narrow\");\n\n"; } // Encode a range MinVersion..MaxVersion into a single bit mask that can be @@ -616,6 +653,8 @@ static unsigned short EncodeVersions(unsigned int MinVersion, void BuiltinNameEmitter::EmitBuiltinTable() { unsigned Index = 0; + unsigned MaxNumTypes = 0; + unsigned MaxVersions = 0; OS << "static const OpenCLBuiltinStruct BuiltinTable[] = {\n"; for (const auto &SLM : SignatureListMap) { @@ -632,18 +671,27 @@ void BuiltinNameEmitter::EmitBuiltinTable() { Overload.first->getValueAsDef("MinVersion")->getValueAsInt("ID"); unsigned int MaxVersion = Overload.first->getValueAsDef("MaxVersion")->getValueAsInt("ID"); + unsigned NumTypes = + Overload.first->getValueAsListOfDefs("Signature").size(); + unsigned Versions = EncodeVersions(MinVersion, MaxVersion); + MaxNumTypes = std::max(MaxNumTypes, NumTypes); + MaxVersions = std::max(MaxVersions, Versions); - OS << " { " << Overload.second << ", " - << Overload.first->getValueAsListOfDefs("Signature").size() << ", " + OS << " { " << Overload.second << ", " << NumTypes << ", " << (Overload.first->getValueAsBit("IsPure")) << ", " << (Overload.first->getValueAsBit("IsConst")) << ", " << (Overload.first->getValueAsBit("IsConv")) << ", " - << FunctionExtensionIndex[ExtName] << ", " - << EncodeVersions(MinVersion, MaxVersion) << " },\n"; + << FunctionExtensionIndex[ExtName] << ", " << Versions << " },\n"; Index++; } } - OS << "};\n\n"; + OS << "};\n\n" + << "static_assert(" << MaxNumTypes + << " < (1u << OpenCLBuiltinNumTypesBits),\n" + << " \"OpenCLBuiltinStruct::NumTypes is too narrow\");\n" + << "static_assert(" << MaxVersions + << " < (1u << OpenCLBuiltinVersionsBits),\n" + << " \"OpenCLBuiltinStruct::Versions is too narrow\");\n\n"; } bool BuiltinNameEmitter::CanReuseSignature( @@ -964,7 +1012,8 @@ static void OCL2Qual(Sema &S, const OpenCLTypeStruct &Ty, // [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.getAddrSpaceQualType(QT[Index], static_cast<LangAS>(Ty.AS)); QT[Index] = Context.getPointerType(QT[Index]); } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
