Skip to content

Commit f308c48

Browse files
schittirromanovvlad
authored andcommitted
[SYCL] sampler implementation
This patch contains sampler class runtime implementation and compiler support Signed-off-by: Sindhu Chittireddy <[email protected]>
1 parent 8280756 commit f308c48

File tree

15 files changed

+557
-3
lines changed

15 files changed

+557
-3
lines changed

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ class Util {
6363
/// accessor class.
6464
static bool isSyclAccessorType(const QualType &Ty);
6565

66+
/// Checks whether given clang type is a full specialization of the sycl
67+
/// sampler class.
68+
static bool isSyclSamplerType(const QualType &Ty);
69+
6670
/// Checks whether given clang type is the sycl stream class.
6771
static bool isSyclStreamType(const QualType &Ty);
6872

@@ -516,6 +520,59 @@ CreateSYCLKernelBody(Sema &S, FunctionDecl *KernelCallerFunc, DeclContext *DC) {
516520
CXXMemberCallExpr *Call = CXXMemberCallExpr::Create(
517521
S.Context, ME, ParamStmts, ResultTy, VK, SourceLocation());
518522
BodyStmts.push_back(Call);
523+
} else if (CRD && Util::isSyclSamplerType(FieldType)) {
524+
525+
// Sampler has only one TargetFuncParam, which should be set in
526+
// __init method: _ValueType
527+
const size_t NumParams = 1;
528+
llvm::SmallVector<DeclRefExpr *, NumParams> ParamDREs(NumParams);
529+
auto TFP = TargetFuncParam;
530+
QualType ParamType = (*TFP)->getOriginalType();
531+
ParamDREs[0] = DeclRefExpr::Create(
532+
S.Context, NestedNameSpecifierLoc(), SourceLocation(), *TFP,
533+
false, DeclarationNameInfo(), ParamType, VK_LValue);
534+
DeclAccessPair FieldDAP = DeclAccessPair::make(Field, AS_none);
535+
536+
// kernel_obj.sampler
537+
auto SamplerME = MemberExpr::Create(
538+
S.Context, CloneRef, false, SourceLocation(),
539+
NestedNameSpecifierLoc(), SourceLocation(), Field, FieldDAP,
540+
DeclarationNameInfo(Field->getDeclName(), SourceLocation()),
541+
nullptr, Field->getType(), VK_LValue, OK_Ordinary);
542+
543+
CXXMethodDecl *InitMethod = nullptr;
544+
for (auto Method : CRD->methods()) {
545+
if (Method->getNameInfo().getName().getAsString() == "__init") {
546+
InitMethod = Method;
547+
break;
548+
}
549+
}
550+
assert(InitMethod && "The sampler must have the __init method");
551+
552+
// kernel_obj.sampler.__init
553+
DeclAccessPair MethodDAP = DeclAccessPair::make(InitMethod, AS_none);
554+
auto ME = MemberExpr::Create(
555+
S.Context, SamplerME, false, SourceLocation(),
556+
NestedNameSpecifierLoc(), SourceLocation(), InitMethod, MethodDAP,
557+
InitMethod->getNameInfo(), nullptr, InitMethod->getType(),
558+
VK_LValue, OK_Ordinary);
559+
560+
// Not referenced -> not emitted
561+
S.MarkFunctionReferenced(SourceLocation(), InitMethod, true);
562+
563+
QualType ResultTy = InitMethod->getReturnType();
564+
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
565+
ResultTy = ResultTy.getNonLValueExprType(S.Context);
566+
567+
// __init needs one parameter
568+
auto ParamItr = InitMethod->param_begin();
569+
// kernel_parameters
570+
llvm::SmallVector<Expr *, NumParams> ParamStmts;
571+
ParamStmts.push_back(getExprForPointer(
572+
S, (*ParamItr)->getOriginalType(), ParamDREs[0]));
573+
CXXMemberCallExpr *Call = CXXMemberCallExpr::Create(
574+
S.Context, ME, ParamStmts, ResultTy, VK, SourceLocation());
575+
BodyStmts.push_back(Call);
519576
} else if (CRD || FieldType->isScalarType()) {
520577
// If field have built-in or a structure/class type just initialize
521578
// this field with corresponding kernel argument using '=' binary
@@ -668,6 +725,15 @@ static void buildArgTys(ASTContext &Context, CXXRecordDecl *KernelObj,
668725
getFieldDeclByName(RecordDecl, {"impl", "Offset"});
669726
assert(OffsetFld && "The accessor.impl must contain the Offset field");
670727
CreateAndAddPrmDsc(OffsetFld, OffsetFld->getType());
728+
} else if (Util::isSyclSamplerType(ArgTy)) {
729+
// the parameter is a SYCL sampler object
730+
const auto *RecordDecl = ArgTy->getAsCXXRecordDecl();
731+
assert(RecordDecl && "sampler must be of a record type");
732+
733+
FieldDecl *ImplFld =
734+
getFieldDeclByName(RecordDecl, {"impl", "m_Sampler"});
735+
assert(ImplFld && "The sampler must contain impl field");
736+
CreateAndAddPrmDsc(ImplFld, ImplFld->getType());
671737
} else if (Util::isSyclStreamType(ArgTy)) {
672738
// the parameter is a SYCL stream object
673739
llvm_unreachable("streams not supported yet");
@@ -724,6 +790,17 @@ static void populateIntHeader(SYCLIntegrationHeader &H, const StringRef Name,
724790
AccTmplTy->getTemplateArgs()[1].getAsIntegral().getExtValue());
725791
int Info = getAccessTarget(AccTmplTy) | (Dims << 11);
726792
H.addParamDesc(SYCLIntegrationHeader::kind_accessor, Info, Offset);
793+
} else if (Util::isSyclSamplerType(ArgTy)) {
794+
// The parameter is a SYCL sampler object
795+
// It has only one descriptor, "m_Sampler"
796+
const auto *SamplerTy = ArgTy->getAsCXXRecordDecl();
797+
assert(SamplerTy && "sampler must be of a record type");
798+
FieldDecl *ImplFld =
799+
getFieldDeclByName(SamplerTy, {"impl", "m_Sampler"}, &Offset);
800+
uint64_t Sz =
801+
Ctx.getTypeSizeInChars(ImplFld->getType()).getQuantity();
802+
H.addParamDesc(SYCLIntegrationHeader::kind_sampler,
803+
static_cast<unsigned>(Sz), static_cast<unsigned>(Offset));
727804
} else if (Util::isSyclStreamType(ArgTy)) {
728805
// the parameter is a SYCL stream object
729806
llvm_unreachable("streams not supported yet");
@@ -1125,6 +1202,14 @@ bool Util::isSyclAccessorType(const QualType &Ty) {
11251202
return matchQualifiedTypeName(Ty, Scopes);
11261203
}
11271204

1205+
bool Util::isSyclSamplerType(const QualType &Ty) {
1206+
static std::array<DeclContextDesc, 3> Scopes = {
1207+
Util::DeclContextDesc{clang::Decl::Kind::Namespace, "cl"},
1208+
Util::DeclContextDesc{clang::Decl::Kind::Namespace, "sycl"},
1209+
Util::DeclContextDesc{clang::Decl::Kind::CXXRecord, "sampler"}};
1210+
return matchQualifiedTypeName(Ty, Scopes);
1211+
}
1212+
11281213
bool Util::isSyclStreamType(const QualType &Ty) {
11291214
static std::array<DeclContextDesc, 3> Scopes = {
11301215
Util::DeclContextDesc{clang::Decl::Kind::Namespace, "cl"},

clang/test/CodeGenSYCL/Inputs/sycl.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,22 @@
88

99
// Dummy runtime classes to model SYCL API.
1010
namespace cl {
11+
namespace __spirv {
12+
class OpTypeSampler;
13+
}
14+
1115
namespace sycl {
16+
struct sampler_impl {
17+
__spirv::OpTypeSampler* m_Sampler;
18+
};
19+
20+
class sampler {
21+
struct sampler_impl impl;
22+
void __init(__spirv::OpTypeSampler* Sampler) { impl.m_Sampler = Sampler; }
23+
24+
public:
25+
void use(void) const {}
26+
};
1227

1328
namespace access {
1429

clang/test/CodeGenSYCL/integration_header.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,17 @@
2424
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 },
2525
// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 4062, 4 },
2626
// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 6112, 7 },
27+
// CHECK-NEXT: { kernel_param_kind_t::kind_sampler, 8, 16 },
2728
// CHECK-EMPTY:
2829
// CHECK-NEXT: //--- _ZTSN16second_namespace13second_kernelIcEE
2930
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 },
3031
// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 6112, 4 },
32+
// CHECK-NEXT: { kernel_param_kind_t::kind_sampler, 8, 8 },
3133
// CHECK-EMPTY:
3234
// CHECK-NEXT: //--- _ZTS12third_kernelILi1Ei5pointIZ4mainE1XEE
3335
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 },
3436
// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 6112, 4 },
37+
// CHECK-NEXT: { kernel_param_kind_t::kind_sampler, 8, 8 },
3538
// CHECK-EMPTY:
3639
// CHECK-NEXT: };
3740
//
@@ -65,6 +68,7 @@ int main() {
6568
cl::sycl::access::placeholder::true_t>
6669
acc2;
6770
int i = 13;
71+
cl::sycl::sampler smplr;
6872
// TODO: Uncomemnt when structures in kernel arguments are correctly processed
6973
// by SYCL compiler
7074
/* struct {
@@ -77,17 +81,20 @@ int main() {
7781

7882
acc1.use();
7983
acc2.use();
84+
smplr.use();
8085
}
8186
});
8287

8388
kernel_single_task<class second_namespace::second_kernel<char>>([=]() {
8489
if (i == 13) {
8590
acc2.use();
91+
smplr.use();
8692
}
8793
});
8894
kernel_single_task<class third_kernel<1, int,point<struct X>>>([=]() {
8995
if (i == 13) {
9096
acc2.use();
97+
smplr.use();
9198
}
9299
});
93100

clang/test/CodeGenSYCL/sampler.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -triple spir64-unknown-linux-sycldevice -std=c++11 -I %S/Inputs -fsycl-is-device -disable-llvm-passes -emit-llvm -x c++ %s -o - | FileCheck --enable-var-scope %s
2+
// CHECK: define spir_kernel void @{{[a-zA-Z0-9_]+}}(%spirv.Sampler* [[SAMPLER_ARG:%[a-zA-Z0-9_]+]])
3+
// CHECK-NEXT: entry:
4+
// CHECK-NEXT: [[SAMPLER_ARG]].addr = alloca %spirv.Sampler*, align 8
5+
// CHECK-NEXT: [[ANON:%[0-9]+]] = alloca %class.anon, align 8
6+
// CHECK-NEXT: store %spirv.Sampler* [[SAMPLER_ARG]], %spirv.Sampler** [[SAMPLER_ARG]].addr, align 8, !tbaa !9
7+
// CHECK-NEXT: [[BITCAST:%[0-9]+]] = bitcast %class.anon* [[ANON]] to i8*
8+
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[BITCAST]]) #4
9+
// CHECK-NEXT: [[GEP:%[0-9]+]] = getelementptr inbounds %class.anon, %class.anon* [[ANON]], i32 0, i32 0
10+
// CHECK-NEXT: [[LOAD_SAMPLER_ARG:%[0-9]+]] = load %spirv.Sampler*, %spirv.Sampler** [[SAMPLER_ARG]].addr, align 8, !tbaa !9
11+
// CHECK-NEXT: call spir_func void @{{[a-zA-Z0-9_]+}}(%"class.cl::sycl::sampler"* [[GEP]], %spirv.Sampler* [[LOAD_SAMPLER_ARG]])
12+
//
13+
#include "sycl.hpp"
14+
15+
template <typename KernelName, typename KernelType>
16+
__attribute__((sycl_kernel)) void kernel_single_task(KernelType kernelFunc) {
17+
kernelFunc();
18+
}
19+
20+
int main() {
21+
cl::sycl::sampler smplr;
22+
kernel_single_task<class first_kernel>([=]() {
23+
smplr.use();
24+
});
25+
26+
return 0;
27+
}

clang/test/SemaSYCL/Inputs/sycl.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#endif
99

1010
namespace cl {
11+
namespace __spirv {
12+
class OpTypeSampler;
13+
}
1114
namespace sycl {
1215
namespace access {
1316

@@ -65,11 +68,24 @@ class accessor {
6568
void use(void) const {}
6669
void use(void*) const {}
6770
_ImplT<dimensions> impl;
71+
6872
private:
6973
void __init(__global dataT *Ptr, range<dimensions> AccessRange,
7074
range<dimensions> MemRange, id<dimensions> Offset) {}
7175
};
7276

77+
struct sampler_impl {
78+
__spirv::OpTypeSampler *m_Sampler;
79+
};
80+
81+
class sampler {
82+
struct sampler_impl impl;
83+
void __init(__spirv::OpTypeSampler *Sampler) { impl.m_Sampler = Sampler; }
84+
85+
public:
86+
void use(void) const {}
87+
};
88+
7389
} // namespace sycl
7490
} // namespace cl
7591

clang/test/SemaSYCL/sampler.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clang -S -I %S/Inputs --sycl -Xclang -ast-dump %s | FileCheck %s
2+
3+
#include <sycl.hpp>
4+
5+
template <typename name, typename Func>
6+
__attribute__((sycl_kernel)) void kernel(Func kernelFunc) {
7+
kernelFunc();
8+
}
9+
10+
int main() {
11+
cl::sycl::sampler Sampler;
12+
kernel<class use_kernel_for_test>([=]() {
13+
Sampler.use();
14+
});
15+
return 0;
16+
}
17+
18+
// Check declaration of the test kernel
19+
// CHECK: FunctionDecl {{.*}}use_kernel_for_test 'void (__spirv::OpTypeSampler *)'
20+
//
21+
// Check parameters of the test kernel
22+
// CHECK: ParmVarDecl {{.*}} used _arg_m_Sampler '__spirv::OpTypeSampler *'
23+
//
24+
// Check that sampler field of the test kernel object is initialized using __init method
25+
// CHECK: CXXMemberCallExpr {{.*}} 'void'
26+
// CHECK-NEXT: MemberExpr {{.*}} 'void (__spirv::OpTypeSampler *)' lvalue .__init
27+
// CHECK-NEXT: MemberExpr {{.*}} 'cl::sycl::sampler':'cl::sycl::sampler' lvalue
28+
// CHECK-NEXT: DeclRefExpr {{.*}} '(lambda at {{.*}}sampler.cpp{{.*}})' lvalue Var {{.*}} '(lambda at {{.*}}sampler.cpp{{.*}})'
29+
//
30+
// Check the parameters of __init method
31+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '__spirv::OpTypeSampler *' <LValueToRValue>
32+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '__spirv::OpTypeSampler *' lvalue <NoOp>
33+
// CHECK-NEXT: DeclRefExpr {{.*}} '__spirv::OpTypeSampler *' lvalue ParmVar {{.*}} '_arg_m_Sampler' '__spirv::OpTypeSampler

sycl/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ add_library("${SYCLLibrary}" SHARED
135135
"${sourceRootPath}/detail/program_manager/program_manager.cpp"
136136
"${sourceRootPath}/detail/queue_impl.cpp"
137137
"${sourceRootPath}/detail/os_util.cpp"
138+
"${sourceRootPath}/detail/sampler_impl.cpp"
138139
"${sourceRootPath}/detail/scheduler/commands.cpp"
139140
"${sourceRootPath}/detail/scheduler/printers.cpp"
140141
"${sourceRootPath}/detail/scheduler/scheduler.cpp"
@@ -148,6 +149,7 @@ add_library("${SYCLLibrary}" SHARED
148149
"${sourceRootPath}/kernel.cpp"
149150
"${sourceRootPath}/platform.cpp"
150151
"${sourceRootPath}/queue.cpp"
152+
"${sourceRootPath}/sampler.cpp"
151153
"${sourceRootPath}/spirv_ops.cpp"
152154
)
153155

sycl/include/CL/__spirv/spirv_types.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ enum MemorySemantics {
4343
// Only in such cases the class is recognized as SPIRV type OpTypeEvent.
4444
class OpTypeEvent;
4545

46+
// SPIRV type for sampler class
47+
class OpTypeSampler;
48+
4649
enum GroupOperation { Reduce = 0, InclusiveScan = 1, ExclusiveScan = 2 };
4750
} // namespace __spirv
4851
} // namespace cl

sycl/include/CL/sycl.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <CL/sycl/program.hpp>
3434
#include <CL/sycl/queue.hpp>
3535
#include <CL/sycl/range.hpp>
36+
#include <CL/sycl/sampler.hpp>
3637
#include <CL/sycl/types.hpp>
3738
#include <CL/sycl/version.hpp>
3839

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//==----------------- sampler_impl.hpp - SYCL standard header file ---------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#pragma once
10+
11+
#include <CL/__spirv/spirv_types.hpp>
12+
#include <CL/sycl/context.hpp>
13+
14+
#include <unordered_map>
15+
16+
namespace cl {
17+
namespace sycl {
18+
19+
enum class addressing_mode : unsigned int;
20+
enum class filtering_mode : unsigned int;
21+
enum class coordinate_normalization_mode : unsigned int;
22+
23+
namespace detail {
24+
class sampler_impl {
25+
public:
26+
#ifdef __SYCL_DEVICE_ONLY__
27+
__spirv::OpTypeSampler *m_Sampler;
28+
sampler_impl(__spirv::OpTypeSampler *Sampler) : m_Sampler(Sampler) {}
29+
#else
30+
cl_sampler m_Sampler;
31+
context m_SyclContext;
32+
std::unordered_map<context, cl_sampler> m_contextToSampler;
33+
34+
private:
35+
coordinate_normalization_mode m_CoordNormMode;
36+
addressing_mode m_AddrMode;
37+
filtering_mode m_FiltMode;
38+
bool m_ReleaseSampler;
39+
40+
public:
41+
sampler_impl(coordinate_normalization_mode normalizationMode,
42+
addressing_mode addressingMode, filtering_mode filteringMode);
43+
44+
sampler_impl(cl_sampler clSampler, const context &syclContext);
45+
46+
addressing_mode get_addressing_mode() const;
47+
48+
filtering_mode get_filtering_mode() const;
49+
50+
coordinate_normalization_mode get_coordinate_normalization_mode() const;
51+
52+
cl_sampler getOrCreateSampler(const context &Context);
53+
#endif
54+
55+
#ifdef __SYCL_DEVICE_ONLY__
56+
~sampler_impl() = default;
57+
#else
58+
~sampler_impl();
59+
#endif
60+
};
61+
62+
} // namespace detail
63+
} // namespace sycl
64+
} // namespace cl

0 commit comments

Comments
 (0)