|
38 | 38 | ///
|
39 | 39 | //===----------------------------------------------------------------------===//
|
40 | 40 |
|
| 41 | +#ifndef SPIRVTOOCL_H |
| 42 | +#define SPIRVTOOCL_H |
| 43 | + |
41 | 44 | #include "OCLUtil.h"
|
42 | 45 | #include "SPIRVInternal.h"
|
43 | 46 | #include "llvm/IR/InstVisitor.h"
|
| 47 | +#include "llvm/IR/PassManager.h" |
44 | 48 | #include "llvm/Pass.h"
|
45 | 49 |
|
46 | 50 | #include <string>
|
@@ -185,4 +189,142 @@ class SPIRVToOCLLegacy : public ModulePass {
|
185 | 189 | bool runOnModule(Module &M) override = 0;
|
186 | 190 | };
|
187 | 191 |
|
| 192 | +class SPIRVToOCL12Base : public SPIRVToOCLBase { |
| 193 | +public: |
| 194 | + bool runSPIRVToOCL(Module &M) override; |
| 195 | + |
| 196 | + /// Transform __spirv_MemoryBarrier to atomic_work_item_fence. |
| 197 | + /// __spirv_MemoryBarrier(scope, sema) => |
| 198 | + /// atomic_work_item_fence(flag(sema), order(sema), map(scope)) |
| 199 | + void visitCallSPIRVMemoryBarrier(CallInst *CI) override; |
| 200 | + |
| 201 | + /// Transform __spirv_ControlBarrier to barrier. |
| 202 | + /// __spirv_ControlBarrier(execScope, memScope, sema) => |
| 203 | + /// barrier(flag(sema)) |
| 204 | + void visitCallSPIRVControlBarrier(CallInst *CI) override; |
| 205 | + |
| 206 | + /// Transform __spirv_OpAtomic functions. It firstly conduct generic |
| 207 | + /// mutations for all builtins and then mutate some of them seperately |
| 208 | + Instruction *visitCallSPIRVAtomicBuiltin(CallInst *CI, Op OC) override; |
| 209 | + |
| 210 | + /// Transform __spirv_OpAtomicIIncrement / OpAtomicIDecrement to |
| 211 | + /// atomic_inc / atomic_dec |
| 212 | + Instruction *visitCallSPIRVAtomicIncDec(CallInst *CI, Op OC) override; |
| 213 | + |
| 214 | + /// Transform __spirv_OpAtomicUMin/SMin/UMax/SMax into |
| 215 | + /// atomic_min/atomic_max, as there is no distinction in OpenCL 1.2 |
| 216 | + /// between signed and unsigned version of those functions |
| 217 | + Instruction *visitCallSPIRVAtomicUMinUMax(CallInst *CI, Op OC); |
| 218 | + |
| 219 | + /// Transform __spirv_OpAtomicLoad to atomic_add(*ptr, 0) |
| 220 | + Instruction *visitCallSPIRVAtomicLoad(CallInst *CI); |
| 221 | + |
| 222 | + /// Transform __spirv_OpAtomicStore to atomic_xchg(*ptr, value) |
| 223 | + Instruction *visitCallSPIRVAtomicStore(CallInst *CI); |
| 224 | + |
| 225 | + /// Transform __spirv_OpAtomicFlagClear to atomic_xchg(*ptr, 0) |
| 226 | + /// with ignoring the result |
| 227 | + Instruction *visitCallSPIRVAtomicFlagClear(CallInst *CI); |
| 228 | + |
| 229 | + /// Transform __spirv_OpAtomicFlagTestAndTest to |
| 230 | + /// (bool)atomic_xchg(*ptr, 1) |
| 231 | + Instruction *visitCallSPIRVAtomicFlagTestAndSet(CallInst *CI); |
| 232 | + |
| 233 | + /// Transform __spirv_OpAtomicCompareExchange and |
| 234 | + /// __spirv_OpAtomicCompareExchangeWeak into atomic_cmpxchg. There is no |
| 235 | + /// weak version of function in OpenCL 1.2 |
| 236 | + Instruction *visitCallSPIRVAtomicCmpExchg(CallInst *CI, Op OC) override; |
| 237 | + |
| 238 | + /// Conduct generic mutations for all atomic builtins |
| 239 | + CallInst *mutateCommonAtomicArguments(CallInst *CI, Op OC) override; |
| 240 | + |
| 241 | + /// Transform atomic builtin name into correct ocl-dependent name |
| 242 | + Instruction *mutateAtomicName(CallInst *CI, Op OC) override; |
| 243 | + |
| 244 | + /// Transform SPIR-V atomic instruction opcode into OpenCL 1.2 builtin name. |
| 245 | + /// Depending on the type, the return name starts with "atomic_" for 32-bit |
| 246 | + /// types or with "atom_" for 64-bit types, as specified by |
| 247 | + /// cl_khr_int64_base_atomics and cl_khr_int64_extended_atomics extensions. |
| 248 | + std::string mapAtomicName(Op OC, Type *Ty); |
| 249 | +}; |
| 250 | + |
| 251 | +class SPIRVToOCL12Pass : public llvm::PassInfoMixin<SPIRVToOCL12Pass>, |
| 252 | + public SPIRVToOCL12Base { |
| 253 | +public: |
| 254 | + llvm::PreservedAnalyses run(llvm::Module &M, |
| 255 | + llvm::ModuleAnalysisManager &MAM) { |
| 256 | + return runSPIRVToOCL(M) ? llvm::PreservedAnalyses::none() |
| 257 | + : llvm::PreservedAnalyses::all(); |
| 258 | + } |
| 259 | +}; |
| 260 | + |
| 261 | +class SPIRVToOCL12Legacy : public SPIRVToOCL12Base, public SPIRVToOCLLegacy { |
| 262 | +public: |
| 263 | + SPIRVToOCL12Legacy() : SPIRVToOCLLegacy(ID) { |
| 264 | + initializeSPIRVToOCL12LegacyPass(*PassRegistry::getPassRegistry()); |
| 265 | + } |
| 266 | + bool runOnModule(Module &M) override; |
| 267 | + |
| 268 | + static char ID; |
| 269 | +}; |
| 270 | + |
| 271 | +class SPIRVToOCL20Base : public SPIRVToOCLBase { |
| 272 | +public: |
| 273 | + bool runSPIRVToOCL(Module &M) override; |
| 274 | + |
| 275 | + /// Transform __spirv_MemoryBarrier to atomic_work_item_fence. |
| 276 | + /// __spirv_MemoryBarrier(scope, sema) => |
| 277 | + /// atomic_work_item_fence(flag(sema), order(sema), map(scope)) |
| 278 | + void visitCallSPIRVMemoryBarrier(CallInst *CI) override; |
| 279 | + |
| 280 | + /// Transform __spirv_ControlBarrier to work_group_barrier/sub_group_barrier. |
| 281 | + /// If execution scope is ScopeWorkgroup: |
| 282 | + /// __spirv_ControlBarrier(execScope, memScope, sema) => |
| 283 | + /// work_group_barrier(flag(sema), map(memScope)) |
| 284 | + /// Otherwise: |
| 285 | + /// __spirv_ControlBarrier(execScope, memScope, sema) => |
| 286 | + /// sub_group_barrier(flag(sema), map(memScope)) |
| 287 | + void visitCallSPIRVControlBarrier(CallInst *CI) override; |
| 288 | + |
| 289 | + /// Transform __spirv_Atomic* to atomic_*. |
| 290 | + /// __spirv_Atomic*(atomic_op, scope, sema, ops, ...) => |
| 291 | + /// atomic_*(generic atomic_op, ops, ..., order(sema), map(scope)) |
| 292 | + Instruction *visitCallSPIRVAtomicBuiltin(CallInst *CI, Op OC) override; |
| 293 | + |
| 294 | + /// Transform __spirv_OpAtomicIIncrement / OpAtomicIDecrement to |
| 295 | + /// atomic_fetch_add_explicit / atomic_fetch_sub_explicit |
| 296 | + Instruction *visitCallSPIRVAtomicIncDec(CallInst *CI, Op OC) override; |
| 297 | + |
| 298 | + /// Conduct generic mutations for all atomic builtins |
| 299 | + CallInst *mutateCommonAtomicArguments(CallInst *CI, Op OC) override; |
| 300 | + |
| 301 | + /// Transform atomic builtin name into correct ocl-dependent name |
| 302 | + Instruction *mutateAtomicName(CallInst *CI, Op OC) override; |
| 303 | + |
| 304 | + /// Transform __spirv_OpAtomicCompareExchange/Weak into |
| 305 | + /// compare_exchange_strong/weak_explicit |
| 306 | + Instruction *visitCallSPIRVAtomicCmpExchg(CallInst *CI, Op OC) override; |
| 307 | +}; |
| 308 | + |
| 309 | +class SPIRVToOCL20Pass : public llvm::PassInfoMixin<SPIRVToOCL20Pass>, |
| 310 | + public SPIRVToOCL20Base { |
| 311 | +public: |
| 312 | + llvm::PreservedAnalyses run(llvm::Module &M, |
| 313 | + llvm::ModuleAnalysisManager &MAM) { |
| 314 | + return runSPIRVToOCL(M) ? llvm::PreservedAnalyses::none() |
| 315 | + : llvm::PreservedAnalyses::all(); |
| 316 | + } |
| 317 | +}; |
| 318 | + |
| 319 | +class SPIRVToOCL20Legacy : public SPIRVToOCLLegacy, public SPIRVToOCL20Base { |
| 320 | +public: |
| 321 | + SPIRVToOCL20Legacy() : SPIRVToOCLLegacy(ID) { |
| 322 | + initializeSPIRVToOCL20LegacyPass(*PassRegistry::getPassRegistry()); |
| 323 | + } |
| 324 | + bool runOnModule(Module &M) override; |
| 325 | + static char ID; |
| 326 | +}; |
| 327 | + |
188 | 328 | } // namespace SPIRV
|
| 329 | + |
| 330 | +#endif // SPIRVTOOCL_H |
0 commit comments