Skip to content

Commit

Permalink
Merge branch 'sycl' into test-optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
bader authored Aug 5, 2020
2 parents d5ff978 + 414c1e5 commit 1be5f2d
Show file tree
Hide file tree
Showing 52 changed files with 811 additions and 192 deletions.
6 changes: 3 additions & 3 deletions buildbot/dependency.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ ocl_cpu_rt_ver=2020.10.7.0.15
# https://github.com/intel/llvm/releases/download/2020-WW31/win-oclcpuexp-2020.10.7.0.15_rel.zip
ocl_cpu_rt_ver_win=2020.10.7.0.15
# Same GPU driver supports Level Zero and OpenCL:
# https://github.com/intel/compute-runtime/releases/tag/20.25.17111
# https://github.com/intel/compute-runtime/releases/tag/20.29.17408
ocl_gpu_rt_ver=20.29.17408
# Same GPU driver supports Level Zero and OpenCL:
# https://downloadmirror.intel.com/29674/a08/igfx_win10_100.8336.zip
ocl_gpu_rt_ver_win=27.20.100.8336
intel_sycl_ver=build
# https://github.com/oneapi-src/oneTBB/releases/download/v2020.2/tbb-2020.2-lin.tgz
# TODO provide URL for Linux TBB driver
tbb_ver=2021.1.8.515
# https://github.com/oneapi-src/oneTBB/releases/download/v2020.2/tbb-2020.2-win.zip
# TODO provide URL for Windows TBB driver
tbb_ver_win=2021.1.8.514
# https://github.com/intel/llvm/releases/download/2020-WW31/fpgaemu-2020.10.7.0.15_rel.tar.gz
ocl_fpga_emu_ver=2020.10.7.0.15
Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,7 @@ def SYCLDevice : InheritableAttr {
def SYCLKernel : InheritableAttr {
let Spellings = [Clang<"sycl_kernel">];
let Subjects = SubjectList<[FunctionTmpl]>;
let LangOpts = [SYCLIsDevice];
let LangOpts = [SYCLIsHost, SYCLIsDevice];
let Documentation = [SYCLKernelDocs];
}

Expand Down Expand Up @@ -1188,6 +1188,14 @@ def SYCLDeviceIndirectlyCallable : InheritableAttr {
let PragmaAttributeSupport = 0;
}

def SYCLIntelBufferLocation : InheritableAttr {
// No spelling, as this attribute can't be created in the source code.
let Spellings = [];
let Args = [UnsignedArgument<"LocationID">];
let LangOpts = [SYCLIsDevice, SYCLIsHost];
let Documentation = [SYCLIntelBufferLocationAttrDocs];
}

def SYCLIntelKernelArgsRestrict : InheritableAttr {
let Spellings = [ CXX11<"intel", "kernel_args_restrict"> ];
let Subjects = SubjectList<[Function], ErrorDiag>;
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -1994,6 +1994,25 @@ can be lowered.
}];
}

def SYCLIntelBufferLocationAttrDocs : Documentation {
let Category = DocCatFunction;
let Heading = "kernel_args_buffer_location";
let Content = [{
This attribute is implicitly added to OpenCL pointer kernel parameters generated
from a SYCL kernel object. It lacks a spelling, as it is not intended to be used
by the programmer.

This attribute causes clang to generate metadata on the OpenCL kernel containing
the number of kernel parameters. The metadata contains an integer that is set
according to the values passed through the ``accessor`` property
``buffer_location``. These values are mapped to the actual locations of the
global buffers (such as DDR, QDR, etc) and applied to pointer kernel parameters.
Number of metadata arguments is the same as a number of kernel parameters, so
any parameter that isn't an ``accessor`` with ``buffer_location`` property is
annotated by '-1' in the metadata node.
}];
}

def SYCLIntelKernelArgsRestrictDocs : Documentation {
let Category = DocCatVariable;
let Heading = "kernel_args_restrict";
Expand Down
14 changes: 12 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10919,8 +10919,8 @@ def warn_sycl_kernel_invalid_template_param_type : Warning<
"template parameter of a function template with the 'sycl_kernel' attribute"
" cannot be a non-type template parameter">, InGroup<IgnoredAttributes>;
def warn_sycl_kernel_num_of_function_params : Warning<
"function template with 'sycl_kernel' attribute must have a single parameter">,
InGroup<IgnoredAttributes>;
"function template with 'sycl_kernel' attribute must have at least one"
" parameter">, InGroup<IgnoredAttributes>;
def warn_sycl_kernel_return_type : Warning<
"function template with 'sycl_kernel' attribute must have a 'void' return type">,
InGroup<IgnoredAttributes>;
Expand Down Expand Up @@ -10980,6 +10980,16 @@ def warn_boolean_attribute_argument_is_not_valid: Warning<
def err_sycl_attibute_cannot_be_applied_here
: Error<"%0 attribute cannot be applied to a "
"static function or function in an anonymous namespace">;
def err_sycl_compiletime_property_duplication : Error<
"Can't apply %0 property twice to the same accessor">;
def err_sycl_invalid_property_list_param_number : Error<
"%0 must have exactly one template parameter">;
def err_sycl_invalid_accessor_property_template_param : Error<
"Fifth template parameter of the accessor must be of a property_list type">;
def err_sycl_invalid_property_list_template_param : Error<
"%select{property_list|property_list pack argument|buffer_location}0 "
"template parameter must be a "
"%select{parameter pack|type|non-negative integer}1">;
def warn_sycl_attibute_function_raw_ptr
: Warning<"SYCL 1.2.1 specification does not allow %0 attribute applied "
"to a function with a raw pointer "
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (D && D->hasAttr<CFICanonicalJumpTableAttr>())
Fn->addFnAttr("cfi-canonical-jump-table");

if (getLangOpts().SYCLIsHost && D && D->hasAttr<SYCLKernelAttr>())
Fn->addFnAttr("sycl_kernel");

if (getLangOpts().OpenCL || getLangOpts().SYCLIsDevice) {
// Add metadata for a kernel function.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,9 @@ void CodeGenModule::GenOpenCLArgMetadata(llvm::Function *Fn,
// MDNode for the kernel argument names.
SmallVector<llvm::Metadata *, 8> argNames;

// MDNode for the intel_buffer_location attribute.
SmallVector<llvm::Metadata *, 8> argSYCLBufferLocationAttr;

if (FD && CGF)
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
const ParmVarDecl *parm = FD->getParamDecl(i);
Expand Down Expand Up @@ -1536,6 +1539,14 @@ void CodeGenModule::GenOpenCLArgMetadata(llvm::Function *Fn,

// Get argument name.
argNames.push_back(llvm::MDString::get(VMContext, parm->getName()));

auto *SYCLBufferLocationAttr =
parm->getAttr<SYCLIntelBufferLocationAttr>();
argSYCLBufferLocationAttr.push_back(
(SYCLBufferLocationAttr)
? llvm::ConstantAsMetadata::get(CGF->Builder.getInt32(
SYCLBufferLocationAttr->getLocationID()))
: llvm::ConstantAsMetadata::get(CGF->Builder.getInt32(-1)));
}

Fn->setMetadata("kernel_arg_addr_space",
Expand All @@ -1551,6 +1562,9 @@ void CodeGenModule::GenOpenCLArgMetadata(llvm::Function *Fn,
if (getCodeGenOpts().EmitOpenCLArgMetadata)
Fn->setMetadata("kernel_arg_name",
llvm::MDNode::get(VMContext, argNames));
if (LangOpts.SYCLIsDevice)
Fn->setMetadata("kernel_arg_buffer_location",
llvm::MDNode::get(VMContext, argSYCLBufferLocationAttr));
}

/// Determines whether the language options require us to model
Expand Down
13 changes: 7 additions & 6 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7188,15 +7188,16 @@ static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate();
assert(FT && "Function template is expected");

// Function template must have at least two template parameters.
// Function template must have at least two template parameters so it
// can be used in OpenCL kernel generation.
const TemplateParameterList *TL = FT->getTemplateParameters();
if (TL->size() < 2) {
if (S.LangOpts.SYCLIsDevice && TL->size() < 2) {
S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params);
return;
}

// Template parameters must be typenames.
for (unsigned I = 0; I < 2; ++I) {
// The first two template parameters must be typenames.
for (unsigned I = 0; I < 2 && I < TL->size(); ++I) {
const NamedDecl *TParam = TL->getParam(I);
if (isa<NonTypeTemplateParmDecl>(TParam)) {
S.Diag(FT->getLocation(),
Expand All @@ -7205,8 +7206,8 @@ static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}

// Function must have at least one argument.
if (getFunctionOrMethodNumParams(D) != 1) {
// Function must have at least one parameter.
if (getFunctionOrMethodNumParams(D) < 1) {
S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params);
return;
}
Expand Down
156 changes: 149 additions & 7 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ class Util {
/// half class.
static bool isSyclHalfType(const QualType &Ty);

/// Checks whether given clang type is a full specialization of the SYCL
/// property_list class.
static bool isPropertyListType(const QualType &Ty);

/// Checks whether given clang type is a full specialization of the SYCL
/// buffer_location class.
static bool isSyclBufferLocationType(const QualType &Ty);

/// Checks whether given clang type is a standard SYCL API class with given
/// name.
/// \param Ty the clang type being checked
Expand Down Expand Up @@ -1076,6 +1084,66 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler {
return false;
}

void checkPropertyListType(TemplateArgument PropList, SourceLocation Loc) {
if (PropList.getKind() != TemplateArgument::ArgKind::Type) {
SemaRef.Diag(Loc,
diag::err_sycl_invalid_accessor_property_template_param);
return;
}
QualType PropListTy = PropList.getAsType();
if (!Util::isPropertyListType(PropListTy)) {
SemaRef.Diag(Loc,
diag::err_sycl_invalid_accessor_property_template_param);
return;
}
const auto *PropListDecl =
cast<ClassTemplateSpecializationDecl>(PropListTy->getAsRecordDecl());
if (PropListDecl->getTemplateArgs().size() != 1) {
SemaRef.Diag(Loc, diag::err_sycl_invalid_property_list_param_number)
<< "property_list";
return;
}
const auto TemplArg = PropListDecl->getTemplateArgs()[0];
if (TemplArg.getKind() != TemplateArgument::ArgKind::Pack) {
SemaRef.Diag(Loc, diag::err_sycl_invalid_property_list_template_param)
<< /*property_list*/ 0 << /*parameter pack*/ 0;
return;
}
for (TemplateArgument::pack_iterator Prop = TemplArg.pack_begin();
Prop != TemplArg.pack_end(); ++Prop) {
if (Prop->getKind() != TemplateArgument::ArgKind::Type) {
SemaRef.Diag(Loc, diag::err_sycl_invalid_property_list_template_param)
<< /*property_list pack argument*/ 1 << /*type*/ 1;
return;
}
QualType PropTy = Prop->getAsType();
if (Util::isSyclBufferLocationType(PropTy))
checkBufferLocationType(PropTy, Loc);
}
}

void checkBufferLocationType(QualType PropTy, SourceLocation Loc) {
const auto *PropDecl =
dyn_cast<ClassTemplateSpecializationDecl>(PropTy->getAsRecordDecl());
if (PropDecl->getTemplateArgs().size() != 1) {
SemaRef.Diag(Loc, diag::err_sycl_invalid_property_list_param_number)
<< "buffer_location";
return;
}
const auto BufferLoc = PropDecl->getTemplateArgs()[0];
if (BufferLoc.getKind() != TemplateArgument::ArgKind::Integral) {
SemaRef.Diag(Loc, diag::err_sycl_invalid_property_list_template_param)
<< /*buffer_location*/ 2 << /*non-negative integer*/ 2;
return;
}
int LocationID = static_cast<int>(BufferLoc.getAsIntegral().getExtValue());
if (LocationID < 0) {
SemaRef.Diag(Loc, diag::err_sycl_invalid_property_list_template_param)
<< /*buffer_location*/ 2 << /*non-negative integer*/ 2;
return;
}
}

void checkAccessorType(QualType Ty, SourceRange Loc) {
assert(Util::isSyclAccessorType(Ty) &&
"Should only be called on SYCL accessor types.");
Expand All @@ -1087,6 +1155,8 @@ class SyclKernelFieldChecker : public SyclKernelFieldHandler {
TemplateArgument TA = TAL.get(0);
const QualType TemplateArgTy = TA.getAsType();

if (TAL.size() > 5)
checkPropertyListType(TAL.get(5), Loc.getBegin());
llvm::DenseSet<QualType> Visited;
checkSYCLType(SemaRef, TemplateArgTy, Loc, Visited);
}
Expand Down Expand Up @@ -1158,8 +1228,9 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {

void addParam(ParamDesc newParamDesc, QualType FieldTy) {
// Create a new ParmVarDecl based on the new info.
ASTContext &Ctx = SemaRef.getASTContext();
auto *NewParam = ParmVarDecl::Create(
SemaRef.getASTContext(), KernelDecl, SourceLocation(), SourceLocation(),
Ctx, KernelDecl, SourceLocation(), SourceLocation(),
std::get<1>(newParamDesc), std::get<0>(newParamDesc),
std::get<2>(newParamDesc), SC_None, /*DefArg*/ nullptr);
NewParam->setScopeInfo(0, Params.size());
Expand All @@ -1169,11 +1240,56 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
Params.push_back(NewParam);
}

// Handle accessor properties. If any properties were found in
// the property_list - add the appropriate attributes to ParmVarDecl.
void handleAccessorPropertyList(ParmVarDecl *Param,
const CXXRecordDecl *RecordDecl,
SourceLocation Loc) {
const auto *AccTy = cast<ClassTemplateSpecializationDecl>(RecordDecl);
// TODO: when SYCL headers' part is ready - replace this 'if' with an error
if (AccTy->getTemplateArgs().size() < 6)
return;
const auto PropList = cast<TemplateArgument>(AccTy->getTemplateArgs()[5]);
QualType PropListTy = PropList.getAsType();
const auto *PropListDecl =
cast<ClassTemplateSpecializationDecl>(PropListTy->getAsRecordDecl());
const auto TemplArg = PropListDecl->getTemplateArgs()[0];
// Move through TemplateArgs list of a property list and search for
// properties. If found - apply the appropriate attribute to ParmVarDecl.
for (TemplateArgument::pack_iterator Prop = TemplArg.pack_begin();
Prop != TemplArg.pack_end(); ++Prop) {
QualType PropTy = Prop->getAsType();
if (Util::isSyclBufferLocationType(PropTy))
handleBufferLocationProperty(Param, PropTy, Loc);
}
}

// Obtain an integer value stored in a template parameter of buffer_location
// property to pass it to buffer_location kernel attribute
void handleBufferLocationProperty(ParmVarDecl *Param, QualType PropTy,
SourceLocation Loc) {
// If we have more than 1 buffer_location properties on a single
// accessor - emit an error
if (Param->hasAttr<SYCLIntelBufferLocationAttr>()) {
SemaRef.Diag(Loc, diag::err_sycl_compiletime_property_duplication)
<< "buffer_location";
return;
}
ASTContext &Ctx = SemaRef.getASTContext();
const auto *PropDecl =
cast<ClassTemplateSpecializationDecl>(PropTy->getAsRecordDecl());
const auto BufferLoc = PropDecl->getTemplateArgs()[0];
int LocationID = static_cast<int>(BufferLoc.getAsIntegral().getExtValue());
Param->addAttr(
SYCLIntelBufferLocationAttr::CreateImplicit(Ctx, LocationID));
}

// All special SYCL objects must have __init method. We extract types for
// kernel parameters from __init method parameters. We will use __init method
// and kernel parameters which we build here to initialize special objects in
// the kernel body.
bool handleSpecialType(FieldDecl *FD, QualType FieldTy) {
bool handleSpecialType(FieldDecl *FD, QualType FieldTy,
bool isAccessorType = false) {
const auto *RecordDecl = FieldTy->getAsCXXRecordDecl();
assert(RecordDecl && "The accessor/sampler must be a RecordDecl");
CXXMethodDecl *InitMethod = getMethodByName(RecordDecl, InitMethodName);
Expand All @@ -1182,8 +1298,13 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
// Don't do -1 here because we count on this to be the first parameter added
// (if any).
size_t ParamIndex = Params.size();
for (const ParmVarDecl *Param : InitMethod->parameters())
addParam(FD, Param->getType().getCanonicalType());
for (const ParmVarDecl *Param : InitMethod->parameters()) {
QualType ParamTy = Param->getType();
addParam(FD, ParamTy.getCanonicalType());
if (ParamTy.getTypePtr()->isPointerType() && isAccessorType)
handleAccessorPropertyList(Params.back(), RecordDecl,
FD->getLocation());
}
LastParamIndex = ParamIndex;
return true;
}
Expand Down Expand Up @@ -1253,14 +1374,18 @@ class SyclKernelDeclCreator : public SyclKernelFieldHandler {
// Don't do -1 here because we count on this to be the first parameter added
// (if any).
size_t ParamIndex = Params.size();
for (const ParmVarDecl *Param : InitMethod->parameters())
addParam(BS, Param->getType().getCanonicalType());
for (const ParmVarDecl *Param : InitMethod->parameters()) {
QualType ParamTy = Param->getType();
addParam(BS, ParamTy.getCanonicalType());
if (ParamTy.getTypePtr()->isPointerType())
handleAccessorPropertyList(Params.back(), RecordDecl, BS.getBeginLoc());
}
LastParamIndex = ParamIndex;
return true;
}

bool handleSyclAccessorType(FieldDecl *FD, QualType FieldTy) final {
return handleSpecialType(FD, FieldTy);
return handleSpecialType(FD, FieldTy, /*isAccessorType*/ true);
}

bool handleSyclSamplerType(FieldDecl *FD, QualType FieldTy) final {
Expand Down Expand Up @@ -2834,6 +2959,23 @@ bool Util::isSyclSpecConstantType(const QualType &Ty) {
return matchQualifiedTypeName(Ty, Scopes);
}

bool Util::isPropertyListType(const QualType &Ty) {
return isSyclType(Ty, "property_list", true /*Tmpl*/);
}

bool Util::isSyclBufferLocationType(const QualType &Ty) {
const StringRef &Name = "buffer_location";
std::array<DeclContextDesc, 4> Scopes = {
Util::DeclContextDesc{clang::Decl::Kind::Namespace, "cl"},
Util::DeclContextDesc{clang::Decl::Kind::Namespace, "sycl"},
// TODO: this doesn't belong to property namespace, instead it shall be
// in its own namespace. Change it, when the actual implementation in SYCL
// headers is ready
Util::DeclContextDesc{clang::Decl::Kind::Namespace, "property"},
Util::DeclContextDesc{Decl::Kind::ClassTemplateSpecialization, Name}};
return matchQualifiedTypeName(Ty, Scopes);
}

bool Util::isSyclType(const QualType &Ty, StringRef Name, bool Tmpl) {
Decl::Kind ClassDeclKind =
Tmpl ? Decl::Kind::ClassTemplateSpecialization : Decl::Kind::CXXRecord;
Expand Down
Loading

0 comments on commit 1be5f2d

Please sign in to comment.