Skip to content

Commit b6aa4cc

Browse files
authored
[SYCL][FPGA] Update [[intel::max_concurrency()]] attribute support (#6126)
This patch improves support for [[intel::max_concurrency()]] implementation. Fixes bugs the way attribute handled duplicate attribute diagnostics. Adds missing diagnostics test cases. Splits AST and diagnostics part for better codes readability(part of [SYCL] Split diagnostic and AST parts for sema tests. #4118). Signed-off-by: Soumi Manna soumi.manna@intel.com
1 parent 3e1c1bf commit b6aa4cc

File tree

3 files changed

+188
-155
lines changed

3 files changed

+188
-155
lines changed

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7623,14 +7623,17 @@ SYCLIntelFPGAMaxConcurrencyAttr *Sema::MergeSYCLIntelFPGAMaxConcurrencyAttr(
76237623
// Check to see if there's a duplicate attribute with different values
76247624
// already applied to the declaration.
76257625
if (const auto *DeclAttr = D->getAttr<SYCLIntelFPGAMaxConcurrencyAttr>()) {
7626-
const auto *DeclExpr = dyn_cast<ConstantExpr>(DeclAttr->getNThreadsExpr());
7627-
const auto *MergeExpr = dyn_cast<ConstantExpr>(A.getNThreadsExpr());
7628-
if (DeclExpr && MergeExpr &&
7629-
DeclExpr->getResultAsAPSInt() != MergeExpr->getResultAsAPSInt()) {
7630-
Diag(DeclAttr->getLoc(), diag::warn_duplicate_attribute) << &A;
7631-
Diag(A.getLoc(), diag::note_previous_attribute);
7626+
if (const auto *DeclExpr =
7627+
dyn_cast<ConstantExpr>(DeclAttr->getNThreadsExpr())) {
7628+
if (const auto *MergeExpr = dyn_cast<ConstantExpr>(A.getNThreadsExpr())) {
7629+
if (DeclExpr->getResultAsAPSInt() != MergeExpr->getResultAsAPSInt()) {
7630+
Diag(DeclAttr->getLoc(), diag::warn_duplicate_attribute) << &A;
7631+
Diag(A.getLoc(), diag::note_previous_attribute);
7632+
}
7633+
// Do not add a duplicate attribute.
7634+
return nullptr;
7635+
}
76327636
}
7633-
return nullptr;
76347637
}
76357638

76367639
return ::new (Context)
@@ -7654,14 +7657,21 @@ void Sema::AddSYCLIntelFPGAMaxConcurrencyAttr(Decl *D,
76547657
return;
76557658
}
76567659

7660+
// Check to see if there's a duplicate attribute with different values
7661+
// already applied to the declaration.
76577662
if (const auto *DeclAttr = D->getAttr<SYCLIntelFPGAMaxConcurrencyAttr>()) {
7658-
const auto *DeclExpr =
7659-
dyn_cast<ConstantExpr>(DeclAttr->getNThreadsExpr());
7660-
if (DeclExpr && ArgVal != DeclExpr->getResultAsAPSInt()) {
7661-
Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI;
7662-
Diag(DeclAttr->getLoc(), diag::note_previous_attribute);
7663+
// If the other attribute argument is instantiation dependent, we won't
7664+
// have converted it to a constant expression yet and thus we test
7665+
// whether this is a null pointer.
7666+
if (const auto *DeclExpr =
7667+
dyn_cast<ConstantExpr>(DeclAttr->getNThreadsExpr())) {
7668+
if (ArgVal != DeclExpr->getResultAsAPSInt()) {
7669+
Diag(CI.getLoc(), diag::warn_duplicate_attribute) << CI;
7670+
Diag(DeclAttr->getLoc(), diag::note_previous_attribute);
7671+
}
7672+
// Drop the duplicate attribute.
7673+
return;
76637674
}
7664-
return;
76657675
}
76667676
}
76677677

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -Wno-sycl-2017-compat -ast-dump %s | FileCheck %s
2+
3+
// Tests for AST of Intel FPGA max concurrency function attribute.
4+
#include "sycl.hpp"
5+
6+
using namespace cl::sycl;
7+
queue q;
8+
9+
// CHECK: FunctionDecl {{.*}} func1 'void ()'
10+
// CHECK-NEXT: CompoundStmt
11+
// CHECK-NEXT: SYCLIntelFPGAMaxConcurrencyAttr
12+
// CHECK-NEXT: ConstantExpr{{.*}}'int'
13+
// CHECK-NEXT: value: Int 1
14+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
15+
[[intel::max_concurrency(1)]] void func1() {}
16+
17+
// CHECK: FunctionDecl {{.*}} func2 'void ()'
18+
// CHECK-NEXT: CompoundStmt
19+
// CHECK-NEXT: SYCLIntelFPGAMaxConcurrencyAttr
20+
// CHECK-NEXT: ConstantExpr{{.*}}'int'
21+
// CHECK-NEXT: value: Int 0
22+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
23+
[[intel::max_concurrency(0)]] void func2() {}
24+
25+
// CHECK: FunctionTemplateDecl {{.*}} func3
26+
// CHECK: FunctionDecl {{.*}} func3 'void ()'
27+
// CHECK-NEXT: CompoundStmt
28+
// CHECK_NEXT: SYCLIntelFPGAMaxConcurrencyAttr
29+
// CHECK_NEXT: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'N' 'int'
30+
// CHECK: FunctionDecl {{.*}} func3 'void ()'
31+
// CHECK-NEXT: TemplateArgument integral 5
32+
// CHECK-NEXT: CompoundStmt
33+
// CHECK-NEXT: SYCLIntelFPGAMaxConcurrencyAttr
34+
// CHECK-NEXT: ConstantExpr{{.*}}'int'
35+
// CHECK-NEXT: value: Int 5
36+
// CHECK-NEXT: SubstNonTypeTemplateParmExpr
37+
// CHECK-NEXT: NonTypeTemplateParmDecl
38+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 5
39+
template <int N>
40+
[[intel::max_concurrency(N)]] void func3() {}
41+
42+
class KernelFunctor {
43+
public:
44+
void operator()() const {
45+
func1();
46+
func2();
47+
}
48+
};
49+
50+
template <int N>
51+
class KernelFunctor2 {
52+
public:
53+
[[intel::max_concurrency(N)]] void operator()() const {
54+
}
55+
};
56+
57+
void foo() {
58+
q.submit([&](handler &h) {
59+
// Test attribute is not propagated.
60+
// CHECK: FunctionDecl {{.*}}kernel_name_1
61+
// CHECK-NOT: SYCLIntelFPGAMaxConcurrencyAttr
62+
KernelFunctor f1;
63+
h.single_task<class kernel_name_1>(f1);
64+
65+
// CHECK: FunctionDecl {{.*}}kernel_name_2
66+
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr
67+
// CHECK-NEXT: ConstantExpr{{.*}}'int'
68+
// CHECK-NEXT: value: Int 3
69+
// CHECK-NEXT: SubstNonTypeTemplateParmExpr
70+
// CHECK-NEXT: NonTypeTemplateParmDecl
71+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
72+
KernelFunctor2<3> f2;
73+
h.single_task<class kernel_name_2>(f2);
74+
75+
// CHECK: FunctionDecl {{.*}}kernel_name_3
76+
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr
77+
// CHECK-NEXT: ConstantExpr{{.*}}'int'
78+
// CHECK-NEXT: value: Int 4
79+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4
80+
h.single_task<class kernel_name_3>(
81+
[]() [[intel::max_concurrency(4)]] {});
82+
83+
// Ignore duplicate attribute.
84+
h.single_task<class kernel_name_4>(
85+
// CHECK: FunctionDecl {{.*}}kernel_name_4
86+
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr
87+
// CHECK-NEXT: ConstantExpr {{.*}} 'int'
88+
// CHECK-NEXT: value: Int 3
89+
// CHECK-NEXT: IntegerLiteral{{.*}}3{{$}}
90+
// CHECK-NOT: SYCLIntelFPGAMaxConcurrencyAttr
91+
[]() [[intel::max_concurrency(3),
92+
intel::max_concurrency(3)]] {});
93+
});
94+
95+
func3<5>();
96+
}
Lines changed: 69 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,159 +1,86 @@
1-
// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -sycl-std=2020 -fsyntax-only -ast-dump -verify -pedantic %s | FileCheck %s
1+
// RUN: %clang_cc1 -fsycl-is-device -verify %s
22

3-
#include "sycl.hpp"
3+
// Test that checks max_concurrency attribute support on function.
44

5-
using namespace cl::sycl;
5+
// Tests for incorrect argument values for Intel FPGA max_concurrency function attribute.
6+
[[intel::max_concurrency]] void one() {} // expected-error {{'max_concurrency' attribute takes one argument}}
67

7-
class Functor0 {
8-
public:
9-
[[intel::max_concurrency(0)]] void operator()() const {}
10-
};
8+
[[intel::max_concurrency(5)]] int a; // expected-error{{'max_concurrency' attribute only applies to 'for', 'while', 'do' statements, and functions}}
119

12-
class Functor1 {
13-
public:
14-
[[intel::max_concurrency(4)]] void operator()() const {}
15-
};
10+
[[intel::max_concurrency("foo")]] void func() {} // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const char[4]'}}
1611

17-
[[intel::max_concurrency]] void foo() {} // expected-error {{'max_concurrency' attribute takes one argument}}
12+
[[intel::max_concurrency(-1)]] void func1() {} // expected-error{{'max_concurrency' attribute requires a non-negative integral compile time constant expression}}
13+
14+
[[intel::max_concurrency(0, 1)]] void func2() {} // expected-error{{'max_concurrency' attribute takes one argument}}
15+
16+
// Tests for Intel FPGA max_concurrency function attribute duplication.
17+
// No diagnostic is emitted because the arguments match. Duplicate attribute is silently ignored.
18+
[[intel::max_concurrency(2)]] [[intel::max_concurrency(2)]] void func3() {}
19+
20+
// No diagnostic is emitted because the arguments match.
21+
[[intel::max_concurrency(4)]] void func4();
22+
[[intel::max_concurrency(4)]] void func4(); // OK
23+
24+
// Diagnostic is emitted because the arguments mismatch.
25+
[[intel::max_concurrency(2)]] // expected-note {{previous attribute is here}}
26+
[[intel::max_concurrency(4)]] void
27+
func5() {} // expected-warning@-1 {{attribute 'max_concurrency' is already applied with different arguments}}
28+
29+
[[intel::max_concurrency(1)]] void func6(); // expected-note {{previous attribute is here}}
30+
[[intel::max_concurrency(3)]] void func6(); // expected-warning {{attribute 'max_concurrency' is already applied with different arguments}}
1831

1932
// Tests for Intel FPGA max_concurrency and disable_loop_pipelining function attributes compatibility.
2033
// expected-error@+2 {{'max_concurrency' and 'disable_loop_pipelining' attributes are not compatible}}
2134
// expected-note@+1 {{conflicting attribute is here}}
22-
[[intel::disable_loop_pipelining]] [[intel::max_concurrency(2)]] void check();
35+
[[intel::disable_loop_pipelining]] [[intel::max_concurrency(2)]] void func7();
2336

2437
// expected-error@+2 {{'disable_loop_pipelining' and 'max_concurrency' attributes are not compatible}}
2538
// expected-note@+1 {{conflicting attribute is here}}
26-
[[intel::max_concurrency(4)]] [[intel::disable_loop_pipelining]] void check1();
39+
[[intel::max_concurrency(4)]] [[intel::disable_loop_pipelining]] void func8();
2740

2841
// expected-error@+3 {{'disable_loop_pipelining' and 'max_concurrency' attributes are not compatible}}
2942
// expected-note@+1 {{conflicting attribute is here}}
30-
[[intel::max_concurrency(4)]] void check2();
31-
[[intel::disable_loop_pipelining]] void check2();
32-
33-
class Functor2 {
34-
public:
35-
void operator()() const {
36-
foo();
37-
}
38-
};
39-
40-
template <int NT>
41-
class Functor3 {
42-
public:
43-
[[intel::max_concurrency(NT)]] void operator()() const {}
44-
// expected-error@+1 {{'max_concurrency' attribute only applies to 'for', 'while', 'do' statements, and functions}}
45-
[[intel::max_concurrency(2)]] int a[10];
46-
};
47-
48-
// expected-error@+1 {{'max_concurrency' attribute takes one argument}}
49-
[[intel::max_concurrency(3, 3)]] void goo() {}
50-
51-
class Functor4 {
52-
public:
53-
void operator() () const {
54-
goo();
55-
}
56-
};
57-
58-
// expected-error@+1 {{'max_concurrency' attribute requires a non-negative integral compile time constant expression}}
59-
[[intel::max_concurrency(-1)]] void bar() {}
60-
class Functor5 {
61-
public:
62-
void operator() () const {
63-
bar();
64-
}
65-
};
66-
67-
[[intel::max_concurrency(0)]] void bar0() {}
68-
class Functor6 {
69-
public:
70-
void operator() () const {
71-
bar0();
72-
}
73-
};
74-
75-
// expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'const char[16]'}}
76-
[[intel::max_concurrency("numberofthreads")]] void zoo() {}
77-
78-
template <int NT>
79-
[[intel::max_concurrency(NT)]] void func() {}
80-
81-
[[intel::max_concurrency(8)]] void dup(); // expected-note {{previous attribute is here}}
82-
[[intel::max_concurrency(9)]] void dup() {} // expected-warning {{attribute 'max_concurrency' is already applied with different arguments}}
83-
84-
int main() {
85-
queue q;
86-
87-
q.submit([&](handler &h) {
88-
Functor1 f0;
89-
h.single_task<class kernel_name1>(f0);
90-
91-
Functor1 f1;
92-
h.single_task<class kernel_name1>(f1);
93-
94-
Functor2 f2;
95-
h.single_task<class kernel_name2>(f2);
96-
97-
h.single_task<class kernel_name3>(
98-
[]() [[intel::max_concurrency(3)]]{});
99-
100-
Functor3<4> f3;
101-
h.single_task<class kernel_name4>(f3);
102-
103-
h.single_task<class kernel_name5>([]() {
104-
func<5>();
105-
});
106-
107-
});
43+
[[intel::max_concurrency(4)]] void func9();
44+
[[intel::disable_loop_pipelining]] void func9();
45+
46+
// Tests that check template parameter support for Intel FPGA initiation_interval function attributes
47+
template <int N>
48+
[[intel::max_concurrency(N)]] void func10(); // expected-error {{'max_concurrency' attribute requires a non-negative integral compile time constant expression}}
49+
50+
template <int size>
51+
[[intel::max_concurrency(10)]] void func11(); // expected-note {{previous attribute is here}}
52+
template <int size>
53+
[[intel::max_concurrency(size)]] void func11() {} // expected-warning {{attribute 'max_concurrency' is already applied with different arguments}}
54+
55+
void checkTemplates() {
56+
func10<4>(); // OK
57+
func10<-1>(); // expected-note {{in instantiation of function template specialization 'func10<-1>' requested here}}
58+
func10<0>(); // OK
59+
func11<20>(); // expected-note {{in instantiation of function template specialization 'func11<20>' requested here}}
10860
}
10961

110-
// CHECK: CXXMethodDecl {{.*}} operator() {{.*}}
111-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr
112-
// CHECK: ConstantExpr {{.*}} 'int'
113-
// CHECK: value: Int 0
114-
// CHECK: IntegerLiteral {{.*}}0{{$}}
115-
// CHECK: CXXMethodDecl {{.*}}used operator() {{.*}}
116-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}}
117-
// CHECK: ConstantExpr {{.*}} 'int'
118-
// CHECK: value: Int 4
119-
// CHECK: IntegerLiteral {{.*}}4{{$}}
120-
// CHECK: CXXMethodDecl {{.*}}operator() {{.*}}
121-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}}
122-
// CHECK: DeclRefExpr {{.*}} 'int' NonTypeTemplateParm {{.*}} 'NT' 'int'
123-
// CHECK: CXXMethodDecl {{.*}}{{.*}}used operator() {{.*}}
124-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}}
125-
// CHECK: ConstantExpr {{.*}} 'int'
126-
// CHECK: value: Int 4
127-
// CHECK: IntegerLiteral {{.*}}4{{$}}
128-
// CHECK: FunctionDecl {{.*}}{{.*}} used bar0 {{.*}}
129-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}}
130-
// CHECK: ConstantExpr {{.*}} 'int'
131-
// CHECK: value: Int 0
132-
// CHECK:IntegerLiteral {{.*}}{{.*}}0{{$}}
133-
// CHECK: FunctionDecl {{.*}}{{.*}}func {{.*}}
134-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}}
135-
// CHECK: FunctionDecl {{.*}}{{.*}}used func 'void ()'
136-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}}
137-
// CHECK: ConstantExpr {{.*}} 'int'
138-
// CHECK: value: Int 5
139-
// CHECK: IntegerLiteral {{.*}}5{{$}}
140-
// CHECK: FunctionDecl {{.*}}{{.*}}dup {{.*}}
141-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}}
142-
// CHECK: ConstantExpr {{.*}} 'int'
143-
// CHECK: value: Int 8
144-
// CHECK: IntegerLiteral {{.*}}8{{$}}
145-
// CHECK: FunctionDecl {{.*}}{{.*}}dup {{.*}}
146-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}}
147-
// CHECK: ConstantExpr {{.*}} 'int'
148-
// CHECK: value: Int 9
149-
// CHECK: IntegerLiteral {{.*}}9{{$}}
150-
// CHECK: FunctionDecl {{.*}}{{.*}}kernel_name1{{.*}}
151-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}}
152-
// CHECK: ConstantExpr {{.*}} 'int'
153-
// CHECK: value: Int 4
154-
// CHECK: IntegerLiteral{{.*}}4{{$}}
155-
// CHECK: FunctionDecl {{.*}}{{.*}}kernel_name4{{.*}}
156-
// CHECK: SYCLIntelFPGAMaxConcurrencyAttr {{.*}}
157-
// CHECK: ConstantExpr {{.*}} 'int'
158-
// CHECK: value: Int 4
159-
// CHECK: IntegerLiteral{{.*}}4{{$}}
62+
// Test that checks expression is not a constant expression.
63+
// expected-note@+1{{declared here}}
64+
int baz();
65+
// expected-error@+2{{expression is not an integral constant expression}}
66+
// expected-note@+1{{non-constexpr function 'baz' cannot be used in a constant expression}}
67+
[[intel::max_concurrency(baz() + 1)]] void func12();
68+
69+
// Test that checks expression is a constant expression.
70+
constexpr int bar() { return 0; }
71+
[[intel::max_concurrency(bar() + 2)]] void func13(); // OK
72+
73+
// Test that checks wrong function template instantiation and ensures that the type
74+
// is checked properly when instantiating from the template definition.
75+
template <typename Ty>
76+
// expected-error@+2 {{integral constant expression must have integral or unscoped enumeration type, not 'S'}}
77+
// expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'float'}}
78+
[[intel::max_concurrency(Ty{})]] void func14() {}
79+
80+
struct S {};
81+
void test() {
82+
// expected-note@+1{{in instantiation of function template specialization 'func14<S>' requested here}}
83+
func14<S>();
84+
// expected-note@+1{{in instantiation of function template specialization 'func14<float>' requested here}}
85+
func14<float>();
86+
}

0 commit comments

Comments
 (0)