@@ -80,6 +80,14 @@ class Util {
8080  // / half class.
8181  static  bool  isSyclHalfType (const  QualType &Ty);
8282
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+ 
8391  // / Checks whether given clang type is a standard SYCL API class with given
8492  // / name.
8593  // / \param Ty    the clang type being checked
@@ -1076,6 +1084,66 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler {
10761084    return  false ;
10771085  }
10781086
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+ 
10791147  void  checkAccessorType (QualType Ty, SourceRange Loc) {
10801148    assert (Util::isSyclAccessorType (Ty) &&
10811149           " Should only be called on SYCL accessor types." 
@@ -1087,6 +1155,8 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler {
10871155      TemplateArgument TA = TAL.get (0 );
10881156      const  QualType TemplateArgTy = TA.getAsType ();
10891157
1158+       if  (TAL.size () > 5 )
1159+         checkPropertyListType (TAL.get (5 ), Loc.getBegin ());
10901160      llvm::DenseSet<QualType> Visited;
10911161      checkSYCLType (SemaRef, TemplateArgTy, Loc, Visited);
10921162    }
@@ -1158,8 +1228,9 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
11581228
11591229  void  addParam (ParamDesc newParamDesc, QualType FieldTy) {
11601230    //  Create a new ParmVarDecl based on the new info.
1231+     ASTContext &Ctx = SemaRef.getASTContext ();
11611232    auto  *NewParam = ParmVarDecl::Create (
1162-         SemaRef. getASTContext () , KernelDecl, SourceLocation (), SourceLocation (),
1233+         Ctx , KernelDecl, SourceLocation (), SourceLocation (),
11631234        std::get<1 >(newParamDesc), std::get<0 >(newParamDesc),
11641235        std::get<2 >(newParamDesc), SC_None, /* DefArg*/ nullptr );
11651236    NewParam->setScopeInfo (0 , Params.size ());
@@ -1169,11 +1240,56 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
11691240    Params.push_back (NewParam);
11701241  }
11711242
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+ 
11721287  //  All special SYCL objects must have __init method. We extract types for
11731288  //  kernel parameters from __init method parameters. We will use __init method
11741289  //  and kernel parameters which we build here to initialize special objects in
11751290  //  the kernel body.
1176-   bool  handleSpecialType (FieldDecl *FD, QualType FieldTy) {
1291+   bool  handleSpecialType (FieldDecl *FD, QualType FieldTy,
1292+                          bool  isAccessorType = false ) {
11771293    const  auto  *RecordDecl = FieldTy->getAsCXXRecordDecl ();
11781294    assert (RecordDecl && " The accessor/sampler must be a RecordDecl" 
11791295    CXXMethodDecl *InitMethod = getMethodByName (RecordDecl, InitMethodName);
@@ -1182,8 +1298,13 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
11821298    //  Don't do -1 here because we count on this to be the first parameter added
11831299    //  (if any).
11841300    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+     }
11871308    LastParamIndex = ParamIndex;
11881309    return  true ;
11891310  }
@@ -1253,14 +1374,18 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
12531374    //  Don't do -1 here because we count on this to be the first parameter added
12541375    //  (if any).
12551376    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+     }
12581383    LastParamIndex = ParamIndex;
12591384    return  true ;
12601385  }
12611386
12621387  bool  handleSyclAccessorType (FieldDecl *FD, QualType FieldTy) final  {
1263-     return  handleSpecialType (FD, FieldTy);
1388+     return  handleSpecialType (FD, FieldTy,  /* isAccessorType */   true );
12641389  }
12651390
12661391  bool  handleSyclSamplerType (FieldDecl *FD, QualType FieldTy) final  {
@@ -2834,6 +2959,23 @@ bool Util::isSyclSpecConstantType(const QualType &Ty) {
28342959  return  matchQualifiedTypeName (Ty, Scopes);
28352960}
28362961
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+ 
28372979bool  Util::isSyclType (const  QualType &Ty, StringRef Name, bool  Tmpl) {
28382980  Decl::Kind ClassDeclKind =
28392981      Tmpl ? Decl::Kind::ClassTemplateSpecialization : Decl::Kind::CXXRecord;
0 commit comments