-
Notifications
You must be signed in to change notification settings - Fork 769
[SYCL] Update spec constant handling for struct hierarchies #17204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
eef0346
65997ed
0e5d70a
285be66
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
; For C++ types that come from nested class hierarchy, the LLVM type corresponding | ||
; to that type seems to match the nested structure. However, it also seems that | ||
; when defining a constant for that type, the LLVM value defining the constant has a type | ||
; that is different, and is esssentially a flattened out version of the C++ type. | ||
; For example, this test is IR generated from getting the value of a spec constant | ||
; of a struct `scary` that has a deep nested hierarchy, but the specialization_id holding | ||
; the default value of `scary` is a flat struct with all the fields of `scary` flattened out. | ||
; (compare %struct.scary and @_ZL16scary_spec_const) | ||
; This test makes that the spec constant pass can handle such cases. | ||
; (note: IR generated from sycl/test-e2e/SpecConstants/2020/hierarchy.cpp) | ||
; RUN: sycl-post-link -properties --spec-const=native -S %s -o %t.table | ||
; RUN: FileCheck %s -input-file=%t_0.ll | ||
|
||
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" | ||
target triple = "spir64-unknown-unknown" | ||
|
||
%struct.anon = type { i32, i32 } | ||
%struct.anon.0 = type { i32 } | ||
%struct.scary = type { %struct.layer4.base, [15 x i8] } | ||
%struct.layer4.base = type { %struct.layer3.base } | ||
%struct.layer3.base = type <{ %struct.layer2, [4 x i8], %struct.foo.base }> | ||
%struct.layer2 = type { %struct.layer1 } | ||
%struct.layer1 = type { %struct.base } | ||
%struct.base = type { float, i8, i32, %struct.anon } | ||
%struct.foo.base = type <{ i32, [4 x i8], [5 x i64], [5 x %struct.anon.0], [5 x i8] }> | ||
|
||
@__usid_str = private unnamed_addr constant [44 x i8] c"uid52dfb70f8b72bae7____ZL16scary_spec_const\00", align 1 | ||
@_ZL16scary_spec_const = internal addrspace(1) constant { { float, i8, i32, %struct.anon, [4 x i8], i32, [5 x i64], [5 x %struct.anon.0], [5 x i8], [15 x i8] } } { { float, i8, i32, %struct.anon, [4 x i8], i32, [5 x i64], [5 x %struct.anon.0], [5 x i8], [15 x i8] } { float 0.000000e+00, i8 98, i32 0, %struct.anon zeroinitializer, [4 x i8] undef, i32 3, [5 x i64] [i64 5, i64 0, i64 0, i64 0, i64 0], [5 x %struct.anon.0] [%struct.anon.0 { i32 1 }, %struct.anon.0 { i32 2 }, %struct.anon.0 zeroinitializer, %struct.anon.0 zeroinitializer, %struct.anon.0 zeroinitializer], [5 x i8] c"abc\00\00", [15 x i8] undef } }, align 16 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should not use LLVM IR test format for checking "what clang generates". Clang will generate something different in the future, which this test won't cover. You should use SYCL end-to-end tests to validate end-to-end test behavior. |
||
|
||
define weak_odr dso_local spir_kernel void @_ZTSZ4mainEUlN4sycl3_V114kernel_handlerEE_(ptr addrspace(1) noundef align 16 %_arg_p) { | ||
entry: | ||
%ref.tmp.i = alloca %struct.scary, align 16 | ||
%ref.tmp.ascast.i = addrspacecast ptr %ref.tmp.i to ptr addrspace(4) | ||
call spir_func void @_Z40__sycl_getComposite2020SpecConstantValueI5scaryET_PKcPKvS5_(ptr addrspace(4) dead_on_unwind writable sret(%struct.scary) align 16 %ref.tmp.ascast.i, ptr addrspace(4) noundef addrspacecast (ptr @__usid_str to ptr addrspace(4)), ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @_ZL16scary_spec_const to ptr addrspace(4)), ptr addrspace(4) noundef null) | ||
call void @llvm.memcpy.p1.p0.i64(ptr addrspace(1) align 16 %_arg_p, ptr align 16 %ref.tmp.i, i64 97, i1 false) | ||
ret void | ||
} | ||
|
||
declare dso_local spir_func void @_Z40__sycl_getComposite2020SpecConstantValueI5scaryET_PKcPKvS5_(ptr addrspace(4) dead_on_unwind writable sret(%struct.scary) align 16, ptr addrspace(4) noundef, ptr addrspace(4) noundef, ptr addrspace(4) noundef) | ||
|
||
|
||
; CHECK: %[[#SCV0:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 0, float 0.000000e+00) | ||
; CHECK: %[[#SCV1:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 1, i8 98) | ||
; CHECK: %[[#SCV2:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 2, i32 0) | ||
; CHECK: %[[#SCV3:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 3, i32 0) | ||
; CHECK: %[[#SCV4:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 4, i32 0) | ||
; CHECK: %[[#SCV5:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(i32 %[[#SCV3]], i32 %[[#SCV4]]) | ||
; CHECK: %[[#SCV6:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(float %[[#SCV0]], i8 %[[#SCV1]], i32 %[[#SCV2]], %struct.anon %[[#SCV5]]) | ||
; CHECK: %[[#SCV7:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(%struct.base %[[#SCV6]]) | ||
; CHECK: %[[#SCV8:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(%struct.layer1 %[[#SCV7]]) | ||
; CHECK: %[[#SCV9:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 6, i32 3) | ||
; CHECK: %[[#SCV10:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 8, i64 5) | ||
; CHECK: %[[#SCV11:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 9, i64 0) | ||
; CHECK: %[[#SCV12:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 10, i64 0) | ||
; CHECK: %[[#SCV13:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 11, i64 0) | ||
; CHECK: %[[#SCV14:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 12, i64 0) | ||
; CHECK: %[[#SCV15:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(i64 %[[#SCV10]], i64 %[[#SCV11]], i64 %[[#SCV12]], i64 %[[#SCV13]], i64 %[[#SCV14]]) | ||
; CHECK: %[[#SCV16:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 13, i32 1) | ||
; CHECK: %[[#SCV17:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(i32 %[[#SCV16]]) | ||
; CHECK: %[[#SCV18:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 14, i32 2) | ||
; CHECK: %[[#SCV19:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(i32 %[[#SCV18]]) | ||
; CHECK: %[[#SCV20:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 15, i32 0) | ||
; CHECK: %[[#SCV21:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(i32 %[[#SCV20]]) | ||
; CHECK: %[[#SCV22:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 16, i32 0) | ||
; CHECK: %[[#SCV23:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(i32 %[[#SCV22]]) | ||
; CHECK: %[[#SCV24:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 17, i32 0) | ||
; CHECK: %[[#SCV25:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(i32 %[[#SCV24]]) | ||
; CHECK: %[[#SCV26:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(%struct.anon.0 %[[#SCV17]], %struct.anon.0 %[[#SCV19]], %struct.anon.0 %[[#SCV21]], %struct.anon.0 %[[#SCV23]], %struct.anon.0 %[[#SCV25]]) | ||
; CHECK: %[[#SCV27:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 18, i8 97) | ||
; CHECK: %[[#SCV28:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 19, i8 98) | ||
; CHECK: %[[#SCV29:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 20, i8 99) | ||
; CHECK: %[[#SCV30:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 21, i8 0) | ||
; CHECK: %[[#SCV31:]] = {{.*}}@{{.*}}SpecConstant{{.*}}(i32 22, i8 0) | ||
; CHECK: %[[#SCV32:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(i8 %[[#SCV27]], i8 %[[#SCV28]], i8 %[[#SCV29]], i8 %[[#SCV30]], i8 %[[#SCV31]]) | ||
; CHECK: %[[#SCV33:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(i32 %[[#SCV9]], [4 x i8] undef, [5 x i64] %[[#SCV15]], [5 x %struct.anon.0] %[[#SCV26]], [5 x i8] %[[#SCV32]]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These undef uses are generated by |
||
; CHECK: %[[#SCV34:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(%struct.layer2 %[[#SCV8]], [4 x i8] undef, %struct.foo.base %[[#SCV33]]) | ||
; CHECK: %[[#SCV35:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(%struct.layer3.base %[[#SCV34]]) | ||
; CHECK: %[[#SCV36:]] = {{.*}}@{{.*}}SpecConstantComposite{{.*}}(%struct.layer4.base %[[#SCV35]], [15 x i8] undef) | ||
|
||
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) | ||
declare void @llvm.memcpy.p1.p0.i64(ptr addrspace(1) noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// RUN: %{build} -o %t.out | ||
// RUN: %{run} %t.out | ||
#include <sycl/detail/core.hpp> | ||
#include <sycl/specialization_id.hpp> | ||
#include <sycl/usm.hpp> | ||
|
||
using namespace sycl; | ||
struct base { | ||
float a; | ||
char b = 'b'; | ||
int c; | ||
struct { | ||
int x; | ||
int y; | ||
} d; | ||
}; | ||
struct layer1 : base {}; | ||
struct layer2 : layer1 {}; | ||
struct foo { | ||
int e = 3; | ||
long long f[5] = {5}; | ||
struct { | ||
int value; | ||
} g[5] = {1, 2}; | ||
char h[5] = {'a', 'b', 'c'}; | ||
}; | ||
struct alignas(16) layer3 : layer2, foo {}; | ||
struct layer4 : layer3 {}; | ||
struct scary : layer4 {}; | ||
|
||
constexpr scary default_scary{}; | ||
constexpr scary zero_scary{base{0, 0, 0, {0, 0}}, foo{0, {}, {}, {}}}; | ||
constexpr specialization_id<scary> scary_spec_const(default_scary); | ||
|
||
int main() { | ||
queue Q; | ||
auto *p = malloc_shared<scary>(1, Q); | ||
new (p) scary{zero_scary}; | ||
|
||
Q.single_task([=](kernel_handler h) { | ||
*p = h.get_specialization_constant<scary_spec_const>(); | ||
}).wait(); | ||
|
||
int nfails = 0; | ||
#define EXPECT_EQ(a, b, ...) \ | ||
if (a != b) { \ | ||
nfails++; \ | ||
std::cout << "FAIL: " << #a << " != " << #b << " (" << (int)a \ | ||
<< " != " << (int)b << ")\n"; \ | ||
} | ||
|
||
// base | ||
EXPECT_EQ(p->a, 0, ); | ||
EXPECT_EQ(p->b, 'b'); | ||
EXPECT_EQ(p->c, 0); | ||
EXPECT_EQ(p->d.x, 0); | ||
EXPECT_EQ(p->d.y, 0); | ||
|
||
// foo | ||
EXPECT_EQ(p->e, 3); | ||
|
||
EXPECT_EQ(p->f[0], 5); | ||
EXPECT_EQ(p->f[1], 0); | ||
EXPECT_EQ(p->f[2], 0); | ||
EXPECT_EQ(p->f[3], 0); | ||
EXPECT_EQ(p->f[4], 0); | ||
|
||
EXPECT_EQ(p->g[0].value, 1); | ||
EXPECT_EQ(p->g[1].value, 2); | ||
EXPECT_EQ(p->g[2].value, 0); | ||
EXPECT_EQ(p->g[3].value, 0); | ||
EXPECT_EQ(p->g[4].value, 0); | ||
|
||
EXPECT_EQ(p->h[0], 'a'); | ||
EXPECT_EQ(p->h[1], 'b'); | ||
EXPECT_EQ(p->h[2], 'c'); | ||
EXPECT_EQ(p->h[3], 0); | ||
EXPECT_EQ(p->h[4], 0); | ||
|
||
if (nfails == 0) { | ||
std::cout << "PASS\n"; | ||
} else { | ||
std::cout << "FAIL\n"; | ||
} | ||
|
||
free(p, Q); | ||
return nfails; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will be changed to
Constant::getNullValue(ElTy)
in #17341