1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
//===--------- Misc.cpp - OpenMP device misc interfaces ----------- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
#include "Allocator.h"
#include "Configuration.h"
#include "DeviceTypes.h"
#include "Shared/RPCOpcodes.h"
#include "shared/rpc.h"
#include "Debug.h"
namespace ompx {
namespace impl {
/// Lookup a device-side function using a host pointer /p HstPtr using the table
/// provided by the device plugin. The table is an ordered pair of host and
/// device pointers sorted on the value of the host pointer.
static void *indirectCallLookup(void *HstPtr) {
if (!HstPtr)
return nullptr;
struct IndirectCallTable {
void *HstPtr;
void *DevPtr;
};
IndirectCallTable *Table =
reinterpret_cast<IndirectCallTable *>(config::getIndirectCallTablePtr());
uint64_t TableSize = config::getIndirectCallTableSize();
// If the table is empty we assume this is device pointer.
if (!Table || !TableSize)
return HstPtr;
uint32_t Left = 0;
uint32_t Right = TableSize;
// If the pointer is definitely not contained in the table we exit early.
if (HstPtr < Table[Left].HstPtr || HstPtr > Table[Right - 1].HstPtr)
return HstPtr;
while (Left != Right) {
uint32_t Current = Left + (Right - Left) / 2;
if (Table[Current].HstPtr == HstPtr)
return Table[Current].DevPtr;
if (HstPtr < Table[Current].HstPtr)
Right = Current;
else
Left = Current;
}
// If we searched the whole table and found nothing this is a device pointer.
return HstPtr;
}
/// The openmp client instance used to communicate with the server.
[[gnu::visibility("protected"),
gnu::weak]] rpc::Client Client asm("__llvm_rpc_client");
} // namespace impl
} // namespace ompx
/// Interfaces
///
///{
extern "C" {
int32_t __kmpc_cancellationpoint(IdentTy *, int32_t, int32_t) { return 0; }
int32_t __kmpc_cancel(IdentTy *, int32_t, int32_t) { return 0; }
double omp_get_wtick(void) {
// The number of ticks per second for the AMDGPU clock varies by card and can
// only be retrieved by querying the driver. We rely on the device environment
// to inform us what the proper frequency is. NVPTX uses a nanosecond
// resolution, we could omit the global read but this makes it consistent.
return 1.0 / ompx::config::getClockFrequency();
}
double omp_get_wtime(void) {
return static_cast<double>(__builtin_readsteadycounter()) * omp_get_wtick();
}
void *__llvm_omp_indirect_call_lookup(void *HstPtr) {
return ompx::impl::indirectCallLookup(HstPtr);
}
void *omp_alloc(size_t size, omp_allocator_handle_t allocator) {
switch (allocator) {
case omp_default_mem_alloc:
case omp_large_cap_mem_alloc:
case omp_const_mem_alloc:
case omp_high_bw_mem_alloc:
case omp_low_lat_mem_alloc:
return malloc(size);
default:
return nullptr;
}
}
void omp_free(void *ptr, omp_allocator_handle_t allocator) {
switch (allocator) {
case omp_default_mem_alloc:
case omp_large_cap_mem_alloc:
case omp_const_mem_alloc:
case omp_high_bw_mem_alloc:
case omp_low_lat_mem_alloc:
free(ptr);
return;
case omp_null_allocator:
default:
return;
}
}
unsigned long long __llvm_omp_host_call(void *fn, void *data, size_t size) {
rpc::Client::Port Port = ompx::impl::Client.open<OFFLOAD_HOST_CALL>();
Port.send_n(data, size);
Port.send([=](rpc::Buffer *buffer, uint32_t) {
buffer->data[0] = reinterpret_cast<uintptr_t>(fn);
});
unsigned long long Ret;
Port.recv([&](rpc::Buffer *Buffer, uint32_t) {
Ret = static_cast<unsigned long long>(Buffer->data[0]);
});
Port.close();
return Ret;
}
}
///}
|