Index: clang/lib/Sema/OpenCLBuiltins.td =================================================================== --- clang/lib/Sema/OpenCLBuiltins.td +++ clang/lib/Sema/OpenCLBuiltins.td @@ -88,11 +88,11 @@ // OpenCL vector types (e.g.: int2, int3, int16, float8, ...). class VectorType : Type<_Ty.Name, _Ty.QTName> { let VecWidth = _VecWidth; + let AccessQualifier = ""; // Inherited fields let IsPointer = _Ty.IsPointer; let IsConst = _Ty.IsConst; let IsVolatile = _Ty.IsVolatile; - let AccessQualifier = _Ty.AccessQualifier; let AddrSpace = _Ty.AddrSpace; } @@ -130,10 +130,16 @@ let AddrSpace = _Ty.AddrSpace; } -// OpenCL image types (e.g. image2d_t, ...) -class ImageType : - Type<_Ty.Name, _QTName> { +// OpenCL image types (e.g.: image2d) +class ImageType : + Type<_Ty.Name, QualType<_Ty.QTName.Name#_AccessQualifier#"Ty", 0>> { + let VecWidth = 0; let AccessQualifier = _AccessQualifier; + // Inherited fields + let IsPointer = _Ty.IsPointer; + let IsConst = _Ty.IsConst; + let IsVolatile = _Ty.IsVolatile; + let AddrSpace = _Ty.AddrSpace; } // Store a list of Types. @@ -205,37 +211,22 @@ // using VectorTypes. -// OpenCL v1.2 s6.1.3: Other Built-in Data Types -// These definitions with a "null" name are "abstract". They should not -// be used in definitions of Builtin functions. -def image2d_t : Type<"image2d_t", QualType<"null", 1>>; -def image3d_t : Type<"image3d_t", QualType<"null", 1>>; -def image2d_array_t : Type<"image2d_array_t", QualType<"null", 1>>; -def image1d_t : Type<"image1d_t", QualType<"null", 1>>; -def image1d_buffer_t : Type<"image1d_buffer_t", QualType<"null", 1>>; -def image1d_array_t : Type<"image1d_array_t", QualType<"null", 1>>; -// Unlike the few functions above, the following definitions can be used -// in definitions of Builtin functions (they have a QualType with a name). -foreach v = ["RO", "WO", "RW"] in { - def image2d_#v#_t : ImageType, - v>; - def image3d_#v#_t : ImageType, - v>; - def image2d_array#v#_t : ImageType, - v>; - def image1d_#v#_t : ImageType, - v>; - def image1d_buffer#v#_t : ImageType, - v>; - def image1d_array#v#_t : ImageType, - v>; -} +// OpenCL v1.0/1.2/2.0 : 6.1.3 : Other Built-in Data Types +// These definitions are "abstract". They should not be used as such. +// They need an access qualifier specified (RO/WO/RW). +// See where image types are used as example. +def Image2d : Type<"image2d_t", QualType<"OCLImage2d", 1>>; +def Image3d : Type<"image3d_t", QualType<"OCLImage3d", 1>>; +def Image2dArray : Type<"image2d_array_t", QualType<"OCLImage2dArray", 1>>; +def Image1d : Type<"image1d_t", QualType<"OCLImage1d", 1>>; +def Image1dBuffer : Type<"image1d_buffer_t", QualType<"OCLImage1dBuffer", 1>>; +def Image1dArray : Type<"image1d_array_t", QualType<"OCLImage1dArray", 1>>; +def Image2dDepth : Type<"image2d_depth_t", QualType<"OCLImage2dDepth", 1>>; +def Image2dArrayDepth : Type<"image2d_array_depth_t", QualType<"OCLImage2dArrayDepth", 1>>; +def Image2dMsaa : Type<"image2d_msaa_t", QualType<"OCLImage2dMSAA", 1>>; +def Image2dArrayMsaa : Type<"image2d_array_msaa_t", QualType<"OCLImage2dArrayMSAA", 1>>; +def Image2dMsaaDepth : Type<"image2d_msaa_depth_t", QualType<"OCLImage2dMSAADepth", 1>>; +def Image2dArrayMsaaDepth : Type<"image2d_array_msaa_depth_t", QualType<"OCLImage2dArrayMSAADepth", 1>>; def Sampler : Type<"Sampler", QualType<"OCLSamplerTy">>; def Event : Type<"Event", QualType<"OCLEventTy">>; @@ -341,14 +332,52 @@ def : Builtin; } -// OpenCL v1.2 s6.12.14: Built-in Image Read Functions -def read_imagef : Builtin<"read_imagef", - [VectorType, image2d_RO_t, VectorType]>; -def write_imagef : Builtin<"write_imagef", - [Void, - image2d_WO_t, - VectorType, - VectorType]>; + +// OpenCL extension v2.0 s5.1.9 : Built-in Image Read Functions +// --- Table 8 --- +foreach aQual = ["RO"] in { + foreach name = ["read_imageh"] in { + foreach Type1 = [Int, Float] in { + foreach Type2 = [Image2d, Image1dArray] in { + def : Builtin, ImageType, Sampler, VectorType]>; + } + foreach Type2 = [Image3d, Image2dArray] in { + def : Builtin, ImageType, Sampler, VectorType]>; + } + foreach Type2 = [Image1d] in { + def : Builtin, ImageType, Sampler, Type1]>; + } + } + } +} +// OpenCL extension v2.0 s5.1.10 : Built-in Image Sampler-less Read Functions +// --- Table 9 --- +foreach aQual = ["RO", "RW"] in { + foreach name = ["read_imageh"] in { + foreach Type1 = [Image2d, Image1dArray] in { + def : Builtin, ImageType, VectorType]>; + } + foreach Type1 = [Image3d, Image2dArray] in { + def : Builtin, ImageType, VectorType]>; + } + foreach Type1 = [Image1d, Image1dBuffer] in { + def : Builtin, ImageType, Int]>; + } + } +} +// OpenCL extension v2.0 s5.1.11 : Built-in Image Write Functions +// --- Table 10 --- +foreach aQual = ["WO", "RW"] in { + foreach name = ["write_imageh"] in { + def : Builtin, VectorType, VectorType]>; + def : Builtin, VectorType, VectorType]>; + def : Builtin, Int, VectorType]>; + def : Builtin, Int, VectorType]>; + def : Builtin, VectorType, VectorType]>; + def : Builtin, VectorType, VectorType]>; + } +} + // OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions Index: clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl =================================================================== --- clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl +++ clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl @@ -4,10 +4,13 @@ // Test the -fdeclare-opencl-builtins option. +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + // Provide typedefs when invoking clang without -finclude-default-header. #ifdef NO_HEADER typedef char char2 __attribute__((ext_vector_type(2))); typedef float float4 __attribute__((ext_vector_type(4))); +typedef half half4 __attribute__((ext_vector_type(4))); typedef int int2 __attribute__((ext_vector_type(2))); typedef int int4 __attribute__((ext_vector_type(4))); typedef long long2 __attribute__((ext_vector_type(2))); @@ -38,6 +41,28 @@ i4 = convert_int4_sat(f4); } +kernel void basic_image_readonly(read_only image2d_t image_read_only_image2d) { + int2 i2; + sampler_t sampler; + + read_imageh(image_read_only_image2d, i2); + read_imageh(image_read_only_image2d, sampler, i2); +} + +kernel void basic_image_readwrite(read_write image3d_t image_read_write_image3d) { + half4 h4; + int4 i4; + + write_imageh(image_read_write_image3d, i4, h4); +} + +kernel void basic_image_writeonly(write_only image1d_buffer_t image_write_only_image1d_buffer) { + half4 h4; + int i; + + write_imageh(image_write_only_image1d_buffer, i, h4); +} + kernel void basic_subgroup(global uint *out) { out[0] = get_sub_group_size(); } Index: clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -40,9 +40,10 @@ // }; // // static const OpenCLTypeStruct TypeTable[] = { -// { OCLT_double, 2, 0, 0, 0, clang::LangAS::Default}, +// { OCLT_double, 2, 0, 0, 0, 0, clang::LangAS::Default}, // // This represents the double type, with a vector width of 2, -// // which is not a pointer (0), not a const (0), not a volatile (0). +// // which is not a pointer (0), not a const (0), not a volatile (0), +// // and no access specifier (0). // // The address space is not relevant since this is not a pointer. // ... // Other types with their vector size. // }; @@ -172,7 +173,7 @@ // have several attributes (e.g. the size of the vector (if applicable), // if this is a pointer type, a const type, ...). // E.g.: - // { OCLT_Double, 2, 0, 0, 0, clang::LangAS::Default}, + // { OCLT_Double, 2, 0, 0, 0, 0, clang::LangAS::Default}, // is describing the type "Double", being a vector of 2 elements. See the // struct OpenCLTypeStruct for more information. void EmitTypeTable(); @@ -338,6 +339,8 @@ const bool IsConst; // 0 if the type is not volatile. const bool IsVolatile; + // 0:none, 1:read_only, 2:write_only, 3:read_write + const unsigned AccessQualifier; // Address space of the pointer (if applicable). const LangAS AS; }; @@ -397,14 +400,40 @@ void BuiltinNameEmitter::EmitTypeTable() { + // Access Qualifier + unsigned AQ; + std::string AQName; + OS << "static const OpenCLTypeStruct TypeTable[] = {\n"; for (const auto &T : TypeMap) { + AQ = 0; + AQName = T.first->getValueAsString("AccessQualifier"); + switch (AQName[0]) { + case 'R': + switch (AQName[1]) { + case 'O': // RO + AQ = 1; + break; + case 'W': // RW + AQ = 3; + break; + } + break; + case 'W': // WO + AQ = 2; + break; + default: // none + AQ = 0; + break; + } + OS << " // " << T.second << "\n"; OS << " { OCLT_" << T.first->getValueAsString("Name") << ", " << T.first->getValueAsInt("VecWidth") << ", " << T.first->getValueAsBit("IsPointer") << ", " << T.first->getValueAsBit("IsConst") << ", " << T.first->getValueAsBit("IsVolatile") << ", " + << AQ << ", " // AccessQualifier << T.first->getValueAsString("AddrSpace") << "},\n"; } OS << "};\n\n"; @@ -571,6 +600,75 @@ // functions. OS << "\n\n switch (Ty.ID) {\n"; + // Switch cases for image types (Image2d, Image3d, ...) + std::vector ImageTypes = + Records.getAllDerivedDefinitions("ImageType"); + + // ImageTypesMap maps the name of an image type to its 3 instances + // (RO, WO, RW). + // ImageTypesMap("Image2d") = < + // + // > + std::map> ImageTypesMap; + + // Populate ImageTypesMap. + for (auto *IT : ImageTypes) { + std::map>::iterator Entry = + ImageTypesMap.find(IT->getValueAsString("Name")); + if (Entry == ImageTypesMap.end()) { + SmallVector 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 QualType associated ("RO", "WO", "RW"). + // The "AccessQualifier" field allows to find which one is needed. + // The code emitted for the "Image2d" type is as below: + // case OCLT_image2d_t: + // switch (Ty.AccessQualifier) { + // case 1: // RO + // QT.push_back(Context.OCLImage2dROTy); + // break; + // case 3: // RW + // QT.push_back(Context.OCLImage2dRWTy); + // break; + // case 2: // WO + // QT.push_back(Context.OCLImage2dWOTy); + // break; + // } + // break; + for (const auto &ITE : ImageTypesMap) { + OS << " case OCLT_" << ITE.first.str() << ":\n"; + OS << " switch (Ty.AccessQualifier) {\n"; + for (const auto &Image : ITE.second) { + switch (Image->getValueAsString("AccessQualifier").str()[0]) { + case 'R': + switch (Image->getValueAsString("AccessQualifier").str()[1]) { + case 'O': + OS << " case 1: // RO\n"; + break; + case 'W': + OS << " case 3: // RW\n"; + break; + } + break; + case 'W': + OS << " case 2: // WO\n"; + break; + } + OS << " QT.push_back(Context." + << Image->getValueAsDef("QTName")->getValueAsString("Name") << ");\n" + << " break;\n"; + } + OS << " }\n"; + OS << " break;\n"; + } + // Switch case for generic types. // The genererated code for the FGenTypeN generic type is: // case OCLT_FGenTypeN: @@ -627,7 +725,10 @@ StringMap TypesSeen; for (const auto *T : Types) { - // Check we have not seen this Type + // Check this isn't an image type + if (ImageTypesMap.find(T->getValueAsString("Name")) != ImageTypesMap.end()) + continue; + // Check we haven't seen this Type if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end()) continue; TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));