1 //===--- Kernel.cpp - OpenMP device kernel interface -------------- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains the kernel entry points for the device. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "Debug.h" 14 #include "Interface.h" 15 #include "Mapping.h" 16 #include "State.h" 17 #include "Synchronization.h" 18 #include "Types.h" 19 20 using namespace _OMP; 21 22 #pragma omp begin declare target device_type(nohost) 23 24 static void inititializeRuntime(bool IsSPMD) { 25 // Order is important here. 26 synchronize::init(IsSPMD); 27 mapping::init(IsSPMD); 28 state::init(IsSPMD); 29 } 30 31 /// Simple generic state machine for worker threads. 32 static void genericStateMachine(IdentTy *Ident) { 33 FunctionTracingRAII(); 34 35 uint32_t TId = mapping::getThreadIdInBlock(); 36 37 do { 38 ParallelRegionFnTy WorkFn = 0; 39 40 // Wait for the signal that we have a new work function. 41 synchronize::threads(); 42 43 // Retrieve the work function from the runtime. 44 bool IsActive = __kmpc_kernel_parallel(&WorkFn); 45 46 // If there is nothing more to do, break out of the state machine by 47 // returning to the caller. 48 if (!WorkFn) 49 return; 50 51 if (IsActive) { 52 ASSERT(!mapping::isSPMDMode()); 53 ((void (*)(uint32_t, uint32_t))WorkFn)(0, TId); 54 __kmpc_kernel_end_parallel(); 55 } 56 57 synchronize::threads(); 58 59 } while (true); 60 } 61 62 extern "C" { 63 64 /// Initialization 65 /// 66 /// \param Ident Source location identification, can be NULL. 67 /// 68 int32_t __kmpc_target_init(IdentTy *Ident, int8_t Mode, 69 bool UseGenericStateMachine, bool) { 70 FunctionTracingRAII(); 71 const bool IsSPMD = Mode & OMP_TGT_EXEC_MODE_SPMD; 72 if (IsSPMD) { 73 inititializeRuntime(/* IsSPMD */ true); 74 synchronize::threadsAligned(); 75 } else { 76 inititializeRuntime(/* IsSPMD */ false); 77 // No need to wait since only the main threads will execute user 78 // code and workers will run into a barrier right away. 79 } 80 81 if (IsSPMD) { 82 state::assumeInitialState(IsSPMD); 83 return -1; 84 } 85 86 if (mapping::isInitialThreadInLevel0(IsSPMD)) 87 return -1; 88 89 // Enter the generic state machine if enabled and if this thread can possibly 90 // be an active worker thread. 91 // 92 // The latter check is important for NVIDIA Pascal (but not Volta) and AMD 93 // GPU. In those cases, a single thread can apparently satisfy a barrier on 94 // behalf of all threads in the same warp. Thus, it would not be safe for 95 // other threads in the main thread's warp to reach the first 96 // synchronize::threads call in genericStateMachine before the main thread 97 // reaches its corresponding synchronize::threads call: that would permit all 98 // active worker threads to proceed before the main thread has actually set 99 // state::ParallelRegionFn, and then they would immediately quit without 100 // doing any work. mapping::getBlockSize() does not include any of the main 101 // thread's warp, so none of its threads can ever be active worker threads. 102 if (UseGenericStateMachine && 103 mapping::getThreadIdInBlock() < mapping::getBlockSize(IsSPMD)) 104 genericStateMachine(Ident); 105 106 return mapping::getThreadIdInBlock(); 107 } 108 109 /// De-Initialization 110 /// 111 /// In non-SPMD, this function releases the workers trapped in a state machine 112 /// and also any memory dynamically allocated by the runtime. 113 /// 114 /// \param Ident Source location identification, can be NULL. 115 /// 116 void __kmpc_target_deinit(IdentTy *Ident, int8_t Mode, bool) { 117 FunctionTracingRAII(); 118 const bool IsSPMD = Mode & OMP_TGT_EXEC_MODE_SPMD; 119 state::assumeInitialState(IsSPMD); 120 if (IsSPMD) 121 return; 122 123 // Signal the workers to exit the state machine and exit the kernel. 124 state::ParallelRegionFn = nullptr; 125 } 126 127 int8_t __kmpc_is_spmd_exec_mode() { 128 FunctionTracingRAII(); 129 return mapping::isSPMDMode(); 130 } 131 } 132 133 #pragma omp end declare target 134