Skip to content

Commit 7edf29c

Browse files
Fznamznonvladimirlaz
authored andcommitted
[SYCL] Fix accessor to subset of buffer indexing (compiler part)
To get correct offset in subscript operator we should use range of original buffer. To keep accessor functionality like "get_range" and "get_count" spec conformant we should use accessor's own range. Introduced AccessRange and MemRange to accessor implemetation. This fields can be initialized through __init method. Signed-off-by: Vladimir Lazarev <[email protected]> Signed-off-by: Mariya Podchishchaeva <[email protected]>
1 parent 873ad55 commit 7edf29c

File tree

7 files changed

+109
-80
lines changed

7 files changed

+109
-80
lines changed

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
#include "clang/AST/QualTypeNames.h"
1515
#include "clang/AST/RecordLayout.h"
1616
#include "clang/AST/RecursiveASTVisitor.h"
17+
#include "clang/Analysis/CallGraph.h"
1718
#include "clang/Sema/Sema.h"
1819
#include "llvm/ADT/SmallPtrSet.h"
1920
#include "llvm/ADT/SmallVector.h"
2021
#include "llvm/Support/FileSystem.h"
2122
#include "llvm/Support/Path.h"
2223
#include "llvm/Support/raw_ostream.h"
23-
#include "clang/Analysis/CallGraph.h"
2424

2525
#include <array>
2626

@@ -95,17 +95,17 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
9595
// all functions used by kernel have already been parsed and have
9696
// definitions.
9797
if (RecursiveSet.count(Callee)) {
98-
SemaRef.Diag(e->getExprLoc(), diag::err_sycl_restrict) <<
99-
KernelCallRecursiveFunction;
98+
SemaRef.Diag(e->getExprLoc(), diag::err_sycl_restrict)
99+
<< KernelCallRecursiveFunction;
100100
SemaRef.Diag(Callee->getSourceRange().getBegin(),
101-
diag::note_sycl_recursive_function_declared_here)
102-
<< KernelCallRecursiveFunction;
101+
diag::note_sycl_recursive_function_declared_here)
102+
<< KernelCallRecursiveFunction;
103103
}
104104

105105
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Callee))
106106
if (Method->isVirtual())
107-
SemaRef.Diag(e->getExprLoc(), diag::err_sycl_restrict) <<
108-
KernelCallVirtualFunction;
107+
SemaRef.Diag(e->getExprLoc(), diag::err_sycl_restrict)
108+
<< KernelCallVirtualFunction;
109109

110110
CheckSYCLType(Callee->getReturnType(), Callee->getSourceRange());
111111

@@ -116,8 +116,8 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
116116
}
117117
}
118118
} else if (!SemaRef.getLangOpts().SYCLAllowFuncPtr)
119-
SemaRef.Diag(e->getExprLoc(), diag::err_sycl_restrict) <<
120-
KernelCallFunctionPointer;
119+
SemaRef.Diag(e->getExprLoc(), diag::err_sycl_restrict)
120+
<< KernelCallFunctionPointer;
121121
return true;
122122
}
123123

@@ -178,8 +178,8 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
178178
if (VarDecl *VD = dyn_cast<VarDecl>(E->getMemberDecl())) {
179179
bool IsConst = VD->getType().getNonReferenceType().isConstQualified();
180180
if (VD->isStaticDataMember() && !IsConst)
181-
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict) <<
182-
KernelNonConstStaticDataVariable;
181+
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict)
182+
<< KernelNonConstStaticDataVariable;
183183
}
184184
return true;
185185
}
@@ -190,24 +190,24 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
190190
bool IsConst = VD->getType().getNonReferenceType().isConstQualified();
191191
if (!IsConst && VD->hasGlobalStorage() && !VD->isStaticLocal() &&
192192
!VD->isStaticDataMember() && !isa<ParmVarDecl>(VD))
193-
SemaRef.Diag(E->getLocation(), diag::err_sycl_restrict) <<
194-
KernelGlobalVariable;
193+
SemaRef.Diag(E->getLocation(), diag::err_sycl_restrict)
194+
<< KernelGlobalVariable;
195195
}
196196
return true;
197197
}
198198

199199
bool VisitCXXNewExpr(CXXNewExpr *E) {
200-
// Memory storage allocation is not allowed in kernels.
201-
// All memory allocation for the device is done on
202-
// the host using accessor classes. Consequently, the default
203-
// allocation operator new overloads that allocate
204-
// storage are disallowed in a SYCL kernel. The placement
205-
// new operator and any user-defined overloads that
206-
// do not allocate storage are permitted.
200+
// Memory storage allocation is not allowed in kernels.
201+
// All memory allocation for the device is done on
202+
// the host using accessor classes. Consequently, the default
203+
// allocation operator new overloads that allocate
204+
// storage are disallowed in a SYCL kernel. The placement
205+
// new operator and any user-defined overloads that
206+
// do not allocate storage are permitted.
207207
if (FunctionDecl *FD = E->getOperatorNew()) {
208208
if (FD->isReplaceableGlobalAllocationFunction()) {
209-
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict) <<
210-
KernelAllocateStorage;
209+
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict)
210+
<< KernelAllocateStorage;
211211
} else if (FunctionDecl *Def = FD->getDefinition()) {
212212
if (!Def->hasAttr<SYCLDeviceAttr>()) {
213213
Def->addAttr(SYCLDeviceAttr::CreateImplicit(SemaRef.Context));
@@ -219,26 +219,26 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
219219
}
220220

221221
bool VisitCXXThrowExpr(CXXThrowExpr *E) {
222-
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict) <<
223-
KernelUseExceptions;
222+
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict)
223+
<< KernelUseExceptions;
224224
return true;
225225
}
226226

227227
bool VisitCXXCatchStmt(CXXCatchStmt *S) {
228-
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict) <<
229-
KernelUseExceptions;
228+
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict)
229+
<< KernelUseExceptions;
230230
return true;
231231
}
232232

233233
bool VisitCXXTryStmt(CXXTryStmt *S) {
234-
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict) <<
235-
KernelUseExceptions;
234+
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict)
235+
<< KernelUseExceptions;
236236
return true;
237237
}
238238

239239
bool VisitSEHTryStmt(SEHTryStmt *S) {
240-
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict) <<
241-
KernelUseExceptions;
240+
SemaRef.Diag(S->getBeginLoc(), diag::err_sycl_restrict)
241+
<< KernelUseExceptions;
242242
return true;
243243
}
244244

@@ -291,8 +291,8 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
291291
}
292292
}
293293
}
294-
private:
295294

295+
private:
296296
bool CheckSYCLType(QualType Ty, SourceRange Loc) {
297297
if (Ty->isVariableArrayType()) {
298298
SemaRef.Diag(Loc.getBegin(), diag::err_vla_unsupported);
@@ -306,7 +306,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
306306
// FIXME: this seems like a temporary fix for SYCL programs
307307
// that pre-declare, use, but not define OclCXX classes,
308308
// which are later translated into SPIRV types.
309-
if(!CRD->hasDefinition())
309+
if (!CRD->hasDefinition())
310310
return true;
311311

312312
if (CRD->isPolymorphic()) {
@@ -450,9 +450,10 @@ CreateSYCLKernelBody(Sema &S, FunctionDecl *KernelCallerFunc, DeclContext *DC) {
450450
QualType FieldType = Field->getType();
451451
CXXRecordDecl *CRD = FieldType->getAsCXXRecordDecl();
452452
if (CRD && Util::isSyclAccessorType(FieldType)) {
453-
// Since this is an accessor next 3 TargetFuncParams including current
454-
// should be set in __init method: _ValueType*, range<int>, id<int>
455-
const size_t NumParams = 3;
453+
// Since this is an accessor next 4 TargetFuncParams including current
454+
// should be set in __init method: _ValueType*, range<int>, range<int>,
455+
// id<int>
456+
const size_t NumParams = 4;
456457
llvm::SmallVector<DeclRefExpr *, NumParams> ParamDREs(NumParams);
457458
auto TFP = TargetFuncParam;
458459
for (size_t I = 0; I < NumParams; ++TFP, ++I) {
@@ -495,7 +496,7 @@ CreateSYCLKernelBody(Sema &S, FunctionDecl *KernelCallerFunc, DeclContext *DC) {
495496
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
496497
ResultTy = ResultTy.getNonLValueExprType(S.Context);
497498

498-
// __init needs three parameter
499+
// __init needs four parameter
499500
auto ParamItr = InitMethod->param_begin();
500501
// kernel_parameters
501502
llvm::SmallVector<Expr *, NumParams> ParamStmts;
@@ -505,7 +506,10 @@ CreateSYCLKernelBody(Sema &S, FunctionDecl *KernelCallerFunc, DeclContext *DC) {
505506
S, ((*ParamItr++))->getOriginalType(), ParamDREs[1]));
506507
ParamStmts.push_back(getExprForRangeOrOffset(
507508
S, ((*ParamItr++))->getOriginalType(), ParamDREs[2]));
508-
// kernel_obj.accessor.__init(_ValueType*, range<int>, id<int>)
509+
ParamStmts.push_back(getExprForRangeOrOffset(
510+
S, ((*ParamItr++))->getOriginalType(), ParamDREs[3]));
511+
// kernel_obj.accessor.__init(_ValueType*, range<int>, range<int>,
512+
// id<int>)
509513
CXXMemberCallExpr *Call = CXXMemberCallExpr::Create(
510514
S.Context, ME, ParamStmts, ResultTy, VK, SourceLocation());
511515
BodyStmts.push_back(Call);
@@ -643,10 +647,17 @@ static void buildArgTys(ASTContext &Context, CXXRecordDecl *KernelObj,
643647

644648
CreateAndAddPrmDsc(Fld, PointerType);
645649

646-
FieldDecl *RangeFld = getFieldDeclByName(RecordDecl, {"__impl", "Range"});
647-
assert(RangeFld &&
648-
"The accessor must contain the Range from the __impl field");
649-
CreateAndAddPrmDsc(RangeFld, RangeFld->getType());
650+
FieldDecl *AccessRangeFld =
651+
getFieldDeclByName(RecordDecl, {"__impl", "AccessRange"});
652+
assert(AccessRangeFld &&
653+
"The accessor must contain the AccessRange from the __impl field");
654+
CreateAndAddPrmDsc(AccessRangeFld, AccessRangeFld->getType());
655+
656+
FieldDecl *MemRangeFld =
657+
getFieldDeclByName(RecordDecl, {"__impl", "MemRange"});
658+
assert(MemRangeFld &&
659+
"The accessor must contain the MemRange from the __impl field");
660+
CreateAndAddPrmDsc(MemRangeFld, MemRangeFld->getType());
650661

651662
FieldDecl *OffsetFld =
652663
getFieldDeclByName(RecordDecl, {"__impl", "Offset"});
@@ -705,13 +716,22 @@ static void populateIntHeader(SYCLIntegrationHeader &H, const StringRef Name,
705716
const auto *AccTmplTy = cast<ClassTemplateSpecializationDecl>(AccTy);
706717
H.addParamDesc(SYCLIntegrationHeader::kind_accessor,
707718
getAccessTarget(AccTmplTy), Offset);
708-
// ... second descriptor (translated to range kernel parameter):
709-
FieldDecl *RngFld =
710-
getFieldDeclByName(AccTy, {"__impl", "Range"}, &Offset);
711-
uint64_t Sz = Ctx.getTypeSizeInChars(RngFld->getType()).getQuantity();
719+
// ... second descriptor (translated to access range kernel parameter):
720+
FieldDecl *AccessRngFld =
721+
getFieldDeclByName(AccTy, {"__impl", "AccessRange"}, &Offset);
722+
uint64_t Sz =
723+
Ctx.getTypeSizeInChars(AccessRngFld->getType()).getQuantity();
724+
H.addParamDesc(SYCLIntegrationHeader::kind_std_layout,
725+
static_cast<unsigned>(Sz), static_cast<unsigned>(Offset));
726+
// ... third descriptor (translated to mem range kernel parameter):
727+
// Get offset in bytes
728+
Offset = Layout.getFieldOffset(Fld->getFieldIndex()) / 8;
729+
FieldDecl *MemRngFld =
730+
getFieldDeclByName(AccTy, {"__impl", "MemRange"}, &Offset);
731+
Sz = Ctx.getTypeSizeInChars(MemRngFld->getType()).getQuantity();
712732
H.addParamDesc(SYCLIntegrationHeader::kind_std_layout,
713733
static_cast<unsigned>(Sz), static_cast<unsigned>(Offset));
714-
// ... third descriptor (translated to id kernel parameter):
734+
// ... fourth descriptor (translated to id kernel parameter):
715735
// Get offset in bytes
716736
Offset = Layout.getFieldOffset(Fld->getFieldIndex()) / 8;
717737
FieldDecl *OffstFld =

clang/test/CodeGenSYCL/Inputs/sycl.hpp

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,11 @@ class property_list {
6464
template <typename... propertyTN>
6565
property_list(propertyTN... props) {}
6666

67-
template <typename propertyT> bool has_property() const { return true; }
67+
template <typename propertyT>
68+
bool has_property() const { return true; }
6869

69-
template <typename propertyT> propertyT get_property() const {
70+
template <typename propertyT>
71+
propertyT get_property() const {
7072
return propertyT{};
7173
}
7274

@@ -77,12 +79,14 @@ class property_list {
7779

7880
template <int dim>
7981
struct id {
80-
template<typename ...T> id(T...args) {} // fake constructor
82+
template <typename... T>
83+
id(T... args) {} // fake constructor
8184
};
8285

8386
template <int dim>
8487
struct range {
85-
template<typename ...T> range(T...args) {} // fake constructor
88+
template <typename... T>
89+
range(T... args) {} // fake constructor
8690
};
8791

8892
template <int dim>
@@ -91,35 +95,36 @@ struct nd_range {
9195

9296
template <int dim>
9397
struct _ImplT {
94-
range<dim> Range;
95-
id<dim> Offset;
98+
range<dim> AccessRange;
99+
range<dim> MemRange;
100+
id<dim> Offset;
96101
};
97102

98103
template <typename dataT, int dimensions, access::mode accessmode,
99-
access::target accessTarget = access::target::global_buffer,
100-
access::placeholder isPlaceholder = access::placeholder::false_t>
101-
class accessor {
102-
103-
public:
104-
105-
void __init(__global dataT *Ptr, range<dimensions> Range,
106-
id<dimensions> Offset) {
107-
}
108-
void use(void) const {}
109-
template <typename ...T> void use(T...args) { }
110-
template <typename ...T> void use(T...args) const { }
111-
_ImplT<dimensions> __impl;
104+
access::target accessTarget = access::target::global_buffer,
105+
access::placeholder isPlaceholder = access::placeholder::false_t>
106+
class accessor {
112107

108+
public:
109+
void __init(__global dataT *Ptr, range<dimensions> AccessRange,
110+
range<dimensions> MemRange, id<dimensions> Offset) {}
111+
void use(void) const {}
112+
template <typename... T>
113+
void use(T... args) {}
114+
template <typename... T>
115+
void use(T... args) const {}
116+
_ImplT<dimensions> __impl;
113117
};
114118

115119
class kernel {};
116120
class context {};
117121
class device {};
118-
class event{};
122+
class event {};
119123

120124
class queue {
121125
public:
122-
template <typename T> event submit(T cgf) { return event{}; }
126+
template <typename T>
127+
event submit(T cgf) { return event{}; }
123128

124129
void wait() {}
125130
void wait_and_throw() {}
@@ -177,7 +182,8 @@ class buffer {
177182
using const_reference = const value_type &;
178183
using allocator_type = AllocatorT;
179184

180-
template <typename ...ParamTypes> buffer(ParamTypes...args) {} // fake constructor
185+
template <typename... ParamTypes>
186+
buffer(ParamTypes... args) {} // fake constructor
181187

182188
buffer(const range<dimensions> &bufferRange,
183189
const property_list &propList = {}) {}
@@ -221,4 +227,3 @@ class buffer {
221227

222228
} // namespace sycl
223229
} // namespace cl
224-

clang/test/CodeGenSYCL/integration_header.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,25 @@
2525
// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 2014, 4 },
2626
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 4 },
2727
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 5 },
28-
// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 2016, 6 },
2928
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 6 },
29+
// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 2016, 7 },
3030
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 7 },
31+
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 8 },
32+
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 9 },
3133
// CHECK-EMPTY:
3234
// CHECK-NEXT: //--- _ZTSN16second_namespace13second_kernelIcEE
3335
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 },
3436
// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 2016, 4 },
3537
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 4 },
3638
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 5 },
39+
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 6 },
3740
// CHECK-EMPTY:
3841
// CHECK-NEXT: //--- _ZTS12third_kernelILi1Ei5pointIZ4mainE1XEE
3942
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 4, 0 },
4043
// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 2016, 4 },
4144
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 4 },
4245
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 5 },
46+
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 6 },
4347
// CHECK-EMPTY:
4448
// CHECK-NEXT: };
4549
//

clang/test/CodeGenSYCL/struct_kernel_param.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// CHECK-NEXT: { kernel_param_kind_t::kind_accessor, 2014, 0 },
77
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 0 },
88
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 1 },
9+
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 1, 2 },
910
// CHECK-NEXT: { kernel_param_kind_t::kind_std_layout, 24, 4 },
1011
// CHECK-EMPTY:
1112
// CHECK-NEXT:};

clang/test/SemaSYCL/Inputs/sycl.hpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ struct id {
5151

5252
template <int dim>
5353
struct _ImplT {
54-
range<dim> Range;
54+
range<dim> AccessRange;
55+
range<dim> MemRange;
5556
id<dim> Offset;
5657
};
5758

@@ -63,10 +64,8 @@ class accessor {
6364
public:
6465
void use(void) const {}
6566
void use(void*) const {}
66-
void __init(__global dataT *Ptr, range<dimensions> Range,
67-
id<dimensions> Offset) {
68-
}
69-
67+
void __init(__global dataT *Ptr, range<dimensions> AccessRange,
68+
range<dimensions> MemRange, id<dimensions> Offset) {}
7069

7170
_ImplT<dimensions> __impl;
7271
};

0 commit comments

Comments
 (0)