Skip to content

Commit 1580c00

Browse files
committed
[SYCL] Add convenience C++ wrappers for PI binary image hierarchy objects.
Signed-off-by: Konstantin S Bobrovsky <[email protected]>
1 parent de4e843 commit 1580c00

File tree

3 files changed

+263
-5
lines changed

3 files changed

+263
-5
lines changed

sycl/include/CL/sycl/detail/pi.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -541,15 +541,15 @@ using _pi_offload_entry = _pi_offload_entry_struct *;
541541

542542
// A type of a binary image property.
543543
typedef enum {
544-
PI_PROP_TYPE_UNKNOWN,
545-
PI_PROP_TYPE_UINT32, // 32-bit integer
546-
PI_PROP_TYPE_STRING // null-terminated string
547-
} _pi_property_type;
544+
PI_PROPERTY_TYPE_UNKNOWN,
545+
PI_PROPERTY_TYPE_UINT32, // 32-bit integer
546+
PI_PROPERTY_TYPE_STRING // null-terminated string
547+
} pi_property_type;
548548

549549
// Device binary image property.
550550
// If the type size of the property value is fixed and is no greater than
551551
// 64 bits, then ValAddr is 0 and the value is stored in the ValSize field.
552-
// Example - PI_PROP_TYPE_UINT32, which is 32-bit
552+
// Example - PI_PROPERTY_TYPE_UINT32, which is 32-bit
553553
struct _pi_device_binary_property_struct {
554554
char *Name; // null-terminated property name
555555
void *ValAddr; // address of property value

sycl/include/CL/sycl/detail/pi.hpp

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,124 @@ void printArgs(Arg0 arg0, Args... args) {
165165
print(arg0);
166166
pi::printArgs(std::forward<Args>(args)...);
167167
}
168+
169+
// C++ wrapper over the _pi_device_binary_property_struct structure.
170+
class DeviceBinaryProperty {
171+
public:
172+
DeviceBinaryProperty(const _pi_device_binary_property_struct *Prop)
173+
: Prop(Prop) {}
174+
175+
pi_uint32 asUint32() const;
176+
const char *asCString() const;
177+
178+
protected:
179+
friend std::ostream &operator<<(std::ostream &Out,
180+
const DeviceBinaryProperty &P);
181+
const _pi_device_binary_property_struct *Prop;
182+
};
183+
184+
std::ostream &operator<<(std::ostream &Out, const DeviceBinaryProperty &P);
185+
186+
// C++ convenience wrapper over the pi_device_binary_struct structure.
187+
class DeviceBinaryImage {
188+
public:
189+
// Represents a range of properties to enable iteration over them.
190+
// Implements the standard C++ STL input iterator interface.
191+
class PropertyRange {
192+
public:
193+
using ValTy = std::remove_pointer<pi_device_binary_property>::type;
194+
195+
class ConstIterator
196+
: public std::iterator<std::input_iterator_tag, // iterator_category
197+
ValTy, // value_type
198+
ptrdiff_t, // difference_type
199+
const pi_device_binary_property, // pointer
200+
pi_device_binary_property> // reference
201+
{
202+
pi_device_binary_property Cur;
203+
204+
public:
205+
ConstIterator(pi_device_binary_property Cur = nullptr) : Cur(Cur) {}
206+
ConstIterator &operator++() {
207+
Cur++;
208+
return *this;
209+
}
210+
ConstIterator operator++(int) {
211+
ConstIterator Ret = *this;
212+
++(*this);
213+
return Ret;
214+
}
215+
bool operator==(ConstIterator Other) const { return Cur == Other.Cur; }
216+
bool operator!=(ConstIterator Other) const { return !(*this == Other); }
217+
reference operator*() const { return Cur; }
218+
};
219+
ConstIterator begin() const { return ConstIterator(Begin); }
220+
ConstIterator end() const { return ConstIterator(End); }
221+
friend class DeviceBinaryImage;
222+
223+
private:
224+
PropertyRange() : Begin(nullptr), End(nullptr) {}
225+
// Searches for a property set with given name and constructs a
226+
// PropertyRange spanning all its elements. If property set is not found,
227+
// the range will span zero elements.
228+
PropertyRange(pi_device_binary Bin, const char *PropSetName)
229+
: PropertyRange() {
230+
init(Bin, PropSetName);
231+
};
232+
void init(pi_device_binary Bin, const char *PropSetName);
233+
pi_device_binary_property Begin;
234+
pi_device_binary_property End;
235+
};
236+
237+
public:
238+
DeviceBinaryImage(pi_device_binary Bin) { init(Bin); }
239+
DeviceBinaryImage() : Bin(nullptr){};
240+
241+
virtual void print() const;
242+
virtual void dump(std::ostream &Out) const;
243+
244+
size_t getSize() const {
245+
assert(Bin && "binary image data not set");
246+
return static_cast<size_t>(Bin->BinaryEnd - Bin->BinaryStart);
247+
}
248+
249+
const char *getCompileOptions() const {
250+
assert(Bin && "binary image data not set");
251+
return Bin->CompileOptions;
252+
}
253+
254+
const char *getLinkOptions() const {
255+
assert(Bin && "binary image data not set");
256+
return Bin->LinkOptions;
257+
}
258+
259+
/// Returns the format of the binary image
260+
pi::PiDeviceBinaryType getFormat() const {
261+
assert(Bin && "binary image data not set");
262+
return Format;
263+
}
264+
265+
/// Gets the iterator range over specialization constants in this this binary
266+
/// image. For each property pointed to by an iterator within the range, the
267+
/// name of the property is the specializaion constant symbolic ID and the
268+
/// value is 32-bit unsigned integer ID.
269+
const PropertyRange &getSpecConstants() const { return SpecConstIDMap; }
270+
virtual ~DeviceBinaryImage() {}
271+
272+
protected:
273+
void init(pi_device_binary Bin);
274+
pi_device_binary get() const { return Bin; }
275+
276+
pi_device_binary Bin;
277+
pi::PiDeviceBinaryType Format = PI_DEVICE_BINARY_TYPE_NONE;
278+
DeviceBinaryImage::PropertyRange SpecConstIDMap;
279+
};
280+
281+
/// Tries to determine the device binary image foramat. Returns
282+
/// PI_DEVICE_BINARY_TYPE_NONE if unsuccessful.
283+
PiDeviceBinaryType getBinaryImageFormat(const unsigned char *ImgData,
284+
size_t ImgSize);
285+
168286
} // namespace pi
169287

170288
namespace RT = cl::sycl::detail::pi;

sycl/source/detail/pi.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,146 @@ void assertion(bool Condition, const char *Message) {
298298
die(Message);
299299
}
300300

301+
std::ostream &operator<<(std::ostream &Out, const DeviceBinaryProperty &P) {
302+
switch (P.Prop->Type) {
303+
case PI_PROPERTY_TYPE_UINT32:
304+
Out << "[UINT32] ";
305+
break;
306+
case PI_PROPERTY_TYPE_STRING:
307+
Out << "[String] ";
308+
break;
309+
default:
310+
assert("unsupported property");
311+
return Out;
312+
}
313+
Out << P.Prop->Name << "=";
314+
315+
switch (P.Prop->Type) {
316+
case PI_PROPERTY_TYPE_UINT32:
317+
Out << P.asUint32();
318+
break;
319+
case PI_PROPERTY_TYPE_STRING:
320+
Out << P.asCString();
321+
break;
322+
default:
323+
assert("unsupported property");
324+
return Out;
325+
}
326+
return Out;
327+
}
328+
329+
void DeviceBinaryImage::print() const {
330+
std::cerr << " --- Image " << Bin << "\n";
331+
if (!Bin)
332+
return;
333+
std::cerr << " Version : " << (int)Bin->Version << "\n";
334+
std::cerr << " Kind : " << (int)Bin->Kind << "\n";
335+
std::cerr << " Format : " << (int)Bin->Format << "\n";
336+
std::cerr << " Target : " << Bin->DeviceTargetSpec << "\n";
337+
std::cerr << " Bin size : "
338+
<< ((intptr_t)Bin->BinaryEnd - (intptr_t)Bin->BinaryStart) << "\n";
339+
std::cerr << " Compile options : "
340+
<< (Bin->CompileOptions ? Bin->CompileOptions : "NULL") << "\n";
341+
std::cerr << " Link options : "
342+
<< (Bin->LinkOptions ? Bin->LinkOptions : "NULL") << "\n";
343+
std::cerr << " Entries : ";
344+
for (_pi_offload_entry EntriesIt = Bin->EntriesBegin;
345+
EntriesIt != Bin->EntriesEnd; ++EntriesIt)
346+
std::cerr << EntriesIt->name << " ";
347+
std::cerr << "\n";
348+
std::cerr << " Properties [" << Bin->PropertySetsBegin << "-"
349+
<< Bin->PropertySetsEnd << "]:\n";
350+
351+
for (pi_device_binary_property_set PS = Bin->PropertySetsBegin;
352+
PS != Bin->PropertySetsEnd; ++PS) {
353+
std::cerr << " Category " << PS->Name << " [" << PS->PropertiesBegin
354+
<< "-" << PS->PropertiesEnd << "]:\n";
355+
356+
for (pi_device_binary_property P = PS->PropertiesBegin;
357+
P != PS->PropertiesEnd; ++P) {
358+
std::cerr << " " << DeviceBinaryProperty(P) << "\n";
359+
}
360+
}
361+
}
362+
363+
void DeviceBinaryImage::dump(std::ostream &Out) const {
364+
size_t ImgSize = getSize();
365+
Out.write(reinterpret_cast<const char *>(Bin->BinaryStart), ImgSize);
366+
}
367+
368+
static pi_uint32 asUint32(const void *Addr) {
369+
assert(Addr && "Addr is NULL");
370+
const auto *P = reinterpret_cast<const unsigned char *>(Addr);
371+
return (*P) | (*(P + 1) << 8) | (*(P + 2) << 16) | (*(P + 3) << 24);
372+
}
373+
374+
pi_uint32 DeviceBinaryProperty::asUint32() const {
375+
assert(Prop->Type == PI_PROPERTY_TYPE_UINT32 && "property type mismatch");
376+
// if type fits into the ValSize - it is used to store the property value
377+
assert(Prop->ValAddr == nullptr && "primitive types must be stored inline");
378+
return sycl::detail::pi::asUint32(&Prop->ValSize);
379+
}
380+
381+
const char *DeviceBinaryProperty::asCString() const {
382+
assert(Prop->Type == PI_PROPERTY_TYPE_STRING && "property type mismatch");
383+
assert(Prop->ValSize > 0 && "property size mismatch");
384+
return pi::cast<const char *>(Prop->ValAddr);
385+
}
386+
387+
void DeviceBinaryImage::PropertyRange::init(pi_device_binary Bin,
388+
const char *PropSetName) {
389+
assert(!this->Begin && !this->End && "already initialized");
390+
pi_device_binary_property_set PS = nullptr;
391+
392+
for (PS = Bin->PropertySetsBegin; PS != Bin->PropertySetsEnd; ++PS) {
393+
assert(PS->Name && "nameless property set - bug in the offload wrapper?");
394+
if (!strcmp(PropSetName, PS->Name))
395+
break;
396+
}
397+
if (PS == Bin->PropertySetsEnd) {
398+
Begin = End = nullptr;
399+
return;
400+
}
401+
Begin = PS->PropertiesBegin;
402+
End = Begin ? PS->PropertiesEnd : nullptr;
403+
}
404+
405+
RT::PiDeviceBinaryType getBinaryImageFormat(const unsigned char *ImgData,
406+
size_t ImgSize) {
407+
struct {
408+
RT::PiDeviceBinaryType Fmt;
409+
const uint32_t Magic;
410+
} Fmts[] = {{PI_DEVICE_BINARY_TYPE_SPIRV, 0x07230203},
411+
{PI_DEVICE_BINARY_TYPE_LLVMIR_BITCODE, 0xDEC04342}};
412+
413+
if (ImgSize >= sizeof(Fmts[0].Magic)) {
414+
std::remove_const<decltype(Fmts[0].Magic)>::type Hdr = 0;
415+
std::copy(ImgData, ImgData + sizeof(Hdr), reinterpret_cast<char *>(&Hdr));
416+
417+
for (const auto &Fmt : Fmts) {
418+
if (Hdr == Fmt.Magic)
419+
return Fmt.Fmt;
420+
}
421+
}
422+
return PI_DEVICE_BINARY_TYPE_NONE;
423+
}
424+
425+
void DeviceBinaryImage::init(pi_device_binary Bin) {
426+
this->Bin = Bin;
427+
// If device binary image format wasn't set by its producer, then can't change
428+
// now, because 'Bin' data is part of the executable image loaded into memory
429+
// which can't be modified (easily).
430+
// TODO clang driver + ClangOffloadWrapper can figure out the format and set
431+
// it when invoking the offload wrapper job
432+
Format = static_cast<pi::PiDeviceBinaryType>(Bin->Format);
433+
434+
if (Format == PI_DEVICE_BINARY_TYPE_NONE)
435+
// try to determine the format; may remain "NONE"
436+
Format = getBinaryImageFormat(Bin->BinaryStart, getSize());
437+
438+
SpecConstIDMap.init(Bin, PI_PROPERTY_SET_SPEC_CONST_MAP);
439+
}
440+
301441
} // namespace pi
302442
} // namespace detail
303443
} // namespace sycl

0 commit comments

Comments
 (0)