167ab875fSJohannes Doerfert //===------- Mapping.cpp - OpenMP device runtime mapping helpers -- C++ -*-===//
267ab875fSJohannes Doerfert //
367ab875fSJohannes Doerfert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
467ab875fSJohannes Doerfert // See https://llvm.org/LICENSE.txt for license information.
567ab875fSJohannes Doerfert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
667ab875fSJohannes Doerfert //
767ab875fSJohannes Doerfert //===----------------------------------------------------------------------===//
867ab875fSJohannes Doerfert //
967ab875fSJohannes Doerfert //
1067ab875fSJohannes Doerfert //===----------------------------------------------------------------------===//
1167ab875fSJohannes Doerfert
1267ab875fSJohannes Doerfert #include "Mapping.h"
1393bebdc7SJohannes Doerfert #include "Interface.h"
1467ab875fSJohannes Doerfert #include "State.h"
1567ab875fSJohannes Doerfert #include "Types.h"
1667ab875fSJohannes Doerfert #include "Utils.h"
1767ab875fSJohannes Doerfert
18b4f8443dSJoseph Huber #pragma omp begin declare target device_type(nohost)
1967ab875fSJohannes Doerfert
20842f875cSJon Chesterfield #include "llvm/Frontend/OpenMP/OMPGridValues.h"
21842f875cSJon Chesterfield
2267ab875fSJohannes Doerfert using namespace _OMP;
2367ab875fSJohannes Doerfert
2467ab875fSJohannes Doerfert namespace _OMP {
2567ab875fSJohannes Doerfert namespace impl {
2667ab875fSJohannes Doerfert
27b4f8443dSJoseph Huber // Forward declarations defined to be defined for AMDGCN and NVPTX.
28b4f8443dSJoseph Huber const llvm::omp::GV &getGridValue();
29b4f8443dSJoseph Huber uint32_t getGridDim(uint32_t n, uint16_t d);
30b4f8443dSJoseph Huber uint32_t getWorkgroupDim(uint32_t group_id, uint32_t grid_size,
31b4f8443dSJoseph Huber uint16_t group_size);
32b4f8443dSJoseph Huber uint32_t getNumHardwareThreadsInBlock();
33b4f8443dSJoseph Huber LaneMaskTy activemask();
34b4f8443dSJoseph Huber LaneMaskTy lanemaskLT();
35b4f8443dSJoseph Huber LaneMaskTy lanemaskGT();
36b4f8443dSJoseph Huber uint32_t getThreadIdInWarp();
37b4f8443dSJoseph Huber uint32_t getThreadIdInBlock();
38b4f8443dSJoseph Huber uint32_t getKernelSize();
39b4f8443dSJoseph Huber uint32_t getBlockId();
40b4f8443dSJoseph Huber uint32_t getNumberOfBlocks();
41b4f8443dSJoseph Huber uint32_t getWarpId();
42b4f8443dSJoseph Huber uint32_t getNumberOfWarpsInBlock();
43b4f8443dSJoseph Huber
4467ab875fSJohannes Doerfert /// AMDGCN Implementation
4567ab875fSJohannes Doerfert ///
4667ab875fSJohannes Doerfert ///{
4767ab875fSJohannes Doerfert #pragma omp begin declare variant match(device = {arch(amdgcn)})
4867ab875fSJohannes Doerfert
getGridValue()49ce0caf41SJoseph Huber const llvm::omp::GV &getGridValue() {
507272982eSJon Chesterfield return llvm::omp::getAMDGPUGridValues<__AMDGCN_WAVEFRONT_SIZE>();
51842f875cSJon Chesterfield }
52842f875cSJon Chesterfield
getGridDim(uint32_t n,uint16_t d)5367ab875fSJohannes Doerfert uint32_t getGridDim(uint32_t n, uint16_t d) {
5467ab875fSJohannes Doerfert uint32_t q = n / d;
5567ab875fSJohannes Doerfert return q + (n > q * d);
5667ab875fSJohannes Doerfert }
5767ab875fSJohannes Doerfert
getWorkgroupDim(uint32_t group_id,uint32_t grid_size,uint16_t group_size)5867ab875fSJohannes Doerfert uint32_t getWorkgroupDim(uint32_t group_id, uint32_t grid_size,
5967ab875fSJohannes Doerfert uint16_t group_size) {
6067ab875fSJohannes Doerfert uint32_t r = grid_size - group_id * group_size;
6167ab875fSJohannes Doerfert return (r < group_size) ? r : group_size;
6267ab875fSJohannes Doerfert }
6367ab875fSJohannes Doerfert
getNumHardwareThreadsInBlock()6493bebdc7SJohannes Doerfert uint32_t getNumHardwareThreadsInBlock() {
6593bebdc7SJohannes Doerfert return getWorkgroupDim(__builtin_amdgcn_workgroup_id_x(),
6693bebdc7SJohannes Doerfert __builtin_amdgcn_grid_size_x(),
6793bebdc7SJohannes Doerfert __builtin_amdgcn_workgroup_size_x());
6893bebdc7SJohannes Doerfert }
6993bebdc7SJohannes Doerfert
activemask()7067ab875fSJohannes Doerfert LaneMaskTy activemask() { return __builtin_amdgcn_read_exec(); }
7167ab875fSJohannes Doerfert
lanemaskLT()7267ab875fSJohannes Doerfert LaneMaskTy lanemaskLT() {
7367ab875fSJohannes Doerfert uint32_t Lane = mapping::getThreadIdInWarp();
7467ab875fSJohannes Doerfert int64_t Ballot = mapping::activemask();
7567ab875fSJohannes Doerfert uint64_t Mask = ((uint64_t)1 << Lane) - (uint64_t)1;
7667ab875fSJohannes Doerfert return Mask & Ballot;
7767ab875fSJohannes Doerfert }
7867ab875fSJohannes Doerfert
lanemaskGT()7967ab875fSJohannes Doerfert LaneMaskTy lanemaskGT() {
8067ab875fSJohannes Doerfert uint32_t Lane = mapping::getThreadIdInWarp();
8167ab875fSJohannes Doerfert if (Lane == (mapping::getWarpSize() - 1))
8267ab875fSJohannes Doerfert return 0;
8367ab875fSJohannes Doerfert int64_t Ballot = mapping::activemask();
8467ab875fSJohannes Doerfert uint64_t Mask = (~((uint64_t)0)) << (Lane + 1);
8567ab875fSJohannes Doerfert return Mask & Ballot;
8667ab875fSJohannes Doerfert }
8767ab875fSJohannes Doerfert
getThreadIdInWarp()8867ab875fSJohannes Doerfert uint32_t getThreadIdInWarp() {
8967ab875fSJohannes Doerfert return __builtin_amdgcn_mbcnt_hi(~0u, __builtin_amdgcn_mbcnt_lo(~0u, 0u));
9067ab875fSJohannes Doerfert }
9167ab875fSJohannes Doerfert
getThreadIdInBlock()9267ab875fSJohannes Doerfert uint32_t getThreadIdInBlock() { return __builtin_amdgcn_workitem_id_x(); }
9367ab875fSJohannes Doerfert
getKernelSize()9467ab875fSJohannes Doerfert uint32_t getKernelSize() { return __builtin_amdgcn_grid_size_x(); }
9567ab875fSJohannes Doerfert
getBlockId()9667ab875fSJohannes Doerfert uint32_t getBlockId() { return __builtin_amdgcn_workgroup_id_x(); }
9767ab875fSJohannes Doerfert
getNumberOfBlocks()9867ab875fSJohannes Doerfert uint32_t getNumberOfBlocks() {
9967ab875fSJohannes Doerfert return getGridDim(__builtin_amdgcn_grid_size_x(),
10067ab875fSJohannes Doerfert __builtin_amdgcn_workgroup_size_x());
10167ab875fSJohannes Doerfert }
10267ab875fSJohannes Doerfert
getWarpId()10367ab875fSJohannes Doerfert uint32_t getWarpId() {
10493bebdc7SJohannes Doerfert return impl::getThreadIdInBlock() / mapping::getWarpSize();
10567ab875fSJohannes Doerfert }
10667ab875fSJohannes Doerfert
getNumberOfWarpsInBlock()10767ab875fSJohannes Doerfert uint32_t getNumberOfWarpsInBlock() {
10867ab875fSJohannes Doerfert return mapping::getBlockSize() / mapping::getWarpSize();
10967ab875fSJohannes Doerfert }
11067ab875fSJohannes Doerfert
11167ab875fSJohannes Doerfert #pragma omp end declare variant
11267ab875fSJohannes Doerfert ///}
11367ab875fSJohannes Doerfert
11467ab875fSJohannes Doerfert /// NVPTX Implementation
11567ab875fSJohannes Doerfert ///
11667ab875fSJohannes Doerfert ///{
11767ab875fSJohannes Doerfert #pragma omp begin declare variant match( \
11867ab875fSJohannes Doerfert device = {arch(nvptx, nvptx64)}, implementation = {extension(match_any)})
11967ab875fSJohannes Doerfert
getNumHardwareThreadsInBlock()12093bebdc7SJohannes Doerfert uint32_t getNumHardwareThreadsInBlock() {
12193bebdc7SJohannes Doerfert return __nvvm_read_ptx_sreg_ntid_x();
12293bebdc7SJohannes Doerfert }
12393bebdc7SJohannes Doerfert
getGridValue()124ce0caf41SJoseph Huber const llvm::omp::GV &getGridValue() { return llvm::omp::NVPTXGridValues; }
125842f875cSJon Chesterfield
activemask()12667ab875fSJohannes Doerfert LaneMaskTy activemask() {
12767ab875fSJohannes Doerfert unsigned int Mask;
12867ab875fSJohannes Doerfert asm("activemask.b32 %0;" : "=r"(Mask));
12967ab875fSJohannes Doerfert return Mask;
13067ab875fSJohannes Doerfert }
13167ab875fSJohannes Doerfert
lanemaskLT()13267ab875fSJohannes Doerfert LaneMaskTy lanemaskLT() {
13367ab875fSJohannes Doerfert __kmpc_impl_lanemask_t Res;
13467ab875fSJohannes Doerfert asm("mov.u32 %0, %%lanemask_lt;" : "=r"(Res));
13567ab875fSJohannes Doerfert return Res;
13667ab875fSJohannes Doerfert }
13767ab875fSJohannes Doerfert
lanemaskGT()13867ab875fSJohannes Doerfert LaneMaskTy lanemaskGT() {
13967ab875fSJohannes Doerfert __kmpc_impl_lanemask_t Res;
14067ab875fSJohannes Doerfert asm("mov.u32 %0, %%lanemask_gt;" : "=r"(Res));
14167ab875fSJohannes Doerfert return Res;
14267ab875fSJohannes Doerfert }
14367ab875fSJohannes Doerfert
getThreadIdInBlock()14467ab875fSJohannes Doerfert uint32_t getThreadIdInBlock() { return __nvvm_read_ptx_sreg_tid_x(); }
14567ab875fSJohannes Doerfert
getThreadIdInWarp()14693bebdc7SJohannes Doerfert uint32_t getThreadIdInWarp() {
14793bebdc7SJohannes Doerfert return impl::getThreadIdInBlock() & (mapping::getWarpSize() - 1);
14867ab875fSJohannes Doerfert }
14967ab875fSJohannes Doerfert
getKernelSize()15093bebdc7SJohannes Doerfert uint32_t getKernelSize() {
15193bebdc7SJohannes Doerfert return __nvvm_read_ptx_sreg_nctaid_x() *
15293bebdc7SJohannes Doerfert mapping::getNumberOfProcessorElements();
15393bebdc7SJohannes Doerfert }
15467ab875fSJohannes Doerfert
getBlockId()15567ab875fSJohannes Doerfert uint32_t getBlockId() { return __nvvm_read_ptx_sreg_ctaid_x(); }
15667ab875fSJohannes Doerfert
getNumberOfBlocks()15767ab875fSJohannes Doerfert uint32_t getNumberOfBlocks() { return __nvvm_read_ptx_sreg_nctaid_x(); }
15867ab875fSJohannes Doerfert
getWarpId()15967ab875fSJohannes Doerfert uint32_t getWarpId() {
16093bebdc7SJohannes Doerfert return impl::getThreadIdInBlock() / mapping::getWarpSize();
16167ab875fSJohannes Doerfert }
16267ab875fSJohannes Doerfert
getNumberOfWarpsInBlock()16367ab875fSJohannes Doerfert uint32_t getNumberOfWarpsInBlock() {
16467ab875fSJohannes Doerfert return (mapping::getBlockSize() + mapping::getWarpSize() - 1) /
16567ab875fSJohannes Doerfert mapping::getWarpSize();
16667ab875fSJohannes Doerfert }
16767ab875fSJohannes Doerfert
16867ab875fSJohannes Doerfert #pragma omp end declare variant
16967ab875fSJohannes Doerfert ///}
17067ab875fSJohannes Doerfert
getWarpSize()171842f875cSJon Chesterfield uint32_t getWarpSize() { return getGridValue().GV_Warp_Size; }
172842f875cSJon Chesterfield
17367ab875fSJohannes Doerfert } // namespace impl
17467ab875fSJohannes Doerfert } // namespace _OMP
17567ab875fSJohannes Doerfert
17693bebdc7SJohannes Doerfert /// We have to be deliberate about the distinction of `mapping::` and `impl::`
17793bebdc7SJohannes Doerfert /// below to avoid repeating assumptions or including irrelevant ones.
17893bebdc7SJohannes Doerfert ///{
17993bebdc7SJohannes Doerfert
isInLastWarp()180ccb5d272SJohannes Doerfert static bool isInLastWarp() {
18167ab875fSJohannes Doerfert uint32_t MainTId = (mapping::getNumberOfProcessorElements() - 1) &
18267ab875fSJohannes Doerfert ~(mapping::getWarpSize() - 1);
18367ab875fSJohannes Doerfert return mapping::getThreadIdInBlock() == MainTId;
18467ab875fSJohannes Doerfert }
18567ab875fSJohannes Doerfert
isMainThreadInGenericMode(bool IsSPMD)186ccb5d272SJohannes Doerfert bool mapping::isMainThreadInGenericMode(bool IsSPMD) {
187ccb5d272SJohannes Doerfert if (IsSPMD || icv::Level)
188ccb5d272SJohannes Doerfert return false;
189ccb5d272SJohannes Doerfert
190ccb5d272SJohannes Doerfert // Check if this is the last warp in the block.
191ccb5d272SJohannes Doerfert return isInLastWarp();
192ccb5d272SJohannes Doerfert }
193ccb5d272SJohannes Doerfert
isMainThreadInGenericMode()19485ad5663SJoseph Huber bool mapping::isMainThreadInGenericMode() {
19585ad5663SJoseph Huber return mapping::isMainThreadInGenericMode(mapping::isSPMDMode());
19685ad5663SJoseph Huber }
19785ad5663SJoseph Huber
isInitialThreadInLevel0(bool IsSPMD)198ccb5d272SJohannes Doerfert bool mapping::isInitialThreadInLevel0(bool IsSPMD) {
199ccb5d272SJohannes Doerfert if (IsSPMD)
200ccb5d272SJohannes Doerfert return mapping::getThreadIdInBlock() == 0;
201ccb5d272SJohannes Doerfert return isInLastWarp();
202ccb5d272SJohannes Doerfert }
203ccb5d272SJohannes Doerfert
isLeaderInWarp()20467ab875fSJohannes Doerfert bool mapping::isLeaderInWarp() {
20567ab875fSJohannes Doerfert __kmpc_impl_lanemask_t Active = mapping::activemask();
20667ab875fSJohannes Doerfert __kmpc_impl_lanemask_t LaneMaskLT = mapping::lanemaskLT();
20767ab875fSJohannes Doerfert return utils::popc(Active & LaneMaskLT) == 0;
20867ab875fSJohannes Doerfert }
20967ab875fSJohannes Doerfert
activemask()21067ab875fSJohannes Doerfert LaneMaskTy mapping::activemask() { return impl::activemask(); }
21167ab875fSJohannes Doerfert
lanemaskLT()21267ab875fSJohannes Doerfert LaneMaskTy mapping::lanemaskLT() { return impl::lanemaskLT(); }
21367ab875fSJohannes Doerfert
lanemaskGT()21467ab875fSJohannes Doerfert LaneMaskTy mapping::lanemaskGT() { return impl::lanemaskGT(); }
21567ab875fSJohannes Doerfert
getThreadIdInWarp()21693bebdc7SJohannes Doerfert uint32_t mapping::getThreadIdInWarp() {
21793bebdc7SJohannes Doerfert uint32_t ThreadIdInWarp = impl::getThreadIdInWarp();
21893bebdc7SJohannes Doerfert ASSERT(ThreadIdInWarp < impl::getWarpSize());
21993bebdc7SJohannes Doerfert return ThreadIdInWarp;
22067ab875fSJohannes Doerfert }
22167ab875fSJohannes Doerfert
getThreadIdInBlock()22293bebdc7SJohannes Doerfert uint32_t mapping::getThreadIdInBlock() {
22393bebdc7SJohannes Doerfert uint32_t ThreadIdInBlock = impl::getThreadIdInBlock();
22493bebdc7SJohannes Doerfert ASSERT(ThreadIdInBlock < impl::getNumHardwareThreadsInBlock());
22593bebdc7SJohannes Doerfert return ThreadIdInBlock;
22693bebdc7SJohannes Doerfert }
22767ab875fSJohannes Doerfert
getWarpSize()22867ab875fSJohannes Doerfert uint32_t mapping::getWarpSize() { return impl::getWarpSize(); }
22967ab875fSJohannes Doerfert
getBlockSize(bool IsSPMD)23057b4c526SJohannes Doerfert uint32_t mapping::getBlockSize(bool IsSPMD) {
23193bebdc7SJohannes Doerfert uint32_t BlockSize = mapping::getNumberOfProcessorElements() -
23257b4c526SJohannes Doerfert (!IsSPMD * impl::getWarpSize());
23393bebdc7SJohannes Doerfert return BlockSize;
23467ab875fSJohannes Doerfert }
getBlockSize()23557b4c526SJohannes Doerfert uint32_t mapping::getBlockSize() {
23657b4c526SJohannes Doerfert return mapping::getBlockSize(mapping::isSPMDMode());
23757b4c526SJohannes Doerfert }
23867ab875fSJohannes Doerfert
getKernelSize()23993bebdc7SJohannes Doerfert uint32_t mapping::getKernelSize() { return impl::getKernelSize(); }
24093bebdc7SJohannes Doerfert
getWarpId()24193bebdc7SJohannes Doerfert uint32_t mapping::getWarpId() {
24293bebdc7SJohannes Doerfert uint32_t WarpID = impl::getWarpId();
24393bebdc7SJohannes Doerfert ASSERT(WarpID < impl::getNumberOfWarpsInBlock());
24493bebdc7SJohannes Doerfert return WarpID;
24593bebdc7SJohannes Doerfert }
24693bebdc7SJohannes Doerfert
getBlockId()24793bebdc7SJohannes Doerfert uint32_t mapping::getBlockId() {
24893bebdc7SJohannes Doerfert uint32_t BlockId = impl::getBlockId();
24993bebdc7SJohannes Doerfert ASSERT(BlockId < impl::getNumberOfBlocks());
25093bebdc7SJohannes Doerfert return BlockId;
25193bebdc7SJohannes Doerfert }
25293bebdc7SJohannes Doerfert
getNumberOfWarpsInBlock()25393bebdc7SJohannes Doerfert uint32_t mapping::getNumberOfWarpsInBlock() {
25493bebdc7SJohannes Doerfert uint32_t NumberOfWarpsInBlocks = impl::getNumberOfWarpsInBlock();
25593bebdc7SJohannes Doerfert ASSERT(impl::getWarpId() < NumberOfWarpsInBlocks);
25693bebdc7SJohannes Doerfert return NumberOfWarpsInBlocks;
25793bebdc7SJohannes Doerfert }
25893bebdc7SJohannes Doerfert
getNumberOfBlocks()25993bebdc7SJohannes Doerfert uint32_t mapping::getNumberOfBlocks() {
26093bebdc7SJohannes Doerfert uint32_t NumberOfBlocks = impl::getNumberOfBlocks();
26193bebdc7SJohannes Doerfert ASSERT(impl::getBlockId() < NumberOfBlocks);
26293bebdc7SJohannes Doerfert return NumberOfBlocks;
26393bebdc7SJohannes Doerfert }
26493bebdc7SJohannes Doerfert
getNumberOfProcessorElements()26593bebdc7SJohannes Doerfert uint32_t mapping::getNumberOfProcessorElements() {
26693bebdc7SJohannes Doerfert uint32_t NumberOfProcessorElements = impl::getNumHardwareThreadsInBlock();
26793bebdc7SJohannes Doerfert ASSERT(impl::getThreadIdInBlock() < NumberOfProcessorElements);
26893bebdc7SJohannes Doerfert return NumberOfProcessorElements;
26993bebdc7SJohannes Doerfert }
27093bebdc7SJohannes Doerfert
27193bebdc7SJohannes Doerfert ///}
27293bebdc7SJohannes Doerfert
27367ab875fSJohannes Doerfert /// Execution mode
27467ab875fSJohannes Doerfert ///
27567ab875fSJohannes Doerfert ///{
276e2dcc221SJoseph Huber
277e2dcc221SJoseph Huber // TODO: This is a workaround for initialization coming from kernels outside of
278e2dcc221SJoseph Huber // the TU. We will need to solve this more correctly in the future.
279421b1f55SJoseph Huber int __attribute__((weak)) KEEP_ALIVE SHARED(IsSPMDMode);
28067ab875fSJohannes Doerfert
init(bool IsSPMD)28167ab875fSJohannes Doerfert void mapping::init(bool IsSPMD) {
282ccb5d272SJohannes Doerfert if (mapping::isInitialThreadInLevel0(IsSPMD))
28367ab875fSJohannes Doerfert IsSPMDMode = IsSPMD;
28467ab875fSJohannes Doerfert }
28567ab875fSJohannes Doerfert
isSPMDMode()28667ab875fSJohannes Doerfert bool mapping::isSPMDMode() { return IsSPMDMode; }
28767ab875fSJohannes Doerfert
isGenericMode()28867ab875fSJohannes Doerfert bool mapping::isGenericMode() { return !isSPMDMode(); }
28967ab875fSJohannes Doerfert ///}
29067ab875fSJohannes Doerfert
291e95731ccSJoseph Huber extern "C" {
__kmpc_get_hardware_thread_id_in_block()292*fd8fd9e5SJoseph Huber __attribute__((noinline)) uint32_t __kmpc_get_hardware_thread_id_in_block() {
29374f91741SJoseph Huber FunctionTracingRAII();
294e95731ccSJoseph Huber return mapping::getThreadIdInBlock();
295e95731ccSJoseph Huber }
296bad44d5fSJoseph Huber
__kmpc_get_hardware_num_threads_in_block()297*fd8fd9e5SJoseph Huber __attribute__((noinline)) uint32_t __kmpc_get_hardware_num_threads_in_block() {
29874f91741SJoseph Huber FunctionTracingRAII();
29993bebdc7SJohannes Doerfert return impl::getNumHardwareThreadsInBlock();
300bad44d5fSJoseph Huber }
301737c4a26SAtmn Patel
__kmpc_get_warp_size()302*fd8fd9e5SJoseph Huber __attribute__((noinline)) uint32_t __kmpc_get_warp_size() {
303737c4a26SAtmn Patel FunctionTracingRAII();
304737c4a26SAtmn Patel return impl::getWarpSize();
305737c4a26SAtmn Patel }
306e95731ccSJoseph Huber }
30767ab875fSJohannes Doerfert #pragma omp end declare target
308