Skip to content

Commit 61d60b6

Browse files
MrSidimsbader
authored andcommitted
[SYCL][FPGA] Implement num_simd_work_items kernel attribute
Applies to a device function/lambda function. Indicates the number of X work items that should be processed in parallel. Valid values are positive integers. Signed-off-by: Dmitry Sidorov <[email protected]>
1 parent 2840458 commit 61d60b6

File tree

8 files changed

+164
-6
lines changed

8 files changed

+164
-6
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,15 @@ def SYCLIntelKernelArgsRestrict : InheritableAttr {
11141114
let Documentation = [ SYCLIntelKernelArgsRestrictDocs ];
11151115
}
11161116

1117+
def SYCLIntelNumSimdWorkItems : InheritableAttr {
1118+
let Spellings = [CXX11<"intelfpga","num_simd_work_items">];
1119+
let Args = [UnsignedArgument<"Number">];
1120+
let LangOpts = [SYCLIsDevice, SYCLIsHost];
1121+
let Subjects = SubjectList<[Function], ErrorDiag>;
1122+
let Documentation = [SYCLIntelNumSimdWorkItemsAttrDocs];
1123+
let PragmaAttributeSupport = 0;
1124+
}
1125+
11171126
def C11NoReturn : InheritableAttr {
11181127
let Spellings = [Keyword<"_Noreturn">];
11191128
let Subjects = SubjectList<[Function], ErrorDiag>;

clang/include/clang/Basic/AttrDocs.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,17 @@ function, and no effect otherwise.
19581958
}];
19591959
}
19601960

1961+
def SYCLIntelNumSimdWorkItemsAttrDocs : Documentation {
1962+
let Category = DocCatFunction;
1963+
let Heading = "num_simd_work_items (IntelFPGA)";
1964+
let Content = [{
1965+
Applies to a device function/lambda function. Indicates the number of work
1966+
items that should be processed in parallel. Valid values are positive integers.
1967+
If ``intelfpga::num_simd_work_items`` is applied to a function called from a
1968+
device kernel, the attribute is ignored and it is not propagated to a kernel.
1969+
}];
1970+
}
1971+
19611972
def SYCLFPGAPipeDocs : Documentation {
19621973
let Category = DocCatStmt;
19631974
let Heading = "pipe (read_only, write_only)";

clang/include/clang/Basic/AttributeCommonInfo.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ class AttributeCommonInfo {
154154
// to the call operator declaration.
155155
auto ParsedAttr = getParsedKind();
156156
if (ParsedAttr == AT_SYCLIntelKernelArgsRestrict ||
157-
(ParsedAttr == AT_ReqdWorkGroupSize && isCXX11Attribute()))
157+
(ParsedAttr == AT_ReqdWorkGroupSize && isCXX11Attribute()) ||
158+
ParsedAttr == AT_SYCLIntelNumSimdWorkItems)
158159
return true;
159160

160161
return false;

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,14 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
587587
Fn->setMetadata("intel_reqd_sub_group_size",
588588
llvm::MDNode::get(Context, AttrMDArgs));
589589
}
590+
591+
if (const SYCLIntelNumSimdWorkItemsAttr *A =
592+
FD->getAttr<SYCLIntelNumSimdWorkItemsAttr>()) {
593+
llvm::Metadata *AttrMDArgs[] = {
594+
llvm::ConstantAsMetadata::get(Builder.getInt32(A->getNumber()))};
595+
Fn->setMetadata("num_simd_work_items",
596+
llvm::MDNode::get(Context, AttrMDArgs));
597+
}
590598
}
591599

592600
/// Determine whether the function F ends with a return stmt.

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2903,6 +2903,31 @@ static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
29032903
IntelReqdSubGroupSizeAttr(S.Context, AL, SGSize));
29042904
}
29052905

2906+
// Handles num_simd_work_items.
2907+
static void handleNumSimdWorkItemsAttr(Sema &S, Decl *D,
2908+
const ParsedAttr &Attr) {
2909+
if (D->isInvalidDecl())
2910+
return;
2911+
2912+
uint32_t NumSimdWorkItems = 0;
2913+
const Expr *E = Attr.getArgAsExpr(0);
2914+
if (!checkUInt32Argument(S, Attr, E, NumSimdWorkItems, 0,
2915+
/*StrictlyUnsigned=*/true))
2916+
return;
2917+
2918+
if (NumSimdWorkItems == 0) {
2919+
S.Diag(Attr.getLoc(), diag::err_attribute_argument_is_zero)
2920+
<< Attr << E->getSourceRange();
2921+
return;
2922+
}
2923+
2924+
if (D->getAttr<SYCLIntelNumSimdWorkItemsAttr>())
2925+
S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr;
2926+
2927+
D->addAttr(::new (S.Context) SYCLIntelNumSimdWorkItemsAttr(
2928+
S.Context, Attr, NumSimdWorkItems));
2929+
}
2930+
29062931
static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
29072932
if (!AL.hasParsedType()) {
29082933
S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
@@ -7323,6 +7348,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
73237348
case ParsedAttr::AT_IntelReqdSubGroupSize:
73247349
handleSubGroupSize(S, D, AL);
73257350
break;
7351+
case ParsedAttr::AT_SYCLIntelNumSimdWorkItems:
7352+
handleNumSimdWorkItemsAttr(S, D, AL);
7353+
break;
73267354
case ParsedAttr::AT_VecTypeHint:
73277355
handleVecTypeHint(S, D, AL);
73287356
break;

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -428,18 +428,27 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
428428
Attrs.insert(A);
429429
if (auto *A = FD->getAttr<ReqdWorkGroupSizeAttr>())
430430
Attrs.insert(A);
431+
432+
// Allow the following kernel attributes only on lambda functions and
433+
// function objects that are called directly from a kernel (i.e. the one
434+
// passed to the parallel_for function). For all other cases,
435+
// emit a warning and ignore.
431436
if (auto *A = FD->getAttr<SYCLIntelKernelArgsRestrictAttr>()) {
432-
// Allow the intel::kernel_args_restrict only on the lambda (function
433-
// object) function, that is called directly from a kernel (i.e. the one
434-
// passed to the parallel_for function). Emit a warning and ignore all
435-
// other cases.
436437
if (ParentFD == SYCLKernel) {
437438
Attrs.insert(A);
438439
} else {
439440
SemaRef.Diag(A->getLocation(), diag::warn_attribute_ignored) << A;
440441
FD->dropAttr<SYCLIntelKernelArgsRestrictAttr>();
441442
}
442443
}
444+
if (auto *A = FD->getAttr<SYCLIntelNumSimdWorkItemsAttr>()) {
445+
if (ParentFD == SYCLKernel) {
446+
Attrs.insert(A);
447+
} else {
448+
SemaRef.Diag(A->getLocation(), diag::warn_attribute_ignored) << A;
449+
FD->dropAttr<SYCLIntelNumSimdWorkItemsAttr>();
450+
}
451+
}
443452

444453
// TODO: vec_len_hint should be handled here
445454

@@ -1338,7 +1347,8 @@ void Sema::MarkDevice(void) {
13381347
}
13391348
break;
13401349
}
1341-
case attr::Kind::SYCLIntelKernelArgsRestrict: {
1350+
case attr::Kind::SYCLIntelKernelArgsRestrict:
1351+
case attr::Kind::SYCLIntelNumSimdWorkItems: {
13421352
SYCLKernel->addAttr(A);
13431353
break;
13441354
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %clang_cc1 -std=c++11 -triple spir64-unknown-unknown-sycldevice -disable-llvm-passes -fsycl-is-device -emit-llvm -o - %s | FileCheck %s
2+
3+
class Foo {
4+
public:
5+
[[intelfpga::num_simd_work_items(1)]] void operator()() {}
6+
};
7+
8+
template <typename name, typename Func>
9+
__attribute__((sycl_kernel)) void kernel(Func kernelFunc) {
10+
kernelFunc();
11+
}
12+
13+
void bar() {
14+
Foo boo;
15+
kernel<class kernel_name1>(boo);
16+
17+
kernel<class kernel_name2>(
18+
[]() [[intelfpga::num_simd_work_items(42)]] {});
19+
20+
}
21+
22+
// CHECK: define spir_kernel void @{{.*}}kernel_name1() {{.*}} !num_simd_work_items ![[NUM1:[0-9]+]]
23+
// CHECK: define spir_kernel void @{{.*}}kernel_name2() {{.*}} !num_simd_work_items ![[NUM42:[0-9]+]]
24+
// CHECK: ![[NUM1]] = !{i32 1}
25+
// CHECK: ![[NUM42]] = !{i32 42}
26+
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// RUN: %clang %s -fsyntax-only -fsycl-device-only -DTRIGGER_ERROR -Xclang -verify
2+
// RUN: %clang %s -fsyntax-only -Xclang -ast-dump -fsycl-device-only | FileCheck %s
3+
// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -verify %s
4+
5+
#ifndef __SYCL_DEVICE_ONLY__
6+
struct FuncObj {
7+
[[intelfpga::num_simd_work_items(42)]] // expected-no-diagnostics
8+
void operator()() {}
9+
};
10+
11+
template <typename name, typename Func>
12+
void kernel(Func kernelFunc) {
13+
kernelFunc();
14+
}
15+
16+
void foo() {
17+
kernel<class test_kernel1>(
18+
FuncObj());
19+
}
20+
21+
#else // __SYCL_DEVICE_ONLY__
22+
23+
[[intelfpga::num_simd_work_items(2)]] // expected-warning{{'num_simd_work_items' attribute ignored}}
24+
void func_ignore() {}
25+
26+
struct FuncObj {
27+
[[intelfpga::num_simd_work_items(42)]]
28+
void operator()() {}
29+
};
30+
31+
template <typename name, typename Func>
32+
__attribute__((sycl_kernel)) void kernel(Func kernelFunc) {
33+
kernelFunc();
34+
}
35+
36+
int main() {
37+
// CHECK-LABEL: FunctionDecl {{.*}} _ZTSZ4mainE12test_kernel1
38+
// CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} 42
39+
kernel<class test_kernel1>(
40+
FuncObj());
41+
42+
// CHECK-LABEL: FunctionDecl {{.*}} _ZTSZ4mainE12test_kernel2
43+
// CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} 8
44+
kernel<class test_kernel2>(
45+
[]() [[intelfpga::num_simd_work_items(8)]] {});
46+
47+
// CHECK-LABEL: FunctionDecl {{.*}} _ZTSZ4mainE12test_kernel3
48+
// CHECK-NOT: SYCLIntelNumSimdWorkItemsAttr {{.*}} 2
49+
kernel<class test_kernel3>(
50+
[]() {func_ignore();});
51+
52+
#ifdef TRIGGER_ERROR
53+
[[intelfpga::num_simd_work_items(0)]] int Var = 0; // expected-error{{'num_simd_work_items' attribute only applies to functions}}
54+
55+
kernel<class test_kernel4>(
56+
[]() [[intelfpga::num_simd_work_items(0)]] {}); // expected-error{{'num_simd_work_items' attribute must be greater than 0}}
57+
58+
kernel<class test_kernel5>(
59+
[]() [[intelfpga::num_simd_work_items(-42)]] {}); // expected-error{{'num_simd_work_items' attribute requires a non-negative integral compile time constant expression}}
60+
61+
kernel<class test_kernel6>(
62+
[]() [[intelfpga::num_simd_work_items(1), intelfpga::num_simd_work_items(2)]] {}); // expected-warning{{attribute 'num_simd_work_items' is already applied with different parameters}}
63+
#endif // TRIGGER_ERROR
64+
}
65+
#endif // __SYCL_DEVICE_ONLY__

0 commit comments

Comments
 (0)