@@ -80,6 +80,14 @@ class Util {
80
80
// / half class.
81
81
static bool isSyclHalfType (const QualType &Ty);
82
82
83
+ // / Checks whether given clang type is a full specialization of the SYCL
84
+ // / property_list class.
85
+ static bool isPropertyListType (const QualType &Ty);
86
+
87
+ // / Checks whether given clang type is a full specialization of the SYCL
88
+ // / buffer_location class.
89
+ static bool isSyclBufferLocationType (const QualType &Ty);
90
+
83
91
// / Checks whether given clang type is a standard SYCL API class with given
84
92
// / name.
85
93
// / \param Ty the clang type being checked
@@ -1076,6 +1084,66 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler {
1076
1084
return false ;
1077
1085
}
1078
1086
1087
+ void checkPropertyListType (TemplateArgument PropList, SourceLocation Loc) {
1088
+ if (PropList.getKind () != TemplateArgument::ArgKind::Type) {
1089
+ SemaRef.Diag (Loc,
1090
+ diag::err_sycl_invalid_accessor_property_template_param);
1091
+ return ;
1092
+ }
1093
+ QualType PropListTy = PropList.getAsType ();
1094
+ if (!Util::isPropertyListType (PropListTy)) {
1095
+ SemaRef.Diag (Loc,
1096
+ diag::err_sycl_invalid_accessor_property_template_param);
1097
+ return ;
1098
+ }
1099
+ const auto *PropListDecl =
1100
+ cast<ClassTemplateSpecializationDecl>(PropListTy->getAsRecordDecl ());
1101
+ if (PropListDecl->getTemplateArgs ().size () != 1 ) {
1102
+ SemaRef.Diag (Loc, diag::err_sycl_invalid_property_list_param_number)
1103
+ << " property_list" ;
1104
+ return ;
1105
+ }
1106
+ const auto TemplArg = PropListDecl->getTemplateArgs ()[0 ];
1107
+ if (TemplArg.getKind () != TemplateArgument::ArgKind::Pack) {
1108
+ SemaRef.Diag (Loc, diag::err_sycl_invalid_property_list_template_param)
1109
+ << /* property_list*/ 0 << /* parameter pack*/ 0 ;
1110
+ return ;
1111
+ }
1112
+ for (TemplateArgument::pack_iterator Prop = TemplArg.pack_begin ();
1113
+ Prop != TemplArg.pack_end (); ++Prop) {
1114
+ if (Prop->getKind () != TemplateArgument::ArgKind::Type) {
1115
+ SemaRef.Diag (Loc, diag::err_sycl_invalid_property_list_template_param)
1116
+ << /* property_list pack argument*/ 1 << /* type*/ 1 ;
1117
+ return ;
1118
+ }
1119
+ QualType PropTy = Prop->getAsType ();
1120
+ if (Util::isSyclBufferLocationType (PropTy))
1121
+ checkBufferLocationType (PropTy, Loc);
1122
+ }
1123
+ }
1124
+
1125
+ void checkBufferLocationType (QualType PropTy, SourceLocation Loc) {
1126
+ const auto *PropDecl =
1127
+ dyn_cast<ClassTemplateSpecializationDecl>(PropTy->getAsRecordDecl ());
1128
+ if (PropDecl->getTemplateArgs ().size () != 1 ) {
1129
+ SemaRef.Diag (Loc, diag::err_sycl_invalid_property_list_param_number)
1130
+ << " buffer_location" ;
1131
+ return ;
1132
+ }
1133
+ const auto BufferLoc = PropDecl->getTemplateArgs ()[0 ];
1134
+ if (BufferLoc.getKind () != TemplateArgument::ArgKind::Integral) {
1135
+ SemaRef.Diag (Loc, diag::err_sycl_invalid_property_list_template_param)
1136
+ << /* buffer_location*/ 2 << /* non-negative integer*/ 2 ;
1137
+ return ;
1138
+ }
1139
+ int LocationID = static_cast <int >(BufferLoc.getAsIntegral ().getExtValue ());
1140
+ if (LocationID < 0 ) {
1141
+ SemaRef.Diag (Loc, diag::err_sycl_invalid_property_list_template_param)
1142
+ << /* buffer_location*/ 2 << /* non-negative integer*/ 2 ;
1143
+ return ;
1144
+ }
1145
+ }
1146
+
1079
1147
void checkAccessorType (QualType Ty, SourceRange Loc) {
1080
1148
assert (Util::isSyclAccessorType (Ty) &&
1081
1149
" Should only be called on SYCL accessor types." );
@@ -1087,6 +1155,8 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler {
1087
1155
TemplateArgument TA = TAL.get (0 );
1088
1156
const QualType TemplateArgTy = TA.getAsType ();
1089
1157
1158
+ if (TAL.size () > 5 )
1159
+ checkPropertyListType (TAL.get (5 ), Loc.getBegin ());
1090
1160
llvm::DenseSet<QualType> Visited;
1091
1161
checkSYCLType (SemaRef, TemplateArgTy, Loc, Visited);
1092
1162
}
@@ -1158,8 +1228,9 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
1158
1228
1159
1229
void addParam (ParamDesc newParamDesc, QualType FieldTy) {
1160
1230
// Create a new ParmVarDecl based on the new info.
1231
+ ASTContext &Ctx = SemaRef.getASTContext ();
1161
1232
auto *NewParam = ParmVarDecl::Create (
1162
- SemaRef. getASTContext () , KernelDecl, SourceLocation (), SourceLocation (),
1233
+ Ctx , KernelDecl, SourceLocation (), SourceLocation (),
1163
1234
std::get<1 >(newParamDesc), std::get<0 >(newParamDesc),
1164
1235
std::get<2 >(newParamDesc), SC_None, /* DefArg*/ nullptr );
1165
1236
NewParam->setScopeInfo (0 , Params.size ());
@@ -1169,11 +1240,56 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
1169
1240
Params.push_back (NewParam);
1170
1241
}
1171
1242
1243
+ // Handle accessor properties. If any properties were found in
1244
+ // the property_list - add the appropriate attributes to ParmVarDecl.
1245
+ void handleAccessorPropertyList (ParmVarDecl *Param,
1246
+ const CXXRecordDecl *RecordDecl,
1247
+ SourceLocation Loc) {
1248
+ const auto *AccTy = cast<ClassTemplateSpecializationDecl>(RecordDecl);
1249
+ // TODO: when SYCL headers' part is ready - replace this 'if' with an error
1250
+ if (AccTy->getTemplateArgs ().size () < 6 )
1251
+ return ;
1252
+ const auto PropList = cast<TemplateArgument>(AccTy->getTemplateArgs ()[5 ]);
1253
+ QualType PropListTy = PropList.getAsType ();
1254
+ const auto *PropListDecl =
1255
+ cast<ClassTemplateSpecializationDecl>(PropListTy->getAsRecordDecl ());
1256
+ const auto TemplArg = PropListDecl->getTemplateArgs ()[0 ];
1257
+ // Move through TemplateArgs list of a property list and search for
1258
+ // properties. If found - apply the appropriate attribute to ParmVarDecl.
1259
+ for (TemplateArgument::pack_iterator Prop = TemplArg.pack_begin ();
1260
+ Prop != TemplArg.pack_end (); ++Prop) {
1261
+ QualType PropTy = Prop->getAsType ();
1262
+ if (Util::isSyclBufferLocationType (PropTy))
1263
+ handleBufferLocationProperty (Param, PropTy, Loc);
1264
+ }
1265
+ }
1266
+
1267
+ // Obtain an integer value stored in a template parameter of buffer_location
1268
+ // property to pass it to buffer_location kernel attribute
1269
+ void handleBufferLocationProperty (ParmVarDecl *Param, QualType PropTy,
1270
+ SourceLocation Loc) {
1271
+ // If we have more than 1 buffer_location properties on a single
1272
+ // accessor - emit an error
1273
+ if (Param->hasAttr <SYCLIntelBufferLocationAttr>()) {
1274
+ SemaRef.Diag (Loc, diag::err_sycl_compiletime_property_duplication)
1275
+ << " buffer_location" ;
1276
+ return ;
1277
+ }
1278
+ ASTContext &Ctx = SemaRef.getASTContext ();
1279
+ const auto *PropDecl =
1280
+ cast<ClassTemplateSpecializationDecl>(PropTy->getAsRecordDecl ());
1281
+ const auto BufferLoc = PropDecl->getTemplateArgs ()[0 ];
1282
+ int LocationID = static_cast <int >(BufferLoc.getAsIntegral ().getExtValue ());
1283
+ Param->addAttr (
1284
+ SYCLIntelBufferLocationAttr::CreateImplicit (Ctx, LocationID));
1285
+ }
1286
+
1172
1287
// All special SYCL objects must have __init method. We extract types for
1173
1288
// kernel parameters from __init method parameters. We will use __init method
1174
1289
// and kernel parameters which we build here to initialize special objects in
1175
1290
// the kernel body.
1176
- bool handleSpecialType (FieldDecl *FD, QualType FieldTy) {
1291
+ bool handleSpecialType (FieldDecl *FD, QualType FieldTy,
1292
+ bool isAccessorType = false ) {
1177
1293
const auto *RecordDecl = FieldTy->getAsCXXRecordDecl ();
1178
1294
assert (RecordDecl && " The accessor/sampler must be a RecordDecl" );
1179
1295
CXXMethodDecl *InitMethod = getMethodByName (RecordDecl, InitMethodName);
@@ -1182,8 +1298,13 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
1182
1298
// Don't do -1 here because we count on this to be the first parameter added
1183
1299
// (if any).
1184
1300
size_t ParamIndex = Params.size ();
1185
- for (const ParmVarDecl *Param : InitMethod->parameters ())
1186
- addParam (FD, Param->getType ().getCanonicalType ());
1301
+ for (const ParmVarDecl *Param : InitMethod->parameters ()) {
1302
+ QualType ParamTy = Param->getType ();
1303
+ addParam (FD, ParamTy.getCanonicalType ());
1304
+ if (ParamTy.getTypePtr ()->isPointerType () && isAccessorType)
1305
+ handleAccessorPropertyList (Params.back (), RecordDecl,
1306
+ FD->getLocation ());
1307
+ }
1187
1308
LastParamIndex = ParamIndex;
1188
1309
return true ;
1189
1310
}
@@ -1253,14 +1374,18 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
1253
1374
// Don't do -1 here because we count on this to be the first parameter added
1254
1375
// (if any).
1255
1376
size_t ParamIndex = Params.size ();
1256
- for (const ParmVarDecl *Param : InitMethod->parameters ())
1257
- addParam (BS, Param->getType ().getCanonicalType ());
1377
+ for (const ParmVarDecl *Param : InitMethod->parameters ()) {
1378
+ QualType ParamTy = Param->getType ();
1379
+ addParam (BS, ParamTy.getCanonicalType ());
1380
+ if (ParamTy.getTypePtr ()->isPointerType ())
1381
+ handleAccessorPropertyList (Params.back (), RecordDecl, BS.getBeginLoc ());
1382
+ }
1258
1383
LastParamIndex = ParamIndex;
1259
1384
return true ;
1260
1385
}
1261
1386
1262
1387
bool handleSyclAccessorType (FieldDecl *FD, QualType FieldTy) final {
1263
- return handleSpecialType (FD, FieldTy);
1388
+ return handleSpecialType (FD, FieldTy, /* isAccessorType */ true );
1264
1389
}
1265
1390
1266
1391
bool handleSyclSamplerType (FieldDecl *FD, QualType FieldTy) final {
@@ -2834,6 +2959,23 @@ bool Util::isSyclSpecConstantType(const QualType &Ty) {
2834
2959
return matchQualifiedTypeName (Ty, Scopes);
2835
2960
}
2836
2961
2962
+ bool Util::isPropertyListType (const QualType &Ty) {
2963
+ return isSyclType (Ty, " property_list" , true /* Tmpl*/ );
2964
+ }
2965
+
2966
+ bool Util::isSyclBufferLocationType (const QualType &Ty) {
2967
+ const StringRef &Name = " buffer_location" ;
2968
+ std::array<DeclContextDesc, 4 > Scopes = {
2969
+ Util::DeclContextDesc{clang::Decl::Kind::Namespace, " cl" },
2970
+ Util::DeclContextDesc{clang::Decl::Kind::Namespace, " sycl" },
2971
+ // TODO: this doesn't belong to property namespace, instead it shall be
2972
+ // in its own namespace. Change it, when the actual implementation in SYCL
2973
+ // headers is ready
2974
+ Util::DeclContextDesc{clang::Decl::Kind::Namespace, " property" },
2975
+ Util::DeclContextDesc{Decl::Kind::ClassTemplateSpecialization, Name}};
2976
+ return matchQualifiedTypeName (Ty, Scopes);
2977
+ }
2978
+
2837
2979
bool Util::isSyclType (const QualType &Ty, StringRef Name, bool Tmpl) {
2838
2980
Decl::Kind ClassDeclKind =
2839
2981
Tmpl ? Decl::Kind::ClassTemplateSpecialization : Decl::Kind::CXXRecord;
0 commit comments