Skip to content

Commit f09832c

Browse files
authored
[sycl-post-link] Support indirectly called assert (#4027)
Per design doc (https://github.com/intel/llvm/blob/sycl/sycl/doc/Assert.md): If a callgraph for indirect callable function (marked with specific attribute) has a call to __devicelib_assert_fail, then all kernels in the module are conservatively marked as using asserts.
1 parent 1d7e6a6 commit f09832c

File tree

3 files changed

+339
-8
lines changed

3 files changed

+339
-8
lines changed
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
; This test checks that the post-link tool properly generates "assert used"
2+
; property. This case validates that indirectly called function without assert
3+
; does not cause all the module kernels to be marked as ones that can call
4+
; assert indirectly.
5+
6+
; Per design doc, if a callgraph for indirect callable function
7+
; (marked with "referenced-indirectly" attribute in IR) has a call to
8+
; __devicelib_assert_fail, then all kernels in the module are conservatively
9+
; marked as using asserts.
10+
11+
; RUN: sycl-post-link -split=auto -symbols -S %s -o %t.table
12+
; RUN: FileCheck %s -input-file=%t_0.prop
13+
14+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
15+
target triple = "spir64-unknown-linux-sycldevice"
16+
17+
@_ZL2GV = internal addrspace(1) constant [1 x i32] [i32 42], align 4
18+
@.str = private unnamed_addr addrspace(1) constant [2 x i8] c"0\00", align 1
19+
@.str.1 = private unnamed_addr addrspace(1) constant [11 x i8] c"assert.cpp\00", align 1
20+
@__PRETTY_FUNCTION__._Z3foov = private unnamed_addr addrspace(1) constant [11 x i8] c"void foo()\00", align 1
21+
@__spirv_BuiltInGlobalInvocationId = external dso_local local_unnamed_addr addrspace(1) constant <3 x i64>, align 32
22+
@__spirv_BuiltInLocalInvocationId = external dso_local local_unnamed_addr addrspace(1) constant <3 x i64>, align 32
23+
@_ZL10assert_fmt = internal addrspace(2) constant [85 x i8] c"%s:%d: %s: global id: [%lu,%lu,%lu], local id: [%lu,%lu,%lu] Assertion `%s` failed.\0A\00", align 1
24+
25+
; CHECK: [SYCL/assert used]
26+
27+
; CHECK-DAG: main_TU1_kernel1
28+
define dso_local spir_kernel void @main_TU1_kernel1() #2 {
29+
entry:
30+
call spir_func void @foo()
31+
call spir_func void @bar()
32+
ret void
33+
}
34+
35+
define dso_local spir_func void @foo() #2 {
36+
entry:
37+
call spir_func void @_Z4foo1v()
38+
ret void
39+
}
40+
41+
define dso_local spir_func void @bar() #2 {
42+
entry:
43+
call spir_func void @_Z3foov() ; call assert
44+
call spir_func void @_Z4foo2v() ; indirectly called
45+
ret void
46+
}
47+
48+
; CHECK-DAG: main_TU0_kernel0
49+
define dso_local spir_kernel void @main_TU0_kernel0() #0 {
50+
entry:
51+
call spir_func void @_Z3foov() ; call assert
52+
ret void
53+
}
54+
55+
define dso_local spir_func void @_Z3foov() {
56+
entry:
57+
%a = alloca i32, align 4
58+
%ptr = bitcast i32* %a to i32 (i32)*
59+
%call = call spir_func i32 %ptr(i32 1)
60+
%add = add nsw i32 2, %call
61+
store i32 %add, i32* %a, align 4
62+
tail call spir_func void @__assert_fail(i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* addrspacecast ([2 x i8] addrspace(1)* @.str to [2 x i8] addrspace(4)*), i64 0, i64 0), i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* addrspacecast ([11 x i8] addrspace(1)* @.str.1 to [11 x i8] addrspace(4)*), i64 0, i64 0), i32 8, i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* addrspacecast ([11 x i8] addrspace(1)* @__PRETTY_FUNCTION__._Z3foov to [11 x i8] addrspace(4)*), i64 0, i64 0))
63+
ret void
64+
}
65+
66+
; CHECK-NOT: main_TU0_kernel1
67+
define dso_local spir_kernel void @main_TU0_kernel1() #0 {
68+
entry:
69+
call spir_func void @_Z4foo1v()
70+
ret void
71+
}
72+
73+
; Function Attrs: nounwind
74+
define dso_local spir_func void @_Z4foo1v() {
75+
entry:
76+
%a = alloca i32, align 4
77+
store i32 2, i32* %a, align 4
78+
ret void
79+
}
80+
81+
; CHECK-DAG: main_TU1_kernel0
82+
define dso_local spir_kernel void @main_TU1_kernel0() #2 {
83+
entry:
84+
call spir_func void @_Z3foov() ; call assert
85+
ret void
86+
}
87+
88+
89+
; This function is marked with "referenced-indirectly", but it doesn't call an assert
90+
; Function Attrs: nounwind
91+
define dso_local spir_func void @_Z4foo2v() #1 {
92+
entry:
93+
%a = alloca i32, align 4
94+
%0 = load i32, i32 addrspace(4)* getelementptr inbounds ([1 x i32], [1 x i32] addrspace(4)* addrspacecast ([1 x i32] addrspace(1)* @_ZL2GV to [1 x i32] addrspace(4)*), i64 0, i64 0), align 4
95+
%add = add nsw i32 4, %0
96+
store i32 %add, i32* %a, align 4
97+
ret void
98+
}
99+
100+
101+
; Function Attrs: convergent norecurse mustprogress
102+
define weak dso_local spir_func void @__assert_fail(i8 addrspace(4)* %expr, i8 addrspace(4)* %file, i32 %line, i8 addrspace(4)* %func) local_unnamed_addr {
103+
entry:
104+
%call = tail call spir_func i64 @_Z28__spirv_GlobalInvocationId_xv()
105+
%call1 = tail call spir_func i64 @_Z28__spirv_GlobalInvocationId_yv()
106+
%call2 = tail call spir_func i64 @_Z28__spirv_GlobalInvocationId_zv()
107+
%call3 = tail call spir_func i64 @_Z27__spirv_LocalInvocationId_xv()
108+
%call4 = tail call spir_func i64 @_Z27__spirv_LocalInvocationId_yv()
109+
%call5 = tail call spir_func i64 @_Z27__spirv_LocalInvocationId_zv()
110+
tail call spir_func void @__devicelib_assert_fail(i8 addrspace(4)* %expr, i8 addrspace(4)* %file, i32 %line, i8 addrspace(4)* %func, i64 %call, i64 %call1, i64 %call2, i64 %call3, i64 %call4, i64 %call5)
111+
ret void
112+
}
113+
114+
; Function Attrs: inlinehint norecurse mustprogress
115+
declare dso_local spir_func i64 @_Z28__spirv_GlobalInvocationId_xv() local_unnamed_addr
116+
117+
; Function Attrs: inlinehint norecurse mustprogress
118+
declare dso_local spir_func i64 @_Z28__spirv_GlobalInvocationId_yv() local_unnamed_addr
119+
120+
; Function Attrs: inlinehint norecurse mustprogress
121+
declare dso_local spir_func i64 @_Z28__spirv_GlobalInvocationId_zv() local_unnamed_addr
122+
123+
; Function Attrs: inlinehint norecurse mustprogress
124+
declare dso_local spir_func i64 @_Z27__spirv_LocalInvocationId_xv() local_unnamed_addr
125+
126+
; Function Attrs: inlinehint norecurse mustprogress
127+
declare dso_local spir_func i64 @_Z27__spirv_LocalInvocationId_yv() local_unnamed_addr
128+
129+
; Function Attrs: inlinehint norecurse mustprogress
130+
declare dso_local spir_func i64 @_Z27__spirv_LocalInvocationId_zv() local_unnamed_addr
131+
132+
; Function Attrs: convergent norecurse mustprogress
133+
define weak dso_local spir_func void @__devicelib_assert_fail(i8 addrspace(4)* %expr, i8 addrspace(4)* %file, i32 %line, i8 addrspace(4)* %func, i64 %gid0, i64 %gid1, i64 %gid2, i64 %lid0, i64 %lid1, i64 %lid2) local_unnamed_addr {
134+
entry:
135+
%call = tail call spir_func i32 (i8 addrspace(2)*, ...) @_Z18__spirv_ocl_printfPU3AS2Kcz(i8 addrspace(2)* getelementptr inbounds ([85 x i8], [85 x i8] addrspace(2)* @_ZL10assert_fmt, i64 0, i64 0), i8 addrspace(4)* %file, i32 %line, i8 addrspace(4)* %func, i64 %gid0, i64 %gid1, i64 %gid2, i64 %lid0, i64 %lid1, i64 %lid2, i8 addrspace(4)* %expr)
136+
ret void
137+
}
138+
139+
; Function Attrs: convergent
140+
declare dso_local spir_func i32 @_Z18__spirv_ocl_printfPU3AS2Kcz(i8 addrspace(2)*, ...) local_unnamed_addr
141+
142+
attributes #0 = { "sycl-module-id"="TU1.cpp" }
143+
attributes #1 = { "referenced-indirectly" "sycl-module-id"="TU2.cpp" }
144+
attributes #2 = { "sycl-module-id"="TU2.cpp" }
145+
146+
147+
!opencl.spir.version = !{!0, !0}
148+
!spirv.Source = !{!1, !1}
149+
150+
!0 = !{i32 1, i32 2}
151+
!1 = !{i32 4, i32 100000}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
; This test checks that the post-link tool properly generates "assert used"
2+
; property for indirectly called assertions - it should include all the kernels
3+
; even they do not call assertions in their call graph.
4+
; Per design doc, if a callgraph for indirect callable function
5+
; (marked with "referenced-indirectly" attribute in IR) has a call to
6+
; __devicelib_assert_fail, then all kernels in the module are conservatively
7+
; marked as using asserts.
8+
9+
; RUN: sycl-post-link -split=auto -symbols -S %s -o %t.table
10+
; RUN: FileCheck %s -input-file=%t_0.prop
11+
12+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
13+
target triple = "spir64-unknown-linux-sycldevice"
14+
15+
@_ZL2GV = internal addrspace(1) constant [1 x i32] [i32 42], align 4
16+
@.str = private unnamed_addr addrspace(1) constant [2 x i8] c"0\00", align 1
17+
@.str.1 = private unnamed_addr addrspace(1) constant [11 x i8] c"assert.cpp\00", align 1
18+
@__PRETTY_FUNCTION__._Z3foov = private unnamed_addr addrspace(1) constant [11 x i8] c"void foo()\00", align 1
19+
@__spirv_BuiltInGlobalInvocationId = external dso_local local_unnamed_addr addrspace(1) constant <3 x i64>, align 32
20+
@__spirv_BuiltInLocalInvocationId = external dso_local local_unnamed_addr addrspace(1) constant <3 x i64>, align 32
21+
@_ZL10assert_fmt = internal addrspace(2) constant [85 x i8] c"%s:%d: %s: global id: [%lu,%lu,%lu], local id: [%lu,%lu,%lu] Assertion `%s` failed.\0A\00", align 1
22+
23+
; CHECK: [SYCL/assert used]
24+
25+
; CHECK-DAG: main_TU0_kernel0
26+
define dso_local spir_kernel void @main_TU0_kernel0() #0 {
27+
entry:
28+
call spir_func void @_Z3foov()
29+
ret void
30+
}
31+
32+
define dso_local spir_func void @_Z3foov() {
33+
entry:
34+
%a = alloca i32, align 4
35+
%ptr = bitcast i32* %a to i32 (i32)*
36+
%call = call spir_func i32 %ptr(i32 1)
37+
%add = add nsw i32 2, %call
38+
store i32 %add, i32* %a, align 4
39+
tail call spir_func void @__assert_fail(i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* addrspacecast ([2 x i8] addrspace(1)* @.str to [2 x i8] addrspace(4)*), i64 0, i64 0), i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* addrspacecast ([11 x i8] addrspace(1)* @.str.1 to [11 x i8] addrspace(4)*), i64 0, i64 0), i32 8, i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* addrspacecast ([11 x i8] addrspace(1)* @__PRETTY_FUNCTION__._Z3foov to [11 x i8] addrspace(4)*), i64 0, i64 0))
40+
ret void
41+
}
42+
43+
; CHECK-DAG: main_TU0_kernel1
44+
define dso_local spir_kernel void @main_TU0_kernel1() #0 {
45+
entry:
46+
call spir_func void @_Z4foo1v()
47+
ret void
48+
}
49+
50+
; Function Attrs: nounwind
51+
define dso_local spir_func void @_Z4foo1v() {
52+
entry:
53+
%a = alloca i32, align 4
54+
store i32 2, i32* %a, align 4
55+
ret void
56+
}
57+
58+
; CHECK-DAG: main_TU1_kernel0
59+
define dso_local spir_kernel void @main_TU1_kernel0() #2 {
60+
entry:
61+
call spir_func void @_Z3foov()
62+
ret void
63+
}
64+
65+
; CHECK-DAG: main_TU1_kernel1
66+
define dso_local spir_kernel void @main_TU1_kernel1() #2 {
67+
entry:
68+
call spir_func void @_Z4foo2v()
69+
ret void
70+
}
71+
72+
; This function is marked with "referenced-indirectly"
73+
; Function Attrs: nounwind
74+
define dso_local spir_func void @_Z4foo2v() #1 {
75+
entry:
76+
%a = alloca i32, align 4
77+
%0 = load i32, i32 addrspace(4)* getelementptr inbounds ([1 x i32], [1 x i32] addrspace(4)* addrspacecast ([1 x i32] addrspace(1)* @_ZL2GV to [1 x i32] addrspace(4)*), i64 0, i64 0), align 4
78+
%add = add nsw i32 4, %0
79+
store i32 %add, i32* %a, align 4
80+
tail call spir_func void @__assert_fail(i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* addrspacecast ([2 x i8] addrspace(1)* @.str to [2 x i8] addrspace(4)*), i64 0, i64 0), i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* addrspacecast ([11 x i8] addrspace(1)* @.str.1 to [11 x i8] addrspace(4)*), i64 0, i64 0), i32 8, i8 addrspace(4)* getelementptr inbounds ([11 x i8], [11 x i8] addrspace(4)* addrspacecast ([11 x i8] addrspace(1)* @__PRETTY_FUNCTION__._Z3foov to [11 x i8] addrspace(4)*), i64 0, i64 0))
81+
ret void
82+
}
83+
84+
85+
; Function Attrs: convergent norecurse mustprogress
86+
define weak dso_local spir_func void @__assert_fail(i8 addrspace(4)* %expr, i8 addrspace(4)* %file, i32 %line, i8 addrspace(4)* %func) local_unnamed_addr {
87+
entry:
88+
%call = tail call spir_func i64 @_Z28__spirv_GlobalInvocationId_xv()
89+
%call1 = tail call spir_func i64 @_Z28__spirv_GlobalInvocationId_yv()
90+
%call2 = tail call spir_func i64 @_Z28__spirv_GlobalInvocationId_zv()
91+
%call3 = tail call spir_func i64 @_Z27__spirv_LocalInvocationId_xv()
92+
%call4 = tail call spir_func i64 @_Z27__spirv_LocalInvocationId_yv()
93+
%call5 = tail call spir_func i64 @_Z27__spirv_LocalInvocationId_zv()
94+
tail call spir_func void @__devicelib_assert_fail(i8 addrspace(4)* %expr, i8 addrspace(4)* %file, i32 %line, i8 addrspace(4)* %func, i64 %call, i64 %call1, i64 %call2, i64 %call3, i64 %call4, i64 %call5)
95+
ret void
96+
}
97+
98+
; Function Attrs: inlinehint norecurse mustprogress
99+
declare dso_local spir_func i64 @_Z28__spirv_GlobalInvocationId_xv() local_unnamed_addr
100+
101+
; Function Attrs: inlinehint norecurse mustprogress
102+
declare dso_local spir_func i64 @_Z28__spirv_GlobalInvocationId_yv() local_unnamed_addr
103+
104+
; Function Attrs: inlinehint norecurse mustprogress
105+
declare dso_local spir_func i64 @_Z28__spirv_GlobalInvocationId_zv() local_unnamed_addr
106+
107+
; Function Attrs: inlinehint norecurse mustprogress
108+
declare dso_local spir_func i64 @_Z27__spirv_LocalInvocationId_xv() local_unnamed_addr
109+
110+
; Function Attrs: inlinehint norecurse mustprogress
111+
declare dso_local spir_func i64 @_Z27__spirv_LocalInvocationId_yv() local_unnamed_addr
112+
113+
; Function Attrs: inlinehint norecurse mustprogress
114+
declare dso_local spir_func i64 @_Z27__spirv_LocalInvocationId_zv() local_unnamed_addr
115+
116+
; Function Attrs: convergent norecurse mustprogress
117+
define weak dso_local spir_func void @__devicelib_assert_fail(i8 addrspace(4)* %expr, i8 addrspace(4)* %file, i32 %line, i8 addrspace(4)* %func, i64 %gid0, i64 %gid1, i64 %gid2, i64 %lid0, i64 %lid1, i64 %lid2) local_unnamed_addr {
118+
entry:
119+
%call = tail call spir_func i32 (i8 addrspace(2)*, ...) @_Z18__spirv_ocl_printfPU3AS2Kcz(i8 addrspace(2)* getelementptr inbounds ([85 x i8], [85 x i8] addrspace(2)* @_ZL10assert_fmt, i64 0, i64 0), i8 addrspace(4)* %file, i32 %line, i8 addrspace(4)* %func, i64 %gid0, i64 %gid1, i64 %gid2, i64 %lid0, i64 %lid1, i64 %lid2, i8 addrspace(4)* %expr)
120+
ret void
121+
}
122+
123+
; Function Attrs: convergent
124+
declare dso_local spir_func i32 @_Z18__spirv_ocl_printfPU3AS2Kcz(i8 addrspace(2)*, ...) local_unnamed_addr
125+
126+
attributes #0 = { "sycl-module-id"="TU1.cpp" }
127+
attributes #1 = { "referenced-indirectly" "sycl-module-id"="TU2.cpp" }
128+
attributes #2 = { "sycl-module-id"="TU2.cpp" }
129+
130+
131+
!opencl.spir.version = !{!0, !0}
132+
!spirv.Source = !{!1, !1}
133+
134+
!0 = !{i32 1, i32 2}
135+
!1 = !{i32 4, i32 100000}

0 commit comments

Comments
 (0)