Skip to content

[SYCL] Refactor of two FPGA function attributes #3274

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 7 commits into from
Mar 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -10219,6 +10219,16 @@ class Sema final {
SYCLIntelNumSimdWorkItemsAttr *
MergeSYCLIntelNumSimdWorkItemsAttr(Decl *D,
const SYCLIntelNumSimdWorkItemsAttr &A);
void AddSYCLIntelSchedulerTargetFmaxMhzAttr(Decl *D,
const AttributeCommonInfo &CI,
Expr *E);
SYCLIntelSchedulerTargetFmaxMhzAttr *MergeSYCLIntelSchedulerTargetFmaxMhzAttr(
Decl *D, const SYCLIntelSchedulerTargetFmaxMhzAttr &A);
void AddSYCLIntelNoGlobalWorkOffsetAttr(Decl *D,
const AttributeCommonInfo &CI,
Expr *E);
SYCLIntelNoGlobalWorkOffsetAttr *MergeSYCLIntelNoGlobalWorkOffsetAttr(
Decl *D, const SYCLIntelNoGlobalWorkOffsetAttr &A);

/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
Expand Down Expand Up @@ -13099,8 +13109,7 @@ void Sema::addIntelSingleArgAttr(Decl *D, const AttributeCommonInfo &CI,
return;
}
}
if (CI.getParsedKind() == ParsedAttr::AT_SYCLIntelSchedulerTargetFmaxMhz ||
CI.getParsedKind() == ParsedAttr::AT_IntelFPGAPrivateCopies) {
if (CI.getParsedKind() == ParsedAttr::AT_IntelFPGAPrivateCopies) {
if (ArgInt < 0) {
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
<< CI << /*non-negative*/ 1;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2622,6 +2622,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
NewAttr = S.MergeIntelReqdSubGroupSizeAttr(D, *A);
else if (const auto *A = dyn_cast<SYCLIntelNumSimdWorkItemsAttr>(Attr))
NewAttr = S.MergeSYCLIntelNumSimdWorkItemsAttr(D, *A);
else if (const auto *A = dyn_cast<SYCLIntelSchedulerTargetFmaxMhzAttr>(Attr))
NewAttr = S.MergeSYCLIntelSchedulerTargetFmaxMhzAttr(D, *A);
else if (const auto *A = dyn_cast<SYCLIntelNoGlobalWorkOffsetAttr>(Attr))
NewAttr = S.MergeSYCLIntelNoGlobalWorkOffsetAttr(D, *A);
else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));

Expand Down
129 changes: 115 additions & 14 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3366,19 +3366,71 @@ static void handleUseStallEnableClustersAttr(Sema &S, Decl *D,
}

// Handle scheduler_target_fmax_mhz
static void handleSchedulerTargetFmaxMhzAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
if (D->isInvalidDecl())
return;
void Sema::AddSYCLIntelSchedulerTargetFmaxMhzAttr(Decl *D,
const AttributeCommonInfo &CI,
Expr *E) {
if (!E->isValueDependent()) {
// Validate that we have an integer constant expression and then store the
// converted constant expression into the semantic attribute so that we
// don't have to evaluate it again later.
llvm::APSInt ArgVal;
ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
if (Res.isInvalid())
return;
E = Res.get();

Expr *E = AL.getArgAsExpr(0);
// This attribute requires a non-negative value.
if (ArgVal < 0) {
Diag(E->getExprLoc(), diag::err_attribute_requires_positive_integer)
<< CI << /*non-negative*/ 1;
return;
}
// Check to see if there's a duplicate attribute with different values
// already applied to the declaration.
if (const auto *DeclAttr =
D->getAttr<SYCLIntelSchedulerTargetFmaxMhzAttr>()) {
// If the other attribute argument is instantiation dependent, we won't
// have converted it to a constant expression yet and thus we test
// whether this is a null pointer.
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getValue());
if (DeclExpr && ArgVal != DeclExpr->getResultAsAPSInt()) {
Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI;
Diag(DeclAttr->getLoc(), diag::note_previous_attribute);
return;
}
}
}

if (D->getAttr<SYCLIntelSchedulerTargetFmaxMhzAttr>())
S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
D->addAttr(::new (Context)
SYCLIntelSchedulerTargetFmaxMhzAttr(Context, CI, E));
}

SYCLIntelSchedulerTargetFmaxMhzAttr *
Sema::MergeSYCLIntelSchedulerTargetFmaxMhzAttr(
Decl *D, const SYCLIntelSchedulerTargetFmaxMhzAttr &A) {
// Check to see if there's a duplicate attribute with different values
// already applied to the declaration.
if (const auto *DeclAttr =
D->getAttr<SYCLIntelSchedulerTargetFmaxMhzAttr>()) {
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getValue());
const auto *MergeExpr = dyn_cast<ConstantExpr>(A.getValue());
if (DeclExpr && MergeExpr &&
DeclExpr->getResultAsAPSInt() != MergeExpr->getResultAsAPSInt()) {
Diag(DeclAttr->getLoc(), diag::warn_duplicate_attribute) << &A;
Diag(A.getLoc(), diag::note_previous_attribute);
return nullptr;
}
}
return ::new (Context)
SYCLIntelSchedulerTargetFmaxMhzAttr(Context, A, A.getValue());
}

static void handleSYCLIntelSchedulerTargetFmaxMhzAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
S.CheckDeprecatedSYCLAttributeSpelling(AL);

S.addIntelSingleArgAttr<SYCLIntelSchedulerTargetFmaxMhzAttr>(D, AL, E);
Expr *E = AL.getArgAsExpr(0);
S.AddSYCLIntelSchedulerTargetFmaxMhzAttr(D, AL, E);
}

// Handles max_global_work_dim.
Expand Down Expand Up @@ -5708,17 +5760,66 @@ static bool checkForDuplicateAttribute(Sema &S, Decl *D,
return false;
}

static void handleNoGlobalWorkOffsetAttr(Sema &S, Decl *D,
const ParsedAttr &A) {
checkForDuplicateAttribute<SYCLIntelNoGlobalWorkOffsetAttr>(S, D, A);
void Sema::AddSYCLIntelNoGlobalWorkOffsetAttr(Decl *D,
const AttributeCommonInfo &CI,
Expr *E) {
if (!E->isValueDependent()) {
// Validate that we have an integer constant expression and then store the
// converted constant expression into the semantic attribute so that we
// don't have to evaluate it again later.
llvm::APSInt ArgVal;
ExprResult Res = VerifyIntegerConstantExpression(E, &ArgVal);
if (Res.isInvalid())
return;
E = Res.get();

// Check to see if there's a duplicate attribute with different values
// already applied to the declaration.
if (const auto *DeclAttr = D->getAttr<SYCLIntelNoGlobalWorkOffsetAttr>()) {
// If the other attribute argument is instantiation dependent, we won't
// have converted it to a constant expression yet and thus we test
// whether this is a null pointer.
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getValue());
if (DeclExpr && ArgVal != DeclExpr->getResultAsAPSInt()) {
Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI;
Diag(DeclAttr->getLoc(), diag::note_previous_attribute);
return;
}
}
}

D->addAttr(::new (Context) SYCLIntelNoGlobalWorkOffsetAttr(Context, CI, E));
}

SYCLIntelNoGlobalWorkOffsetAttr *Sema::MergeSYCLIntelNoGlobalWorkOffsetAttr(
Decl *D, const SYCLIntelNoGlobalWorkOffsetAttr &A) {
// Check to see if there's a duplicate attribute with different values
// already applied to the declaration.
if (const auto *DeclAttr = D->getAttr<SYCLIntelNoGlobalWorkOffsetAttr>()) {
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getValue());
const auto *MergeExpr = dyn_cast<ConstantExpr>(A.getValue());
if (DeclExpr && MergeExpr &&
DeclExpr->getResultAsAPSInt() != MergeExpr->getResultAsAPSInt()) {
Diag(DeclAttr->getLoc(), diag::warn_duplicate_attribute) << &A;
Diag(A.getLoc(), diag::note_previous_attribute);
return nullptr;
}
}
return ::new (Context)
SYCLIntelNoGlobalWorkOffsetAttr(Context, A, A.getValue());
}

static void handleSYCLIntelNoGlobalWorkOffsetAttr(Sema &S, Decl *D,
const ParsedAttr &A) {
S.CheckDeprecatedSYCLAttributeSpelling(A);

// If no attribute argument is specified, set to default value '1'.
Expr *E = A.isArgExpr(0)
? A.getArgAsExpr(0)
: IntegerLiteral::Create(S.Context, llvm::APInt(32, 1),
S.Context.IntTy, A.getLoc());
S.addIntelSingleArgAttr<SYCLIntelNoGlobalWorkOffsetAttr>(D, A, E);

S.AddSYCLIntelNoGlobalWorkOffsetAttr(D, A, E);
}

/// Handle the [[intelfpga::doublepump]] and [[intelfpga::singlepump]] attributes.
Expand Down Expand Up @@ -8897,13 +8998,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleSYCLIntelNumSimdWorkItemsAttr(S, D, AL);
break;
case ParsedAttr::AT_SYCLIntelSchedulerTargetFmaxMhz:
handleSchedulerTargetFmaxMhzAttr(S, D, AL);
handleSYCLIntelSchedulerTargetFmaxMhzAttr(S, D, AL);
break;
case ParsedAttr::AT_SYCLIntelMaxGlobalWorkDim:
handleMaxGlobalWorkDimAttr(S, D, AL);
break;
case ParsedAttr::AT_SYCLIntelNoGlobalWorkOffset:
handleNoGlobalWorkOffsetAttr(S, D, AL);
handleSYCLIntelNoGlobalWorkOffsetAttr(S, D, AL);
break;
case ParsedAttr::AT_SYCLIntelUseStallEnableClusters:
handleUseStallEnableClustersAttr(S, D, AL);
Expand Down
24 changes: 22 additions & 2 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,26 @@ static void instantiateSYCLIntelNumSimdWorkItemsAttr(
S.AddSYCLIntelNumSimdWorkItemsAttr(New, *A, Result.getAs<Expr>());
}

static void instantiateSYCLIntelSchedulerTargetFmaxMhzAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const SYCLIntelSchedulerTargetFmaxMhzAttr *A, Decl *New) {
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(A->getValue(), TemplateArgs);
if (!Result.isInvalid())
S.AddSYCLIntelSchedulerTargetFmaxMhzAttr(New, *A, Result.getAs<Expr>());
}

static void instantiateSYCLIntelNoGlobalWorkOffsetAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const SYCLIntelNoGlobalWorkOffsetAttr *A, Decl *New) {
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(A->getValue(), TemplateArgs);
if (!Result.isInvalid())
S.AddSYCLIntelNoGlobalWorkOffsetAttr(New, *A, Result.getAs<Expr>());
}

template <typename AttrName>
static void instantiateIntelSYCLFunctionAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
Expand Down Expand Up @@ -866,7 +886,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}
if (const auto *SYCLIntelSchedulerTargetFmaxMhz =
dyn_cast<SYCLIntelSchedulerTargetFmaxMhzAttr>(TmplAttr)) {
instantiateIntelSYCLFunctionAttr<SYCLIntelSchedulerTargetFmaxMhzAttr>(
instantiateSYCLIntelSchedulerTargetFmaxMhzAttr(
*this, TemplateArgs, SYCLIntelSchedulerTargetFmaxMhz, New);
continue;
}
Expand All @@ -884,7 +904,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}
if (const auto *SYCLIntelNoGlobalWorkOffset =
dyn_cast<SYCLIntelNoGlobalWorkOffsetAttr>(TmplAttr)) {
instantiateIntelSYCLFunctionAttr<SYCLIntelNoGlobalWorkOffsetAttr>(
instantiateSYCLIntelNoGlobalWorkOffsetAttr(
*this, TemplateArgs, SYCLIntelNoGlobalWorkOffset, New);
continue;
}
Expand Down
4 changes: 2 additions & 2 deletions clang/test/SemaSYCL/intel-fpga-no-global-work-offset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ int main() {
[[intel::no_global_work_offset(1)]] int a;
});

// expected-warning@+2{{attribute 'no_global_work_offset' is already applied}}
h.single_task<class test_kernel7>(
[]() [[intel::no_global_work_offset(0), intel::no_global_work_offset(1)]]{});
[]() [[intel::no_global_work_offset(0), // expected-note {{previous attribute is here}}
intel::no_global_work_offset(1)]]{}); // expected-warning{{attribute 'no_global_work_offset' is already applied with different parameters}}
});
return 0;
}
9 changes: 8 additions & 1 deletion clang/test/SemaSYCL/scheduler_target_fmax_mhz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
[[intelfpga::scheduler_target_fmax_mhz(2)]] void
func() {}

[[intel::scheduler_target_fmax_mhz(12)]] void bar();
[[intel::scheduler_target_fmax_mhz(12)]] void bar() {} // OK

[[intel::scheduler_target_fmax_mhz(12)]] void baz(); // expected-note {{previous attribute is here}}
[[intel::scheduler_target_fmax_mhz(100)]] void baz(); // expected-warning {{attribute 'scheduler_target_fmax_mhz' is already applied with different parameters}}

template <int N>
[[intel::scheduler_target_fmax_mhz(N)]] void zoo() {}

Expand Down Expand Up @@ -47,5 +53,6 @@ int main() {
[]() [[intel::scheduler_target_fmax_mhz(-4)]]{}); // expected-error{{'scheduler_target_fmax_mhz' attribute requires a non-negative integral compile time constant expression}}

cl::sycl::kernel_single_task<class test_kernel6>(
[]() [[intel::scheduler_target_fmax_mhz(1), intel::scheduler_target_fmax_mhz(2)]]{}); // expected-warning{{attribute 'scheduler_target_fmax_mhz' is already applied with different parameters}}
[]() [[intel::scheduler_target_fmax_mhz(1), // expected-note {{previous attribute is here}}
intel::scheduler_target_fmax_mhz(2)]]{}); // expected-warning{{attribute 'scheduler_target_fmax_mhz' is already applied with different parameters}}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ int main() {
KernelFunctor<1>();
}

[[intel::no_global_work_offset]] void func3 ();
[[intel::no_global_work_offset(1)]] void func3() {} // OK

[[intel::no_global_work_offset(0)]] void func4(); // expected-note {{previous attribute is here}}
[[intel::no_global_work_offset]] void func4(); // expected-warning{{attribute 'no_global_work_offset' is already applied with different parameters}}

[[intel::no_global_work_offset(1)]] void func5();
[[intel::no_global_work_offset(1)]] void func5() {} // OK

[[intel::no_global_work_offset(0)]] void func6(); // expected-note {{previous attribute is here}}
[[intel::no_global_work_offset(1)]] void func6(); // expected-warning{{attribute 'no_global_work_offset' is already applied with different parameters}}

// CHECK: ClassTemplateDecl {{.*}} {{.*}} KernelFunctor
// CHECK: ClassTemplateSpecializationDecl {{.*}} {{.*}} class KernelFunctor definition
// CHECK: CXXRecordDecl {{.*}} {{.*}} implicit class KernelFunctor
Expand All @@ -48,14 +60,20 @@ int main() {

// Test that checks template parameter suppport on function.
template <int N>
[[intel::no_global_work_offset(N)]] void func3() {}
[[intel::no_global_work_offset(N)]] void func6() {}

template <int N>
[[intel::no_global_work_offset(0)]] void func7(); // expected-note {{previous attribute is here}}
template <int N>
[[intel::no_global_work_offset(N)]] void func7() {} // expected-warning {{attribute 'no_global_work_offset' is already applied with different parameters}}

int check() {
func3<1>();
func6<1>();
func7<1>(); //expected-note {{in instantiation of function template specialization 'func7<1>' requested here}}
return 0;
}

// CHECK: FunctionDecl {{.*}} {{.*}} func3 'void ()'
// CHECK: FunctionDecl {{.*}} {{.*}} func6 'void ()'
// CHECK: TemplateArgument integral 1
// CHECK: SYCLIntelNoGlobalWorkOffsetAttr {{.*}}
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
Expand Down
Loading