Currently Clang use int32 to represent sampler_t, which have been a source of issue for some backends, because in some backends sampler_t cannot be represented by int32. They have to depend on kernel argument metadata and use IPA to find the sampler arguments and global variables and transform them to target specific sampler type.

This patch uses opaque pointer type `opencl.sampler_t*` for sampler_t. For each use of program-scope sampler variable, it generates a function call of `__translate_sampler_initializer`. For each initialization of function-scope sampler variable, it generates a function call of `__translate_sampler_initializer`. For example,

constant sampler_t s1 = X1; // X1 is an integer literal void f() { f1(s1); f2(s1); const sampler_t s2 = X2; // X2 is an integer literal f3(s2); f4(s2); }

=> Llvm bitcode equivalent to (assuming `opencl.sampler_t` is the opaque type to represent sampler_t):

// opaque struct type for sampler struct opencl.sampler_t; constant opencl.sampler_t *__attribute__((always_inline)) __translate_sampler_initializer(unsigned); // a builtin function for translating sampler literal void f() { f1(__translate_sampler_initializer(X1)); f2(__translate_sampler_initializer(X1)); constant __opencl_sampler_t *s2 = __translate_sampler_initializer(X2); f3(s2); f4(s2); }

Each builtin library can implement its own `__translate_sampler_initializer()`. Since the real sampler type tends to be architecture dependent, allowing it to be initialized by a library function simplifies backend design. A typical implementation of `__translate_sampler_initializer` could be a table lookup of real sampler literal values. Since its argument is always a literal, the returned pointer is known at compile time and easily optimized to finally become some literal values directly put into image read instructions.

The advantage of this representation is:

- Robust - can be optimized without losing information
- Easy to implement – can be implemented by library instead of pass

The implementation of the design is to introduce a opaque sampler type and translates each sampler variable to sampler type in AST, and introduces cast from integer to sampler for each variable initializer. For copy initialization with function-scope variable, create integer to sampler cast. In codegen, sampler type is translated to opaque `opencl.sampler_t*` type. The cast from integer to sampler is translated to function call `__translate_sampler_initializer`. The global variable of sampler type is not translated since they are no longer referenced.

This patch is partially based on Alexey Sotkin's work in Khronos Clang (https://github.com/KhronosGroup/SPIR/commit/3d4eec61623502fc306e8c67c9868be2b136e42b).