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
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2023 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
// __devicelib_assert_fail implementation.
// This is a DPCPP device library extension described in
// https://github.com/triSYCL/sycl/blob/sycl/unified/master/sycl/doc/design/Assert.md
// DPCPP assert(expr) macro ends up in call to __devicelib_assert_fail.
// Per design, the implementation needs to:
// 1. Write "1" to flag field in the assert buffer header. The buffer header is defined below.
// 2. Print the assert message to assert buffer. This is done in a similar fashion as "printf".
// __builtin_IB_printf_to_buffer builtin function is used for this purpose - it basically wraps
// the printf functionality to a buffer provided as an argument.
// 3. Trigger a software exception by setting appropriate Control Register bits.
// This is done by __builtin_IB_software_exception builtin.
// 4. We need to ensure that all stores in this function are uncached.
// This is handled by NontemporalLoadsAndStoresInAssert pass.
#include "IBiF_Header.cl"
enum ERROR_TYPE {
ERROR_TYPE_NONE = 0,
ERROR_TYPE_ASSERT = 1,
ERROR_TYPE_STACK_OVERFLOW = 2,
ERROR_TYPE_BUFFER_OUTOFBOUNDS = 3,
};
__global volatile uchar* __builtin_IB_get_assert_buffer();
void __builtin_IB_software_exception();
int __builtin_IB_printf_to_buffer(global char* buf, global char* currentOffset, int bufSize, ...);
typedef struct {
int size;
int flag;
int begin;
} AssertBufferHeader;
void __devicelib_assert_fail(char *expr, char *file, int line, char *func, long gid0, long gid1, long gid2, long lid0, long lid1, long lid2) {
AssertBufferHeader* header = (AssertBufferHeader*) __builtin_IB_get_assert_buffer();
header->flag = ERROR_TYPE_ASSERT;
global char* buf = (global char*) header;
__builtin_IB_printf_to_buffer(buf, buf + 8, header->size, "%s:%d: %s: global id: [%lu,%lu,%lu], local id: [%lu,%lu,%lu] Assertion `%s` failed.\n", file, line, func, gid0, gid1, gid2, lid0, lid1, lid2, expr);
__builtin_IB_software_exception();
}
ulong __builtin_IB_get_stack_pointer();
int __builtin_IB_get_stack_size_per_thread();
// This function needs to be inserted in entry points.
// Assert buffer mechanism is used for stack overflow detection, because we can reuse much code this way:
// - We need some kind of temp buffer to store the stack size per thread and stack base for each thread.
// Assert buffer is used, so that we don't need to allocate additional one.
// - Runtime checks for nonzero value in the "flag" of AssertBufferHeader and then aborts.
// This is what we want for stack overflow scenario as well.
void __stackoverflow_init() {
int HWTID = __builtin_IB_hw_thread_id();
global volatile int* buf = (global volatile int*)__builtin_IB_get_assert_buffer();
// Go to first int after the AssertBufferHeader
buf += 3;
*buf = __builtin_IB_get_stack_size_per_thread();
buf = buf + 1;
global ulong* stackBase = ((global ulong*)(buf));
stackBase[HWTID] = __builtin_IB_get_stack_pointer();
}
// This function needs to be inserted in places where stack pointer is incremented.
void __stackoverflow_detection() {
int HWTID = __builtin_IB_hw_thread_id();
// +12 will be stack size per thread.
global volatile int* buf = (global volatile int*)__builtin_IB_get_assert_buffer();
buf += 3;
int stackSizePerThread = *buf;
buf += 1;
ulong stackBase = ((global ulong*)(buf))[HWTID];
if (__builtin_IB_get_stack_pointer() - stackBase > stackSizePerThread) {
global volatile AssertBufferHeader* header = (global volatile AssertBufferHeader*) __builtin_IB_get_assert_buffer();
printf("Stack overflow detected!\n");
header->flag = ERROR_TYPE_STACK_OVERFLOW;
__builtin_IB_software_exception();
}
}
void __bufferoutofbounds_assert(const char* file, int line, int column, const char* bufferName, long bufferOffsetInBytes, long bufferSize, int localId0, int localId1, int localId2, int globalId0, int globalId1, int globalId2) {
printf("Buffer offset is out of bounds!\n"
" Location: %s:%d:%d\n"
" Address: %s + 0x%X\n"
" Buffer size: 0x%X\n"
" Local ID: [%d, %d, %d]\n"
" Global ID: [%d, %d, %d]\n",
file, line, column, bufferName, bufferOffsetInBytes, bufferSize, localId0, localId1, localId2, globalId0, globalId1, globalId2);
AssertBufferHeader* header = __builtin_IB_get_assert_buffer();
header->flag = ERROR_TYPE_BUFFER_OUTOFBOUNDS;
__builtin_IB_software_exception();
}
void __bufferoutofbounds_assert_nodebug(long bufferAddress, long bufferOffsetInBytes, long bufferSize, int localId0, int localId1, int localId2, int globalId0, int globalId1, int globalId2) {
printf("Buffer offset is out of bounds!\n"
" Address: 0x%X + 0x%X\n"
" Buffer size: 0x%X\n"
" Local ID: [%d, %d, %d]\n"
" Global ID: [%d, %d, %d]\n",
bufferAddress, bufferOffsetInBytes, bufferSize, localId0, localId1, localId2, globalId0, globalId1, globalId2);
AssertBufferHeader* header = __builtin_IB_get_assert_buffer();
header->flag = ERROR_TYPE_BUFFER_OUTOFBOUNDS;
__builtin_IB_software_exception();
}
void __minimumvalidaddresschecking_assert(const char* file, int line, int column, long address) {
printf("Load/store uses the address less than the minimum valid address!\n"
" Location: %s:%d:%d\n"
" Address: 0x%X\n",
file, line, column, address);
AssertBufferHeader* header = __builtin_IB_get_assert_buffer();
header->flag = ERROR_TYPE_ASSERT;
__builtin_IB_software_exception();
}
void __minimumvalidaddresschecking_assert_nodebug(long address) {
printf("Load/store uses the address less than the minimum valid address!\n"
" Address: 0x%X\n",
address);
AssertBufferHeader* header = __builtin_IB_get_assert_buffer();
header->flag = ERROR_TYPE_ASSERT;
__builtin_IB_software_exception();
}
|