Index: clang/lib/Sema/OpenCLBuiltins.td =================================================================== --- clang/lib/Sema/OpenCLBuiltins.td +++ clang/lib/Sema/OpenCLBuiltins.td @@ -87,11 +87,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; } @@ -129,10 +129,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; } // List of Types. @@ -221,37 +227,21 @@ // OpenCL v1.0/1.2/2.0 s6.1.2: Built-in Vector Data Types. // Built-in vector data types are created by TableGen's OpenCLBuiltinEmitter. -// 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 s6.1.3: Other Built-in Data Types. +// The image definitions are "abstract". They should not be used without +// specifying an access qualifier (RO/WO/RW). +def Image1d : Type<"Image1d", QualType<"OCLImage1d", 1>>; +def Image2d : Type<"Image2d", QualType<"OCLImage2d", 1>>; +def Image3d : Type<"Image3d", QualType<"OCLImage3d", 1>>; +def Image1dArray : Type<"Image1dArray", QualType<"OCLImage1dArray", 1>>; +def Image1dBuffer : Type<"Image1dBuffer", QualType<"OCLImage1dBuffer", 1>>; +def Image2dArray : Type<"Image2dArray", QualType<"OCLImage2dArray", 1>>; +def Image2dDepth : Type<"Image2dDepth", QualType<"OCLImage2dDepth", 1>>; +def Image2dArrayDepth : Type<"Image2dArrayDepth", QualType<"OCLImage2dArrayDepth", 1>>; +def Image2dMsaa : Type<"Image2dMsaa", QualType<"OCLImage2dMSAA", 1>>; +def Image2dArrayMsaa : Type<"Image2dArrayMsaa", QualType<"OCLImage2dArrayMSAA", 1>>; +def Image2dMsaaDepth : Type<"Image2dMsaaDepth", QualType<"OCLImage2dMSAADepth", 1>>; +def Image2dArrayMsaaDepth : Type<"Image2dArrayMsaaDepth", QualType<"OCLImage2dArrayMSAADepth", 1>>; def Sampler : Type<"Sampler", QualType<"OCLSamplerTy">>; def Event : Type<"Event", QualType<"OCLEventTy">>; @@ -398,14 +388,132 @@ 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 v1.1 s6.11.3, v1.2 s6.12.14, v2.0 s6.13.14: Image Read and Write Functions +// OpenCL Extension v2.0 s5.1.8 and s6.1.8: Image Read and Write Functions +// --- Table 22: Image Read Functions with Samplers --- +foreach imgTy = [Image1d] in { + foreach coordTy = [Int, Float] in { + def : Builtin<"read_imagef", [VectorType, ImageType, Sampler, coordTy]>; + def : Builtin<"read_imagei", [VectorType, ImageType, Sampler, coordTy]>; + def : Builtin<"read_imageui", [VectorType, ImageType, Sampler, coordTy]>; + } +} +foreach imgTy = [Image2d, Image1dArray] in { + foreach coordTy = [Int, Float] in { + def : Builtin<"read_imagef", [VectorType, ImageType, Sampler, VectorType]>; + def : Builtin<"read_imagei", [VectorType, ImageType, Sampler, VectorType]>; + def : Builtin<"read_imageui", [VectorType, ImageType, Sampler, VectorType]>; + } +} +foreach imgTy = [Image3d, Image2dArray] in { + foreach coordTy = [Int, Float] in { + def : Builtin<"read_imagef", [VectorType, ImageType, Sampler, VectorType]>; + def : Builtin<"read_imagei", [VectorType, ImageType, Sampler, VectorType]>; + def : Builtin<"read_imageui", [VectorType, ImageType, Sampler, VectorType]>; + } +} +foreach coordTy = [Int, Float] in { + def : Builtin<"read_imagef", [Float, ImageType, Sampler, VectorType]>; + def : Builtin<"read_imagef", [Float, ImageType, Sampler, VectorType]>; +} + +// --- Table 23: Sampler-less Read Functions --- +foreach aQual = ["RO", "RW"] in { + foreach imgTy = [Image2d, Image1dArray] in { + def : Builtin<"read_imagef", [VectorType, ImageType, VectorType]>; + def : Builtin<"read_imagei", [VectorType, ImageType, VectorType]>; + def : Builtin<"read_imageui", [VectorType, ImageType, VectorType]>; + } + foreach imgTy = [Image3d, Image2dArray] in { + def : Builtin<"read_imagef", [VectorType, ImageType, VectorType]>; + def : Builtin<"read_imagei", [VectorType, ImageType, VectorType]>; + def : Builtin<"read_imageui", [VectorType, ImageType, VectorType]>; + } + foreach imgTy = [Image1d, Image1dBuffer] in { + def : Builtin<"read_imagef", [VectorType, ImageType, Int]>; + def : Builtin<"read_imagei", [VectorType, ImageType, Int]>; + def : Builtin<"read_imageui", [VectorType, ImageType, Int]>; + } + def : Builtin<"read_imagef", [Float, ImageType, VectorType]>; + def : Builtin<"read_imagef", [Float, ImageType, VectorType]>; +} + +// --- Table 24: Image Write Functions --- +foreach aQual = ["WO", "RW"] in { + foreach imgTy = [Image2d] in { + def : Builtin<"write_imagef", [Void, ImageType, VectorType, VectorType]>; + def : Builtin<"write_imagei", [Void, ImageType, VectorType, VectorType]>; + def : Builtin<"write_imageui", [Void, ImageType, VectorType, VectorType]>; + } + foreach imgTy = [Image2dArray] in { + def : Builtin<"write_imagef", [Void, ImageType, VectorType, VectorType]>; + def : Builtin<"write_imagei", [Void, ImageType, VectorType, VectorType]>; + def : Builtin<"write_imageui", [Void, ImageType, VectorType, VectorType]>; + } + foreach imgTy = [Image1d, Image1dBuffer] in { + def : Builtin<"write_imagef", [Void, ImageType, Int, VectorType]>; + def : Builtin<"write_imagei", [Void, ImageType, Int, VectorType]>; + def : Builtin<"write_imageui", [Void, ImageType, Int, VectorType]>; + } + foreach imgTy = [Image1dArray] in { + def : Builtin<"write_imagef", [Void, ImageType, VectorType, VectorType]>; + def : Builtin<"write_imagei", [Void, ImageType, VectorType, VectorType]>; + def : Builtin<"write_imageui", [Void, ImageType, VectorType, VectorType]>; + } + foreach imgTy = [Image3d] in { + def : Builtin<"write_imagef", [Void, ImageType, VectorType, VectorType]>; + def : Builtin<"write_imagei", [Void, ImageType, VectorType, VectorType]>; + def : Builtin<"write_imageui", [Void, ImageType, VectorType, VectorType]>; + } + def : Builtin<"write_imagef", [Void, ImageType, VectorType, Float]>; + def : Builtin<"write_imagef", [Void, ImageType, VectorType, Float]>; +} + +// OpenCL extension v2.0 s5.1.9: Built-in Image Read Functions +// --- Table 8 --- +foreach aQual = ["RO"] in { + foreach name = ["read_imageh"] in { + foreach coordTy = [Int, Float] in { + foreach imgTy = [Image2d, Image1dArray] in { + def : Builtin, ImageType, Sampler, VectorType]>; + } + foreach imgTy = [Image3d, Image2dArray] in { + def : Builtin, ImageType, Sampler, VectorType]>; + } + foreach imgTy = [Image1d] in { + def : Builtin, ImageType, Sampler, coordTy]>; + } + } + } +} +// 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 imgTy = [Image2d, Image1dArray] in { + def : Builtin, ImageType, VectorType]>; + } + foreach imgTy = [Image3d, Image2dArray] in { + def : Builtin, ImageType, VectorType]>; + } + foreach imgTy = [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,11 +4,14 @@ // 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 char char4 __attribute__((ext_vector_type(4))); 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))); @@ -46,6 +49,33 @@ return max(c4, c); } +kernel void basic_image_readonly(read_only image2d_t image_read_only_image2d) { + int2 i2; + sampler_t sampler; + half4 res; + float4 resf; + + resf = read_imagef(image_read_only_image2d, i2); + res = read_imageh(image_read_only_image2d, i2); + res = 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; + float4 f4; + int i; + + write_imagef(image_write_only_image1d_buffer, i, f4); + 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 @@ -56,6 +56,7 @@ #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" @@ -233,6 +234,13 @@ // Structure definitions. OS << R"( +// Image access qualifier. +enum OpenCLAccessQual : unsigned char { + OCLAQ_None, + OCLAQ_ReadOnly, + OCLAQ_WriteOnly, + OCLAQ_ReadWrite +}; // Represents a return type or argument type. struct OpenCLTypeStruct { @@ -246,6 +254,8 @@ 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; }; @@ -347,12 +357,20 @@ void BuiltinNameEmitter::EmitTypeTable() { OS << "static const OpenCLTypeStruct TypeTable[] = {\n"; for (const auto &T : TypeMap) { - OS << " // " << T.second << "\n"; - OS << " {OCLT_" << T.first->getValueAsString("Name") << ", " + const char *AccessQual = + StringSwitch(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"; @@ -455,6 +473,47 @@ // Start of switch statement over all types. OS << "\n switch (Ty.ID) {\n"; + // Switch cases for image types (Image2d, Image3d, ...) + std::vector ImageTypes = + Records.getAllDerivedDefinitions("ImageType"); + + // Map an image type name to its 3 access-qualified types (RO, WO, RW). + std::map> ImageTypesMap; + for (auto *IT : ImageTypes) { + auto 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 + // 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( + 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"; @@ -495,6 +554,9 @@ StringMap 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; @@ -512,7 +574,9 @@ } // End of switch statement. - OS << " } // end of switch (Ty.ID)\n\n"; + 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