diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 321efe710af02..f10053bb6b18e 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7623,14 +7623,17 @@ SYCLIntelFPGAMaxConcurrencyAttr *Sema::MergeSYCLIntelFPGAMaxConcurrencyAttr( // Check to see if there's a duplicate attribute with different values // already applied to the declaration. if (const auto *DeclAttr = D->getAttr()) { - const auto *DeclExpr = dyn_cast(DeclAttr->getNThreadsExpr()); - const auto *MergeExpr = dyn_cast(A.getNThreadsExpr()); - if (DeclExpr && MergeExpr && - DeclExpr->getResultAsAPSInt() != MergeExpr->getResultAsAPSInt()) { - Diag(DeclAttr->getLoc(), diag::warn_duplicate_attribute) << &A; - Diag(A.getLoc(), diag::note_previous_attribute); + if (const auto *DeclExpr = + dyn_cast(DeclAttr->getNThreadsExpr())) { + if (const auto *MergeExpr = dyn_cast(A.getNThreadsExpr())) { + if (DeclExpr->getResultAsAPSInt() != MergeExpr->getResultAsAPSInt()) { + Diag(DeclAttr->getLoc(), diag::warn_duplicate_attribute) << &A; + Diag(A.getLoc(), diag::note_previous_attribute); + } + // Do not add a duplicate attribute. + return nullptr; + } } - return nullptr; } return ::new (Context) @@ -7654,14 +7657,21 @@ void Sema::AddSYCLIntelFPGAMaxConcurrencyAttr(Decl *D, return; } + // Check to see if there's a duplicate attribute with different values + // already applied to the declaration. if (const auto *DeclAttr = D->getAttr()) { - const auto *DeclExpr = - dyn_cast(DeclAttr->getNThreadsExpr()); - if (DeclExpr && ArgVal != DeclExpr->getResultAsAPSInt()) { - Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI; - Diag(DeclAttr->getLoc(), diag::note_previous_attribute); + // 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. + if (const auto *DeclExpr = + dyn_cast(DeclAttr->getNThreadsExpr())) { + if (ArgVal != DeclExpr->getResultAsAPSInt()) { + Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI; + Diag(DeclAttr->getLoc(), diag::note_previous_attribute); + } + // Drop the duplicate attribute. + return; } - return; } } diff --git a/clang/test/SemaSYCL/max-concurrency-ast.cpp b/clang/test/SemaSYCL/max-concurrency-ast.cpp new file mode 100644 index 0000000000000..fab7dd3d4ccbd --- /dev/null +++ b/clang/test/SemaSYCL/max-concurrency-ast.cpp @@ -0,0 +1,96 @@ +// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -Wno-sycl-2017-compat -ast-dump %s | FileCheck %s + +// Tests for AST of Intel FPGA max concurrency function attribute. +#include "sycl.hpp" + +using namespace cl::sycl; +queue q; + +// CHECK: FunctionDecl {{.*}} func1 'void ()' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: SYCLIntelFPGAMaxConcurrencyAttr +// CHECK-NEXT: ConstantExpr{{.*}}'int' +// CHECK-NEXT: value: Int 1 +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 +[[intel::max_concurrency(1)]] void func1() {} + +// CHECK: FunctionDecl {{.*}} func2 'void ()' +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: SYCLIntelFPGAMaxConcurrencyAttr +// CHECK-NEXT: ConstantExpr{{.*}}'int' +// CHECK-NEXT: value: Int 0 +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0 +[[intel::max_concurrency(0)]] void func2() {} + +// CHECK: FunctionTemplateDecl {{.*}} func3 +// CHECK: FunctionDecl {{.*}} func3 'void ()' +// CHECK-NEXT: CompoundStmt +// CHECK_NEXT: SYCLIntelFPGAMaxConcurrencyAttr +// CHECK_NEXT: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'N' 'int' +// CHECK: FunctionDecl {{.*}} func3 'void ()' +// CHECK-NEXT: TemplateArgument integral 5 +// CHECK-NEXT: CompoundStmt +// CHECK-NEXT: SYCLIntelFPGAMaxConcurrencyAttr +// CHECK-NEXT: ConstantExpr{{.*}}'int' +// CHECK-NEXT: value: Int 5 +// CHECK-NEXT: SubstNonTypeTemplateParmExpr +// CHECK-NEXT: NonTypeTemplateParmDecl +// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 5 +template +[[intel::max_concurrency(N)]] void func3() {} + +class KernelFunctor { +public: + void operator()() const { + func1(); + func2(); + } +}; + +template +class KernelFunctor2 { +public: + [[intel::max_concurrency(N)]] void operator()() const { + } +}; + +void foo() { + q.submit([&](handler &h) { + // Test attribute is not propagated. + // CHECK: FunctionDecl {{.*}}kernel_name_1 + // CHECK-NOT: SYCLIntelFPGAMaxConcurrencyAttr + KernelFunctor f1; + h.single_task(f1); + + // CHECK: FunctionDecl {{.*}}kernel_name_2 + // CHECK: SYCLIntelFPGAMaxConcurrencyAttr + // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: SubstNonTypeTemplateParmExpr + // CHECK-NEXT: NonTypeTemplateParmDecl + // CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3 + KernelFunctor2<3> f2; + h.single_task(f2); + + // CHECK: FunctionDecl {{.*}}kernel_name_3 + // CHECK: SYCLIntelFPGAMaxConcurrencyAttr + // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 4 + // CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4 + h.single_task( + []() [[intel::max_concurrency(4)]] {}); + + // Ignore duplicate attribute. + h.single_task( + // CHECK: FunctionDecl {{.*}}kernel_name_4 + // CHECK: SYCLIntelFPGAMaxConcurrencyAttr + // CHECK-NEXT: ConstantExpr {{.*}} 'int' + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} + // CHECK-NOT: SYCLIntelFPGAMaxConcurrencyAttr + []() [[intel::max_concurrency(3), + intel::max_concurrency(3)]] {}); + }); + + func3<5>(); +} diff --git a/clang/test/SemaSYCL/max-concurrency.cpp b/clang/test/SemaSYCL/max-concurrency.cpp index 19b5fc88c6c23..93b180e86bed5 100644 --- a/clang/test/SemaSYCL/max-concurrency.cpp +++ b/clang/test/SemaSYCL/max-concurrency.cpp @@ -1,159 +1,86 @@ -// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -sycl-std=2020 -fsyntax-only -ast-dump -verify -pedantic %s | FileCheck %s +// RUN: %clang_cc1 -fsycl-is-device -verify %s -#include "sycl.hpp" +// Test that checks max_concurrency attribute support on function. -using namespace cl::sycl; +// Tests for incorrect argument values for Intel FPGA max_concurrency function attribute. +[[intel::max_concurrency]] void one() {} // expected-error {{'max_concurrency' attribute takes one argument}} -class Functor0 { -public: - [[intel::max_concurrency(0)]] void operator()() const {} -}; +[[intel::max_concurrency(5)]] int a; // expected-error{{'max_concurrency' attribute only applies to 'for', 'while', 'do' statements, and functions}} -class Functor1 { -public: - [[intel::max_concurrency(4)]] void operator()() const {} -}; +[[intel::max_concurrency("foo")]] void func() {} // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const char[4]'}} -[[intel::max_concurrency]] void foo() {} // expected-error {{'max_concurrency' attribute takes one argument}} +[[intel::max_concurrency(-1)]] void func1() {} // expected-error{{'max_concurrency' attribute requires a non-negative integral compile time constant expression}} + +[[intel::max_concurrency(0, 1)]] void func2() {} // expected-error{{'max_concurrency' attribute takes one argument}} + +// Tests for Intel FPGA max_concurrency function attribute duplication. +// No diagnostic is emitted because the arguments match. Duplicate attribute is silently ignored. +[[intel::max_concurrency(2)]] [[intel::max_concurrency(2)]] void func3() {} + +// No diagnostic is emitted because the arguments match. +[[intel::max_concurrency(4)]] void func4(); +[[intel::max_concurrency(4)]] void func4(); // OK + +// Diagnostic is emitted because the arguments mismatch. +[[intel::max_concurrency(2)]] // expected-note {{previous attribute is here}} +[[intel::max_concurrency(4)]] void +func5() {} // expected-warning@-1 {{attribute 'max_concurrency' is already applied with different arguments}} + +[[intel::max_concurrency(1)]] void func6(); // expected-note {{previous attribute is here}} +[[intel::max_concurrency(3)]] void func6(); // expected-warning {{attribute 'max_concurrency' is already applied with different arguments}} // Tests for Intel FPGA max_concurrency and disable_loop_pipelining function attributes compatibility. // expected-error@+2 {{'max_concurrency' and 'disable_loop_pipelining' attributes are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -[[intel::disable_loop_pipelining]] [[intel::max_concurrency(2)]] void check(); +[[intel::disable_loop_pipelining]] [[intel::max_concurrency(2)]] void func7(); // expected-error@+2 {{'disable_loop_pipelining' and 'max_concurrency' attributes are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -[[intel::max_concurrency(4)]] [[intel::disable_loop_pipelining]] void check1(); +[[intel::max_concurrency(4)]] [[intel::disable_loop_pipelining]] void func8(); // expected-error@+3 {{'disable_loop_pipelining' and 'max_concurrency' attributes are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -[[intel::max_concurrency(4)]] void check2(); -[[intel::disable_loop_pipelining]] void check2(); - -class Functor2 { -public: - void operator()() const { - foo(); - } -}; - -template -class Functor3 { -public: - [[intel::max_concurrency(NT)]] void operator()() const {} - // expected-error@+1 {{'max_concurrency' attribute only applies to 'for', 'while', 'do' statements, and functions}} - [[intel::max_concurrency(2)]] int a[10]; -}; - -// expected-error@+1 {{'max_concurrency' attribute takes one argument}} -[[intel::max_concurrency(3, 3)]] void goo() {} - -class Functor4 { -public: - void operator() () const { - goo(); - } -}; - -// expected-error@+1 {{'max_concurrency' attribute requires a non-negative integral compile time constant expression}} -[[intel::max_concurrency(-1)]] void bar() {} -class Functor5 { -public: - void operator() () const { - bar(); - } -}; - -[[intel::max_concurrency(0)]] void bar0() {} -class Functor6 { -public: - void operator() () const { - bar0(); - } -}; - -// expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'const char[16]'}} -[[intel::max_concurrency("numberofthreads")]] void zoo() {} - -template -[[intel::max_concurrency(NT)]] void func() {} - -[[intel::max_concurrency(8)]] void dup(); // expected-note {{previous attribute is here}} -[[intel::max_concurrency(9)]] void dup() {} // expected-warning {{attribute 'max_concurrency' is already applied with different arguments}} - -int main() { - queue q; - - q.submit([&](handler &h) { - Functor1 f0; - h.single_task(f0); - - Functor1 f1; - h.single_task(f1); - - Functor2 f2; - h.single_task(f2); - - h.single_task( - []() [[intel::max_concurrency(3)]]{}); - - Functor3<4> f3; - h.single_task(f3); - - h.single_task([]() { - func<5>(); - }); - - }); +[[intel::max_concurrency(4)]] void func9(); +[[intel::disable_loop_pipelining]] void func9(); + +// Tests that check template parameter support for Intel FPGA initiation_interval function attributes +template +[[intel::max_concurrency(N)]] void func10(); // expected-error {{'max_concurrency' attribute requires a non-negative integral compile time constant expression}} + +template +[[intel::max_concurrency(10)]] void func11(); // expected-note {{previous attribute is here}} +template +[[intel::max_concurrency(size)]] void func11() {} // expected-warning {{attribute 'max_concurrency' is already applied with different arguments}} + +void checkTemplates() { + func10<4>(); // OK + func10<-1>(); // expected-note {{in instantiation of function template specialization 'func10<-1>' requested here}} + func10<0>(); // OK + func11<20>(); // expected-note {{in instantiation of function template specialization 'func11<20>' requested here}} } -// CHECK: CXXMethodDecl {{.*}} operator() {{.*}} -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr -// CHECK: ConstantExpr {{.*}} 'int' -// CHECK: value: Int 0 -// CHECK: IntegerLiteral {{.*}}0{{$}} -// CHECK: CXXMethodDecl {{.*}}used operator() {{.*}} -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}} -// CHECK: ConstantExpr {{.*}} 'int' -// CHECK: value: Int 4 -// CHECK: IntegerLiteral {{.*}}4{{$}} -// CHECK: CXXMethodDecl {{.*}}operator() {{.*}} -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}} -// CHECK: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'NT' 'int' -// CHECK: CXXMethodDecl {{.*}}{{.*}}used operator() {{.*}} -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}} -// CHECK: ConstantExpr {{.*}} 'int' -// CHECK: value: Int 4 -// CHECK: IntegerLiteral {{.*}}4{{$}} -// CHECK: FunctionDecl {{.*}}{{.*}} used bar0 {{.*}} -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}} -// CHECK: ConstantExpr {{.*}} 'int' -// CHECK: value: Int 0 -// CHECK:IntegerLiteral {{.*}}{{.*}}0{{$}} -// CHECK: FunctionDecl {{.*}}{{.*}}func {{.*}} -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}} -// CHECK: FunctionDecl {{.*}}{{.*}}used func 'void ()' -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}} -// CHECK: ConstantExpr {{.*}} 'int' -// CHECK: value: Int 5 -// CHECK: IntegerLiteral {{.*}}5{{$}} -// CHECK: FunctionDecl {{.*}}{{.*}}dup {{.*}} -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}} -// CHECK: ConstantExpr {{.*}} 'int' -// CHECK: value: Int 8 -// CHECK: IntegerLiteral {{.*}}8{{$}} -// CHECK: FunctionDecl {{.*}}{{.*}}dup {{.*}} -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}} -// CHECK: ConstantExpr {{.*}} 'int' -// CHECK: value: Int 9 -// CHECK: IntegerLiteral {{.*}}9{{$}} -// CHECK: FunctionDecl {{.*}}{{.*}}kernel_name1{{.*}} -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}} -// CHECK: ConstantExpr {{.*}} 'int' -// CHECK: value: Int 4 -// CHECK: IntegerLiteral{{.*}}4{{$}} -// CHECK: FunctionDecl {{.*}}{{.*}}kernel_name4{{.*}} -// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}} -// CHECK: ConstantExpr {{.*}} 'int' -// CHECK: value: Int 4 -// CHECK: IntegerLiteral{{.*}}4{{$}} +// Test that checks expression is not a constant expression. +// expected-note@+1{{declared here}} +int baz(); +// expected-error@+2{{expression is not an integral constant expression}} +// expected-note@+1{{non-constexpr function 'baz' cannot be used in a constant expression}} +[[intel::max_concurrency(baz() + 1)]] void func12(); + +// Test that checks expression is a constant expression. +constexpr int bar() { return 0; } +[[intel::max_concurrency(bar() + 2)]] void func13(); // OK + +// Test that checks wrong function template instantiation and ensures that the type +// is checked properly when instantiating from the template definition. +template +// expected-error@+2 {{integral constant expression must have integral or unscoped enumeration type, not 'S'}} +// expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'float'}} +[[intel::max_concurrency(Ty{})]] void func14() {} + +struct S {}; +void test() { + // expected-note@+1{{in instantiation of function template specialization 'func14' requested here}} + func14(); + // expected-note@+1{{in instantiation of function template specialization 'func14' requested here}} + func14(); +}