Skip to content

[SYCL] Propagate attributes from redeclarations to SYCL kernel #2063

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 8, 2020
Merged
25 changes: 25 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3217,6 +3217,22 @@ static void adjustDeclContextForDeclaratorDecl(DeclaratorDecl *NewD,
FixSemaDC(VD->getDescribedVarTemplate());
}

template <typename AttributeType>
static void checkDimensionsAndSetDiagnostics(Sema &S, FunctionDecl *New,
FunctionDecl *Old) {
AttributeType *NewDeclAttr = New->getAttr<AttributeType>();
AttributeType *OldDeclAttr = Old->getAttr<AttributeType>();
if ((NewDeclAttr->getXDim() != OldDeclAttr->getXDim()) ||
(NewDeclAttr->getYDim() != OldDeclAttr->getYDim()) ||
(NewDeclAttr->getZDim() != OldDeclAttr->getZDim())) {
S.Diag(New->getLocation(), diag::err_conflicting_sycl_function_attributes)
<< OldDeclAttr << NewDeclAttr;
S.Diag(New->getLocation(), diag::warn_duplicate_attribute) << OldDeclAttr;
S.Diag(OldDeclAttr->getLocation(), diag::note_conflicting_attribute);
S.Diag(NewDeclAttr->getLocation(), diag::note_conflicting_attribute);
}
}

/// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation,
Expand Down Expand Up @@ -3291,6 +3307,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
}
}

if (New->hasAttr<ReqdWorkGroupSizeAttr>() &&
Old->hasAttr<ReqdWorkGroupSizeAttr>())
checkDimensionsAndSetDiagnostics<ReqdWorkGroupSizeAttr>(*this, New, Old);

if (New->hasAttr<SYCLIntelMaxWorkGroupSizeAttr>() &&
Old->hasAttr<SYCLIntelMaxWorkGroupSizeAttr>())
checkDimensionsAndSetDiagnostics<SYCLIntelMaxWorkGroupSizeAttr>(*this, New,
Old);

if (New->hasAttr<InternalLinkageAttr>() &&
!Old->hasAttr<InternalLinkageAttr>()) {
Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {

for (const CallGraphNode *CI : *N) {
if (auto *Callee = dyn_cast<FunctionDecl>(CI->getDecl())) {
Callee = Callee->getCanonicalDecl();
Callee = Callee->getMostRecentDecl();
if (!Visited.count(Callee))
WorkList.push_back({Callee, FD});
}
Expand Down
68 changes: 68 additions & 0 deletions clang/test/SemaSYCL/redeclaration-attribute-propagation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// RUN: %clang_cc1 %s -I %S/Inputs -fsyntax-only -fsycl -fsycl-is-device -triple spir64 -Wno-sycl-2017-compat -verify
// RUN: %clang_cc1 %s -I %S/Inputs -fsyntax-only -fsycl -fsycl-is-device -triple spir64 -DTRIGGER_ERROR -Wno-sycl-2017-compat -verify
// RUN: %clang_cc1 %s -I %S/Inputs -fsyntax-only -ast-dump -fsycl -fsycl-is-device -triple spir64 -Wno-sycl-2017-compat | FileCheck %s

#include <sycl.hpp>

#ifndef TRIGGER_ERROR
//first case - good case
[[intelfpga::no_global_work_offset]] // expected-no-diagnostics
void
func1();

[[intelfpga::max_work_group_size(4, 4, 4)]] void func1();

[[cl::reqd_work_group_size(2, 2, 2)]] void func1() {}

#else
//second case - expect error
[[intelfpga::max_work_group_size(4, 4, 4)]] // expected-note {{conflicting attribute is here}}
void
func2();

[[cl::reqd_work_group_size(8, 8, 8)]] // expected-note {{conflicting attribute is here}}
void
func2() {}

//third case - expect error
[[cl::reqd_work_group_size(4, 4, 4)]] // expected-note {{conflicting attribute is here}}
void
func3();

[[cl::reqd_work_group_size(1, 1, 1)]] // expected-note {{conflicting attribute is here}}
void
// expected-warning@+1 {{attribute 'reqd_work_group_size' is already applied with different parameters}}
func3() {} // expected-error {{'reqd_work_group_size' attribute conflicts with ''reqd_work_group_size'' attribute}}

//fourth case - expect error
[[intelfpga::max_work_group_size(4, 4, 4)]] // expected-note {{conflicting attribute is here}}
void
func4();

[[intelfpga::max_work_group_size(8, 8, 8)]] // expected-note {{conflicting attribute is here}}
void
// expected-warning@+1 {{attribute 'max_work_group_size' is already applied with different parameters}}
func4() {} // expected-error {{'max_work_group_size' attribute conflicts with ''max_work_group_size'' attribute}}
#endif

int main() {
#ifndef TRIGGER_ERROR
// CHECK-LABEL: FunctionDecl {{.*}} main 'int ()'
// CHECK: `-FunctionDecl {{.*}}test_kernel1 'void ()'
// CHECK: -SYCLIntelMaxWorkGroupSizeAttr {{.*}} Inherited 4 4 4
// CHECK: -SYCLIntelNoGlobalWorkOffsetAttr {{.*}} Inherited Enabled
// CHECK: `-ReqdWorkGroupSizeAttr {{.*}} 2 2 2
cl::sycl::kernel_single_task<class test_kernel1>(
[]() { func1(); });

#else
cl::sycl::kernel_single_task<class test_kernel2>(
[]() { func2(); }); // expected-error {{conflicting attributes applied to a SYCL kernel or SYCL_EXTERNAL function}}

cl::sycl::kernel_single_task<class test_kernel3>(
[]() { func3(); });

cl::sycl::kernel_single_task<class test_kernel4>(
[]() { func4(); });
#endif
}