Home | History | Annotate | Download | only in SPIRV
      1 //===- OCLUtil.h - OCL Utilities declarations -------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM/SPIRV Translator
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
      9 //
     10 // Permission is hereby granted, free of charge, to any person obtaining a
     11 // copy of this software and associated documentation files (the "Software"),
     12 // to deal with the Software without restriction, including without limitation
     13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
     14 // and/or sell copies of the Software, and to permit persons to whom the
     15 // Software is furnished to do so, subject to the following conditions:
     16 //
     17 // Redistributions of source code must retain the above copyright notice,
     18 // this list of conditions and the following disclaimers.
     19 // Redistributions in binary form must reproduce the above copyright notice,
     20 // this list of conditions and the following disclaimers in the documentation
     21 // and/or other materials provided with the distribution.
     22 // Neither the names of Advanced Micro Devices, Inc., nor the names of its
     23 // contributors may be used to endorse or promote products derived from this
     24 // Software without specific prior written permission.
     25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     26 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     28 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     30 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
     31 // THE SOFTWARE.
     32 //
     33 //===----------------------------------------------------------------------===//
     34 //
     35 // This file declares OCL utility functions.
     36 //
     37 //===----------------------------------------------------------------------===//
     38 #include "SPIRVInternal.h"
     39 
     40 #include <utility>
     41 #include <tuple>
     42 #include <functional>
     43 using namespace SPIRV;
     44 using namespace llvm;
     45 using namespace spv;
     46 
     47 namespace OCLUtil {
     48 
     49 ///////////////////////////////////////////////////////////////////////////////
     50 //
     51 // Enums
     52 //
     53 ///////////////////////////////////////////////////////////////////////////////
     54 
     55 enum OCLMemFenceKind {
     56   OCLMF_Local = 1,
     57   OCLMF_Global = 2,
     58   OCLMF_Image = 4,
     59 };
     60 
     61 enum OCLScopeKind {
     62   OCLMS_work_item,
     63   OCLMS_work_group,
     64   OCLMS_device,
     65   OCLMS_all_svm_devices,
     66   OCLMS_sub_group,
     67 };
     68 
     69 enum OCLMemOrderKind {
     70   OCLMO_relaxed,
     71   OCLMO_acquire,
     72   OCLMO_release,
     73   OCLMO_acq_rel,
     74   OCLMO_seq_cst
     75 };
     76 
     77 ///////////////////////////////////////////////////////////////////////////////
     78 //
     79 // Types
     80 //
     81 ///////////////////////////////////////////////////////////////////////////////
     82 
     83 typedef SPIRVMap<OCLMemFenceKind, MemorySemanticsMask>
     84   OCLMemFenceMap;
     85 
     86 typedef SPIRVMap<OCLMemOrderKind, unsigned, MemorySemanticsMask>
     87   OCLMemOrderMap;
     88 
     89 typedef SPIRVMap<OCLScopeKind, Scope>
     90   OCLMemScopeMap;
     91 
     92 typedef SPIRVMap<std::string, SPIRVGroupOperationKind>
     93   SPIRSPIRVGroupOperationMap;
     94 
     95 typedef SPIRVMap<std::string, SPIRVFPRoundingModeKind>
     96   SPIRSPIRVFPRoundingModeMap;
     97 
     98 typedef SPIRVMap<std::string, Op, SPIRVInstruction>
     99   OCLSPIRVBuiltinMap;
    100 
    101 typedef SPIRVMap<std::string, SPIRVBuiltinVariableKind>
    102   SPIRSPIRVBuiltinVariableMap;
    103 
    104 /// Tuple of literals for atomic_work_item_fence (flag, order, scope)
    105 typedef std::tuple<unsigned, OCLMemOrderKind, OCLScopeKind>
    106   AtomicWorkItemFenceLiterals;
    107 
    108 /// Tuple of literals for work_group_barrier or sub_group_barrier
    109 ///     (flag, mem_scope, exec_scope)
    110 typedef std::tuple<unsigned, OCLScopeKind, OCLScopeKind>
    111   BarrierLiterals;
    112 
    113 class OCLOpaqueType;
    114 typedef SPIRVMap<std::string, Op, OCLOpaqueType>
    115   OCLOpaqueTypeOpCodeMap;
    116 
    117 /// Information for translating OCL builtin.
    118 struct OCLBuiltinTransInfo {
    119   std::string UniqName;
    120   std::string MangledName;
    121   std::string Postfix;      // Postfix to be added
    122   /// Postprocessor of operands
    123   std::function<void(std::vector<Value *>&)> PostProc;
    124   Type* RetTy;              // Return type of the translated function
    125   bool isRetSigned;         // When RetTy is int, determines if extensions
    126                             // on it should be a sext or zet.
    127   OCLBuiltinTransInfo() : RetTy(nullptr), isRetSigned(false) {
    128     PostProc = [](std::vector<Value *>&){};
    129   }
    130 };
    131 
    132 ///////////////////////////////////////////////////////////////////////////////
    133 //
    134 // Constants
    135 //
    136 ///////////////////////////////////////////////////////////////////////////////
    137 namespace kOCLBuiltinName {
    138   const static char All[]                       = "all";
    139   const static char Any[]                       = "any";
    140   const static char AsyncWorkGroupCopy[]        = "async_work_group_copy";
    141   const static char AsyncWorkGroupStridedCopy[] = "async_work_group_strided_copy";
    142   const static char AtomPrefix[]         = "atom_";
    143   const static char AtomCmpXchg[]        = "atom_cmpxchg";
    144   const static char AtomicPrefix[]       = "atomic_";
    145   const static char AtomicCmpXchg[]      = "atomic_cmpxchg";
    146   const static char AtomicCmpXchgStrong[]         = "atomic_compare_exchange_strong";
    147   const static char AtomicCmpXchgStrongExplicit[] = "atomic_compare_exchange_strong_explicit";
    148   const static char AtomicCmpXchgWeak[]           = "atomic_compare_exchange_weak";
    149   const static char AtomicCmpXchgWeakExplicit[]   = "atomic_compare_exchange_weak_explicit";
    150   const static char AtomicInit[]          = "atomic_init";
    151   const static char AtomicWorkItemFence[] = "atomic_work_item_fence";
    152   const static char Barrier[]            = "barrier";
    153   const static char Clamp[]              = "clamp";
    154   const static char ConvertPrefix[]      = "convert_";
    155   const static char Dot[]                = "dot";
    156   const static char EnqueueKernel[]      = "enqueue_kernel";
    157   const static char FMax[]               = "fmax";
    158   const static char FMin[]               = "fmin";
    159   const static char GetFence[]           = "get_fence";
    160   const static char GetImageArraySize[]  = "get_image_array_size";
    161   const static char GetImageChannelOrder[]    = "get_image_channel_order";
    162   const static char GetImageChannelDataType[] = "get_image_channel_data_type";
    163   const static char GetImageDepth[]      = "get_image_depth";
    164   const static char GetImageDim[]        = "get_image_dim";
    165   const static char GetImageHeight[]     = "get_image_height";
    166   const static char GetImageWidth[]      = "get_image_width";
    167   const static char IsFinite[]           = "isfinite";
    168   const static char IsNan[]              = "isnan";
    169   const static char IsNormal[]           = "isnormal";
    170   const static char IsInf[]              = "isinf";
    171   const static char Max[]                = "max";
    172   const static char MemFence[]           = "mem_fence";
    173   const static char Min[]                = "min";
    174   const static char Mix[]                = "mix";
    175   const static char NDRangePrefix[]      = "ndrange_";
    176   const static char Pipe[]               = "pipe";
    177   const static char ReadImage[]          = "read_image";
    178   const static char ReadPipe[]           = "read_pipe";
    179   const static char RoundingPrefix[]     = "_r";
    180   const static char Sampled[]            = "sampled_";
    181   const static char SampledReadImage[]   = "sampled_read_image";
    182   const static char Signbit[]            = "signbit";
    183   const static char SmoothStep[]         = "smoothstep";
    184   const static char Step[]               = "step";
    185   const static char SubGroupPrefix[]     = "sub_group_";
    186   const static char SubGroupBarrier[]    = "sub_group_barrier";
    187   const static char SubPrefix[]          = "sub_";
    188   const static char ToGlobal[]           = "to_global";
    189   const static char ToLocal[]            = "to_local";
    190   const static char ToPrivate[]          = "to_private";
    191   const static char VLoadPrefix[]        = "vload";
    192   const static char VLoadAPrefix[]       = "vloada";
    193   const static char VLoadHalf[]          = "vload_half";
    194   const static char VStorePrefix[]       = "vstore";
    195   const static char VStoreAPrefix[]      = "vstorea";
    196   const static char WaitGroupEvent[]     = "wait_group_events";
    197   const static char WriteImage[]         = "write_image";
    198   const static char WorkGroupBarrier[]   = "work_group_barrier";
    199   const static char WritePipe[]          = "write_pipe";
    200   const static char WorkGroupPrefix[]    = "work_group_";
    201   const static char WorkGroupAll[]       = "work_group_all";
    202   const static char WorkGroupAny[]       = "work_group_any";
    203   const static char SubGroupAll[]        = "sub_group_all";
    204   const static char SubGroupAny[]        = "sub_group_any";
    205   const static char WorkPrefix[]         = "work_";
    206 }
    207 
    208 /// Offset for OpenCL image channel order enumeration values.
    209 const unsigned int OCLImageChannelOrderOffset = 0x10B0;
    210 
    211 /// Offset for OpenCL image channel data type enumeration values.
    212 const unsigned int OCLImageChannelDataTypeOffset = 0x10D0;
    213 
    214 /// OCL 1.x atomic memory order when translated to 2.0 atomics.
    215 const OCLMemOrderKind OCLLegacyAtomicMemOrder = OCLMO_seq_cst;
    216 
    217 /// OCL 1.x atomic memory scope when translated to 2.0 atomics.
    218 const OCLScopeKind OCLLegacyAtomicMemScope = OCLMS_device;
    219 
    220 namespace kOCLVer {
    221   const unsigned CL12 = 102000;
    222   const unsigned CL20 = 200000;
    223   const unsigned CL21 = 201000;
    224 }
    225 
    226 namespace OclExt {
    227 enum Kind {
    228 #define _SPIRV_OP(x) x,
    229   _SPIRV_OP(cl_images)
    230   _SPIRV_OP(cl_doubles)
    231   _SPIRV_OP(cl_khr_int64_base_atomics)
    232   _SPIRV_OP(cl_khr_int64_extended_atomics)
    233   _SPIRV_OP(cl_khr_fp16)
    234   _SPIRV_OP(cl_khr_gl_sharing)
    235   _SPIRV_OP(cl_khr_gl_event)
    236   _SPIRV_OP(cl_khr_d3d10_sharing)
    237   _SPIRV_OP(cl_khr_media_sharing)
    238   _SPIRV_OP(cl_khr_d3d11_sharing)
    239   _SPIRV_OP(cl_khr_global_int32_base_atomics)
    240   _SPIRV_OP(cl_khr_global_int32_extended_atomics)
    241   _SPIRV_OP(cl_khr_local_int32_base_atomics)
    242   _SPIRV_OP(cl_khr_local_int32_extended_atomics)
    243   _SPIRV_OP(cl_khr_byte_addressable_store)
    244   _SPIRV_OP(cl_khr_3d_image_writes)
    245   _SPIRV_OP(cl_khr_gl_msaa_sharing)
    246   _SPIRV_OP(cl_khr_depth_images)
    247   _SPIRV_OP(cl_khr_gl_depth_images)
    248   _SPIRV_OP(cl_khr_subgroups)
    249   _SPIRV_OP(cl_khr_mipmap_image)
    250   _SPIRV_OP(cl_khr_mipmap_image_writes)
    251   _SPIRV_OP(cl_khr_egl_event)
    252   _SPIRV_OP(cl_khr_srgb_image_writes)
    253 #undef _SPIRV_OP
    254 };
    255 }
    256 
    257 
    258 ///////////////////////////////////////////////////////////////////////////////
    259 //
    260 // Functions
    261 //
    262 ///////////////////////////////////////////////////////////////////////////////
    263 
    264 /// Get instruction index for SPIR-V extended instruction for OpenCL.std
    265 ///   extended instruction set.
    266 /// \param MangledName The mangled name of OpenCL builtin function.
    267 /// \param DemangledName The demangled name of OpenCL builtin function if
    268 ///   not empty.
    269 /// \return instruction index of extended instruction if the OpenCL builtin
    270 ///   function is translated to an extended instruction, otherwise ~0U.
    271 unsigned getExtOp(StringRef MangledName,
    272     const std::string &DemangledName = "");
    273 
    274 /// Get an empty SPIR-V instruction.
    275 std::unique_ptr<SPIRVEntry>
    276 getSPIRVInst(const OCLBuiltinTransInfo &Info);
    277 
    278 /// Get literal arguments of call of atomic_work_item_fence.
    279 AtomicWorkItemFenceLiterals getAtomicWorkItemFenceLiterals(CallInst* CI);
    280 
    281 /// Get literal arguments of call of work_group_barrier or sub_group_barrier.
    282 BarrierLiterals getBarrierLiterals(CallInst* CI);
    283 
    284 /// Get number of memory order arguments for atomic builtin function.
    285 size_t getAtomicBuiltinNumMemoryOrderArgs(StringRef Name);
    286 
    287 /// Get OCL version from metadata opencl.ocl.version.
    288 /// \param AllowMulti Allows multiple operands if true.
    289 /// \return OCL version encoded as Major*10^5+Minor*10^3+Rev,
    290 /// e.g. 201000 for OCL 2.1, 200000 for OCL 2.0, 102000 for OCL 1.2,
    291 /// 0 if metadata not found.
    292 /// If there are multiple operands, check they are identical.
    293 unsigned getOCLVersion(Module *M, bool AllowMulti = false);
    294 
    295 /// Encode OpenCL version as Major*10^5+Minor*10^3+Rev.
    296 unsigned
    297 encodeOCLVer(unsigned short Major,
    298     unsigned char Minor, unsigned char Rev);
    299 
    300 /// Decode OpenCL version which is encoded as Major*10^5+Minor*10^3+Rev
    301 std::tuple<unsigned short, unsigned char, unsigned char>
    302 decodeOCLVer(unsigned Ver);
    303 
    304 /// Decode a MDNode assuming it contains three integer constants.
    305 void decodeMDNode(MDNode* N, unsigned& X, unsigned& Y, unsigned& Z);
    306 
    307 /// Decode OpenCL vector type hint MDNode and encode it as SPIR-V execution
    308 /// mode VecTypeHint.
    309 unsigned transVecTypeHint(MDNode* Node);
    310 
    311 /// Decode SPIR-V encoding of vector type hint execution mode.
    312 Type *decodeVecTypeHint(LLVMContext &C, unsigned code);
    313 
    314 SPIRAddressSpace getOCLOpaqueTypeAddrSpace(Op OpCode);
    315 SPIR::TypeAttributeEnum getOCLOpaqueTypeAddrSpace(SPIR::TypePrimitiveEnum prim);
    316 
    317 inline unsigned mapOCLMemSemanticToSPIRV(unsigned MemFenceFlag,
    318     OCLMemOrderKind Order) {
    319   return OCLMemOrderMap::map(Order) |
    320       mapBitMask<OCLMemFenceMap>(MemFenceFlag);
    321 }
    322 
    323 inline unsigned mapOCLMemFenceFlagToSPIRV(unsigned MemFenceFlag) {
    324   return mapBitMask<OCLMemFenceMap>(MemFenceFlag);
    325 }
    326 
    327 inline std::pair<unsigned, OCLMemOrderKind>
    328 mapSPIRVMemSemanticToOCL(unsigned Sema) {
    329   return std::make_pair(rmapBitMask<OCLMemFenceMap>(Sema),
    330     OCLMemOrderMap::rmap(extractSPIRVMemOrderSemantic(Sema)));
    331 }
    332 
    333 inline OCLMemOrderKind
    334 mapSPIRVMemOrderToOCL(unsigned Sema) {
    335   return OCLMemOrderMap::rmap(extractSPIRVMemOrderSemantic(Sema));
    336 }
    337 
    338 /// Mutate call instruction to call OpenCL builtin function.
    339 CallInst *
    340 mutateCallInstOCL(Module *M, CallInst *CI,
    341     std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate,
    342     AttributeSet *Attrs = nullptr);
    343 
    344 /// Mutate call instruction to call OpenCL builtin function.
    345 Instruction *
    346 mutateCallInstOCL(Module *M, CallInst *CI,
    347     std::function<std::string (CallInst *, std::vector<Value *> &,
    348         Type *&RetTy)> ArgMutate,
    349     std::function<Instruction *(CallInst *)> RetMutate,
    350     AttributeSet *Attrs = nullptr);
    351 
    352 /// Mutate a function to OpenCL builtin function.
    353 void
    354 mutateFunctionOCL(Function *F,
    355     std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate,
    356     AttributeSet *Attrs = nullptr);
    357 
    358 /// Check if instruction is bitcast from spirv.ConstantSampler to spirv.Sampler
    359 bool
    360 isSamplerInitializer(Instruction *Inst);
    361 
    362 /// Check if instruction is bitcast from spirv.ConstantPipeStorage
    363 /// to spirv.PipeStorage
    364 bool
    365 isPipeStorageInitializer(Instruction *Inst);
    366 
    367 /// Check (isSamplerInitializer || isPipeStorageInitializer)
    368 bool
    369 isSpecialTypeInitializer(Instruction* Inst);
    370 
    371 } // namespace OCLUtil
    372 
    373 ///////////////////////////////////////////////////////////////////////////////
    374 //
    375 // Map definitions
    376 //
    377 ///////////////////////////////////////////////////////////////////////////////
    378 
    379 using namespace OCLUtil;
    380 namespace SPIRV {
    381 template<> inline void
    382 SPIRVMap<OCLMemFenceKind, MemorySemanticsMask>::init() {
    383   add(OCLMF_Local, MemorySemanticsWorkgroupMemoryMask);
    384   add(OCLMF_Global, MemorySemanticsCrossWorkgroupMemoryMask);
    385   add(OCLMF_Image, MemorySemanticsImageMemoryMask);
    386 }
    387 
    388 template<> inline void
    389 SPIRVMap<OCLMemOrderKind, unsigned, MemorySemanticsMask>::init() {
    390   add(OCLMO_relaxed, MemorySemanticsMaskNone);
    391   add(OCLMO_acquire, MemorySemanticsAcquireMask);
    392   add(OCLMO_release, MemorySemanticsReleaseMask);
    393   add(OCLMO_acq_rel, MemorySemanticsAcquireReleaseMask);
    394   add(OCLMO_seq_cst, MemorySemanticsSequentiallyConsistentMask);
    395 }
    396 
    397 template<> inline void
    398 SPIRVMap<OCLScopeKind, Scope>::init() {
    399   add(OCLMS_work_item, ScopeInvocation);
    400   add(OCLMS_work_group, ScopeWorkgroup);
    401   add(OCLMS_device, ScopeDevice);
    402   add(OCLMS_all_svm_devices, ScopeCrossDevice);
    403   add(OCLMS_sub_group, ScopeSubgroup);
    404 }
    405 
    406 template<> inline void
    407 SPIRVMap<std::string, SPIRVGroupOperationKind>::init() {
    408   add("reduce", GroupOperationReduce);
    409   add("scan_inclusive", GroupOperationInclusiveScan);
    410   add("scan_exclusive", GroupOperationExclusiveScan);
    411 }
    412 
    413 template<> inline void
    414 SPIRVMap<std::string, SPIRVFPRoundingModeKind>::init() {
    415   add("rte", FPRoundingModeRTE);
    416   add("rtz", FPRoundingModeRTZ);
    417   add("rtp", FPRoundingModeRTP);
    418   add("rtn", FPRoundingModeRTN);
    419 }
    420 
    421 template<> inline void
    422 SPIRVMap<OclExt::Kind, std::string>::init() {
    423 #define _SPIRV_OP(x) add(OclExt::x, #x);
    424   _SPIRV_OP(cl_images)
    425   _SPIRV_OP(cl_doubles)
    426   _SPIRV_OP(cl_khr_int64_base_atomics)
    427   _SPIRV_OP(cl_khr_int64_extended_atomics)
    428   _SPIRV_OP(cl_khr_fp16)
    429   _SPIRV_OP(cl_khr_gl_sharing)
    430   _SPIRV_OP(cl_khr_gl_event)
    431   _SPIRV_OP(cl_khr_d3d10_sharing)
    432   _SPIRV_OP(cl_khr_media_sharing)
    433   _SPIRV_OP(cl_khr_d3d11_sharing)
    434   _SPIRV_OP(cl_khr_global_int32_base_atomics)
    435   _SPIRV_OP(cl_khr_global_int32_extended_atomics)
    436   _SPIRV_OP(cl_khr_local_int32_base_atomics)
    437   _SPIRV_OP(cl_khr_local_int32_extended_atomics)
    438   _SPIRV_OP(cl_khr_byte_addressable_store)
    439   _SPIRV_OP(cl_khr_3d_image_writes)
    440   _SPIRV_OP(cl_khr_gl_msaa_sharing)
    441   _SPIRV_OP(cl_khr_depth_images)
    442   _SPIRV_OP(cl_khr_gl_depth_images)
    443   _SPIRV_OP(cl_khr_subgroups)
    444   _SPIRV_OP(cl_khr_mipmap_image)
    445   _SPIRV_OP(cl_khr_mipmap_image_writes)
    446   _SPIRV_OP(cl_khr_egl_event)
    447   _SPIRV_OP(cl_khr_srgb_image_writes)
    448 #undef _SPIRV_OP
    449 }
    450 
    451 template<> inline void
    452 SPIRVMap<OclExt::Kind, SPIRVCapabilityKind>::init() {
    453   add(OclExt::cl_images, CapabilityImageBasic);
    454   add(OclExt::cl_doubles, CapabilityFloat64);
    455   add(OclExt::cl_khr_int64_base_atomics, CapabilityInt64Atomics);
    456   add(OclExt::cl_khr_int64_extended_atomics, CapabilityInt64Atomics);
    457   add(OclExt::cl_khr_fp16, CapabilityFloat16);
    458   add(OclExt::cl_khr_subgroups, CapabilityGroups);
    459   add(OclExt::cl_khr_mipmap_image, CapabilityImageMipmap);
    460   add(OclExt::cl_khr_mipmap_image_writes, CapabilityImageMipmap);
    461 }
    462 
    463 /// Map OpenCL work functions to SPIR-V builtin variables.
    464 template<> inline void
    465 SPIRVMap<std::string, SPIRVBuiltinVariableKind>::init() {
    466   add("get_work_dim", BuiltInWorkDim);
    467   add("get_global_size", BuiltInGlobalSize);
    468   add("get_global_id", BuiltInGlobalInvocationId);
    469   add("get_global_offset", BuiltInGlobalOffset);
    470   add("get_local_size", BuiltInWorkgroupSize);
    471   add("get_enqueued_local_size", BuiltInEnqueuedWorkgroupSize);
    472   add("get_local_id", BuiltInLocalInvocationId);
    473   add("get_num_groups", BuiltInNumWorkgroups);
    474   add("get_group_id", BuiltInWorkgroupId);
    475   add("get_global_linear_id", BuiltInGlobalLinearId);
    476   add("get_local_linear_id", BuiltInLocalInvocationIndex);
    477   add("get_sub_group_size", BuiltInSubgroupSize);
    478   add("get_max_sub_group_size", BuiltInSubgroupMaxSize);
    479   add("get_num_sub_groups", BuiltInNumSubgroups);
    480   add("get_enqueued_num_sub_groups", BuiltInNumEnqueuedSubgroups);
    481   add("get_sub_group_id", BuiltInSubgroupId);
    482   add("get_sub_group_local_id", BuiltInSubgroupLocalInvocationId);
    483 }
    484 
    485 // Maps uniqued OCL builtin function name to SPIR-V op code.
    486 // A uniqued OCL builtin function name may be different from the real
    487 // OCL builtin function name. e.g. instead of atomic_min, atomic_umin
    488 // is used for atomic_min with unsigned integer parameter.
    489 // work_group_ and sub_group_ functions are unified as group_ functions
    490 // except work_group_barrier.
    491 class SPIRVInstruction;
    492 template<> inline void
    493 SPIRVMap<std::string, Op, SPIRVInstruction>::init() {
    494 #define _SPIRV_OP(x,y) add("atom_"#x, OpAtomic##y);
    495 // cl_khr_int64_base_atomics builtins
    496 _SPIRV_OP(add, IAdd)
    497 _SPIRV_OP(sub, ISub)
    498 _SPIRV_OP(xchg, Exchange)
    499 _SPIRV_OP(dec, IDecrement)
    500 _SPIRV_OP(inc, IIncrement)
    501 _SPIRV_OP(cmpxchg, CompareExchange)
    502 // cl_khr_int64_extended_atomics builtins
    503 _SPIRV_OP(min, SMin)
    504 _SPIRV_OP(max, SMax)
    505 _SPIRV_OP(and, And)
    506 _SPIRV_OP(or, Or)
    507 _SPIRV_OP(xor, Xor)
    508 #undef _SPIRV_OP
    509 #define _SPIRV_OP(x,y) add("atomic_"#x, Op##y);
    510 // CL 2.0 atomic builtins
    511 _SPIRV_OP(flag_test_and_set_explicit, AtomicFlagTestAndSet)
    512 _SPIRV_OP(flag_clear_explicit, AtomicFlagClear)
    513 _SPIRV_OP(load_explicit, AtomicLoad)
    514 _SPIRV_OP(store_explicit, AtomicStore)
    515 _SPIRV_OP(exchange_explicit, AtomicExchange)
    516 _SPIRV_OP(compare_exchange_strong_explicit, AtomicCompareExchange)
    517 _SPIRV_OP(compare_exchange_weak_explicit, AtomicCompareExchangeWeak)
    518 _SPIRV_OP(inc, AtomicIIncrement)
    519 _SPIRV_OP(dec, AtomicIDecrement)
    520 _SPIRV_OP(fetch_add_explicit, AtomicIAdd)
    521 _SPIRV_OP(fetch_sub_explicit, AtomicISub)
    522 _SPIRV_OP(fetch_umin_explicit, AtomicUMin)
    523 _SPIRV_OP(fetch_umax_explicit, AtomicUMax)
    524 _SPIRV_OP(fetch_min_explicit, AtomicSMin)
    525 _SPIRV_OP(fetch_max_explicit, AtomicSMax)
    526 _SPIRV_OP(fetch_and_explicit, AtomicAnd)
    527 _SPIRV_OP(fetch_or_explicit, AtomicOr)
    528 _SPIRV_OP(fetch_xor_explicit, AtomicXor)
    529 #undef _SPIRV_OP
    530 #define _SPIRV_OP(x,y) add(#x, Op##y);
    531 _SPIRV_OP(dot, Dot)
    532 _SPIRV_OP(async_work_group_copy, GroupAsyncCopy)
    533 _SPIRV_OP(async_work_group_strided_copy, GroupAsyncCopy)
    534 _SPIRV_OP(wait_group_events, GroupWaitEvents)
    535 _SPIRV_OP(isequal, FOrdEqual)
    536 _SPIRV_OP(isnotequal, FUnordNotEqual)
    537 _SPIRV_OP(isgreater, FOrdGreaterThan)
    538 _SPIRV_OP(isgreaterequal, FOrdGreaterThanEqual)
    539 _SPIRV_OP(isless, FOrdLessThan)
    540 _SPIRV_OP(islessequal, FOrdLessThanEqual)
    541 _SPIRV_OP(islessgreater, LessOrGreater)
    542 _SPIRV_OP(isordered, Ordered)
    543 _SPIRV_OP(isunordered, Unordered)
    544 _SPIRV_OP(isfinite, IsFinite)
    545 _SPIRV_OP(isinf, IsInf)
    546 _SPIRV_OP(isnan, IsNan)
    547 _SPIRV_OP(isnormal, IsNormal)
    548 _SPIRV_OP(signbit, SignBitSet)
    549 _SPIRV_OP(any, Any)
    550 _SPIRV_OP(all, All)
    551 _SPIRV_OP(get_fence, GenericPtrMemSemantics)
    552 // CL 2.0 kernel enqueue builtins
    553 _SPIRV_OP(enqueue_marker, EnqueueMarker)
    554 _SPIRV_OP(enqueue_kernel, EnqueueKernel)
    555 _SPIRV_OP(get_kernel_ndrange_subgroup_count, GetKernelNDrangeSubGroupCount)
    556 _SPIRV_OP(get_kernel_ndrange_max_subgroup_count, GetKernelNDrangeMaxSubGroupSize)
    557 _SPIRV_OP(get_kernel_work_group_size, GetKernelWorkGroupSize)
    558 _SPIRV_OP(get_kernel_preferred_work_group_size_multiple, GetKernelPreferredWorkGroupSizeMultiple)
    559 _SPIRV_OP(retain_event, RetainEvent)
    560 _SPIRV_OP(release_event, ReleaseEvent)
    561 _SPIRV_OP(create_user_event, CreateUserEvent)
    562 _SPIRV_OP(is_valid_event, IsValidEvent)
    563 _SPIRV_OP(set_user_event_status, SetUserEventStatus)
    564 _SPIRV_OP(capture_event_profiling_info, CaptureEventProfilingInfo)
    565 _SPIRV_OP(get_default_queue, GetDefaultQueue)
    566 _SPIRV_OP(ndrange_1D, BuildNDRange)
    567 _SPIRV_OP(ndrange_2D, BuildNDRange)
    568 _SPIRV_OP(ndrange_3D, BuildNDRange)
    569 // Generic Address Space Casts
    570 _SPIRV_OP(to_global, GenericCastToPtrExplicit)
    571 _SPIRV_OP(to_local, GenericCastToPtrExplicit)
    572 _SPIRV_OP(to_private, GenericCastToPtrExplicit)
    573 _SPIRV_OP(work_group_barrier, ControlBarrier)
    574 // CL 2.0 pipe builtins
    575 _SPIRV_OP(read_pipe, ReadPipe)
    576 _SPIRV_OP(write_pipe, WritePipe)
    577 _SPIRV_OP(reserved_read_pipe, ReservedReadPipe)
    578 _SPIRV_OP(reserved_write_pipe, ReservedWritePipe)
    579 _SPIRV_OP(reserve_read_pipe, ReserveReadPipePackets)
    580 _SPIRV_OP(reserve_write_pipe, ReserveWritePipePackets)
    581 _SPIRV_OP(commit_read_pipe, CommitReadPipe)
    582 _SPIRV_OP(commit_write_pipe, CommitWritePipe)
    583 _SPIRV_OP(is_valid_reserve_id, IsValidReserveId)
    584 _SPIRV_OP(group_reserve_read_pipe, GroupReserveReadPipePackets)
    585 _SPIRV_OP(group_reserve_write_pipe, GroupReserveWritePipePackets)
    586 _SPIRV_OP(group_commit_read_pipe, GroupCommitReadPipe)
    587 _SPIRV_OP(group_commit_write_pipe, GroupCommitWritePipe)
    588 _SPIRV_OP(get_pipe_num_packets, GetNumPipePackets)
    589 _SPIRV_OP(get_pipe_max_packets, GetMaxPipePackets)
    590 // CL 2.0 workgroup builtins
    591 _SPIRV_OP(group_all, GroupAll)
    592 _SPIRV_OP(group_any, GroupAny)
    593 _SPIRV_OP(group_broadcast, GroupBroadcast)
    594 _SPIRV_OP(group_iadd, GroupIAdd)
    595 _SPIRV_OP(group_fadd, GroupFAdd)
    596 _SPIRV_OP(group_fmin, GroupFMin)
    597 _SPIRV_OP(group_umin, GroupUMin)
    598 _SPIRV_OP(group_smin, GroupSMin)
    599 _SPIRV_OP(group_fmax, GroupFMax)
    600 _SPIRV_OP(group_umax, GroupUMax)
    601 _SPIRV_OP(group_smax, GroupSMax)
    602 // CL image builtins
    603 _SPIRV_OP(SampledImage, SampledImage)
    604 _SPIRV_OP(ImageSampleExplicitLod, ImageSampleExplicitLod)
    605 _SPIRV_OP(read_image, ImageRead)
    606 _SPIRV_OP(write_image, ImageWrite)
    607 _SPIRV_OP(get_image_channel_data_type, ImageQueryFormat)
    608 _SPIRV_OP(get_image_channel_order, ImageQueryOrder)
    609 _SPIRV_OP(get_image_num_mip_levels, ImageQueryLevels)
    610 _SPIRV_OP(get_image_num_samples, ImageQuerySamples)
    611 #undef _SPIRV_OP
    612 }
    613 
    614 template<> inline void
    615 SPIRVMap<std::string, Op, OCLOpaqueType>::init() {
    616   add("opencl.event_t", OpTypeEvent);
    617   add("opencl.pipe_t", OpTypePipe);
    618   add("opencl.clk_event_t", OpTypeDeviceEvent);
    619   add("opencl.reserve_id_t", OpTypeReserveId);
    620   add("opencl.queue_t", OpTypeQueue);
    621 }
    622 
    623 } // namespace SPIRV
    624