Skip to content

Commit c5641a7

Browse files
authored
Add basic xmethod impl for accessor.operator[] (#821)
* Add basic xmethod impl for accessor.operator[] Intended to address templated function/operator debugging problem in GDB. The added script is the currently used implementation in our gdb - it only covers single-index `accessor.operator[]` with multiple dimensions, that may be extended in the future depending on user experience requirements. It is much desirable to distribute this as part of compiler package because it depends on private implementation details of SYCL headers and must always be strictly in sync. Signed-off-by: Mihails Strasuns <[email protected]> * Install xmethods as part of sycl-headers Signed-off-by: Mihails Strasuns <[email protected]>
2 parents 926e38e + a01f049 commit c5641a7

File tree

5 files changed

+188
-0
lines changed

5 files changed

+188
-0
lines changed

sycl/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ endif()
5151
set(CLANG_VERSION "${CLANG_VERSION_MAJOR}.${CLANG_VERSION_MINOR}.${CLANG_VERSION_PATCHLEVEL}")
5252

5353
set(LLVM_INST_INC_DIRECTORY "lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION}/include")
54+
set(LLVM_PYTHON_DIRECTORY "lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION}/python")
5455
set(dst_dir ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION}/include)
5556

5657
# Find OpenCL headers and libraries installed in the system and use them to
@@ -150,6 +151,12 @@ COMMENT "Copying SYCL headers ...")
150151
# Configure SYCL headers
151152
install(DIRECTORY "${sycl_inc_dir}/." DESTINATION "${LLVM_INST_INC_DIRECTORY}" COMPONENT sycl-headers)
152153

154+
# Auxilliary extras for SYCL headers
155+
add_custom_target(sycl-headers-extras ALL
156+
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/xmethods ${dst_dir}
157+
COMMENT "Copying SYCL header xmethod scripts ...")
158+
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/xmethods" DESTINATION ${LLVM_PYTHON_DIRECTORY} COMPONENT sycl-headers-extras)
159+
153160
set(SYCL_RT_LIBS sycl)
154161
if (MSVC)
155162
list(APPEND SYCL_RT_LIBS sycld)
@@ -244,6 +251,7 @@ set( SYCL_TOOLCHAIN_DEPLOY_COMPONENTS
244251
clang-resource-headers
245252
opencl-headers
246253
sycl-headers
254+
sycl-headers-extras
247255
sycl
248256
pi_opencl
249257
)

sycl/test/accessors.o

147 Bytes
Binary file not shown.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clangxx -fsycl-device-only -c -fno-color-diagnostics -Xclang -ast-dump %s | FileCheck %s
2+
// UNSUPPORTED: windows
3+
#include <CL/sycl/accessor.hpp>
4+
5+
typedef cl::sycl::accessor<int, 1, cl::sycl::access::mode::read> dummy;
6+
7+
// AccessorImplDevice must have MemRange and Offset fields
8+
9+
// CHECK: CXXRecordDecl {{.*}} class AccessorImplDevice definition
10+
// CHECK-NOT: CXXRecordDecl {{.*}} definition
11+
// CHECK: FieldDecl {{.*}} referenced Offset
12+
// CHECK-NOT: CXXRecordDecl {{.*}} definition
13+
// CHECK: FieldDecl {{.*}} referenced MemRange
14+
15+
// accessor.impl must be present and of AccessorImplDevice type
16+
17+
// CHECK: CXXRecordDecl {{.*}} class accessor definition
18+
// CHECK-NOT: CXXRecordDecl {{.*}} definition
19+
// CHECK: FieldDecl {{.*}} referenced impl 'detail::AccessorImplDevice<AdjustedDim>'

sycl/test/xmethods/accessors.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clangxx -c -fno-color-diagnostics -Xclang -ast-dump %s | FileCheck %s
2+
// UNSUPPORTED: windows
3+
#include <CL/sycl/accessor.hpp>
4+
5+
typedef cl::sycl::accessor<int, 1, cl::sycl::access::mode::read> dummy;
6+
7+
// AccessorImplHost must have MMemoryRange, MOffset and MData fields
8+
9+
// CHECK: CXXRecordDecl {{.*}} class AccessorImplHost definition
10+
// CHECK-NOT: CXXRecordDecl {{.*}} definition
11+
// CHECK: FieldDecl {{.*}} referenced MOffset
12+
// CHECK-NOT: CXXRecordDecl {{.*}} definition
13+
// CHECK: FieldDecl {{.*}} referenced MMemoryRange
14+
// CHECK-NOT: CXXRecordDecl {{.*}} definition
15+
// CHECK: FieldDecl {{.*}} referenced MData
16+
17+
// accessor.impl must be present and of shared_ptr<AccessorImplHost> type
18+
19+
// CHECK: CXXRecordDecl {{.*}} class AccessorBaseHost definition
20+
// CHECK-NOT: CXXRecordDecl {{.*}} definition
21+
// CHECK: FieldDecl {{.*}} referenced impl {{.*}}:'std::shared_ptr<cl::sycl::detail::AccessorImplHost>'
22+
// CHECK: CXXRecordDecl {{.*}} class accessor definition
23+
// CHECK-NOT: CXXRecordDecl {{.*}} definition
24+
// CHECK: public {{.*}}:'cl::sycl::detail::AccessorBaseHost'
25+

sycl/xmethods/accessors.py

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2+
# See https://llvm.org/LICENSE.txt for license information.
3+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
import gdb.xmethod
6+
import re
7+
8+
"""
9+
Generalized base class for buffer index calculation
10+
"""
11+
class Accessor:
12+
def memory_range(self, dim):
13+
pass
14+
15+
def offset(self, dim):
16+
pass
17+
18+
def data(self):
19+
pass
20+
21+
def __init__(self, obj, result_type, depth):
22+
self.obj = obj
23+
self.result_type = result_type
24+
self.depth = depth
25+
26+
def index(self, arg):
27+
if arg.type.code == gdb.TYPE_CODE_INT:
28+
return int(arg)
29+
# https://github.com/intel/llvm/blob/97272b7ebd569bfa13811913a31e30f926559217/sycl/include/CL/sycl/accessor.hpp#L678-L690
30+
result = 0
31+
for dim in range(self.depth):
32+
result = result * self.memory_range(dim) + \
33+
self.offset(dim) + \
34+
arg['common_array'][dim]
35+
return result
36+
37+
def value(self, arg):
38+
return self.data().cast(self.result_type.pointer())[self.index(arg)]
39+
40+
41+
"""
42+
For Host device memory layout
43+
"""
44+
class HostAccessor(Accessor):
45+
def payload(self):
46+
return self.obj['impl']['_M_ptr'].dereference()
47+
48+
def memory_range(self, dim):
49+
return self.payload()['MMemoryRange']['common_array'][dim]
50+
51+
def offset(self, dim):
52+
return self.payload()['MOffset']['common_array'][dim]
53+
54+
def data(self):
55+
return self.payload()['MData']
56+
57+
"""
58+
For CPU/GPU memory layout
59+
"""
60+
class DeviceAccessor(Accessor):
61+
def memory_range(self, dim):
62+
return self.obj['impl']['MemRange']['common_array'][dim]
63+
64+
def offset(self, dim):
65+
return self.obj['impl']['Offset']['common_array'][dim]
66+
67+
def data(self):
68+
return self.obj['MData']
69+
70+
71+
"""
72+
Generic implementation for N-dimensional ID
73+
"""
74+
class AccessorOpIndex(gdb.xmethod.XMethodWorker):
75+
def __init__(self, class_type, result_type, depth):
76+
self.class_type = class_type
77+
self.result_type = result_type
78+
self.depth = depth
79+
80+
def get_arg_types(self):
81+
return gdb.lookup_type("cl::sycl::id<%s>" % self.depth)
82+
83+
def get_result_type(self):
84+
return self.result_type
85+
86+
def __call__(self, obj, arg):
87+
# No way to wasily figure out which devices is currently being used,
88+
# try all accessor implementations until one of them works:
89+
accessors = [
90+
DeviceAccessor(obj, self.result_type, self.depth),
91+
HostAccessor(obj, self.result_type, self.depth)
92+
]
93+
for accessor in accessors:
94+
try:
95+
return accessor.value(arg)
96+
except:
97+
pass
98+
99+
print("Failed to call '%s.operator[](%s)" % (obj.type, arg.type))
100+
101+
return None
102+
103+
104+
"""
105+
Introduces an extra overload for 1D case that takes plain size_t
106+
"""
107+
class AccessorOpIndex1D(AccessorOpIndex):
108+
def get_arg_types(self):
109+
assert(self.depth == 1)
110+
return gdb.lookup_type('size_t')
111+
112+
113+
class AccessorOpIndexMatcher(gdb.xmethod.XMethodMatcher):
114+
def __init__(self):
115+
gdb.xmethod.XMethodMatcher.__init__(self, 'AccessorOpIndexMatcher')
116+
117+
def match(self, class_type, method_name):
118+
if method_name != 'operator[]':
119+
return None
120+
121+
result = re.match('^cl::sycl::accessor<.+>$', class_type.tag)
122+
if (result == None):
123+
return None
124+
125+
depth = int(class_type.template_argument(1))
126+
result_type = class_type.template_argument(0)
127+
128+
methods = [
129+
AccessorOpIndex(class_type, result_type, depth)
130+
]
131+
if depth == 1:
132+
methods.append(AccessorOpIndex1D(class_type, result_type, depth))
133+
return methods
134+
135+
136+
gdb.xmethod.register_xmethod_matcher(None, AccessorOpIndexMatcher())

0 commit comments

Comments
 (0)