Skip to content
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
36 changes: 23 additions & 13 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<SYCLIntelFPGAMaxConcurrencyAttr>()) {
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getNThreadsExpr());
const auto *MergeExpr = dyn_cast<ConstantExpr>(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<ConstantExpr>(DeclAttr->getNThreadsExpr())) {
if (const auto *MergeExpr = dyn_cast<ConstantExpr>(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)
Expand All @@ -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<SYCLIntelFPGAMaxConcurrencyAttr>()) {
const auto *DeclExpr =
dyn_cast<ConstantExpr>(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<ConstantExpr>(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;
}
}

Expand Down
96 changes: 96 additions & 0 deletions clang/test/SemaSYCL/max-concurrency-ast.cpp
Original file line number Diff line number Diff line change
@@ -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 <int N>
[[intel::max_concurrency(N)]] void func3() {}

class KernelFunctor {
public:
void operator()() const {
func1();
func2();
}
};

template <int N>
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<class kernel_name_1>(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<class kernel_name_2>(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<class kernel_name_3>(
[]() [[intel::max_concurrency(4)]] {});

// Ignore duplicate attribute.
h.single_task<class kernel_name_4>(
// 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>();
}
211 changes: 69 additions & 142 deletions clang/test/SemaSYCL/max-concurrency.cpp
Original file line number Diff line number Diff line change
@@ -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 <int NT>
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 <int NT>
[[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<class kernel_name1>(f0);

Functor1 f1;
h.single_task<class kernel_name1>(f1);

Functor2 f2;
h.single_task<class kernel_name2>(f2);

h.single_task<class kernel_name3>(
[]() [[intel::max_concurrency(3)]]{});

Functor3<4> f3;
h.single_task<class kernel_name4>(f3);

h.single_task<class kernel_name5>([]() {
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 <int N>
[[intel::max_concurrency(N)]] void func10(); // expected-error {{'max_concurrency' attribute requires a non-negative integral compile time constant expression}}

template <int size>
[[intel::max_concurrency(10)]] void func11(); // expected-note {{previous attribute is here}}
template <int size>
[[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 <typename Ty>
// 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<S>' requested here}}
func14<S>();
// expected-note@+1{{in instantiation of function template specialization 'func14<float>' requested here}}
func14<float>();
}