/* OpenCL built-in library: implementation templates

   Copyright (c) 2011 Erik Schnetter <eschnetter@perimeterinstitute.ca>
                      Perimeter Institute for Theoretical Physics
                 2019 Pekka Jääskeläinen

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

// name-value-element
#define _NVE1(NAME, E) NAME(a.E)
#define NAME1_2(N) (_NVE1(N,s0), _NVE1(N,s1))
#define NAME1_3(N) (_NVE1(N,s0), _NVE1(N,s1), _NVE1(N,s2))
#define NAME1_4(N) (_NVE1(N,s0), _NVE1(N,s1), _NVE1(N,s2), _NVE1(N,s3))
#define NAME1_8(N) (_NVE1(N,s0), _NVE1(N,s1), _NVE1(N,s2), _NVE1(N,s3), \
                    _NVE1(N,s4), _NVE1(N,s5), _NVE1(N,s6), _NVE1(N,s7))
#define NAME1_16(N) (_NVE1(N,s0), _NVE1(N,s1), _NVE1(N,s2), _NVE1(N,s3), \
                     _NVE1(N,s4), _NVE1(N,s5), _NVE1(N,s6), _NVE1(N,s7), \
                     _NVE1(N,s8), _NVE1(N,s9), _NVE1(N,sa), _NVE1(N,sb), \
                     _NVE1(N,sc), _NVE1(N,sd), _NVE1(N,se), _NVE1(N,sf))

#define _NVE2(NAME, E) NAME(a.E, b.E)
#define NAME2_2(N) (_NVE2(N,s0), _NVE2(N,s1))
#define NAME2_3(N) (_NVE2(N,s0), _NVE2(N,s1), _NVE2(N,s2))
#define NAME2_4(N) (_NVE2(N,s0), _NVE2(N,s1), _NVE2(N,s2), _NVE2(N,s3))
#define NAME2_8(N) (_NVE2(N,s0), _NVE2(N,s1), _NVE2(N,s2), _NVE2(N,s3), \
                    _NVE2(N,s4), _NVE2(N,s5), _NVE2(N,s6), _NVE2(N,s7))
#define NAME2_16(N) (_NVE2(N,s0), _NVE2(N,s1), _NVE2(N,s2), _NVE2(N,s3), \
                     _NVE2(N,s4), _NVE2(N,s5), _NVE2(N,s6), _NVE2(N,s7), \
                     _NVE2(N,s8), _NVE2(N,s9), _NVE2(N,sa), _NVE2(N,sb), \
                     _NVE2(N,sc), _NVE2(N,sd), _NVE2(N,se), _NVE2(N,sf))

#define _NVE3(NAME, E) NAME(a.E, b.E, c.E)
#define NAME3_2(N) (_NVE3(N,s0), _NVE3(N,s1))
#define NAME3_3(N) (_NVE3(N,s0), _NVE3(N,s1), _NVE3(N,s2))
#define NAME3_4(N) (_NVE3(N,s0), _NVE3(N,s1), _NVE3(N,s2), _NVE3(N,s3))
#define NAME3_8(N) (_NVE3(N,s0), _NVE3(N,s1), _NVE3(N,s2), _NVE3(N,s3), \
                    _NVE3(N,s4), _NVE3(N,s5), _NVE3(N,s6), _NVE3(N,s7))
#define NAME3_16(N) (_NVE3(N,s0), _NVE3(N,s1), _NVE3(N,s2), _NVE3(N,s3), \
                     _NVE3(N,s4), _NVE3(N,s5), _NVE3(N,s6), _NVE3(N,s7), \
                     _NVE3(N,s8), _NVE3(N,s9), _NVE3(N,sa), _NVE3(N,sb), \
                     _NVE3(N,sc), _NVE3(N,sd), _NVE3(N,se), _NVE3(N,sf))

// Choose a constant with a particular precision
#ifdef cl_khr_fp16
#  define IF_HALF(TYPE, VAL, OTHER) \
          (sizeof(TYPE)==sizeof(half) ? (TYPE)(VAL) : (TYPE)(OTHER))
#else
#  define IF_HALF(TYPE, VAL, OTHER) (OTHER)
#endif

#ifdef cl_khr_fp64
#  define IF_DOUBLE(TYPE, VAL, OTHER) \
          (sizeof(TYPE)==sizeof(double) ? (TYPE)(VAL) : (TYPE)(OTHER))
#else
#  define IF_DOUBLE(TYPE, VAL, OTHER) (OTHER)
#endif

#define TYPED_CONST(TYPE, HALF_VAL, SINGLE_VAL, DOUBLE_VAL) \
        IF_HALF(TYPE, HALF_VAL, IF_DOUBLE(TYPE, DOUBLE_VAL, SINGLE_VAL))

// for CUDA, the Generic AS is the same as private, which causes duplicate definitions
#if defined(__opencl_c_generic_address_space) && !defined(__NVPTX__)
#  define IF_GEN_AS(X) X
#else
#  define IF_GEN_AS(X)
#endif

#ifdef USING_ASTYPE_HELPERS
#  define __IF_ASTYPE_HELPERS(X) X
#else
#  define __IF_ASTYPE_HELPERS(X)
#endif


#define IMPLEMENT_BUILTIN_V_V(NAME, VTYPE, EVAL)        \
  VTYPE _CL_OVERLOADABLE                                \
  NAME(VTYPE a)                                         \
  {                                                     \
    return (VTYPE)EVAL;                                 \
  }
#define DEFINE_BUILTIN_V_V(NAME)                        \
  __IF_FP16(                                            \
  half _CL_OVERLOADABLE                                 \
  NAME(half a)                                          \
  {                                                     \
    return __builtin_##NAME##f16(a);                    \
  }                                                     \
  IMPLEMENT_BUILTIN_V_V(NAME, half2   , NAME1_2(__builtin_##NAME##f16))          \
  IMPLEMENT_BUILTIN_V_V(NAME, half3   , NAME1_3(__builtin_##NAME##f16))          \
  IMPLEMENT_BUILTIN_V_V(NAME, half4   , NAME1_4(__builtin_##NAME##f16))          \
  IMPLEMENT_BUILTIN_V_V(NAME, half8   , NAME1_8(__builtin_##NAME##f16))          \
  IMPLEMENT_BUILTIN_V_V(NAME, half16 , NAME1_16(__builtin_##NAME##f16)))        \
  float _CL_OVERLOADABLE                                \
  NAME(float a)                                         \
  {                                                     \
    return __builtin_##NAME##f(a);                      \
  }                                                     \
  IMPLEMENT_BUILTIN_V_V(NAME, float2  , NAME1_2(__builtin_##NAME##f))          \
  IMPLEMENT_BUILTIN_V_V(NAME, float3  , NAME1_3(__builtin_##NAME##f))          \
  IMPLEMENT_BUILTIN_V_V(NAME, float4  , NAME1_4(__builtin_##NAME##f))          \
  IMPLEMENT_BUILTIN_V_V(NAME, float8  , NAME1_8(__builtin_##NAME##f))          \
  IMPLEMENT_BUILTIN_V_V(NAME, float16 , NAME1_16(__builtin_##NAME##f))         \
  __IF_FP64(                                            \
  double _CL_OVERLOADABLE                               \
  NAME(double a)                                        \
  {                                                     \
    return __builtin_##NAME(a);                         \
  }                                                     \
  IMPLEMENT_BUILTIN_V_V(NAME, double2 , NAME1_2(__builtin_##NAME))          \
  IMPLEMENT_BUILTIN_V_V(NAME, double3 , NAME1_3(__builtin_##NAME))          \
  IMPLEMENT_BUILTIN_V_V(NAME, double4 , NAME1_4(__builtin_##NAME))          \
  IMPLEMENT_BUILTIN_V_V(NAME, double8 , NAME1_8(__builtin_##NAME))          \
  IMPLEMENT_BUILTIN_V_V(NAME, double16, NAME1_16(__builtin_##NAME)))


#define IMPLEMENT_BUILTIN_V_VV(NAME, VTYPE, EVAL)         \
  VTYPE _CL_OVERLOADABLE                                  \
  NAME(VTYPE a, VTYPE b)                                  \
  {                                                       \
    return (VTYPE)EVAL;                                   \
  }
#define DEFINE_BUILTIN_V_VV(NAME)                         \
  __IF_FP16(                                              \
  half _CL_OVERLOADABLE                                   \
  NAME(half a, half b)                                    \
  {                                                       \
    return __builtin_##NAME##f16(a, b);                   \
  }                                                       \
  IMPLEMENT_BUILTIN_V_VV(NAME, half2   , NAME2_2(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, half3   , NAME2_3(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, half4   , NAME2_4(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, half8   , NAME2_8(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, half16  , NAME2_16(NAME))) \
  float _CL_OVERLOADABLE                                  \
  NAME(float a, float b)                                  \
  {                                                       \
    return __builtin_##NAME##f(a, b);                     \
  }                                                       \
  IMPLEMENT_BUILTIN_V_VV(NAME, float2  , NAME2_2(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, float3  , NAME2_3(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, float4  , NAME2_4(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, float8  , NAME2_8(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, float16 , NAME2_16(NAME))  \
  __IF_FP64(                                              \
  double _CL_OVERLOADABLE                                 \
  NAME(double a, double b)                                \
  {                                                       \
    return __builtin_##NAME(a, b);                        \
  }                                                       \
  IMPLEMENT_BUILTIN_V_VV(NAME, double2 , NAME2_2(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, double3 , NAME2_3(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, double4 , NAME2_4(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, double8 , NAME2_8(NAME))   \
  IMPLEMENT_BUILTIN_V_VV(NAME, double16, NAME2_16(NAME)))

#define IMPLEMENT_BUILTIN_V_VVV(NAME, VTYPE, EVAL)        \
  VTYPE __attribute__ ((overloadable))                    \
  NAME(VTYPE a, VTYPE b, VTYPE c)                         \
  {                                                       \
    return (VTYPE)EVAL;                                   \
  }
#define DEFINE_BUILTIN_V_VVV(NAME)                        \
  __IF_FP16(                                              \
  half __attribute__ ((overloadable))                     \
  NAME(half a, half b, half c)                            \
  {                                                       \
    return __builtin_##NAME##f16(a, b, c);                \
  }                                                       \
  IMPLEMENT_BUILTIN_V_VVV(NAME, half2   , NAME3_2(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, half3   , NAME3_3(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, half4   , NAME3_4(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, half8   , NAME3_8(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, half16  , NAME3_16(NAME)))\
  float __attribute__ ((overloadable))                    \
  NAME(float a, float b, float c)                         \
  {                                                       \
    return __builtin_##NAME##f(a, b, c);                  \
  }                                                       \
  IMPLEMENT_BUILTIN_V_VVV(NAME, float2  , NAME3_2(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, float3  , NAME3_3(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, float4  , NAME3_4(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, float8  , NAME3_8(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, float16 , NAME3_16(NAME)) \
  __IF_FP64(                                              \
  double __attribute__ ((overloadable))                   \
  NAME(double a, double b, double c)                      \
  {                                                       \
    return __builtin_##NAME(a, b, c);                     \
  }                                                       \
  IMPLEMENT_BUILTIN_V_VVV(NAME, double2 , NAME3_2(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, double3 , NAME3_3(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, double4 , NAME3_4(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, double8 , NAME3_8(NAME))  \
  IMPLEMENT_BUILTIN_V_VVV(NAME, double16, NAME3_16(NAME)))

#define IMPLEMENT_BUILTIN_V_U(NAME, VTYPE, UTYPE, LO, HI)       \
  VTYPE __attribute__ ((overloadable))                          \
  NAME(UTYPE a)                                                 \
  {                                                             \
    return (VTYPE)(NAME(a.LO), NAME(a.HI));                     \
  }
#define DEFINE_BUILTIN_V_U(NAME)                                \
  __IF_FP16(                                                    \
  half __attribute__ ((overloadable))                           \
  NAME(ushort a)                                                \
  {                                                             \
    return __builtin_##NAME##f16(a);                            \
  }                                                             \
  IMPLEMENT_BUILTIN_V_U(NAME, half2   , ushort2 , lo, hi)       \
  IMPLEMENT_BUILTIN_V_U(NAME, half3   , ushort3 , lo, s2)       \
  IMPLEMENT_BUILTIN_V_U(NAME, half4   , ushort4 , lo, hi)       \
  IMPLEMENT_BUILTIN_V_U(NAME, half8   , ushort8 , lo, hi)       \
  IMPLEMENT_BUILTIN_V_U(NAME, half16  , ushort16, lo, hi))      \
  float __attribute__ ((overloadable))                          \
  NAME(uint a)                                                  \
  {                                                             \
    return __builtin_##NAME##f(a);                              \
  }                                                             \
  IMPLEMENT_BUILTIN_V_U(NAME, float2  , uint2   , lo, hi)       \
  IMPLEMENT_BUILTIN_V_U(NAME, float3  , uint3   , lo, s2)       \
  IMPLEMENT_BUILTIN_V_U(NAME, float4  , uint4   , lo, hi)       \
  IMPLEMENT_BUILTIN_V_U(NAME, float8  , uint8   , lo, hi)       \
  IMPLEMENT_BUILTIN_V_U(NAME, float16 , uint16  , lo, hi)       \
  __IF_FP64(                                                    \
  double __attribute__ ((overloadable))                         \
  NAME(ulong a)                                                 \
  {                                                             \
    return __builtin_##NAME(a);                                 \
  }                                                             \
  IMPLEMENT_BUILTIN_V_U(NAME, double2 , ulong2  , lo, hi)       \
  IMPLEMENT_BUILTIN_V_U(NAME, double3 , ulong3  , lo, s2)       \
  IMPLEMENT_BUILTIN_V_U(NAME, double4 , ulong4  , lo, hi)       \
  IMPLEMENT_BUILTIN_V_U(NAME, double8 , ulong8  , lo, hi)       \
  IMPLEMENT_BUILTIN_V_U(NAME, double16, ulong16 , lo, hi))

#define IMPLEMENT_BUILTIN_J_VV(NAME, VTYPE, JTYPE, LO, HI)      \
  JTYPE __attribute__ ((overloadable))                          \
  NAME(VTYPE a, VTYPE b)                                        \
  {                                                             \
    return (JTYPE)(NAME(a.LO, b.LO), NAME(a.HI, b.HI));         \
  }
#define DEFINE_BUILTIN_J_VV(NAME)                               \
  __IF_FP16(                                                    \
  int __attribute__ ((overloadable))                            \
  NAME(half a, half b)                                          \
  {                                                             \
    return __builtin_##NAME##f16(a, b);                         \
  }                                                             \
  IMPLEMENT_BUILTIN_J_VV(NAME, half2 , short2 , lo, hi)         \
  IMPLEMENT_BUILTIN_J_VV(NAME, half3 , short3 , lo, s2)         \
  IMPLEMENT_BUILTIN_J_VV(NAME, half4 , short4 , lo, hi)         \
  IMPLEMENT_BUILTIN_J_VV(NAME, half8 , short8 , lo, hi)         \
  IMPLEMENT_BUILTIN_J_VV(NAME, half16, short16, lo, hi))        \
  int __attribute__ ((overloadable))                            \
  NAME(float a, float b)                                        \
  {                                                             \
    return __builtin_##NAME##f(a, b);                           \
  }                                                             \
  IMPLEMENT_BUILTIN_J_VV(NAME, float2  , int2  , lo, hi)        \
  IMPLEMENT_BUILTIN_J_VV(NAME, float3  , int3  , lo, s2)        \
  IMPLEMENT_BUILTIN_J_VV(NAME, float4  , int4  , lo, hi)        \
  IMPLEMENT_BUILTIN_J_VV(NAME, float8  , int8  , lo, hi)        \
  IMPLEMENT_BUILTIN_J_VV(NAME, float16 , int16 , lo, hi)        \
  __IF_FP64(                                                    \
  int __attribute__ ((overloadable))                            \
  NAME(double a, double b)                                      \
  {                                                             \
    return __builtin_##NAME(a, b);                              \
  }                                                             \
  IMPLEMENT_BUILTIN_J_VV(NAME, double2 , long2 , lo, hi)        \
  IMPLEMENT_BUILTIN_J_VV(NAME, double3 , long3 , lo, s2)        \
  IMPLEMENT_BUILTIN_J_VV(NAME, double4 , long4 , lo, hi)        \
  IMPLEMENT_BUILTIN_J_VV(NAME, double8 , long8 , lo, hi)        \
  IMPLEMENT_BUILTIN_J_VV(NAME, double16, long16, lo, hi))

#define IMPLEMENT_BUILTIN_L_VV(NAME, VTYPE, STYPE, LTYPE, LO, HI)       \
  LTYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a, VTYPE b)                                                \
  {                                                                     \
    /* change sign? */                                                  \
    int cslo = sizeof(a.LO)==sizeof(STYPE);                             \
    int cshi = sizeof(a.HI)==sizeof(STYPE);                             \
    return (LTYPE)                                                      \
      (cslo ? -NAME(a.LO, b.LO) : NAME(a.LO, b.LO),                     \
       cshi ? -NAME(a.HI, b.HI) : NAME(a.HI, b.HI));                    \
  }
#define DEFINE_BUILTIN_L_VV(NAME)                                       \
  __IF_FP16(                                                            \
  int __attribute__ ((overloadable))                                    \
  NAME(half a, half b)                                                  \
  {                                                                     \
    return __builtin_##NAME##f16(a, b);                                 \
  }                                                                     \
  IMPLEMENT_BUILTIN_L_VV(NAME, half2 , half, short2 , lo, hi)           \
  IMPLEMENT_BUILTIN_L_VV(NAME, half3 , half, short3 , lo, s2)           \
  IMPLEMENT_BUILTIN_L_VV(NAME, half4 , half, short4 , lo, hi)           \
  IMPLEMENT_BUILTIN_L_VV(NAME, half8 , half, short8 , lo, hi)           \
  IMPLEMENT_BUILTIN_L_VV(NAME, half16, half, short16, lo, hi))          \
  int __attribute__ ((overloadable))                                    \
  NAME(float a, float b)                                                \
  {                                                                     \
    return __builtin_##NAME##f(a, b);                                   \
  }                                                                     \
  IMPLEMENT_BUILTIN_L_VV(NAME, float2  , float , int2  , lo, hi)        \
  IMPLEMENT_BUILTIN_L_VV(NAME, float3  , float , int3  , lo, s2)        \
  IMPLEMENT_BUILTIN_L_VV(NAME, float4  , float , int4  , lo, hi)        \
  IMPLEMENT_BUILTIN_L_VV(NAME, float8  , float , int8  , lo, hi)        \
  IMPLEMENT_BUILTIN_L_VV(NAME, float16 , float , int16 , lo, hi)        \
  __IF_FP64(                                                            \
  int __attribute__ ((overloadable))                                    \
  NAME(double a, double b)                                              \
  {                                                                     \
    return __builtin_##NAME(a, b);                                      \
  }                                                                     \
  IMPLEMENT_BUILTIN_L_VV(NAME, double2 , double, long2 , lo, hi)        \
  IMPLEMENT_BUILTIN_L_VV(NAME, double3 , double, long3 , lo, s2)        \
  IMPLEMENT_BUILTIN_L_VV(NAME, double4 , double, long4 , lo, hi)        \
  IMPLEMENT_BUILTIN_L_VV(NAME, double8 , double, long8 , lo, hi)        \
  IMPLEMENT_BUILTIN_L_VV(NAME, double16, double, long16, lo, hi))

#define IMPLEMENT_BUILTIN_V_VJ(NAME, VTYPE, JTYPE, LO, HI)      \
  VTYPE __attribute__ ((overloadable))                          \
  NAME(VTYPE a, JTYPE b)                                        \
  {                                                             \
    return (VTYPE)(NAME(a.LO, b.LO), NAME(a.HI, b.HI));         \
  }
#define DEFINE_BUILTIN_V_VJ(NAME)                               \
  __IF_FP16(                                                    \
  half __attribute__ ((overloadable))                           \
  NAME(half a, int b)                                           \
  {                                                             \
    return __builtin_##NAME##f16(a, b);                         \
  }                                                             \
  IMPLEMENT_BUILTIN_V_VJ(NAME, half2 , int2 , lo, hi)           \
  IMPLEMENT_BUILTIN_V_VJ(NAME, half3 , int3 , lo, s2)           \
  IMPLEMENT_BUILTIN_V_VJ(NAME, half4 , int4 , lo, hi)           \
  IMPLEMENT_BUILTIN_V_VJ(NAME, half8 , int8 , lo, hi)           \
  IMPLEMENT_BUILTIN_V_VJ(NAME, half16, int16, lo, hi))          \
  float __attribute__ ((overloadable))                          \
  NAME(float a, int b)                                          \
  {                                                             \
    return __builtin_##NAME##f(a, b);                           \
  }                                                             \
  IMPLEMENT_BUILTIN_V_VJ(NAME, float2  , int2 , lo, hi)         \
  IMPLEMENT_BUILTIN_V_VJ(NAME, float3  , int3 , lo, s2)         \
  IMPLEMENT_BUILTIN_V_VJ(NAME, float4  , int4 , lo, hi)         \
  IMPLEMENT_BUILTIN_V_VJ(NAME, float8  , int8 , lo, hi)         \
  IMPLEMENT_BUILTIN_V_VJ(NAME, float16 , int16, lo, hi)         \
  __IF_FP64(                                                    \
  double __attribute__ ((overloadable))                         \
  NAME(double a, int b)                                         \
  {                                                             \
    return __builtin_##NAME(a, b);                              \
  }                                                             \
  IMPLEMENT_BUILTIN_V_VJ(NAME, double2 , int2 , lo, hi)         \
  IMPLEMENT_BUILTIN_V_VJ(NAME, double3 , int3 , lo, s2)         \
  IMPLEMENT_BUILTIN_V_VJ(NAME, double4 , int4 , lo, hi)         \
  IMPLEMENT_BUILTIN_V_VJ(NAME, double8 , int8 , lo, hi)         \
  IMPLEMENT_BUILTIN_V_VJ(NAME, double16, int16, lo, hi))

#define IMPLEMENT_BUILTIN_V_VI(NAME, VTYPE, ITYPE, LO, HI)      \
  VTYPE __attribute__ ((overloadable))                          \
  NAME(VTYPE a, ITYPE b)                                        \
  {                                                             \
    return (VTYPE)(NAME(a.LO, b), NAME(a.HI, b));               \
  }
#define DEFINE_BUILTIN_V_VI(NAME)                       \
  __IF_FP16(                                            \
  IMPLEMENT_BUILTIN_V_VI(NAME, half2   , int, lo, hi)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, half3   , int, lo, s2)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, half4   , int, lo, hi)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, half8   , int, lo, hi)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, half16  , int, lo, hi))  \
  IMPLEMENT_BUILTIN_V_VI(NAME, float2  , int, lo, hi)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, float3  , int, lo, s2)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, float4  , int, lo, hi)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, float8  , int, lo, hi)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, float16 , int, lo, hi)   \
  __IF_FP64(                                            \
  IMPLEMENT_BUILTIN_V_VI(NAME, double2 , int, lo, hi)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, double3 , int, lo, s2)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, double4 , int, lo, hi)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, double8 , int, lo, hi)   \
  IMPLEMENT_BUILTIN_V_VI(NAME, double16, int, lo, hi))

#define IMPLEMENT_BUILTIN_J_V(NAME, JTYPE, VTYPE, LO, HI)       \
  JTYPE __attribute__ ((overloadable))                          \
  NAME(VTYPE a)                                                 \
  {                                                             \
    return (JTYPE)(NAME(a.LO), NAME(a.HI));                     \
  }
#define DEFINE_BUILTIN_J_V(NAME)                                \
  __IF_FP16(                                                    \
  int __attribute__ ((overloadable))                            \
  NAME(half a)                                                  \
  {                                                             \
    return __builtin_##NAME##f16(a);                            \
  }                                                             \
  IMPLEMENT_BUILTIN_J_V(NAME, short2 , half2 , lo, hi)          \
  IMPLEMENT_BUILTIN_J_V(NAME, short3 , half3 , lo, s2)          \
  IMPLEMENT_BUILTIN_J_V(NAME, short4 , half4 , lo, hi)          \
  IMPLEMENT_BUILTIN_J_V(NAME, short8 , half8 , lo, hi)          \
  IMPLEMENT_BUILTIN_J_V(NAME, short16, half16, lo, hi))         \
  int __attribute__ ((overloadable))                            \
  NAME(float a)                                                 \
  {                                                             \
    return __builtin_##NAME##f(a);                              \
  }                                                             \
  IMPLEMENT_BUILTIN_J_V(NAME, int2 , float2  , lo, hi)          \
  IMPLEMENT_BUILTIN_J_V(NAME, int3 , float3  , lo, s2)          \
  IMPLEMENT_BUILTIN_J_V(NAME, int4 , float4  , lo, hi)          \
  IMPLEMENT_BUILTIN_J_V(NAME, int8 , float8  , lo, hi)          \
  IMPLEMENT_BUILTIN_J_V(NAME, int16, float16 , lo, hi)          \
  __IF_FP64(                                                    \
  int __attribute__ ((overloadable))                            \
  NAME(double a)                                                \
  {                                                             \
    return __builtin_##NAME(a);                                 \
  }                                                             \
  IMPLEMENT_BUILTIN_J_V(NAME, long2 , double2 , lo, hi)         \
  IMPLEMENT_BUILTIN_J_V(NAME, long3 , double3 , lo, s2)         \
  IMPLEMENT_BUILTIN_J_V(NAME, long4 , double4 , lo, hi)         \
  IMPLEMENT_BUILTIN_J_V(NAME, long8 , double8 , lo, hi)         \
  IMPLEMENT_BUILTIN_J_V(NAME, long16, double16, lo, hi))

#define IMPLEMENT_BUILTIN_K_V(NAME, JTYPE, VTYPE, LO, HI)       \
  JTYPE __attribute__ ((overloadable))                          \
  NAME(VTYPE a)                                                 \
  {                                                             \
    return (JTYPE)(NAME(a.LO), NAME(a.HI));                     \
  }
#define DEFINE_BUILTIN_K_V(NAME)                        \
  __IF_FP16(                                            \
  int __attribute__ ((overloadable))                    \
  NAME(half a)                                          \
  {                                                     \
    return __builtin_##NAME##f16(a);                    \
  }                                                     \
  IMPLEMENT_BUILTIN_K_V(NAME, int2 , half2 , lo, hi)    \
  IMPLEMENT_BUILTIN_K_V(NAME, int3 , half3 , lo, s2)    \
  IMPLEMENT_BUILTIN_K_V(NAME, int4 , half4 , lo, hi)    \
  IMPLEMENT_BUILTIN_K_V(NAME, int8 , half8 , lo, hi)    \
  IMPLEMENT_BUILTIN_K_V(NAME, int16, half16, lo, hi))   \
  int __attribute__ ((overloadable))                    \
  NAME(float a)                                         \
  {                                                     \
    return __builtin_##NAME##f(a);                      \
  }                                                     \
  IMPLEMENT_BUILTIN_K_V(NAME, int2  , float2  , lo, hi) \
  IMPLEMENT_BUILTIN_K_V(NAME, int3  , float3  , lo, s2) \
  IMPLEMENT_BUILTIN_K_V(NAME, int4  , float4  , lo, hi) \
  IMPLEMENT_BUILTIN_K_V(NAME, int8  , float8  , lo, hi) \
  IMPLEMENT_BUILTIN_K_V(NAME, int16 , float16 , lo, hi) \
  __IF_FP64(                                            \
  int __attribute__ ((overloadable))                    \
  NAME(double a)                                        \
  {                                                     \
    return __builtin_##NAME(a);                         \
  }                                                     \
  IMPLEMENT_BUILTIN_K_V(NAME, int2 , double2 , lo, hi)  \
  IMPLEMENT_BUILTIN_K_V(NAME, int3 , double3 , lo, s2)  \
  IMPLEMENT_BUILTIN_K_V(NAME, int4 , double4 , lo, hi)  \
  IMPLEMENT_BUILTIN_K_V(NAME, int8 , double8 , lo, hi)  \
  IMPLEMENT_BUILTIN_K_V(NAME, int16, double16, lo, hi))

#define IMPLEMENT_BUILTIN_L_V(NAME, LTYPE, VTYPE, EVAL)                 \
  LTYPE _CL_OVERLOADABLE                                                \
  NAME(VTYPE a)                                                         \
  {                                                                     \
    /* change sign to -1, required for vector variants of isXYZ() */    \
    return -(LTYPE)EVAL;                                                \
  }
#define DEFINE_BUILTIN_L_V(NAME)                                        \
  __IF_FP16(                                                            \
  int __attribute__ ((overloadable))                                    \
  NAME(half a)                                                          \
  {                                                                     \
    return __builtin_##NAME##f16(a);                                    \
  }                                                                     \
  IMPLEMENT_BUILTIN_L_V(NAME, short2, half2   , NAME1_2(__builtin_##NAME##f16))          \
  IMPLEMENT_BUILTIN_L_V(NAME, short3, half3   , NAME1_3(__builtin_##NAME##f16))          \
  IMPLEMENT_BUILTIN_L_V(NAME, short4, half4   , NAME1_4(__builtin_##NAME##f16))          \
  IMPLEMENT_BUILTIN_L_V(NAME, short8, half8   , NAME1_8(__builtin_##NAME##f16))          \
  IMPLEMENT_BUILTIN_L_V(NAME, short16, half16 , NAME1_16(__builtin_##NAME##f16)))        \
  int __attribute__ ((overloadable))                                    \
  NAME(float a)                                                         \
  {                                                                     \
    return __builtin_##NAME##f(a);                                      \
  }                                                                     \
  IMPLEMENT_BUILTIN_L_V(NAME, int2  , float2  , NAME1_2(__builtin_##NAME##f))          \
  IMPLEMENT_BUILTIN_L_V(NAME, int3  , float3  , NAME1_3(__builtin_##NAME##f))          \
  IMPLEMENT_BUILTIN_L_V(NAME, int4  , float4  , NAME1_4(__builtin_##NAME##f))          \
  IMPLEMENT_BUILTIN_L_V(NAME, int8  , float8  , NAME1_8(__builtin_##NAME##f))          \
  IMPLEMENT_BUILTIN_L_V(NAME, int16 , float16 , NAME1_16(__builtin_##NAME##f))         \
  __IF_FP64(                                                            \
  int __attribute__ ((overloadable))                                    \
  NAME(double a)                                                        \
  {                                                                     \
    return __builtin_##NAME(a);                                         \
  }                                                                     \
  IMPLEMENT_BUILTIN_L_V(NAME, long2 , double2 , NAME1_2(__builtin_##NAME))          \
  IMPLEMENT_BUILTIN_L_V(NAME, long3 , double3 , NAME1_3(__builtin_##NAME))          \
  IMPLEMENT_BUILTIN_L_V(NAME, long4 , double4 , NAME1_4(__builtin_##NAME))          \
  IMPLEMENT_BUILTIN_L_V(NAME, long8 , double8 , NAME1_8(__builtin_##NAME))          \
  IMPLEMENT_BUILTIN_L_V(NAME, long16, double16, NAME1_16(__builtin_##NAME)))

/******************************************************************************/

#define IMPLEMENT_EXPR_V_V(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)     \
  VTYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a)                                                         \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_V_V(NAME, EXPR)                                     \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, half    , half  , short  , short)      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, half2   , half  , short2 , short)      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, half3   , half  , short3 , short)      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, half4   , half  , short4 , short)      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, half8   , half  , short8 , short)      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, half16  , half  , short16, short))     \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, float   , float , int    , int  )      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, float2  , float , int2   , int  )      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, float3  , float , int3   , int  )      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, float4  , float , int4   , int  )      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, float8  , float , int8   , int  )      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, float16 , float , int16  , int  )      \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, double  , double, long   , long )      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, double2 , double, long2  , long )      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, double3 , double, long3  , long )      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, double4 , double, long4  , long )      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, double8 , double, long8  , long )      \
  IMPLEMENT_EXPR_V_V(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_V_VV(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)    \
  __IF_ASTYPE_HELPERS(                                                  \
  static __attribute__ ((overloadable))                                 \
  VTYPE NAME##_as_vtype(JTYPE a)                                        \
  {                                                                     \
    return as_##VTYPE(a);                                               \
  }                                                                     \
  )                                                                     \
  VTYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a, VTYPE b)                                                \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_V_VV(NAME, EXPR)                                    \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, half    , half  , short  , short)     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, half2   , half  , short2 , short)     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, half3   , half  , short3 , short)     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, half4   , half  , short4 , short)     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, half8   , half  , short8 , short)     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, half16  , half  , short16, short))    \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, float   , float , int    , int  )     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, float2  , float , int2   , int  )     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, float3  , float , int3   , int  )     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, float4  , float , int4   , int  )     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, float8  , float , int8   , int  )     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, float16 , float , int16  , int  )     \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, double  , double, long   , long )     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, double2 , double, long2  , long )     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, double3 , double, long3  , long )     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, double4 , double, long4  , long )     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, double8 , double, long8  , long )     \
  IMPLEMENT_EXPR_V_VV(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_V_VVV(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)   \
  __IF_ASTYPE_HELPERS(                                                  \
  static __attribute__ ((overloadable))                                 \
  VTYPE NAME##_as_vtype(JTYPE a)                                        \
  {                                                                     \
    return as_##VTYPE(a);                                               \
  }                                                                     \
  static __attribute__ ((overloadable))                                 \
  JTYPE NAME##_as_jtype(VTYPE a)                                        \
  {                                                                     \
    return as_##JTYPE(a);                                               \
  }                                                                     \
  )                                                                     \
  VTYPE _CL_OVERLOADABLE _CL_READNONE                                   \
  NAME(VTYPE a, VTYPE b, VTYPE c)                                       \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_V_VVV(NAME, EXPR)                                   \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, half    , half  , short  , short)    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, half2   , half  , short2 , short)    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, half3   , half  , short3 , short)    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, half4   , half  , short4 , short)    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, half8   , half  , short8 , short)    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, half16  , half  , short16, short))   \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, float   , float , int    , int  )    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, float2  , float , int2   , int  )    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, float3  , float , int3   , int  )    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, float4  , float , int4   , int  )    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, float8  , float , int8   , int  )    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, float16 , float , int16  , int  )    \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, double  , double, long   , long )    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, double2 , double, long2  , long )    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, double3 , double, long3  , long )    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, double4 , double, long4  , long )    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, double8 , double, long8  , long )    \
  IMPLEMENT_EXPR_V_VVV(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_S_V(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)     \
  STYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a)                                                         \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_S_V(NAME, EXPR)                                     \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, half    , half  , short  , short)      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, half2   , half  , short2 , short)      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, half3   , half  , short3 , short)      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, half4   , half  , short4 , short)      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, half8   , half  , short8 , short)      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, half16  , half  , short16, short))     \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, float   , float , int    , int  )      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, float2  , float , int2   , int  )      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, float3  , float , int3   , int  )      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, float4  , float , int4   , int  )      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, float8  , float , int8   , int  )      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, float16 , float , int16  , int  )      \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, double  , double, long   , long )      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, double2 , double, long2  , long )      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, double3 , double, long3  , long )      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, double4 , double, long4  , long )      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, double8 , double, long8  , long )      \
  IMPLEMENT_EXPR_S_V(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_S_VV(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)    \
  STYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a, VTYPE b)                                                \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_S_VV(NAME, EXPR)                                    \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, half    , half  , short  , short)     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, half2   , half  , short2 , short)     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, half3   , half  , short3 , short)     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, half4   , half  , short4 , short)     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, half8   , half  , short8 , short)     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, half16  , half  , short16, short))    \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, float   , float , int    , int  )     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, float2  , float , int2   , int  )     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, float3  , float , int3   , int  )     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, float4  , float , int4   , int  )     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, float8  , float , int8   , int  )     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, float16 , float , int16  , int  )     \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, double  , double, long   , long )     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, double2 , double, long2  , long )     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, double3 , double, long3  , long )     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, double4 , double, long4  , long )     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, double8 , double, long8  , long )     \
  IMPLEMENT_EXPR_S_VV(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_J_V(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)     \
  JTYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a)                                                         \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_J_V(NAME, EXPR)                                     \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, half    , half  , int    , int  )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, half2   , half  , short2 , short)      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, half3   , half  , short3 , short)      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, half4   , half  , short4 , short)      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, half8   , half  , short8 , short)      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, half16  , half  , short16, short))     \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, float   , float , int    , int  )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, float2  , float , int2   , int  )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, float3  , float , int3   , int  )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, float4  , float , int4   , int  )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, float8  , float , int8   , int  )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, float16 , float , int16  , int  )      \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, double  , double, int    , int  )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, double2 , double, long2  , long )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, double3 , double, long3  , long )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, double4 , double, long4  , long )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, double8 , double, long8  , long )      \
  IMPLEMENT_EXPR_J_V(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_J_VV(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)    \
  JTYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a, VTYPE b)                                                \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_J_VV(NAME, EXPR)                                    \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, half    , half  , int    , int  )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, half2   , half  , short2 , short)     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, half3   , half  , short3 , short)     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, half4   , half  , short4 , short)     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, half8   , half  , short8 , short)     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, half16  , half  , short16, short))    \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, float   , float , int    , int  )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, float2  , float , int2   , int  )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, float3  , float , int3   , int  )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, float4  , float , int4   , int  )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, float8  , float , int8   , int  )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, float16 , float , int16  , int  )     \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, double  , double, int    , int  )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, double2 , double, long2  , long )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, double3 , double, long3  , long )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, double4 , double, long4  , long )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, double8 , double, long8  , long )     \
  IMPLEMENT_EXPR_J_VV(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_V_VVS(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)   \
  VTYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a, VTYPE b, STYPE c)                                       \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
// All V_VVV cases are excluded
#define DEFINE_EXPR_V_VVS(NAME, EXPR)                                   \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, half2   , half  , short2 , short)    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, half3   , half  , short3 , short)    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, half4   , half  , short4 , short)    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, half8   , half  , short8 , short)    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, half16  , half  , short16, short))   \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, float2  , float , int2   , int  )    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, float3  , float , int3   , int  )    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, float4  , float , int4   , int  )    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, float8  , float , int8   , int  )    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, float16 , float , int16  , int  )    \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, double2 , double, long2  , long )    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, double3 , double, long3  , long )    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, double4 , double, long4  , long )    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, double8 , double, long8  , long )    \
  IMPLEMENT_EXPR_V_VVS(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_V_VSS(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)   \
  VTYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a, STYPE b, STYPE c)                                       \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
// All V_VVV cases are excluded
#define DEFINE_EXPR_V_VSS(NAME, EXPR)                                   \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, half2   , half  , short2 , short)    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, half3   , half  , short3 , short)    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, half4   , half  , short4 , short)    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, half8   , half  , short8 , short)    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, half16  , half  , short16, short))   \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, float2  , float , int2   , int  )    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, float3  , float , int3   , int  )    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, float4  , float , int4   , int  )    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, float8  , float , int8   , int  )    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, float16 , float , int16  , int  )    \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, double2 , double, long2  , long )    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, double3 , double, long3  , long )    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, double4 , double, long4  , long )    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, double8 , double, long8  , long )    \
  IMPLEMENT_EXPR_V_VSS(NAME, EXPR, double16, double, long16 , long ))

// All V_VVV cases are excluded
#define IMPLEMENT_EXPR_V_SSV(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)   \
  VTYPE __attribute__ ((overloadable))                                  \
  NAME(STYPE a, STYPE b, VTYPE c)                                       \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_V_SSV(NAME, EXPR)                                   \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, half2   , half  , short2 , short)    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, half3   , half  , short3 , short)    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, half4   , half  , short4 , short)    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, half8   , half  , short8 , short)    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, half16  , half  , short16, short))   \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, float2  , float , int2   , int  )    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, float3  , float , int3   , int  )    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, float4  , float , int4   , int  )    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, float8  , float , int8   , int  )    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, float16 , float , int16  , int  )    \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, double2 , double, long2  , long )    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, double3 , double, long3  , long )    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, double4 , double, long4  , long )    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, double8 , double, long8  , long )    \
  IMPLEMENT_EXPR_V_SSV(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)   \
  VTYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a, VTYPE b, JTYPE c)                                       \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_V_VVJ(NAME, EXPR)                                   \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, half    , half  , short  , short)    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, half2   , half  , short2 , short)    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, half3   , half  , short3 , short)    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, half4   , half  , short4 , short)    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, half8   , half  , short8 , short)    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, half16  , half  , short16, short))   \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, float   , float , int    , int  )    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, float2  , float , int2   , int  )    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, float3  , float , int3   , int  )    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, float4  , float , int4   , int  )    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, float8  , float , int8   , int  )    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, float16 , float , int16  , int  )    \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, double  , double, long   , long )    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, double2 , double, long2  , long )    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, double3 , double, long3  , long )    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, double4 , double, long4  , long )    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, double8 , double, long8  , long )    \
  IMPLEMENT_EXPR_V_VVJ(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_V_U(NAME, EXPR, VTYPE, STYPE, UTYPE, SUTYPE)     \
  __IF_ASTYPE_HELPERS(                                                  \
  static __attribute__ ((overloadable))                                 \
  VTYPE NAME##_as_vtype(UTYPE a)                                        \
  {                                                                     \
    return as_##VTYPE(a);                                               \
  })                                                                    \
  __attribute__ ((overloadable))                                        \
  VTYPE NAME(UTYPE a)                                                   \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef UTYPE utype;                                                \
    typedef SUTYPE sutype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_V_U(NAME, EXPR)                                     \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, half    , half  , ushort  , ushort)    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, half2   , half  , ushort2 , ushort)    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, half3   , half  , ushort3 , ushort)    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, half4   , half  , ushort4 , ushort)    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, half8   , half  , ushort8 , ushort)    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, half16  , half  , ushort16, ushort))   \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, float   , float , uint    , uint  )    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, float2  , float , uint2   , uint  )    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, float3  , float , uint3   , uint  )    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, float4  , float , uint4   , uint  )    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, float8  , float , uint8   , uint  )    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, float16 , float , uint16  , uint  )    \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, double  , double, ulong   , ulong )    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, double2 , double, ulong2  , ulong )    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, double3 , double, ulong3  , ulong )    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, double4 , double, ulong4  , ulong )    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, double8 , double, ulong8  , ulong )    \
  IMPLEMENT_EXPR_V_U(NAME, EXPR, double16, double, ulong16 , ulong ))

#define IMPLEMENT_EXPR_V_VS(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)    \
  VTYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a, STYPE b)                                                \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
// All V_VV cases are excluded
#define DEFINE_EXPR_V_VS(NAME, EXPR)                                    \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, half2   , half  , short2 , short)     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, half3   , half  , short3 , short)     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, half4   , half  , short4 , short)     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, half8   , half  , short8 , short)     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, half16  , half  , short16, short))    \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, float2  , float , int2   , int  )     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, float3  , float , int3   , int  )     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, float4  , float , int4   , int  )     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, float8  , float , int8   , int  )     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, float16 , float , int16  , int  )     \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, double2 , double, long2  , long )     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, double3 , double, long3  , long )     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, double4 , double, long4  , long )     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, double8 , double, long8  , long )     \
  IMPLEMENT_EXPR_V_VS(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_V_VJ(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)    \
  VTYPE __attribute__ ((overloadable))                                  \
  NAME##_convert_vtype(JTYPE a, STYPE dummy)                            \
  {                                                                     \
    return convert_##VTYPE(a);                                          \
  }                                                                     \
  VTYPE __attribute__ ((overloadable))                                  \
  NAME(VTYPE a, JTYPE b)                                                \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_V_VJ(NAME, EXPR)                                    \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, half    , half  , int  , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, half2   , half  , int2 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, half3   , half  , int3 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, half4   , half  , int4 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, half8   , half  , int8 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, half16  , half  , int16, int))        \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, float   , float , int  , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, float2  , float , int2 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, float3  , float , int3 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, float4  , float , int4 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, float8  , float , int8 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, float16 , float , int16, int)         \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, double  , double, int  , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, double2 , double, int2 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, double3 , double, int3 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, double4 , double, int4 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, double8 , double, int8 , int)         \
  IMPLEMENT_EXPR_V_VJ(NAME, EXPR, double16, double, int16, int))

#define IMPLEMENT_EXPR_V_VI(NAME, EXPR, VTYPE, STYPE, ITYPE, JTYPE) \
  VTYPE __attribute__ ((overloadable))                              \
  NAME(VTYPE a, ITYPE b)                                            \
  {                                                                 \
    typedef VTYPE vtype;                                            \
    typedef STYPE stype;                                            \
    typedef ITYPE itype;                                            \
    typedef JTYPE jtype;                                            \
    return EXPR;                                                    \
  }
// All V_VS cases are excluded
#define DEFINE_EXPR_V_VI(NAME, EXPR)                            \
  __IF_FP16(                                                    \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, half2   , half  , int, int2 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, half3   , half  , int, int3 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, half4   , half  , int, int4 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, half8   , half  , int, int8 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, half16  , half  , int, int16))\
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, float2  , float , int, int2 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, float3  , float , int, int3 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, float4  , float , int, int4 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, float8  , float , int, int8 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, float16 , float , int, int16) \
  __IF_FP64(                                             \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, double2 , double, int, int2 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, double3 , double, int, int3 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, double4 , double, int, int4 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, double8 , double, int, int8 ) \
  IMPLEMENT_EXPR_V_VI(NAME, EXPR, double16, double, int, int16))

#define IMPLEMENT_EXPR_V_VPV(NAME, EXPR, VTYPE, STYPE, ITYPE)                 \
  VTYPE __attribute__ ((overloadable)) NAME (VTYPE a, __global VTYPE *b)      \
  {                                                                           \
    typedef VTYPE vtype;                                                      \
    typedef STYPE stype;                                                      \
    typedef ITYPE itype;                                                      \
    return EXPR;                                                              \
  }                                                                           \
  VTYPE __attribute__ ((overloadable)) NAME (VTYPE a, __local VTYPE *b)       \
  {                                                                           \
    typedef VTYPE vtype;                                                      \
    typedef STYPE stype;                                                      \
    typedef ITYPE itype;                                                      \
    return EXPR;                                                              \
  }                                                                           \
  IF_GEN_AS(  \
  VTYPE __attribute__ ((overloadable)) NAME (VTYPE a, __generic VTYPE *b)     \
  {                                                                           \
    typedef VTYPE vtype;                                                      \
    typedef STYPE stype;                                                      \
    typedef ITYPE itype;                                                      \
    return EXPR;                                                              \
  })                                                                          \
  VTYPE __attribute__ ((overloadable)) NAME (VTYPE a, __private VTYPE *b)     \
  {                                                                           \
    typedef VTYPE vtype;                                                      \
    typedef STYPE stype;                                                      \
    typedef ITYPE itype;                                                      \
    return EXPR;                                                              \
  }
#define DEFINE_EXPR_V_VPV(NAME, EXPR)                           \
  __IF_FP16(                                                    \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, half    , half  , short)     \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, half2   , half  , short2)    \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, half3   , half  , short3)    \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, half4   , half  , short4)    \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, half8   , half  , short8)    \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, half16  , half  , short16))  \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, float   , float , int)       \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, float2  , float , int2)      \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, float3  , float , int3)      \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, float4  , float , int4)      \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, float8  , float , int8)      \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, float16 , float , int16)     \
  __IF_FP64(                                                    \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, double  , double, long)      \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, double2 , double, long2)     \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, double3 , double, long3)     \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, double4 , double, long4)     \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, double8 , double, long8)     \
  IMPLEMENT_EXPR_V_VPV(NAME, EXPR, double16, double, long16))

#define IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, VTYPE, STYPE, ITYPE)  \
  VTYPE __attribute__ ((overloadable))                  \
  NAME(VTYPE a, __global ITYPE *b)                      \
  {                                                     \
    typedef VTYPE vtype;                                \
    typedef STYPE stype;                                \
    typedef ITYPE itype;                                \
    return EXPR;                                        \
  }                                                     \
  VTYPE __attribute__ ((overloadable))                  \
  NAME(VTYPE a, __local ITYPE *b)                       \
  {                                                     \
    typedef VTYPE vtype;                                \
    typedef STYPE stype;                                \
    typedef ITYPE itype;                                \
    return EXPR;                                        \
  }                                                     \
  IF_GEN_AS( \
  VTYPE __attribute__ ((overloadable))                  \
  NAME(VTYPE a, __generic ITYPE *b)                     \
  {                                                     \
    typedef VTYPE vtype;                                \
    typedef STYPE stype;                                \
    typedef ITYPE itype;                                \
    return EXPR;                                        \
  })                                                     \
  VTYPE __attribute__ ((overloadable))                  \
  NAME(VTYPE a, __private ITYPE *b)                     \
  {                                                     \
    typedef VTYPE vtype;                                \
    typedef STYPE stype;                                \
    typedef ITYPE itype;                                \
    return EXPR;                                        \
  }
#define DEFINE_EXPR_V_VIPV(NAME, EXPR)                   \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, float   , float , int)    \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, float2  , float , int2)    \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, float3  , float , int3)    \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, float4  , float , int4)    \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, float8  , float , int8)    \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, float16 , float , int16)    \
  __IF_FP64(                                            \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, double  , double, int)    \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, double2 , double, int2)    \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, double3 , double, int3)    \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, double4 , double, int4)    \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, double8 , double, int8)    \
  IMPLEMENT_EXPR_V_VIPV(NAME, EXPR, double16, double, int16))


#define IMPLEMENT_EXPR_V_SV(NAME, EXPR, VTYPE, STYPE, JTYPE, SJTYPE)    \
  VTYPE __attribute__ ((overloadable))                                  \
  NAME(STYPE a, VTYPE b)                                                \
  {                                                                     \
    typedef VTYPE vtype;                                                \
    typedef STYPE stype;                                                \
    typedef JTYPE jtype;                                                \
    typedef SJTYPE sjtype;                                              \
    return EXPR;                                                        \
  }
// All V_VV cases are excluded
#define DEFINE_EXPR_V_SV(NAME, EXPR)                                    \
  __IF_FP16(                                                            \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, half2   , half  , short2 , short)     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, half3   , half  , short3 , short)     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, half4   , half  , short4 , short)     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, half8   , half  , short8 , short)     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, half16  , half  , short16, short))    \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, float2  , float , int2   , int  )     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, float3  , float , int3   , int  )     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, float4  , float , int4   , int  )     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, float8  , float , int8   , int  )     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, float16 , float , int16  , int  )     \
  __IF_FP64(                                                            \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, double2 , double, long2  , long )     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, double3 , double, long3  , long )     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, double4 , double, long4  , long )     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, double8 , double, long8  , long )     \
  IMPLEMENT_EXPR_V_SV(NAME, EXPR, double16, double, long16 , long ))

#define IMPLEMENT_EXPR_F_F(NAME, EXPR, VTYPE, STYPE)    \
  VTYPE __attribute__ ((overloadable))                  \
  NAME(VTYPE a)                                         \
  {                                                     \
    typedef VTYPE vtype;                                \
    typedef STYPE stype;                                \
    return EXPR;                                        \
  }
#define DEFINE_EXPR_F_F(NAME, EXPR)                     \
  __IF_FP16(                                            \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, half   , half )        \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, half2  , half )        \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, half3  , half )        \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, half4  , half )        \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, half8  , half )        \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, half16 , half ))       \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, float   , float )      \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, float2  , float )      \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, float3  , float )      \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, float4  , float )      \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, float8  , float )      \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, float16 , float )      \
  __IF_FP64(                                            \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, double   , double )    \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, double2  , double )    \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, double3  , double )    \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, double4  , double )    \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, double8  , double )    \
  IMPLEMENT_EXPR_F_F(NAME, EXPR, double16 , double ))


#define IMPLEMENT_EXPR_F_FF(NAME, EXPR, VTYPE, STYPE, JTYPE)    \
  VTYPE __attribute__ ((overloadable))                          \
  NAME(VTYPE a, VTYPE b)                                        \
  {                                                             \
    typedef VTYPE vtype;                                        \
    typedef STYPE stype;                                        \
    typedef JTYPE jtype;                                        \
    return EXPR;                                                \
  }

#define DEFINE_EXPR_F_FF(NAME, EXPR)                            \
  __IF_FP16(                                                    \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, half   , half , short)        \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, half2  , half , short2)       \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, half3  , half , short3)       \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, half4  , half , short4)       \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, half8  , half , short8)       \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, half16 , half , short16))     \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, float   , float , int   )     \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, float2  , float , int2  )     \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, float3  , float , int3  )     \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, float4  , float , int4  )     \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, float8  , float , int8  )     \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, float16 , float , int16 )     \
  __IF_FP64(                                                    \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, double   , double , long)     \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, double2  , double , long2)    \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, double3  , double , long3)    \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, double4  , double , long4)    \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, double8  , double , long8)    \
  IMPLEMENT_EXPR_F_FF(NAME, EXPR, double16 , double , long16))



#define IMPLEMENT_BUILTIN_G_G(NAME, GTYPE, UGTYPE, LO, HI)      \
  GTYPE __attribute__ ((overloadable))                          \
  NAME(GTYPE a)                                                 \
  {                                                             \
    return (GTYPE)(NAME(a.LO), NAME(a.HI));                     \
  }
#define DEFINE_BUILTIN_G_G(NAME)                                \
  char __attribute__ ((overloadable))                           \
  NAME(char a)                                                  \
  {                                                             \
    return __builtin_##NAME##hh(a);                             \
  }                                                             \
  uchar __attribute__ ((overloadable))                          \
  NAME(uchar a)                                                 \
  {                                                             \
    return __builtin_##NAME##uhh(a);                            \
  }                                                             \
  short __attribute__ ((overloadable))                          \
  NAME(short a)                                                 \
  {                                                             \
    return __builtin_##NAME##h(a);                              \
  }                                                             \
  ushort __attribute__ ((overloadable))                         \
  NAME(ushort a)                                                \
  {                                                             \
    return __builtin_##NAME##uh(a);                             \
  }                                                             \
  int __attribute__ ((overloadable))                            \
  NAME(int a)                                                   \
  {                                                             \
    return __builtin_##NAME(a);                                 \
  }                                                             \
  uint __attribute__ ((overloadable))                           \
  NAME(uint a)                                                  \
  {                                                             \
    return __builtin_##NAME##u(a);                              \
  }                                                             \
  __IF_INT64(                                                   \
  long __attribute__ ((overloadable))                           \
  NAME(long a)                                                  \
  {                                                             \
    return __builtin_##NAME##l(a);                              \
  }                                                             \
  ulong __attribute__ ((overloadable))                          \
  NAME(ulong a)                                                 \
  {                                                             \
    return __builtin_##NAME##ul(a);                             \
  })                                                            \
  IMPLEMENT_BUILTIN_G_G(NAME, char2   , uchar2  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, char3   , uchar3  , lo, s2)       \
  IMPLEMENT_BUILTIN_G_G(NAME, char4   , uchar4  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, char8   , uchar8  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, char16  , uchar16 , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, uchar2  , uchar2  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, uchar3  , uchar3  , lo, s2)       \
  IMPLEMENT_BUILTIN_G_G(NAME, uchar4  , uchar4  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, uchar8  , uchar8  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, uchar16 , uchar16 , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, short2  , ushort2 , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, short3  , ushort3 , lo, s2)       \
  IMPLEMENT_BUILTIN_G_G(NAME, short4  , ushort4 , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, short8  , ushort8 , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, short16 , ushort16, lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, ushort2 , ushort2 , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, ushort3 , ushort3 , lo, s2)       \
  IMPLEMENT_BUILTIN_G_G(NAME, ushort4 , ushort4 , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, ushort8 , ushort8 , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, ushort16, ushort16, lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, int2    , uint2   , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, int3    , uint3   , lo, s2)       \
  IMPLEMENT_BUILTIN_G_G(NAME, int4    , uint4   , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, int8    , uint8   , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, int16   , uint16  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, uint2   , uint2   , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, uint3   , uint3   , lo, s2)       \
  IMPLEMENT_BUILTIN_G_G(NAME, uint4   , uint4   , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, uint8   , uint8   , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, uint16  , uint16  , lo, hi)       \
  __IF_INT64(                                                   \
  IMPLEMENT_BUILTIN_G_G(NAME, long2   , ulong2  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, long3   , ulong3  , lo, s2)       \
  IMPLEMENT_BUILTIN_G_G(NAME, long4   , ulong4  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, long8   , ulong8  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, long16  , ulong16 , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, ulong2  , ulong2  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, ulong3  , ulong3  , lo, s2)       \
  IMPLEMENT_BUILTIN_G_G(NAME, ulong4  , ulong4  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, ulong8  , ulong8  , lo, hi)       \
  IMPLEMENT_BUILTIN_G_G(NAME, ulong16 , ulong16 , lo, hi))

#define IMPLEMENT_BUILTIN_UG_G(NAME, GTYPE, UGTYPE, LO, HI)     \
  UGTYPE __attribute__ ((overloadable))                         \
  NAME(GTYPE a)                                                 \
  {                                                             \
    return (UGTYPE)(NAME(a.LO), NAME(a.HI));                    \
  }
#define DEFINE_BUILTIN_UG_G(NAME)                               \
  uchar __attribute__ ((overloadable))                          \
  NAME(char a)                                                  \
  {                                                             \
    return __builtin_##NAME##hh(a);                             \
  }                                                             \
  uchar __attribute__ ((overloadable))                          \
  NAME(uchar a)                                                 \
  {                                                             \
    return __builtin_##NAME##uhh(a);                            \
  }                                                             \
  ushort __attribute__ ((overloadable))                         \
  NAME(short a)                                                 \
  {                                                             \
    return __builtin_##NAME##h(a);                              \
  }                                                             \
  ushort __attribute__ ((overloadable))                         \
  NAME(ushort a)                                                \
  {                                                             \
    return __builtin_##NAME##uh(a);                             \
  }                                                             \
  uint __attribute__ ((overloadable))                           \
  NAME(int a)                                                   \
  {                                                             \
    return __builtin_##NAME(a);                                 \
  }                                                             \
  uint __attribute__ ((overloadable))                           \
  NAME(uint a)                                                  \
  {                                                             \
    return __builtin_##NAME##u(a);                              \
  }                                                             \
  __IF_INT64(                                                   \
  ulong __attribute__ ((overloadable))                          \
  NAME(long a)                                                  \
  {                                                             \
    return __builtin_##NAME##l(a);                              \
  }                                                             \
  ulong __attribute__ ((overloadable))                          \
  NAME(ulong a)                                                 \
  {                                                             \
    return __builtin_##NAME##ul(a);                             \
  })                                                            \
  IMPLEMENT_BUILTIN_UG_G(NAME, char2   , uchar2  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, char3   , uchar3  , lo, s2)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, char4   , uchar4  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, char8   , uchar8  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, char16  , uchar16 , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, uchar2  , uchar2  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, uchar3  , uchar3  , lo, s2)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, uchar4  , uchar4  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, uchar8  , uchar8  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, uchar16 , uchar16 , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, short2  , ushort2 , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, short3  , ushort3 , lo, s2)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, short4  , ushort4 , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, short8  , ushort8 , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, short16 , ushort16, lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, ushort2 , ushort2 , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, ushort3 , ushort3 , lo, s2)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, ushort4 , ushort4 , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, ushort8 , ushort8 , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, ushort16, ushort16, lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, int2    , uint2   , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, int3    , uint3   , lo, s2)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, int4    , uint4   , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, int8    , uint8   , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, int16   , uint16  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, uint2   , uint2   , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, uint3   , uint3   , lo, s2)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, uint4   , uint4   , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, uint8   , uint8   , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, uint16  , uint16  , lo, hi)      \
  __IF_INT64(                                                   \
  IMPLEMENT_BUILTIN_UG_G(NAME, long2   , ulong2  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, long3   , ulong3  , lo, s2)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, long4   , ulong4  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, long8   , ulong8  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, long16  , ulong16 , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, ulong2  , ulong2  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, ulong3  , ulong3  , lo, s2)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, ulong4  , ulong4  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, ulong8  , ulong8  , lo, hi)      \
  IMPLEMENT_BUILTIN_UG_G(NAME, ulong16 , ulong16 , lo, hi))

#define IMPLEMENT_EXPR_G_G(NAME, EXPR, GTYPE, SGTYPE, UGTYPE, SUGTYPE)  \
  GTYPE __attribute__ ((overloadable))                                  \
  NAME(GTYPE a)                                                         \
  {                                                                     \
    typedef GTYPE gtype;                                                \
    typedef SGTYPE sgtype;                                              \
    typedef UGTYPE ugtype;                                              \
    typedef SUGTYPE sugtype;                                            \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_G_G(NAME, EXPR)                                     \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, char    , char  , uchar   , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, char2   , char  , uchar2  , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, char3   , char  , uchar3  , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, char4   , char  , uchar4  , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, char8   , char  , uchar8  , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, char16  , char  , uchar16 , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uchar   , uchar , uchar   , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uchar2  , uchar , uchar2  , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uchar3  , uchar , uchar3  , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uchar4  , uchar , uchar4  , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uchar8  , uchar , uchar8  , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uchar16 , uchar , uchar16 , uchar )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, short   , short , ushort  , ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, short2  , short , ushort2 , ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, short3  , short , ushort3 , ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, short4  , short , ushort4 , ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, short8  , short , ushort8 , ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, short16 , short , ushort16, ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ushort  , ushort, ushort  , ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ushort2 , ushort, ushort2 , ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ushort3 , ushort, ushort3 , ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ushort4 , ushort, ushort4 , ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ushort8 , ushort, ushort8 , ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ushort16, ushort, ushort16, ushort)    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, int     , int   , uint    , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, int2    , int   , uint2   , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, int3    , int   , uint3   , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, int4    , int   , uint4   , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, int8    , int   , uint8   , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, int16   , int   , uint16  , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uint    , uint  , uint    , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uint2   , uint  , uint2   , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uint3   , uint  , uint3   , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uint4   , uint  , uint4   , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uint8   , uint  , uint8   , uint  )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, uint16  , uint  , uint16  , uint  )    \
  __IF_INT64(                                                           \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, long    , long  , ulong   , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, long2   , long  , ulong2  , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, long3   , long  , ulong3  , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, long4   , long  , ulong4  , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, long8   , long  , ulong8  , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, long16  , long  , ulong16 , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ulong   , ulong , ulong   , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ulong2  , ulong , ulong2  , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ulong3  , ulong , ulong3  , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ulong4  , ulong , ulong4  , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ulong8  , ulong , ulong8  , ulong )    \
  IMPLEMENT_EXPR_G_G(NAME, EXPR, ulong16 , ulong , ulong16 , ulong ))

#define IMPLEMENT_EXPR_UG_G(NAME, EXPR, GTYPE, SGTYPE, UGTYPE, SUGTYPE) \
  UGTYPE __attribute__ ((overloadable))                                 \
  NAME(GTYPE a)                                                         \
  {                                                                     \
    typedef GTYPE gtype;                                                \
    typedef SGTYPE sgtype;                                              \
    typedef UGTYPE ugtype;                                              \
    typedef SUGTYPE sugtype;                                            \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_UG_G(NAME, EXPR)                                    \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, char    , char  , uchar   , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, char2   , char  , uchar2  , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, char3   , char  , uchar3  , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, char4   , char  , uchar4  , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, char8   , char  , uchar8  , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, char16  , char  , uchar16 , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uchar   , uchar , uchar   , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uchar2  , uchar , uchar2  , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uchar3  , uchar , uchar3  , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uchar4  , uchar , uchar4  , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uchar8  , uchar , uchar8  , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uchar16 , uchar , uchar16 , uchar )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, short   , short , ushort  , ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, short2  , short , ushort2 , ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, short3  , short , ushort3 , ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, short4  , short , ushort4 , ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, short8  , short , ushort8 , ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, short16 , short , ushort16, ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ushort  , ushort, ushort  , ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ushort2 , ushort, ushort2 , ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ushort3 , ushort, ushort3 , ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ushort4 , ushort, ushort4 , ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ushort8 , ushort, ushort8 , ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ushort16, ushort, ushort16, ushort)   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, int     , int   , uint    , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, int2    , int   , uint2   , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, int3    , int   , uint3   , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, int4    , int   , uint4   , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, int8    , int   , uint8   , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, int16   , int   , uint16  , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uint    , uint  , uint    , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uint2   , uint  , uint2   , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uint3   , uint  , uint3   , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uint4   , uint  , uint4   , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uint8   , uint  , uint8   , uint  )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, uint16  , uint  , uint16  , uint  )   \
  __IF_INT64(                                                           \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, long    , long  , ulong   , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, long2   , long  , ulong2  , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, long3   , long  , ulong3  , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, long4   , long  , ulong4  , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, long8   , long  , ulong8  , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, long16  , long  , ulong16 , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ulong   , ulong , ulong   , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ulong2  , ulong , ulong2  , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ulong3  , ulong , ulong3  , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ulong4  , ulong , ulong4  , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ulong8  , ulong , ulong8  , ulong )   \
  IMPLEMENT_EXPR_UG_G(NAME, EXPR, ulong16 , ulong , ulong16 , ulong ))

#define IMPLEMENT_EXPR_G_GG(NAME, EXPR, GTYPE, SGTYPE, UGTYPE, SUGTYPE) \
  GTYPE __attribute__ ((overloadable))                                  \
  NAME(GTYPE a, GTYPE b)                                                \
  {                                                                     \
    typedef GTYPE gtype;                                                \
    typedef SGTYPE sgtype;                                              \
    typedef UGTYPE ugtype;                                              \
    typedef SUGTYPE sugtype;                                            \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_G_GG(NAME, EXPR)                                    \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, char    , char  , uchar   , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, char2   , char  , uchar2  , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, char3   , char  , uchar3  , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, char4   , char  , uchar4  , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, char8   , char  , uchar8  , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, char16  , char  , uchar16 , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uchar   , uchar , uchar   , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uchar2  , uchar , uchar2  , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uchar3  , uchar , uchar3  , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uchar4  , uchar , uchar4  , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uchar8  , uchar , uchar8  , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uchar16 , uchar , uchar16 , uchar )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, short   , short , ushort  , ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, short2  , short , ushort2 , ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, short3  , short , ushort3 , ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, short4  , short , ushort4 , ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, short8  , short , ushort8 , ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, short16 , short , ushort16, ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ushort  , ushort, ushort  , ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ushort2 , ushort, ushort2 , ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ushort3 , ushort, ushort3 , ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ushort4 , ushort, ushort4 , ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ushort8 , ushort, ushort8 , ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ushort16, ushort, ushort16, ushort)   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, int     , int   , uint    , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, int2    , int   , uint2   , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, int3    , int   , uint3   , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, int4    , int   , uint4   , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, int8    , int   , uint8   , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, int16   , int   , uint16  , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uint    , uint  , uint    , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uint2   , uint  , uint2   , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uint3   , uint  , uint3   , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uint4   , uint  , uint4   , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uint8   , uint  , uint8   , uint  )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, uint16  , uint  , uint16  , uint  )   \
  __IF_INT64(                                                           \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, long    , long  , ulong   , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, long2   , long  , ulong2  , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, long3   , long  , ulong3  , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, long4   , long  , ulong4  , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, long8   , long  , ulong8  , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, long16  , long  , ulong16 , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ulong   , ulong , ulong   , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ulong2  , ulong , ulong2  , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ulong3  , ulong , ulong3  , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ulong4  , ulong , ulong4  , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ulong8  , ulong , ulong8  , ulong )   \
  IMPLEMENT_EXPR_G_GG(NAME, EXPR, ulong16 , ulong , ulong16 , ulong ))

#define IMPLEMENT_EXPR_G_GGG(NAME, EXPR, GTYPE, SGTYPE, UGTYPE, SUGTYPE) \
  GTYPE _CL_OVERLOADABLE _CL_READNONE                                  \
  NAME(GTYPE a, GTYPE b, GTYPE c)                                       \
  {                                                                     \
    typedef GTYPE gtype;                                                \
    typedef SGTYPE sgtype;                                              \
    typedef UGTYPE ugtype;                                              \
    typedef SUGTYPE sugtype;                                            \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_G_GGG(NAME, EXPR)                                   \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, char    , char  , uchar   , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, char2   , char  , uchar2  , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, char3   , char  , uchar3  , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, char4   , char  , uchar4  , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, char8   , char  , uchar8  , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, char16  , char  , uchar16 , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uchar   , uchar , uchar   , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uchar2  , uchar , uchar2  , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uchar3  , uchar , uchar3  , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uchar4  , uchar , uchar4  , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uchar8  , uchar , uchar8  , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uchar16 , uchar , uchar16 , uchar )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, short   , short , ushort  , ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, short2  , short , ushort2 , ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, short3  , short , ushort3 , ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, short4  , short , ushort4 , ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, short8  , short , ushort8 , ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, short16 , short , ushort16, ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ushort  , ushort, ushort  , ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ushort2 , ushort, ushort2 , ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ushort3 , ushort, ushort3 , ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ushort4 , ushort, ushort4 , ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ushort8 , ushort, ushort8 , ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ushort16, ushort, ushort16, ushort)  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, int     , int   , uint    , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, int2    , int   , uint2   , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, int3    , int   , uint3   , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, int4    , int   , uint4   , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, int8    , int   , uint8   , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, int16   , int   , uint16  , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uint    , uint  , uint    , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uint2   , uint  , uint2   , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uint3   , uint  , uint3   , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uint4   , uint  , uint4   , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uint8   , uint  , uint8   , uint  )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, uint16  , uint  , uint16  , uint  )  \
  __IF_INT64(                                                           \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, long    , long  , ulong   , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, long2   , long  , ulong2  , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, long3   , long  , ulong3  , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, long4   , long  , ulong4  , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, long8   , long  , ulong8  , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, long16  , long  , ulong16 , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ulong   , ulong , ulong   , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ulong2  , ulong , ulong2  , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ulong3  , ulong , ulong3  , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ulong4  , ulong , ulong4  , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ulong8  , ulong , ulong8  , ulong )  \
  IMPLEMENT_EXPR_G_GGG(NAME, EXPR, ulong16 , ulong , ulong16 , ulong ))

#define IMPLEMENT_EXPR_G_GS(NAME, EXPR, GTYPE, SGTYPE, UGTYPE, SUGTYPE) \
  GTYPE __attribute__ ((overloadable))                                  \
  NAME(GTYPE a, SGTYPE b)                                               \
  {                                                                     \
    typedef GTYPE gtype;                                                \
    typedef SGTYPE sgtype;                                              \
    typedef UGTYPE ugtype;                                              \
    typedef SUGTYPE sugtype;                                            \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_G_GS(NAME, EXPR)                                    \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, char2   , char  , uchar2  , uchar )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, char3   , char  , uchar3  , uchar )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, char4   , char  , uchar4  , uchar )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, char8   , char  , uchar8  , uchar )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, char16  , char  , uchar16 , uchar )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, uchar2  , uchar , uchar2  , uchar )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, uchar3  , uchar , uchar3  , uchar )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, uchar4  , uchar , uchar4  , uchar )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, uchar8  , uchar , uchar8  , uchar )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, uchar16 , uchar , uchar16 , uchar )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, short2  , short , ushort2 , ushort)   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, short3  , short , ushort3 , ushort)   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, short4  , short , ushort4 , ushort)   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, short8  , short , ushort8 , ushort)   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, short16 , short , ushort16, ushort)   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, ushort2 , ushort, ushort2 , ushort)   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, ushort3 , ushort, ushort3 , ushort)   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, ushort4 , ushort, ushort4 , ushort)   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, ushort8 , ushort, ushort8 , ushort)   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, ushort16, ushort, ushort16, ushort)   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, int2    , int   , uint2   , uint  )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, int3    , int   , uint3   , uint  )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, int4    , int   , uint4   , uint  )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, int8    , int   , uint8   , uint  )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, int16   , int   , uint16  , uint  )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, uint2   , uint  , uint2   , uint  )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, uint3   , uint  , uint3   , uint  )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, uint4   , uint  , uint4   , uint  )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, uint8   , uint  , uint8   , uint  )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, uint16  , uint  , uint16  , uint  )   \
  __IF_INT64(                                                           \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, long2   , long  , ulong2  , ulong )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, long3   , long  , ulong3  , ulong )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, long4   , long  , ulong4  , ulong )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, long8   , long  , ulong8  , ulong )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, long16  , long  , ulong16 , ulong )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, ulong2  , ulong , ulong2  , ulong )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, ulong3  , ulong , ulong3  , ulong )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, ulong4  , ulong , ulong4  , ulong )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, ulong8  , ulong , ulong8  , ulong )   \
  IMPLEMENT_EXPR_G_GS(NAME, EXPR, ulong16 , ulong , ulong16 , ulong ))

#define IMPLEMENT_EXPR_G_GSS(NAME, EXPR, GTYPE, SGTYPE, UGTYPE, SUGTYPE) \
  GTYPE _CL_OVERLOADABLE _CL_READNONE                                  \
  NAME(GTYPE a, SGTYPE b, SGTYPE c)                                     \
  {                                                                     \
    typedef GTYPE gtype;                                                \
    typedef SGTYPE sgtype;                                              \
    typedef UGTYPE ugtype;                                              \
    typedef SUGTYPE sugtype;                                            \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_G_GSS(NAME, EXPR)                                   \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, char2   , char  , uchar2  , uchar )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, char3   , char  , uchar3  , uchar )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, char4   , char  , uchar4  , uchar )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, char8   , char  , uchar8  , uchar )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, char16  , char  , uchar16 , uchar )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, uchar2  , uchar , uchar2  , uchar )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, uchar3  , uchar , uchar3  , uchar )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, uchar4  , uchar , uchar4  , uchar )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, uchar8  , uchar , uchar8  , uchar )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, uchar16 , uchar , uchar16 , uchar )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, short2  , short , ushort2 , ushort)  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, short3  , short , ushort3 , ushort)  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, short4  , short , ushort4 , ushort)  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, short8  , short , ushort8 , ushort)  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, short16 , short , ushort16, ushort)  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, ushort2 , ushort, ushort2 , ushort)  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, ushort3 , ushort, ushort3 , ushort)  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, ushort4 , ushort, ushort4 , ushort)  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, ushort8 , ushort, ushort8 , ushort)  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, ushort16, ushort, ushort16, ushort)  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, int2    , int   , uint2   , uint  )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, int3    , int   , uint3   , uint  )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, int4    , int   , uint4   , uint  )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, int8    , int   , uint8   , uint  )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, int16   , int   , uint16  , uint  )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, uint2   , uint  , uint2   , uint  )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, uint3   , uint  , uint3   , uint  )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, uint4   , uint  , uint4   , uint  )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, uint8   , uint  , uint8   , uint  )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, uint16  , uint  , uint16  , uint  )  \
  __IF_INT64(                                                           \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, long2   , long  , ulong2  , ulong )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, long3   , long  , ulong3  , ulong )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, long4   , long  , ulong4  , ulong )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, long8   , long  , ulong8  , ulong )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, long16  , long  , ulong16 , ulong )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, ulong2  , ulong , ulong2  , ulong )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, ulong3  , ulong , ulong3  , ulong )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, ulong4  , ulong , ulong4  , ulong )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, ulong8  , ulong , ulong8  , ulong )  \
  IMPLEMENT_EXPR_G_GSS(NAME, EXPR, ulong16 , ulong , ulong16 , ulong ))

#define IMPLEMENT_EXPR_UG_GG(NAME, EXPR, GTYPE, SGTYPE, UGTYPE, SUGTYPE) \
  UGTYPE __attribute__ ((overloadable))                                 \
  NAME(GTYPE a, GTYPE b)                                                \
  {                                                                     \
    typedef GTYPE gtype;                                                \
    typedef SGTYPE sgtype;                                              \
    typedef UGTYPE ugtype;                                              \
    typedef SUGTYPE sugtype;                                            \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_UG_GG(NAME, EXPR)                                   \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, char    , char  , uchar   , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, char2   , char  , uchar2  , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, char3   , char  , uchar3  , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, char4   , char  , uchar4  , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, char8   , char  , uchar8  , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, char16  , char  , uchar16 , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uchar   , uchar , uchar   , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uchar2  , uchar , uchar2  , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uchar3  , uchar , uchar3  , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uchar4  , uchar , uchar4  , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uchar8  , uchar , uchar8  , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uchar16 , uchar , uchar16 , uchar )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, short   , short , ushort  , ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, short2  , short , ushort2 , ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, short3  , short , ushort3 , ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, short4  , short , ushort4 , ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, short8  , short , ushort8 , ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, short16 , short , ushort16, ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ushort  , ushort, ushort  , ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ushort2 , ushort, ushort2 , ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ushort3 , ushort, ushort3 , ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ushort4 , ushort, ushort4 , ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ushort8 , ushort, ushort8 , ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ushort16, ushort, ushort16, ushort)  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, int     , int   , uint    , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, int2    , int   , uint2   , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, int3    , int   , uint3   , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, int4    , int   , uint4   , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, int8    , int   , uint8   , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, int16   , int   , uint16  , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uint    , uint  , uint    , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uint2   , uint  , uint2   , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uint3   , uint  , uint3   , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uint4   , uint  , uint4   , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uint8   , uint  , uint8   , uint  )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, uint16  , uint  , uint16  , uint  )  \
  __IF_INT64(                                                           \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, long    , long  , ulong   , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, long2   , long  , ulong2  , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, long3   , long  , ulong3  , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, long4   , long  , ulong4  , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, long8   , long  , ulong8  , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, long16  , long  , ulong16 , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ulong   , ulong , ulong   , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ulong2  , ulong , ulong2  , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ulong3  , ulong , ulong3  , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ulong4  , ulong , ulong4  , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ulong8  , ulong , ulong8  , ulong )  \
  IMPLEMENT_EXPR_UG_GG(NAME, EXPR, ulong16 , ulong , ulong16 , ulong ))

#define IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, GTYPE, SGTYPE, UGTYPE, LGTYPE) \
  LGTYPE __attribute__ ((overloadable))                                 \
  NAME(GTYPE a, UGTYPE b)                                               \
  {                                                                     \
    typedef GTYPE gtype;                                                \
    typedef SGTYPE sgtype;                                              \
    typedef UGTYPE ugtype;                                              \
    typedef LGTYPE lgtype;                                              \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_LG_GUG(NAME, EXPR)                                  \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, char    , char  , uchar   , short   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, char2   , char  , uchar2  , short2  ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, char3   , char  , uchar3  , short3  ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, char4   , char  , uchar4  , short4  ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, char8   , char  , uchar8  , short8  ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, char16  , char  , uchar16 , short16 ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uchar   , uchar , uchar   , ushort  ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uchar2  , uchar , uchar2  , ushort2 ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uchar3  , uchar , uchar3  , ushort3 ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uchar4  , uchar , uchar4  , ushort4 ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uchar8  , uchar , uchar8  , ushort8 ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uchar16 , uchar , uchar16 , ushort16) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, short   , short , ushort  , int     ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, short2  , short , ushort2 , int2    ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, short3  , short , ushort3 , int3    ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, short4  , short , ushort4 , int4    ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, short8  , short , ushort8 , int8    ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, short16 , short , ushort16, int16   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, ushort  , ushort, ushort  , uint    ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, ushort2 , ushort, ushort2 , uint2   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, ushort3 , ushort, ushort3 , uint3   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, ushort4 , ushort, ushort4 , uint4   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, ushort8 , ushort, ushort8 , uint8   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, ushort16, ushort, ushort16, uint16  ) \
  __IF_INT64(                                                           \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, int     , int   , uint    , long    ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, int2    , int   , uint2   , long2   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, int3    , int   , uint3   , long3   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, int4    , int   , uint4   , long4   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, int8    , int   , uint8   , long8   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, int16   , int   , uint16  , long16  ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uint    , uint  , uint    , ulong   ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uint2   , uint  , uint2   , ulong2  ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uint3   , uint  , uint3   , ulong3  ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uint4   , uint  , uint4   , ulong4  ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uint8   , uint  , uint8   , ulong8  ) \
  IMPLEMENT_EXPR_LG_GUG(NAME, EXPR, uint16  , uint  , uint16  , ulong16 ))

#define IMPLEMENT_EXPR_J_JJ(NAME, EXPR, JTYPE, SJTYPE, UJTYPE, SUJTYPE) \
  JTYPE __attribute__ ((overloadable))                                  \
  NAME(JTYPE a, JTYPE b)                                                \
  {                                                                     \
    typedef JTYPE gtype;                                                \
    typedef SJTYPE sgtype;                                              \
    typedef UJTYPE ugtype;                                              \
    typedef SUJTYPE sugtype;                                            \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_J_JJ(NAME, EXPR)                                    \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, int     , int   , uint    , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, int2    , int   , uint2   , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, int3    , int   , uint3   , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, int4    , int   , uint4   , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, int8    , int   , uint8   , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, int16   , int   , uint16  , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, uint    , uint  , uint    , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, uint2   , uint  , uint2   , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, uint3   , uint  , uint3   , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, uint4   , uint  , uint4   , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, uint8   , uint  , uint8   , uint  )   \
  IMPLEMENT_EXPR_J_JJ(NAME, EXPR, uint16  , uint  , uint16  , uint  )
#define IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, JTYPE, SJTYPE, UJTYPE, SUJTYPE) \
  JTYPE __attribute__ ((overloadable))                                  \
  NAME(JTYPE a, JTYPE b, JTYPE c)                                       \
  {                                                                     \
    typedef JTYPE gtype;                                                \
    typedef SJTYPE sgtype;                                              \
    typedef UJTYPE ugtype;                                              \
    typedef SUJTYPE sugtype;                                            \
    return EXPR;                                                        \
  }
#define DEFINE_EXPR_J_JJJ(NAME, EXPR)                                   \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, int     , int   , uint    , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, int2    , int   , uint2   , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, int3    , int   , uint3   , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, int4    , int   , uint4   , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, int8    , int   , uint8   , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, int16   , int   , uint16  , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, uint    , uint  , uint    , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, uint2   , uint  , uint2   , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, uint3   , uint  , uint3   , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, uint4   , uint  , uint4   , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, uint8   , uint  , uint8   , uint  )  \
  IMPLEMENT_EXPR_J_JJJ(NAME, EXPR, uint16  , uint  , uint16  , uint  )

/* Defines an OpenCL builtin function for all floating point
   gentypes and addressspaces using Clang scalar builtins. */
#define IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE(NAME, VTYPE, ADDRSPACE)             \
  VTYPE __attribute__ ((overloadable)) NAME (VTYPE a, ADDRSPACE VTYPE *b)     \
  {                                                                           \
    __private VTYPE c;                                                        \
    __private VTYPE r = NAME (a, &c);                                         \
    *b = c;                                                                   \
    return r;                                                                 \
  }

#define IMPLEMENT_BUILTIN_V_VPV(NAME, VTYPE, LTYPE, HTYPE, LO, HI)            \
  VTYPE __attribute__ ((overloadable)) NAME (VTYPE a, VTYPE __private *b)     \
  {                                                                           \
    LTYPE c = b->LO;                                                          \
    HTYPE d = b->HI;                                                          \
    VTYPE r = (VTYPE)(NAME (a.LO, &c), NAME (a.HI, &d));                      \
    b->LO = c;                                                                \
    b->HI = d;                                                                \
    return r;                                                                 \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, VTYPE, __local)                    \
  IF_GEN_AS (IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, VTYPE, __generic))      \
  IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, VTYPE, __global)
#define DEFINE_BUILTIN_V_VPV(NAME)                                            \
  __IF_FP16 (                                                                 \
  half _CL_OVERLOADABLE _CL_READNONE NAME (half a, __private half *b)         \
  {                                                                           \
    __private float c;                                                        \
    __private float r = __builtin_##NAME##f16 (a, &c);                        \
    *b = c;                                                                   \
    return r;                                                                 \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, half, __local)                     \
  IF_GEN_AS(IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, half, __generic))        \
  IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, half, __global)                    \
  IMPLEMENT_BUILTIN_V_VPV (NAME, half2, half, half, lo, hi)                   \
  IMPLEMENT_BUILTIN_V_VPV (NAME, half3, half2, half, lo, s2)                  \
  IMPLEMENT_BUILTIN_V_VPV (NAME, half4, half2, half2, lo, hi)                 \
  IMPLEMENT_BUILTIN_V_VPV (NAME, half8, half4, half4, lo, hi)                 \
  IMPLEMENT_BUILTIN_V_VPV (NAME, half16, half8, half8, lo, hi))               \
  float _CL_OVERLOADABLE _CL_READNONE NAME (float a, __private float *b)      \
  {                                                                           \
    return __builtin_##NAME##f (a, b);                                        \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, float, __local)                    \
  IF_GEN_AS(IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, float, __generic))       \
  IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, float, __global)                   \
  IMPLEMENT_BUILTIN_V_VPV (NAME, float2, float, float, lo, hi)                \
  IMPLEMENT_BUILTIN_V_VPV (NAME, float3, float2, float, lo, s2)               \
  IMPLEMENT_BUILTIN_V_VPV (NAME, float4, float2, float2, lo, hi)              \
  IMPLEMENT_BUILTIN_V_VPV (NAME, float8, float4, float4, lo, hi)              \
  IMPLEMENT_BUILTIN_V_VPV (NAME, float16, float8, float8, lo, hi)             \
  __IF_FP64 (                                                                 \
  double _CL_OVERLOADABLE _CL_READNONE NAME (double a, __private double *b)   \
  {                                                                           \
    return __builtin_##NAME (a, b);                                           \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, double, __local)                   \
  IF_GEN_AS(IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, double, __generic))      \
  IMPLEMENT_BUILTIN_V_VPV_ADDRSPACE (NAME, double, __global)                  \
  IMPLEMENT_BUILTIN_V_VPV (NAME, double2, double, double, lo, hi)             \
  IMPLEMENT_BUILTIN_V_VPV (NAME, double3, double2, double, lo, s2)            \
  IMPLEMENT_BUILTIN_V_VPV (NAME, double4, double2, double2, lo, hi)           \
  IMPLEMENT_BUILTIN_V_VPV (NAME, double8, double4, double4, lo, hi)           \
  IMPLEMENT_BUILTIN_V_VPV (NAME, double16, double8, double8, lo, hi))

#define IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE(NAME, VTYPE, JTYPE, ADDRSPACE)     \
  VTYPE __attribute__ ((overloadable))                                        \
      NAME (VTYPE a, VTYPE b, ADDRSPACE JTYPE *c)                             \
  {                                                                           \
    __private JTYPE d;                                                        \
    __private VTYPE r = NAME (a, b, &d);                                      \
    *c = d;                                                                   \
    return r;                                                                 \
  }

#define IMPLEMENT_BUILTIN_V_VVPJ(NAME, VTYPE, JTYPE, LTYPE, HTYPE, LO, HI)    \
  VTYPE __attribute__ ((overloadable))                                        \
  NAME (VTYPE a, VTYPE b, JTYPE __private *c)                                 \
  {                                                                           \
    LTYPE d = c->LO;                                                          \
    HTYPE e = c->HI;                                                          \
    VTYPE r = (VTYPE)(NAME (a.LO, b.LO, &d), NAME (a.HI, b.HI, &e));          \
    c->LO = d;                                                                \
    c->HI = e;                                                                \
    return r;                                                                 \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, VTYPE, JTYPE, __local)            \
  IF_GEN_AS (                                                                 \
      IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, VTYPE, JTYPE, __generic))     \
  IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, VTYPE, JTYPE, __global)

#define DEFINE_BUILTIN_V_VVPJ(NAME)                                           \
  __IF_FP16 (                                                                 \
  half _CL_OVERLOADABLE _CL_READNONE NAME (half a, half b, int __private *c)  \
  {                                                                           \
    __private int d;                                                          \
    __private float r = __builtin_##NAME##f16 (a, b, &d);                     \
    *c = d;                                                                   \
    return r;                                                                 \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, half, int, __local)               \
  IF_GEN_AS(IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, half, int, __generic))  \
  IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, half, int, __global)              \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, half2, int2, int, int, lo, hi)              \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, half3, int3, int2, int, lo, s2)             \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, half4, int4, int2, int2, lo, hi)            \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, half8, int8, int4, int4, lo, hi)            \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, half16, int16, int8, int8, lo, hi))         \
  float _CL_OVERLOADABLE _CL_READNONE NAME (float a, float b, int __private *c) \
  {                                                                           \
    return __builtin_##NAME##f (a, b, c);                                     \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, float, int, __local)              \
  IF_GEN_AS (                                                                 \
      IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, float, int, __generic))       \
  IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, float, int, __global)             \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, float2, int2, int, int, lo, hi)             \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, float3, int3, int2, int, lo, s2)            \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, float4, int4, int2, int2, lo, hi)           \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, float8, int8, int4, int4, lo, hi)           \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, float16, int16, int8, int8, lo, hi)         \
  __IF_FP64 (                                                                 \
  double _CL_OVERLOADABLE _CL_READNONE NAME (double a, double b, int __private *c) \
  {                                                                           \
    return __builtin_##NAME (a, b, c);                                        \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, double, int, __local)             \
  IF_GEN_AS(IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, double, int, __generic)) \
  IMPLEMENT_BUILTIN_V_VVPJ_ADDRSPACE (NAME, double, int, __global)            \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, double2, int2, int, int, lo, hi)            \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, double3, int3, int2, int, lo, s2)           \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, double4, int4, int2, int2, lo, hi)          \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, double8, int8, int4, int4, lo, hi)          \
  IMPLEMENT_BUILTIN_V_VVPJ (NAME, double16, int16, int8, int8, lo, hi))

#define IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE(NAME, VTYPE, JTYPE, ADDRSPACE)      \
  VTYPE __attribute__ ((overloadable)) NAME (VTYPE a, ADDRSPACE JTYPE *c)     \
  {                                                                           \
    __private JTYPE d;                                                        \
    __private VTYPE r = NAME (a, &d);                                         \
    *c = d;                                                                   \
    return r;                                                                 \
  }

#define IMPLEMENT_BUILTIN_V_VPJ(NAME, VTYPE, JTYPE, LTYPE, HTYPE, LO, HI)     \
  VTYPE __attribute__ ((overloadable)) NAME (VTYPE a, JTYPE __private *c)     \
  {                                                                           \
    LTYPE d = c->LO;                                                          \
    HTYPE e = c->HI;                                                          \
    VTYPE r = (VTYPE)(NAME (a.LO, &d), NAME (a.HI, &e));                      \
    c->LO = d;                                                                \
    c->HI = e;                                                                \
    return r;                                                                 \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, VTYPE, JTYPE, __local)             \
  IF_GEN_AS (                                                                 \
      IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, VTYPE, JTYPE, __generic))      \
  IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, VTYPE, JTYPE, __global)

#define DEFINE_BUILTIN_V_VPJ(NAME)                                            \
  __IF_FP16 (                                                                 \
  half _CL_OVERLOADABLE _CL_READNONE NAME (half a, int __private *c)          \
  {                                                                           \
    __private int d;                                                          \
    __private float r = __builtin_##NAME##f16 (a, &d);                        \
    *c = d;                                                                   \
    return r;                                                                 \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, half, int, __local)                \
  IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, half, int, __global)               \
  IF_GEN_AS(IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, half, int, __generic))   \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, half2, int2, int, int, lo, hi)               \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, half3, int3, int2, int, lo, s2)              \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, half4, int4, int2, int2, lo, hi)             \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, half8, int8, int4, int4, lo, hi)             \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, half16, int16, int8, int8, lo, hi))          \
  float _CL_OVERLOADABLE _CL_READNONE NAME (float a, int __private *c)        \
  {                                                                           \
    return __builtin_##NAME##f (a, c);                                        \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, float, int, __local)               \
  IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, float, int, __global)              \
  IF_GEN_AS (IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, float, int, __generic)) \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, float2, int2, int, int, lo, hi)              \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, float3, int3, int2, int, lo, s2)             \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, float4, int4, int2, int2, lo, hi)            \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, float8, int8, int4, int4, lo, hi)            \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, float16, int16, int8, int8, lo, hi)          \
  __IF_FP64 (                                                                 \
  double _CL_OVERLOADABLE _CL_READNONE NAME (double a, int __private *c)      \
  {                                                                           \
    return __builtin_##NAME (a, c);                                           \
  }                                                                           \
  IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, double, int, __local)              \
  IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, double, int, __global)             \
  IF_GEN_AS(IMPLEMENT_BUILTIN_V_VPJ_ADDRSPACE (NAME, double, int, __generic)) \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, double2, int2, int, int, lo, hi)             \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, double3, int3, int2, int, lo, s2)            \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, double4, int4, int2, int2, lo, hi)           \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, double8, int8, int4, int4, lo, hi)           \
  IMPLEMENT_BUILTIN_V_VPJ (NAME, double16, int16, int8, int8, lo, hi))

#define __SINGLE_WI                             \
    if (get_local_id(0) == 0 &&                 \
        get_local_id(1) == 0 &&                 \
        get_local_id(2) == 0)

#ifndef _CL_DECLARE_FUNC_V_V
#define _CL_DECLARE_FUNC_V_V(NAME)              \
  float    _CL_OVERLOADABLE NAME(float   );     \
  float2   _CL_OVERLOADABLE NAME(float2  );     \
  float3   _CL_OVERLOADABLE NAME(float3  );     \
  float4   _CL_OVERLOADABLE NAME(float4  );     \
  float8   _CL_OVERLOADABLE NAME(float8  );     \
  float16  _CL_OVERLOADABLE NAME(float16 );     \
  __IF_FP64(                                    \
  double   _CL_OVERLOADABLE NAME(double  );     \
  double2  _CL_OVERLOADABLE NAME(double2 );     \
  double3  _CL_OVERLOADABLE NAME(double3 );     \
  double4  _CL_OVERLOADABLE NAME(double4 );     \
  double8  _CL_OVERLOADABLE NAME(double8 );     \
  double16 _CL_OVERLOADABLE NAME(double16);)
#endif

#ifndef _CL_DECLARE_FUNC_K_V
#define _CL_DECLARE_FUNC_K_V(NAME)              \
  int   _CL_OVERLOADABLE NAME(float   );        \
  int2  _CL_OVERLOADABLE NAME(float2  );        \
  int3  _CL_OVERLOADABLE NAME(float3  );        \
  int4  _CL_OVERLOADABLE NAME(float4  );        \
  int8  _CL_OVERLOADABLE NAME(float8  );        \
  int16 _CL_OVERLOADABLE NAME(float16 );        \
  __IF_FP64(                                    \
  long   _CL_OVERLOADABLE NAME(double  );       \
  long2  _CL_OVERLOADABLE NAME(double2 );       \
  long3  _CL_OVERLOADABLE NAME(double3 );       \
  long4  _CL_OVERLOADABLE NAME(double4 );       \
  long8  _CL_OVERLOADABLE NAME(double8 );       \
  long16 _CL_OVERLOADABLE NAME(double16);)
#endif
