فهرست منبع

[OpenCL] Add image type handling for builtins

Image types were previously available, but not working.  This patch
adds image type handling.

Rename the image type definitions in the .td file to make them
consistent with other type names.  Use abstract types to represent the
unqualified types.  Instantiate access-qualified image types at the
point of use using, e.g. `ImageType<Image2d, "RO">`.

Add/update TableGen definitions for the read_image/write_image
builtin functions.

Patch by Pierre Gondois and Sven van Haastregt.

Differential Revision: https://reviews.llvm.org/D63480

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@371046 91177308-0d34-0410-b5e6-96231b3b80d8
Sven van Haastregt 6 سال پیش
والد
کامیت
446ef3b0d8
3فایلهای تغییر یافته به همراه248 افزوده شده و 46 حذف شده
  1. 151 43
      lib/Sema/OpenCLBuiltins.td
  2. 30 0
      test/SemaOpenCL/fdeclare-opencl-builtins.cl
  3. 67 3
      utils/TableGen/ClangOpenCLBuiltinEmitter.cpp

+ 151 - 43
lib/Sema/OpenCLBuiltins.td

@@ -87,11 +87,11 @@ class Type<string _Name, QualType _QTName> {
 // OpenCL vector types (e.g. int2, int3, int16, float8, ...).
 // OpenCL vector types (e.g. int2, int3, int16, float8, ...).
 class VectorType<Type _Ty, int _VecWidth> : Type<_Ty.Name, _Ty.QTName> {
 class VectorType<Type _Ty, int _VecWidth> : Type<_Ty.Name, _Ty.QTName> {
   let VecWidth = _VecWidth;
   let VecWidth = _VecWidth;
+  let AccessQualifier = "";
   // Inherited fields
   // Inherited fields
   let IsPointer = _Ty.IsPointer;
   let IsPointer = _Ty.IsPointer;
   let IsConst = _Ty.IsConst;
   let IsConst = _Ty.IsConst;
   let IsVolatile = _Ty.IsVolatile;
   let IsVolatile = _Ty.IsVolatile;
-  let AccessQualifier = _Ty.AccessQualifier;
   let AddrSpace = _Ty.AddrSpace;
   let AddrSpace = _Ty.AddrSpace;
 }
 }
 
 
@@ -129,10 +129,16 @@ class VolatileType<Type _Ty> : Type<_Ty.Name, _Ty.QTName> {
   let AddrSpace = _Ty.AddrSpace;
   let AddrSpace = _Ty.AddrSpace;
 }
 }
 
 
-// OpenCL image types (e.g. image2d_t, ...)
-class ImageType<Type _Ty, QualType _QTName, string _AccessQualifier> :
-                                              Type<_Ty.Name, _QTName> {
+// OpenCL image types (e.g. image2d).
+class ImageType<Type _Ty, string _AccessQualifier> :
+          Type<_Ty.Name, QualType<_Ty.QTName.Name#_AccessQualifier#"Ty", 0>> {
+  let VecWidth = 0;
   let AccessQualifier = _AccessQualifier;
   let AccessQualifier = _AccessQualifier;
+  // Inherited fields
+  let IsPointer = _Ty.IsPointer;
+  let IsConst = _Ty.IsConst;
+  let IsVolatile = _Ty.IsVolatile;
+  let AddrSpace = _Ty.AddrSpace;
 }
 }
 
 
 // List of Types.
 // List of Types.
@@ -221,37 +227,21 @@ def Void      : Type<"void_t",    QualType<"VoidTy">>;
 // OpenCL v1.0/1.2/2.0 s6.1.2: Built-in Vector Data Types.
 // 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.
 // 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<image2d_t,
-                                      QualType<"OCLImage2d"#v#"Ty">,
-                                      v>;
-  def image3d_#v#_t       : ImageType<image3d_t,
-                                      QualType<"OCLImage3d"#v#"Ty">,
-                                      v>;
-  def image2d_array#v#_t  : ImageType<image2d_array_t,
-                                      QualType<"OCLImage2dArray"#v#"Ty">,
-                                      v>;
-  def image1d_#v#_t       : ImageType<image1d_t,
-                                      QualType<"OCLImage1d"#v#"Ty">,
-                                      v>;
-  def image1d_buffer#v#_t : ImageType<image1d_buffer_t,
-                                      QualType<"OCLImage1dBuffer"#v#"Ty">,
-                                      v>;
-  def image1d_array#v#_t  : ImageType<image1d_array_t,
-                                      QualType<"OCLImage1dArray"#v#"Ty">,
-                                      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 Sampler           : Type<"Sampler", QualType<"OCLSamplerTy">>;
 def Event             : Type<"Event", QualType<"OCLEventTy">>;
 def Event             : Type<"Event", QualType<"OCLEventTy">>;
@@ -398,14 +388,132 @@ foreach name = ["max", "min"] in {
   def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1]>;
   def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1]>;
 }
 }
 
 
-// OpenCL v1.2 s6.12.14: Built-in Image Read Functions
-def read_imagef : Builtin<"read_imagef",
-                          [VectorType<Float, 4>, image2d_RO_t, VectorType<Int, 2>]>;
-def write_imagef : Builtin<"write_imagef",
-                           [Void,
-                            image2d_WO_t,
-                            VectorType<Int, 2>,
-                            VectorType<Float, 4>]>;
+//--------------------------------------------------------------------
+// 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<Float, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+    def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+    def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+  }
+}
+foreach imgTy = [Image2d, Image1dArray] in {
+  foreach coordTy = [Int, Float] in {
+    def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
+    def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
+    def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
+  }
+}
+foreach imgTy = [Image3d, Image2dArray] in {
+  foreach coordTy = [Int, Float] in {
+    def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+    def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+    def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+  }
+}
+foreach coordTy = [Int, Float] in {
+  def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, "RO">, Sampler, VectorType<coordTy, 2>]>;
+  def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, "RO">, Sampler, VectorType<coordTy, 4>]>;
+}
+
+// --- Table 23: Sampler-less Read Functions ---
+foreach aQual = ["RO", "RW"] in {
+  foreach imgTy = [Image2d, Image1dArray] in {
+    def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+    def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+    def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+  }
+  foreach imgTy = [Image3d, Image2dArray] in {
+    def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+    def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+    def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+  }
+  foreach imgTy = [Image1d, Image1dBuffer] in {
+    def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int]>;
+    def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int]>;
+    def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int]>;
+  }
+  def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>]>;
+  def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>]>;
+}
+
+// --- Table 24: Image Write Functions ---
+foreach aQual = ["WO", "RW"] in {
+  foreach imgTy = [Image2d] in {
+    def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Float, 4>]>;
+    def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Int, 4>]>;
+    def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<UInt, 4>]>;
+  }
+  foreach imgTy = [Image2dArray] in {
+    def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Float, 4>]>;
+    def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Int, 4>]>;
+    def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<UInt, 4>]>;
+  }
+  foreach imgTy = [Image1d, Image1dBuffer] in {
+    def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, Int, VectorType<Float, 4>]>;
+    def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, Int, VectorType<Int, 4>]>;
+    def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, Int, VectorType<UInt, 4>]>;
+  }
+  foreach imgTy = [Image1dArray] in {
+    def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Float, 4>]>;
+    def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Int, 4>]>;
+    def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<UInt, 4>]>;
+  }
+  foreach imgTy = [Image3d] in {
+    def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Float, 4>]>;
+    def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Int, 4>]>;
+    def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<UInt, 4>]>;
+  }
+  def : Builtin<"write_imagef", [Void, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>, Float]>;
+  def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, 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<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 2>]>;
+      }
+      foreach imgTy = [Image3d, Image2dArray] in {
+        def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 4>]>;
+      }
+      foreach imgTy = [Image1d] in {
+        def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, 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<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+    }
+    foreach imgTy = [Image3d, Image2dArray] in {
+      def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+    }
+    foreach imgTy = [Image1d, Image1dBuffer] in {
+      def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, 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<name, [Void, ImageType<Image2d, aQual>, VectorType<Int, 2>, VectorType<Half, 4>]>;
+    def : Builtin<name, [Void, ImageType<Image2dArray, aQual>, VectorType<Int, 4>, VectorType<Half, 4>]>;
+    def : Builtin<name, [Void, ImageType<Image1d, aQual>, Int, VectorType<Half, 4>]>;
+    def : Builtin<name, [Void, ImageType<Image1dBuffer, aQual>, Int, VectorType<Half, 4>]>;
+    def : Builtin<name, [Void, ImageType<Image1dArray, aQual>, VectorType<Int, 2>, VectorType<Half, 4>]>;
+    def : Builtin<name, [Void, ImageType<Image3d, aQual>, VectorType<Int, 4>, VectorType<Half, 4>]>;
+  }
+}
 
 
 
 
 // OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions
 // OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions

+ 30 - 0
test/SemaOpenCL/fdeclare-opencl-builtins.cl

@@ -4,11 +4,14 @@
 
 
 // Test the -fdeclare-opencl-builtins option.
 // Test the -fdeclare-opencl-builtins option.
 
 
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+
 // Provide typedefs when invoking clang without -finclude-default-header.
 // Provide typedefs when invoking clang without -finclude-default-header.
 #ifdef NO_HEADER
 #ifdef NO_HEADER
 typedef char char2 __attribute__((ext_vector_type(2)));
 typedef char char2 __attribute__((ext_vector_type(2)));
 typedef char char4 __attribute__((ext_vector_type(4)));
 typedef char char4 __attribute__((ext_vector_type(4)));
 typedef float float4 __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 int2 __attribute__((ext_vector_type(2)));
 typedef int int4 __attribute__((ext_vector_type(4)));
 typedef int int4 __attribute__((ext_vector_type(4)));
 typedef long long2 __attribute__((ext_vector_type(2)));
 typedef long long2 __attribute__((ext_vector_type(2)));
@@ -46,6 +49,33 @@ char4 test_int(char c, char4 c4) {
   return max(c4, c);
   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) {
 kernel void basic_subgroup(global uint *out) {
   out[0] = get_sub_group_size();
   out[0] = get_sub_group_size();
 }
 }

+ 67 - 3
utils/TableGen/ClangOpenCLBuiltinEmitter.cpp

@@ -56,6 +56,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Error.h"
@@ -233,6 +234,13 @@ void BuiltinNameEmitter::EmitDeclarations() {
 
 
   // Structure definitions.
   // Structure definitions.
   OS << R"(
   OS << R"(
+// Image access qualifier.
+enum OpenCLAccessQual : unsigned char {
+  OCLAQ_None,
+  OCLAQ_ReadOnly,
+  OCLAQ_WriteOnly,
+  OCLAQ_ReadWrite
+};
 
 
 // Represents a return type or argument type.
 // Represents a return type or argument type.
 struct OpenCLTypeStruct {
 struct OpenCLTypeStruct {
@@ -246,6 +254,8 @@ struct OpenCLTypeStruct {
   const bool IsConst;
   const bool IsConst;
   // 0 if the type is not volatile.
   // 0 if the type is not volatile.
   const bool IsVolatile;
   const bool IsVolatile;
+  // Access qualifier.
+  const OpenCLAccessQual AccessQualifier;
   // Address space of the pointer (if applicable).
   // Address space of the pointer (if applicable).
   const LangAS AS;
   const LangAS AS;
 };
 };
@@ -347,12 +357,20 @@ void BuiltinNameEmitter::GetOverloads() {
 void BuiltinNameEmitter::EmitTypeTable() {
 void BuiltinNameEmitter::EmitTypeTable() {
   OS << "static const OpenCLTypeStruct TypeTable[] = {\n";
   OS << "static const OpenCLTypeStruct TypeTable[] = {\n";
   for (const auto &T : TypeMap) {
   for (const auto &T : TypeMap) {
-    OS << "  // " << T.second << "\n";
-    OS << "  {OCLT_" << T.first->getValueAsString("Name") << ", "
+    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->getValueAsInt("VecWidth") << ", "
        << T.first->getValueAsBit("IsPointer") << ", "
        << T.first->getValueAsBit("IsPointer") << ", "
        << T.first->getValueAsBit("IsConst") << ", "
        << T.first->getValueAsBit("IsConst") << ", "
        << T.first->getValueAsBit("IsVolatile") << ", "
        << T.first->getValueAsBit("IsVolatile") << ", "
+       << AccessQual << ", "
        << T.first->getValueAsString("AddrSpace") << "},\n";
        << T.first->getValueAsString("AddrSpace") << "},\n";
   }
   }
   OS << "};\n\n";
   OS << "};\n\n";
@@ -455,6 +473,47 @@ static void OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty,
   // Start of switch statement over all types.
   // Start of switch statement over all types.
   OS << "\n  switch (Ty.ID) {\n";
   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.
   // Switch cases for generic types.
   for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) {
   for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) {
     OS << "    case OCLT_" << GenType->getValueAsString("Name") << ":\n";
     OS << "    case OCLT_" << GenType->getValueAsString("Name") << ":\n";
@@ -495,6 +554,9 @@ static void OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty,
   StringMap<bool> TypesSeen;
   StringMap<bool> TypesSeen;
 
 
   for (const auto *T : Types) {
   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
     // Check we have not seen this Type
     if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end())
     if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end())
       continue;
       continue;
@@ -512,7 +574,9 @@ static void OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty,
   }
   }
 
 
   // End of switch statement.
   // 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.
   // Step 2.
   // Add ExtVector types if this was a generic type, as the switch statement
   // Add ExtVector types if this was a generic type, as the switch statement