File: assert.cl

package info (click to toggle)
intel-graphics-compiler 1.0.17791.18-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 102,312 kB
  • sloc: cpp: 935,343; lisp: 286,143; ansic: 16,196; python: 3,279; yacc: 2,487; lex: 1,642; pascal: 300; sh: 174; makefile: 27
file content (134 lines) | stat: -rw-r--r-- 6,271 bytes parent folder | download | duplicates (2)
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();
}