-
Notifications
You must be signed in to change notification settings - Fork 736
/
device_binary_image.hpp
281 lines (239 loc) · 9.63 KB
/
device_binary_image.hpp
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
//==----- device_binary_image.hpp --- SYCL device binary image abstraction -==//
//
// 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
//
//===----------------------------------------------------------------------===//
#pragma once
#include <detail/compiler.hpp>
#include <sycl/detail/common.hpp>
#include <sycl/detail/os_util.hpp>
#include <sycl/detail/ur.hpp>
#include <ur_api.h>
#include "ur_utils.hpp"
#include <sycl/detail/iostream_proxy.hpp>
#include <atomic>
#include <cstring>
#include <memory>
namespace sycl {
inline namespace _V1 {
namespace detail {
// A wrapper for passing around byte array properties
class ByteArray {
public:
using ConstIterator = const std::uint8_t *;
ByteArray(const std::uint8_t *Ptr, std::size_t Size) : Ptr{Ptr}, Size{Size} {}
const std::uint8_t &operator[](std::size_t Idx) const { return Ptr[Idx]; }
std::size_t size() const { return Size; }
ConstIterator begin() const { return Ptr; }
ConstIterator end() const { return Ptr + Size; }
template <typename... Ts> auto consume() {
if constexpr (sizeof...(Ts) == 1)
return consumeOneElem<Ts...>();
else
return std::tuple{consumeOneElem<Ts>()...};
}
void dropBytes(std::size_t Bytes) {
assert(Bytes <= Size && "Not enough bytes left!");
Ptr += Bytes;
Size -= Bytes;
}
template <typename T> void drop() { return dropBytes(sizeof(T)); }
bool empty() const { return Size == 0; }
private:
template <typename T> T consumeOneElem() {
assert(sizeof(T) <= Size && "Out of bounds!");
T Val;
std::memcpy(&Val, Ptr, sizeof(T));
drop<T>();
return Val;
}
const std::uint8_t *Ptr;
std::size_t Size;
};
// C++ wrapper over the _sycl_device_binary_property_struct structure.
class DeviceBinaryProperty {
public:
DeviceBinaryProperty(const _sycl_device_binary_property_struct *Prop)
: Prop(Prop) {}
uint32_t asUint32() const;
ByteArray asByteArray() const;
const char *asCString() const;
protected:
friend std::ostream &operator<<(std::ostream &Out,
const DeviceBinaryProperty &P);
const _sycl_device_binary_property_struct *Prop;
};
std::ostream &operator<<(std::ostream &Out, const DeviceBinaryProperty &P);
// SYCL RT wrapper over UR binary image.
class RTDeviceBinaryImage {
public:
// Represents a range of properties to enable iteration over them.
// Implements the standard C++ STL input iterator interface.
class PropertyRange {
public:
using ValTy = std::remove_pointer<sycl_device_binary_property>::type;
class ConstIterator {
sycl_device_binary_property Cur;
public:
using iterator_category = std::input_iterator_tag;
using value_type = ValTy;
using difference_type = ptrdiff_t;
using pointer = const sycl_device_binary_property;
using reference = sycl_device_binary_property;
ConstIterator(sycl_device_binary_property Cur = nullptr) : Cur(Cur) {}
ConstIterator &operator++() {
Cur++;
return *this;
}
ConstIterator operator++(int) {
ConstIterator Ret = *this;
++(*this);
return Ret;
}
bool operator==(ConstIterator Other) const { return Cur == Other.Cur; }
bool operator!=(ConstIterator Other) const { return !(*this == Other); }
reference operator*() const { return Cur; }
};
ConstIterator begin() const { return ConstIterator(Begin); }
ConstIterator end() const { return ConstIterator(End); }
size_t size() const { return std::distance(begin(), end()); }
friend class RTDeviceBinaryImage;
bool isAvailable() const { return !(Begin == nullptr); }
private:
PropertyRange() : Begin(nullptr), End(nullptr) {}
// Searches for a property set with given name and constructs a
// PropertyRange spanning all its elements. If property set is not found,
// the range will span zero elements.
PropertyRange(sycl_device_binary Bin, const char *PropSetName)
: PropertyRange() {
init(Bin, PropSetName);
};
void init(sycl_device_binary Bin, const char *PropSetName);
sycl_device_binary_property Begin;
sycl_device_binary_property End;
};
public:
RTDeviceBinaryImage() : Bin(nullptr) {}
RTDeviceBinaryImage(sycl_device_binary Bin) { init(Bin); }
// Explicitly delete copy constructor/operator= to avoid unintentional copies
RTDeviceBinaryImage(const RTDeviceBinaryImage &) = delete;
RTDeviceBinaryImage &operator=(const RTDeviceBinaryImage &) = delete;
// Explicitly retain move constructors to facilitate potential moves across
// collections
RTDeviceBinaryImage(RTDeviceBinaryImage &&) = default;
RTDeviceBinaryImage &operator=(RTDeviceBinaryImage &&) = default;
virtual ~RTDeviceBinaryImage() {}
bool supportsSpecConstants() const {
return getFormat() == SYCL_DEVICE_BINARY_TYPE_SPIRV;
}
const sycl_device_binary_struct &getRawData() const { return *get(); }
virtual void print() const;
virtual void dump(std::ostream &Out) const;
size_t getSize() const {
assert(Bin && "binary image data not set");
return static_cast<size_t>(Bin->BinaryEnd - Bin->BinaryStart);
}
const char *getCompileOptions() const {
assert(Bin && "binary image data not set");
return Bin->CompileOptions;
}
const char *getLinkOptions() const {
assert(Bin && "binary image data not set");
return Bin->LinkOptions;
}
/// Returns the format of the binary image
ur::DeviceBinaryType getFormat() const {
assert(Bin && "binary image data not set");
return Format;
}
/// Returns a single property from SYCL_MISC_PROP category.
sycl_device_binary_property getProperty(const char *PropName) const;
/// Gets the iterator range over specialization constants in this binary
/// image. For each property pointed to by an iterator within the
/// range, the name of the property is the specialization constant symbolic ID
/// and the value is a list of 3-element tuples of 32-bit unsigned integers,
/// describing the specialization constant.
/// This is done in order to unify representation of both scalar and composite
/// specialization constants: composite specialization constant is represented
/// by its leaf elements, so for scalars the list contains only a single
/// tuple, while for composite there might be more of them.
/// Each tuple consists of ID of scalar specialization constant, its location
/// within a composite (offset in bytes from the beginning or 0 if it is not
/// an element of a composite specialization constant) and its size.
/// For example, for the following structure:
/// struct A { int a; float b; };
/// struct POD { A a[2]; int b; };
/// List of tuples will look like:
/// { ID0, 0, 4 }, // .a[0].a
/// { ID1, 4, 4 }, // .a[0].b
/// { ID2, 8, 4 }, // .a[1].a
/// { ID3, 12, 4 }, // .a[1].b
/// { ID4, 16, 4 }, // .b
/// And for an interger specialization constant, the list of tuples will look
/// like:
/// { ID5, 0, 4 }
const PropertyRange &getSpecConstants() const { return SpecConstIDMap; }
const PropertyRange &getSpecConstantsDefaultValues() const {
return SpecConstDefaultValuesMap;
}
const PropertyRange &getDeviceLibReqMask() const { return DeviceLibReqMask; }
const PropertyRange &getKernelParamOptInfo() const {
return KernelParamOptInfo;
}
const PropertyRange &getAssertUsed() const { return AssertUsed; }
const PropertyRange &getProgramMetadata() const { return ProgramMetadata; }
const std::vector<ur_program_metadata_t> &getProgramMetadataUR() const {
return ProgramMetadataUR;
}
const PropertyRange &getExportedSymbols() const { return ExportedSymbols; }
const PropertyRange &getImportedSymbols() const { return ImportedSymbols; }
const PropertyRange &getDeviceGlobals() const { return DeviceGlobals; }
const PropertyRange &getDeviceRequirements() const {
return DeviceRequirements;
}
const PropertyRange &getHostPipes() const { return HostPipes; }
const PropertyRange &getVirtualFunctions() const { return VirtualFunctions; }
std::uintptr_t getImageID() const {
assert(Bin && "Image ID is not available without a binary image.");
return ImageId;
}
protected:
void init(sycl_device_binary Bin);
sycl_device_binary get() const { return Bin; }
sycl_device_binary Bin;
ur::DeviceBinaryType Format = SYCL_DEVICE_BINARY_TYPE_NONE;
RTDeviceBinaryImage::PropertyRange SpecConstIDMap;
RTDeviceBinaryImage::PropertyRange SpecConstDefaultValuesMap;
RTDeviceBinaryImage::PropertyRange DeviceLibReqMask;
RTDeviceBinaryImage::PropertyRange KernelParamOptInfo;
RTDeviceBinaryImage::PropertyRange AssertUsed;
RTDeviceBinaryImage::PropertyRange ProgramMetadata;
RTDeviceBinaryImage::PropertyRange ExportedSymbols;
RTDeviceBinaryImage::PropertyRange ImportedSymbols;
RTDeviceBinaryImage::PropertyRange DeviceGlobals;
RTDeviceBinaryImage::PropertyRange DeviceRequirements;
RTDeviceBinaryImage::PropertyRange HostPipes;
RTDeviceBinaryImage::PropertyRange VirtualFunctions;
std::vector<ur_program_metadata_t> ProgramMetadataUR;
private:
static std::atomic<uintptr_t> ImageCounter;
uintptr_t ImageId = 0;
};
// Dynamically allocated device binary image, which de-allocates its binary
// data in destructor.
class DynRTDeviceBinaryImage : public RTDeviceBinaryImage {
public:
DynRTDeviceBinaryImage(std::unique_ptr<char[]> &&DataPtr, size_t DataSize);
~DynRTDeviceBinaryImage() override;
void print() const override {
RTDeviceBinaryImage::print();
std::cerr << " DYNAMICALLY CREATED\n";
}
protected:
std::unique_ptr<char[]> Data;
};
} // namespace detail
} // namespace _V1
} // namespace sycl