diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td --- a/clang/lib/Sema/OpenCLBuiltins.td +++ b/clang/lib/Sema/OpenCLBuiltins.td @@ -50,6 +50,18 @@ // Extension associated to a builtin function. class FunctionExtension : AbstractExtension<_Ext>; +// Extension associated to a type. This enables implicit conditionalization of +// builtin function overloads containing a type that depends on an extension. +// During overload resolution, when a builtin function overload contains a type +// with a TypeExtension, those overloads are skipped when the extension is +// disabled. +class TypeExtension : AbstractExtension<_Ext>; + +// TypeExtension definitions. +def NoTypeExt : TypeExtension<"">; +def Fp16TypeExt : TypeExtension<"cl_khr_fp16">; +def Fp64TypeExt : TypeExtension<"cl_khr_fp64">; + // FunctionExtension definitions. def FuncExtNone : FunctionExtension<"">; def FuncExtKhrSubgroups : FunctionExtension<"cl_khr_subgroups">; @@ -119,6 +131,8 @@ string AccessQualifier = ""; // Address space. string AddrSpace = DefaultAS.Name; + // Extension that needs to be enabled to expose a builtin that uses this type. + TypeExtension Extension = NoTypeExt; } // OpenCL vector types (e.g. int2, int3, int16, float8, ...). @@ -130,6 +144,7 @@ let IsConst = _Ty.IsConst; let IsVolatile = _Ty.IsVolatile; let AddrSpace = _Ty.AddrSpace; + let Extension = _Ty.Extension; } // OpenCL pointer types (e.g. int*, float*, ...). @@ -142,6 +157,7 @@ let IsConst = _Ty.IsConst; let IsVolatile = _Ty.IsVolatile; let AccessQualifier = _Ty.AccessQualifier; + let Extension = _Ty.Extension; } // OpenCL const types (e.g. const int). @@ -153,6 +169,7 @@ let IsVolatile = _Ty.IsVolatile; let AccessQualifier = _Ty.AccessQualifier; let AddrSpace = _Ty.AddrSpace; + let Extension = _Ty.Extension; } // OpenCL volatile types (e.g. volatile int). @@ -164,6 +181,7 @@ let IsConst = _Ty.IsConst; let AccessQualifier = _Ty.AccessQualifier; let AddrSpace = _Ty.AddrSpace; + let Extension = _Ty.Extension; } // OpenCL image types (e.g. image2d). @@ -176,6 +194,7 @@ let IsConst = _Ty.IsConst; let IsVolatile = _Ty.IsVolatile; let AddrSpace = _Ty.AddrSpace; + let Extension = _Ty.Extension; } // OpenCL enum type (e.g. memory_scope). @@ -277,8 +296,12 @@ def Long : Type<"long", QualType<"Context.LongTy">>; def ULong : Type<"ulong", QualType<"Context.UnsignedLongTy">>; def Float : Type<"float", QualType<"Context.FloatTy">>; -def Double : Type<"double", QualType<"Context.DoubleTy">>; -def Half : Type<"half", QualType<"Context.HalfTy">>; +let Extension = Fp64TypeExt in { + def Double : Type<"double", QualType<"Context.DoubleTy">>; +} +let Extension = Fp16TypeExt in { + def Half : Type<"half", QualType<"Context.HalfTy">>; +} def Size : Type<"size_t", QualType<"Context.getSizeType()">>; def PtrDiff : Type<"ptrdiff_t", QualType<"Context.getPointerDiffType()">>; def IntPtr : Type<"intptr_t", QualType<"Context.getIntPtrType()">>; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -759,11 +759,20 @@ Context.getDefaultCallingConvention(false, false, true)); PI.Variadic = false; + // Do not attempt to create any FunctionTypes if there are no return types, + // which happens when a type belongs to a disabled extension. + if (RetTypes.size() == 0) + return; + // Create FunctionTypes for each (gen)type. for (unsigned IGenType = 0; IGenType < GenTypeMaxCnt; IGenType++) { SmallVector ArgList; for (unsigned A = 0; A < ArgTypes.size(); A++) { + // Bail out if there is an argument that has no available types. + if (ArgTypes[A].size() == 0) + return; + // Builtins such as "max" have an "sgentype" argument that represents // the corresponding scalar type of a gentype. The number of gentypes // must be a multiple of the number of sgentypes. diff --git a/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl b/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl --- a/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl +++ b/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl @@ -6,6 +6,7 @@ // RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CL2.0 -fdeclare-opencl-builtins -finclude-default-header // RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CLC++ -fdeclare-opencl-builtins -DNO_HEADER // RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CLC++ -fdeclare-opencl-builtins -finclude-default-header +// RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CL2.0 -fdeclare-opencl-builtins -finclude-default-header -cl-ext=-cl_khr_fp64 -DNO_FP64 // Test the -fdeclare-opencl-builtins option. This is not a completeness // test, so it should not test for all builtins defined by OpenCL. Instead @@ -122,15 +123,19 @@ #endif kernel void basic_conversion() { - double d; float f; char2 c2; long2 l2; float4 f4; int4 i4; +#ifdef NO_FP64 + (void)convert_double_rtp(f); + // expected-error@-1{{implicit declaration of function 'convert_double_rtp' is invalid in OpenCL}} +#else + double d; f = convert_float(d); - d = convert_double_rtp(f); +#endif l2 = convert_long2_rtz(c2); i4 = convert_int4_sat(f4); } @@ -271,3 +276,13 @@ // expected-error@-2{{implicit declaration of function 'get_enqueued_local_size' is invalid in OpenCL}} #endif } + +#ifdef NO_FP64 +void test_extension_types(char2 c2) { + // We should see 6 candidates for float and half types, and none for double types. + int i = isnan(c2); + // expected-error@-1{{no matching function for call to 'isnan'}} + // expected-note@-2 6 {{candidate function not viable: no known conversion from '__private char2' (vector of 2 'char' values) to 'float}} + // expected-note@-3 6 {{candidate function not viable: no known conversion from '__private char2' (vector of 2 'char' values) to 'half}} +} +#endif diff --git a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp --- a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -727,34 +727,45 @@ // Switch cases for generic types. for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) { - OS << " case OCLT_" << GenType->getValueAsString("Name") << ":\n"; - OS << " QT.append({"; + OS << " case OCLT_" << GenType->getValueAsString("Name") << ": {\n"; // 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 << T->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") << ", "; + std::vector BaseTypes = + GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List"); + + // Collect all QualTypes for a single vector size into TypeList. + OS << " SmallVector TypeList;\n"; + for (const auto *T : BaseTypes) { + StringRef Ext = + T->getValueAsDef("Extension")->getValueAsString("ExtName"); + if (!Ext.empty()) { + OS << " if (S.getPreprocessor().isMacroDefined(\"" << Ext + << "\")) {\n "; + } + OS << " TypeList.push_back(" + << T->getValueAsDef("QTExpr")->getValueAsString("TypeExpr") << ");\n"; + if (!Ext.empty()) { + OS << " }\n"; } } - 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"; + OS << " GenTypeNumTypes = TypeList.size();\n"; + + // Duplicate the TypeList for every vector size. + std::vector VectorList = + GenType->getValueAsDef("VectorList")->getValueAsListOfInts("List"); + OS << " QT.reserve(" << VectorList.size() * BaseTypes.size() << ");\n" + << " for (unsigned I = 0; I < " << VectorList.size() << "; I++) {\n" + << " QT.append(TypeList);\n" + << " }\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"; + << ";\n" + << " break;\n" + << " }\n"; } // Switch cases for non generic, non image types (int, int4, float, ...). @@ -777,9 +788,20 @@ if (QT->getValueAsBit("IsAbstract") == 1) continue; // Emit the cases for non generic, non image types. - OS << " case OCLT_" << T->getValueAsString("Name") << ":\n" - << " QT.push_back(" << QT->getValueAsString("TypeExpr") << ");\n" - << " break;\n"; + OS << " case OCLT_" << T->getValueAsString("Name") << ":\n"; + + StringRef Ext = T->getValueAsDef("Extension")->getValueAsString("ExtName"); + // If this type depends on an extension, ensure the extension macro is + // defined. + if (!Ext.empty()) { + OS << " if (S.getPreprocessor().isMacroDefined(\"" << Ext + << "\")) {\n "; + } + OS << " QT.push_back(" << QT->getValueAsString("TypeExpr") << ");\n"; + if (!Ext.empty()) { + OS << " }\n"; + } + OS << " break;\n"; } // End of switch statement.