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 declare target
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 
34   uint32_t TId = mapping::getThreadIdInBlock();
35 
36   do {
37     ParallelRegionFnTy WorkFn = 0;
38 
39     // Wait for the signal that we have a new work function.
40     synchronize::threads();
41 
42     // Retrieve the work function from the runtime.
43     bool IsActive = __kmpc_kernel_parallel(&WorkFn);
44 
45     // If there is nothing more to do, break out of the state machine by
46     // returning to the caller.
47     if (!WorkFn)
48       return;
49 
50     if (IsActive) {
51       ASSERT(!mapping::isSPMDMode());
52       ((void (*)(uint32_t, uint32_t))WorkFn)(0, TId);
53       __kmpc_kernel_end_parallel();
54     }
55 
56     synchronize::threads();
57 
58   } while (true);
59 }
60 
61 extern "C" {
62 
63 /// Initialization
64 ///
65 /// \param Ident               Source location identification, can be NULL.
66 ///
67 int32_t __kmpc_target_init(IdentTy *Ident, int8_t Mode,
68                            bool UseGenericStateMachine, bool) {
69   const bool IsSPMD = Mode & OMP_TGT_EXEC_MODE_SPMD;
70   if (IsSPMD) {
71     inititializeRuntime(/* IsSPMD */ true);
72     synchronize::threads();
73   } else {
74     inititializeRuntime(/* IsSPMD */ false);
75     // No need to wait since only the main threads will execute user
76     // code and workers will run into a barrier right away.
77   }
78 
79   if (IsSPMD) {
80     state::assumeInitialState(IsSPMD);
81     return -1;
82   }
83 
84   if (mapping::isMainThreadInGenericMode(IsSPMD))
85     return -1;
86 
87   if (UseGenericStateMachine)
88     genericStateMachine(Ident);
89 
90   return mapping::getThreadIdInBlock();
91 }
92 
93 /// De-Initialization
94 ///
95 /// In non-SPMD, this function releases the workers trapped in a state machine
96 /// and also any memory dynamically allocated by the runtime.
97 ///
98 /// \param Ident Source location identification, can be NULL.
99 ///
100 void __kmpc_target_deinit(IdentTy *Ident, int8_t Mode, bool) {
101   const bool IsSPMD = Mode & OMP_TGT_EXEC_MODE_SPMD;
102   state::assumeInitialState(IsSPMD);
103   if (IsSPMD)
104     return;
105 
106   // Signal the workers to exit the state machine and exit the kernel.
107   state::ParallelRegionFn = nullptr;
108 }
109 
110 int8_t __kmpc_is_spmd_exec_mode() { return mapping::isSPMDMode(); }
111 }
112 
113 #pragma omp end declare target
114