From baa3542b31bdaf1d52d86f5a49ff9464e8c640b5 Mon Sep 17 00:00:00 2001 From: Soumi Manna Date: Wed, 10 Mar 2021 07:30:39 -0800 Subject: [PATCH 1/8] [SYCL][FPGA][NFC] Fix num_simd_work_items and reqd_work_group_size argument check The order of the arguments to reqd_work_group_size in SYCL and OpenCL are reversed. In the OpenCL syntax, reqd_work_group_size(X,Y,Z), X is the index that increments the fastest, followed by Y, then Z. If we preserve that definition of X, Y, and Z, then in SYCL the attribute is specified as reqd_work_group_size(Z,Y,X). This gets more complicated in the case where fewer than three arguments are provided. In such a case it's not the "X" argument that is omitted (by the definitions of X, Y, and Z above) it's the Z dimension that's omitted. So the two argument version has the syntax reqd_work_group_size(Y,X). Similarly, the one argument variant has syntax reqd_work_group_size(X). This patches fixes the problem on https://github.com/intel/llvm/pull/3275 where we checked the wrong argument. In SYCL, the num_simd_work_items must evenly divide the last argument to reqd_work_group_size regardless of how many arguments req_work_group_size has. Signed-off-by: Soumi Manna --- clang/include/clang/Basic/AttrDocs.td | 2 +- clang/lib/Sema/SemaDeclAttr.cpp | 13 +-- .../SemaSYCL/num_simd_work_items_device.cpp | 86 +++++++++---------- 3 files changed, 52 insertions(+), 49 deletions(-) diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index c0821ebd48491..edbbdfc4fc323 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2421,7 +2421,7 @@ device kernel, the attribute is not ignored and it is propagated to the kernel. If the`` intel::reqd_work_group_size`` or ``cl::reqd_work_group_size`` attribute is specified on a declaration along with a intel::num_simd_work_items attribute, the work group size attribute -argument (the first argument) must be evenly divisible by the argument specified +argument (the last argument) must be evenly divisible by the argument specified in the ``intel::num_simd_work_items`` attribute. .. code-block:: c++ diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b67e650afa0be..24329886aa65b 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3151,11 +3151,14 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { return; ZDimExpr = ZDim.get(); + // If the declaration has an [[intel::num_simd_work_items()]] attribute, + // check to see if the last argument can be evenly divided by the + // num_simd_work_items attribute if (const auto *A = D->getAttr()) { int64_t NumSimdWorkItems = A->getValue()->getIntegerConstantExpr(Ctx)->getSExtValue(); - if (XDimVal.getZExtValue() % NumSimdWorkItems != 0) { + if (ZDimVal.getZExtValue() % NumSimdWorkItems != 0) { S.Diag(A->getLocation(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) << A << AL; S.Diag(AL.getLoc(), diag::note_conflicting_attribute); @@ -3302,13 +3305,13 @@ void Sema::AddSYCLIntelNumSimdWorkItemsAttr(Decl *D, } } - // If the declaration has an [[intel::reqd_work_group_size]] attribute, - // check to see if the first argument can be evenly divided by the + // If the declaration has an [[intel::reqd_work_group_size()]] attribute, + // check to see if the last argument can be evenly divided by the // num_simd_work_items attribute. if (const auto *DeclAttr = D->getAttr()) { - Optional XDimVal = DeclAttr->getXDimVal(Context); + Optional ZDimVal = DeclAttr->getZDimVal(Context); - if (*XDimVal % ArgVal != 0) { + if (*ZDimVal % ArgVal != 0) { Diag(CI.getLoc(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) << CI << DeclAttr; Diag(DeclAttr->getLocation(), diag::note_conflicting_attribute); diff --git a/clang/test/SemaSYCL/num_simd_work_items_device.cpp b/clang/test/SemaSYCL/num_simd_work_items_device.cpp index c26f731f4ac37..dd6fa26bdd39e 100644 --- a/clang/test/SemaSYCL/num_simd_work_items_device.cpp +++ b/clang/test/SemaSYCL/num_simd_work_items_device.cpp @@ -42,17 +42,17 @@ struct FuncObj { #ifdef TRIGGER_ERROR // If the declaration has an [[intel::reqd_work_group_size]] or // [[cl::reqd_work_group_size]] attribute, tests that check if -// the work group size attribute argument (the first argument) +// the work group size attribute argument (the last argument) // can be evenly divided by the num_simd_work_items attribute. struct TRIFuncObjBad1 { [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} - [[intel::reqd_work_group_size(5, 3, 3)]] // expected-note{{conflicting attribute is here}} + [[intel::reqd_work_group_size(5, 3, 5)]] // expected-note{{conflicting attribute is here}} void operator()() const {} }; struct TRIFuncObjBad2 { - [[intel::reqd_work_group_size(5, 3, 3)]] // expected-note{{conflicting attribute is here}} + [[intel::reqd_work_group_size(5, 3, 5)]] // expected-note{{conflicting attribute is here}} [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} void operator()() const {} @@ -60,13 +60,13 @@ struct TRIFuncObjBad2 { struct TRIFuncObjBad3 { [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} - [[cl::reqd_work_group_size(5, 3, 3)]] // expected-note{{conflicting attribute is here}} + [[cl::reqd_work_group_size(5, 3, 5)]] // expected-note{{conflicting attribute is here}} void operator()() const {} }; struct TRIFuncObjBad4 { - [[cl::reqd_work_group_size(5, 3, 3)]] // expected-note{{conflicting attribute is here}} + [[cl::reqd_work_group_size(5, 3, 5)]] // expected-note{{conflicting attribute is here}} [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} void operator()() const {} @@ -74,13 +74,13 @@ struct TRIFuncObjBad4 { struct TRIFuncObjBad5 { [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} - [[intel::reqd_work_group_size(5)]] //expected-note{{conflicting attribute is here}} + [[intel::reqd_work_group_size(3)]] //expected-note{{conflicting attribute is here}} void operator()() const {} }; struct TRIFuncObjBad6 { - [[intel::reqd_work_group_size(5)]] // expected-note{{conflicting attribute is here}} + [[intel::reqd_work_group_size(3)]] // expected-note{{conflicting attribute is here}} [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} void operator()() const {} @@ -168,48 +168,48 @@ struct TRIFuncObjBad18 { // can be evenly divided by the num_simd_work_items attribute. struct TRIFuncObjGood1 { [[intel::num_simd_work_items(4)]] - [[intel::reqd_work_group_size(64, 64, 5)]] void + [[intel::reqd_work_group_size(64, 64, 64)]] void operator()() const {} }; struct TRIFuncObjGood2 { - [[intel::reqd_work_group_size(64, 64, 5)]] + [[intel::reqd_work_group_size(64, 64, 64)]] [[intel::num_simd_work_items(4)]] void operator()() const {} }; struct TRIFuncObjGood3 { [[intel::num_simd_work_items(4)]] - [[cl::reqd_work_group_size(64, 64, 5)]] void + [[cl::reqd_work_group_size(64, 64, 64)]] void operator()() const {} }; struct TRIFuncObjGood4 { - [[cl::reqd_work_group_size(64, 64, 5)]] + [[cl::reqd_work_group_size(64, 64, 64)]] [[intel::num_simd_work_items(4)]] void operator()() const {} }; struct TRIFuncObjGood5 { [[intel::num_simd_work_items(4)]] - [[intel::reqd_work_group_size(64)]] void + [[intel::reqd_work_group_size(6, 6, 4)]] void operator()() const {} }; struct TRIFuncObjGood6 { - [[intel::reqd_work_group_size(64)]] + [[intel::reqd_work_group_size(6, 6, 4)]] [[intel::num_simd_work_items(4)]] void operator()() const {} }; struct TRIFuncObjGood7 { [[intel::num_simd_work_items(4)]] - [[intel::reqd_work_group_size(64, 5)]] void + [[intel::reqd_work_group_size(5, 5, 4)]] void operator()() const {} }; struct TRIFuncObjGood8 { - [[intel::reqd_work_group_size(64, 5)]] + [[intel::reqd_work_group_size(5, 5, 4)]] [[intel::num_simd_work_items(4)]] void operator()() const {} }; @@ -251,8 +251,8 @@ int main() { // CHECK-NEXT: value: Int 64 // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} + // CHECK-NEXT: value: Int 64 + // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 @@ -268,8 +268,8 @@ int main() { // CHECK-NEXT: value: Int 64 // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} + // CHECK-NEXT: value: Int 64 + // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 @@ -285,8 +285,8 @@ int main() { // CHECK-NEXT: value: Int 64 // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} + // CHECK-NEXT: value: Int 64 + // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 @@ -302,8 +302,8 @@ int main() { // CHECK-NEXT: value: Int 64 // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} + // CHECK-NEXT: value: Int 64 + // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 @@ -313,14 +313,14 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel8 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 6 + // CHECK-NEXT: IntegerLiteral{{.*}}6{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 1 - // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} + // CHECK-NEXT: value: Int 6 + // CHECK-NEXT: IntegerLiteral{{.*}}6{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 1 - // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} + // CHECK-NEXT: value: Int 4 + // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 @@ -330,14 +330,14 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel9 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 6 + // CHECK-NEXT: IntegerLiteral{{.*}}6{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 1 - // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} + // CHECK-NEXT: value: Int 6 + // CHECK-NEXT: IntegerLiteral{{.*}}6{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 1 - // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} + // CHECK-NEXT: value: Int 4 + // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 @@ -347,14 +347,14 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel10 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 5 + // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 5 // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 1 - // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} + // CHECK-NEXT: value: Int 4 + // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 @@ -364,14 +364,14 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel11 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 5 + // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 5 // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 1 - // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} + // CHECK-NEXT: value: Int 4 + // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 From 00deaeeaabbaf52537c47bfa2f5c71e3758bdd3f Mon Sep 17 00:00:00 2001 From: Soumi Manna Date: Wed, 10 Mar 2021 07:49:48 -0800 Subject: [PATCH 2/8] fix test Signed-off-by: Soumi Manna --- clang/test/SemaSYCL/num_simd_work_items_device.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/SemaSYCL/num_simd_work_items_device.cpp b/clang/test/SemaSYCL/num_simd_work_items_device.cpp index dd6fa26bdd39e..73b81a6fb3421 100644 --- a/clang/test/SemaSYCL/num_simd_work_items_device.cpp +++ b/clang/test/SemaSYCL/num_simd_work_items_device.cpp @@ -164,7 +164,7 @@ struct TRIFuncObjBad18 { #endif // TRIGGER_ERROR // If the declaration has an [[intel::reqd_work_group_size]] or // [[cl::reqd_work_group_size]] attribute, tests that check if -// the work group size attribute argument (the first argument) +// the work group size attribute argument (the last argument) // can be evenly divided by the num_simd_work_items attribute. struct TRIFuncObjGood1 { [[intel::num_simd_work_items(4)]] From e5d1479df7ff427506dbaa7a9cd1d20833d29baa Mon Sep 17 00:00:00 2001 From: Soumi Manna Date: Fri, 12 Mar 2021 06:24:34 -0800 Subject: [PATCH 3/8] Address review comments Signed-off-by: Soumi Manna --- clang/lib/Sema/SemaDeclAttr.cpp | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 24329886aa65b..b9b70b4955baa 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3152,13 +3152,20 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { ZDimExpr = ZDim.get(); // If the declaration has an [[intel::num_simd_work_items()]] attribute, - // check to see if the last argument can be evenly divided by the - // num_simd_work_items attribute + // check to see if the first argument (OpenCL spelling) or last argument + // (SYCL spelling) can be evenly divided by the num_simd_work_items + // attribute since first and last argument are only swapped for the + // Intel SYCL attributes and not the OpenCL ones. if (const auto *A = D->getAttr()) { int64_t NumSimdWorkItems = A->getValue()->getIntegerConstantExpr(Ctx)->getSExtValue(); - if (ZDimVal.getZExtValue() % NumSimdWorkItems != 0) { + unsigned checkWorkGroupSize = + AL.getSyntax() == AttributeCommonInfo::AS_GNU + ? XDimVal.getZExtValue() + : ZDimVal.getZExtValue(); + + if (checkWorkGroupSize % NumSimdWorkItems != 0) { S.Diag(A->getLocation(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) << A << AL; S.Diag(AL.getLoc(), diag::note_conflicting_attribute); @@ -3304,14 +3311,24 @@ void Sema::AddSYCLIntelNumSimdWorkItemsAttr(Decl *D, return; } } - - // If the declaration has an [[intel::reqd_work_group_size()]] attribute, - // check to see if the last argument can be evenly divided by the + // If the declaration has a [[intel::reqd_work_group_size()]] or + // [[cl::reqd_work_group_size()]] attribute, check to see if the + // last argument can be evenly divided by the // num_simd_work_items attribute. + // If the declaration has a __attribute__((reqd_work_group_size)) + // attribute, check to see if the first argument can be evenly + // divided by the num_simd_work_items attribute. + // First and last argument are only swapped for the Intel attributes + // and not the OpenCL ones. if (const auto *DeclAttr = D->getAttr()) { + Optional XDimVal = DeclAttr->getXDimVal(Context); Optional ZDimVal = DeclAttr->getZDimVal(Context); - if (*ZDimVal % ArgVal != 0) { + llvm::APSInt WorkGroupSize = + DeclAttr->getSyntax() == AttributeCommonInfo::AS_GNU + ? *XDimVal : *ZDimVal; + + if (WorkGroupSize % ArgVal != 0) { Diag(CI.getLoc(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) << CI << DeclAttr; Diag(DeclAttr->getLocation(), diag::note_conflicting_attribute); From 602ef39fef2853e545292bea0f3932c126e7d889 Mon Sep 17 00:00:00 2001 From: Soumi Manna Date: Fri, 12 Mar 2021 06:30:43 -0800 Subject: [PATCH 4/8] Fix errors Signed-off-by: Soumi Manna --- clang/lib/Sema/SemaDeclAttr.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b9b70b4955baa..806f8062e5c70 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3161,9 +3161,9 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { A->getValue()->getIntegerConstantExpr(Ctx)->getSExtValue(); unsigned checkWorkGroupSize = - AL.getSyntax() == AttributeCommonInfo::AS_GNU - ? XDimVal.getZExtValue() - : ZDimVal.getZExtValue(); + AL.getSyntax() == AttributeCommonInfo::AS_GNU + ? XDimVal.getZExtValue() + : ZDimVal.getZExtValue(); if (checkWorkGroupSize % NumSimdWorkItems != 0) { S.Diag(A->getLocation(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) @@ -3325,8 +3325,8 @@ void Sema::AddSYCLIntelNumSimdWorkItemsAttr(Decl *D, Optional ZDimVal = DeclAttr->getZDimVal(Context); llvm::APSInt WorkGroupSize = - DeclAttr->getSyntax() == AttributeCommonInfo::AS_GNU - ? *XDimVal : *ZDimVal; + DeclAttr->getSyntax() == AttributeCommonInfo::AS_GNU ? *XDimVal + : *ZDimVal; if (WorkGroupSize % ArgVal != 0) { Diag(CI.getLoc(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) From bf958c656bd0b7d2a355b0c3ef52d6af35f4d83d Mon Sep 17 00:00:00 2001 From: Soumi Manna Date: Fri, 12 Mar 2021 10:08:17 -0800 Subject: [PATCH 5/8] address review comments Signed-off-by: Soumi Manna --- .../SemaSYCL/num_simd_work_items_device.cpp | 190 +++++------------- 1 file changed, 49 insertions(+), 141 deletions(-) diff --git a/clang/test/SemaSYCL/num_simd_work_items_device.cpp b/clang/test/SemaSYCL/num_simd_work_items_device.cpp index 73b81a6fb3421..2641ff5297809 100644 --- a/clang/test/SemaSYCL/num_simd_work_items_device.cpp +++ b/clang/test/SemaSYCL/num_simd_work_items_device.cpp @@ -46,13 +46,13 @@ struct FuncObj { // can be evenly divided by the num_simd_work_items attribute. struct TRIFuncObjBad1 { [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} - [[intel::reqd_work_group_size(5, 3, 5)]] // expected-note{{conflicting attribute is here}} + [[intel::reqd_work_group_size(3, 3, 5)]] // expected-note{{conflicting attribute is here}} void operator()() const {} }; struct TRIFuncObjBad2 { - [[intel::reqd_work_group_size(5, 3, 5)]] // expected-note{{conflicting attribute is here}} + [[intel::reqd_work_group_size(3, 3, 5)]] // expected-note{{conflicting attribute is here}} [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} void operator()() const {} @@ -60,13 +60,13 @@ struct TRIFuncObjBad2 { struct TRIFuncObjBad3 { [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} - [[cl::reqd_work_group_size(5, 3, 5)]] // expected-note{{conflicting attribute is here}} + [[cl::reqd_work_group_size(3, 3, 5)]] // expected-note{{conflicting attribute is here}} void operator()() const {} }; struct TRIFuncObjBad4 { - [[cl::reqd_work_group_size(5, 3, 5)]] // expected-note{{conflicting attribute is here}} + [[cl::reqd_work_group_size(3, 3, 5)]] // expected-note{{conflicting attribute is here}} [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} void operator()() const {} @@ -87,7 +87,7 @@ struct TRIFuncObjBad6 { }; struct TRIFuncObjBad7 { - [[intel::num_simd_work_items(4)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} [[intel::reqd_work_group_size(3, 64)]] // expected-note{{conflicting attribute is here}} void operator()() const {} @@ -95,21 +95,21 @@ struct TRIFuncObjBad7 { struct TRIFuncObjBad8 { [[intel::reqd_work_group_size(3, 64)]] // expected-note{{conflicting attribute is here}} - [[intel::num_simd_work_items(4)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} void operator()() const {} }; // Tests for incorrect argument values for Intel FPGA num_simd_work_items and reqd_work_group_size function attributes struct TRIFuncObjBad9 { - [[intel::reqd_work_group_size(5, 5, 5)]] + [[intel::reqd_work_group_size(3, 3, 5)]] [[intel::num_simd_work_items(0)]] // expected-error{{'num_simd_work_items' attribute requires a positive integral compile time constant expression}} void operator()() const {} }; struct TRIFuncObjBad10 { [[intel::num_simd_work_items(0)]] // expected-error{{'num_simd_work_items' attribute requires a positive integral compile time constant expression}} - [[intel::reqd_work_group_size(5, 5, 5)]] void + [[intel::reqd_work_group_size(3, 3, 5)]] void operator()() const {} }; @@ -168,48 +168,24 @@ struct TRIFuncObjBad18 { // can be evenly divided by the num_simd_work_items attribute. struct TRIFuncObjGood1 { [[intel::num_simd_work_items(4)]] - [[intel::reqd_work_group_size(64, 64, 64)]] void + [[intel::reqd_work_group_size(3, 3, 64)]] void operator()() const {} }; struct TRIFuncObjGood2 { - [[intel::reqd_work_group_size(64, 64, 64)]] + [[intel::reqd_work_group_size(3, 3, 64)]] [[intel::num_simd_work_items(4)]] void operator()() const {} }; struct TRIFuncObjGood3 { [[intel::num_simd_work_items(4)]] - [[cl::reqd_work_group_size(64, 64, 64)]] void + [[cl::reqd_work_group_size(3, 3, 64)]] void operator()() const {} }; struct TRIFuncObjGood4 { - [[cl::reqd_work_group_size(64, 64, 64)]] - [[intel::num_simd_work_items(4)]] void - operator()() const {} -}; - -struct TRIFuncObjGood5 { - [[intel::num_simd_work_items(4)]] - [[intel::reqd_work_group_size(6, 6, 4)]] void - operator()() const {} -}; - -struct TRIFuncObjGood6 { - [[intel::reqd_work_group_size(6, 6, 4)]] - [[intel::num_simd_work_items(4)]] void - operator()() const {} -}; - -struct TRIFuncObjGood7 { - [[intel::num_simd_work_items(4)]] - [[intel::reqd_work_group_size(5, 5, 4)]] void - operator()() const {} -}; - -struct TRIFuncObjGood8 { - [[intel::reqd_work_group_size(5, 5, 4)]] + [[cl::reqd_work_group_size(3, 3, 64)]] [[intel::num_simd_work_items(4)]] void operator()() const {} }; @@ -245,11 +221,11 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel4 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 64 // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} @@ -262,11 +238,11 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel5 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 64 // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} @@ -279,11 +255,11 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel6 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 64 // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} @@ -296,11 +272,11 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel7 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 64 // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} @@ -309,120 +285,52 @@ int main() { // CHECK-NEXT: value: Int 4 // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - h.single_task(TRIFuncObjGood5()); - // CHECK-LABEL: FunctionDecl {{.*}}test_kernel8 - // CHECK: ReqdWorkGroupSizeAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 6 - // CHECK-NEXT: IntegerLiteral{{.*}}6{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 6 - // CHECK-NEXT: IntegerLiteral{{.*}}6{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - - h.single_task(TRIFuncObjGood6()); - // CHECK-LABEL: FunctionDecl {{.*}}test_kernel9 - // CHECK: ReqdWorkGroupSizeAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 6 - // CHECK-NEXT: IntegerLiteral{{.*}}6{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 6 - // CHECK-NEXT: IntegerLiteral{{.*}}6{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - - h.single_task(TRIFuncObjGood7()); - // CHECK-LABEL: FunctionDecl {{.*}}test_kernel10 - // CHECK: ReqdWorkGroupSizeAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - - h.single_task(TRIFuncObjGood8()); - // CHECK-LABEL: FunctionDecl {{.*}}test_kernel11 - // CHECK: ReqdWorkGroupSizeAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - #ifdef TRIGGER_ERROR [[intel::num_simd_work_items(0)]] int Var = 0; // expected-error{{'num_simd_work_items' attribute only applies to functions}} - h.single_task( + h.single_task( []() [[intel::num_simd_work_items(0)]]{}); // expected-error{{'num_simd_work_items' attribute requires a positive integral compile time constant expression}} - h.single_task( + h.single_task( []() [[intel::num_simd_work_items(-42)]]{}); // expected-error{{'num_simd_work_items' attribute requires a positive integral compile time constant expression}} - h.single_task(TRIFuncObjBad1()); + h.single_task(TRIFuncObjBad1()); - h.single_task(TRIFuncObjBad2()); + h.single_task(TRIFuncObjBad2()); - h.single_task(TRIFuncObjBad3()); + h.single_task(TRIFuncObjBad3()); - h.single_task(TRIFuncObjBad4()); + h.single_task(TRIFuncObjBad4()); - h.single_task(TRIFuncObjBad5()); + h.single_task(TRIFuncObjBad5()); - h.single_task(TRIFuncObjBad6()); + h.single_task(TRIFuncObjBad6()); - h.single_task(TRIFuncObjBad7()); + h.single_task(TRIFuncObjBad7()); - h.single_task(TRIFuncObjBad8()); + h.single_task(TRIFuncObjBad8()); - h.single_task(TRIFuncObjBad9()); + h.single_task(TRIFuncObjBad9()); - h.single_task(TRIFuncObjBad10()); + h.single_task(TRIFuncObjBad10()); - h.single_task(TRIFuncObjBad11()); + h.single_task(TRIFuncObjBad11()); - h.single_task(TRIFuncObjBad12()); + h.single_task(TRIFuncObjBad12()); - h.single_task(TRIFuncObjBad13()); + h.single_task(TRIFuncObjBad13()); - h.single_task(TRIFuncObjBad14()); + h.single_task(TRIFuncObjBad14()); - h.single_task(TRIFuncObjBad15()); + h.single_task(TRIFuncObjBad15()); - h.single_task(TRIFuncObjBad16()); + h.single_task(TRIFuncObjBad16()); - h.single_task(TRIFuncObjBad17()); + h.single_task(TRIFuncObjBad17()); - h.single_task(TRIFuncObjBad18()); + h.single_task(TRIFuncObjBad18()); - h.single_task( + h.single_task( []() [[intel::num_simd_work_items(1), intel::num_simd_work_items(2)]]{}); // expected-warning{{attribute 'num_simd_work_items' is already applied with different arguments}} \ // expected-note {{previous attribute is here}} #endif // TRIGGER_ERROR From ca86bb57194dc03e99ef800ef9be269115abec23 Mon Sep 17 00:00:00 2001 From: Soumi Manna Date: Sat, 13 Mar 2021 17:47:13 -0800 Subject: [PATCH 6/8] Address review comments Signed-off-by: Soumi Manna --- clang/include/clang/Basic/Attr.td | 3 + clang/include/clang/Basic/AttrDocs.td | 30 ++++-- clang/lib/Sema/SemaDeclAttr.cpp | 72 ++++++++++---- .../SemaSYCL/num_simd_work_items_device.cpp | 96 ++++++++++++------- ...cl-device-num_simd_work_items-template.cpp | 27 +++++- 5 files changed, 165 insertions(+), 63 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 598a073427194..7132a92b507e7 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2793,6 +2793,9 @@ def ReqdWorkGroupSize : InheritableAttr { ExprArgument<"YDim", /*optional*/1>, ExprArgument<"ZDim", /*optional*/1>]; let Subjects = SubjectList<[Function], ErrorDiag>; + let Accessors = [Accessor<"usesOpenCLArgOrdering", + [GNU<"reqd_work_group_size">, + CXX11<"cl","reqd_work_group_size">]>]; let AdditionalMembers = [{ ArrayRef dimensions() const { return {getXDim(), getYDim(), getZDim()}; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index edbbdfc4fc323..8d49adb67b211 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2418,26 +2418,44 @@ device kernel, the attribute is not ignored and it is propagated to the kernel. [[intel::num_simd_work_items(N)]] void operator()() const {} }; -If the`` intel::reqd_work_group_size`` or ``cl::reqd_work_group_size`` -attribute is specified on a declaration along with a -intel::num_simd_work_items attribute, the work group size attribute -argument (the last argument) must be evenly divisible by the argument specified +If the ``intel::reqd_work_group_size`` attribute is specified on a declaration +along with a ``intel::num_simd_work_items`` attribute, the work group size +(the last argument) must be evenly divisible by the argument specified in the ``intel::num_simd_work_items`` attribute. .. code-block:: c++ struct func { [[intel::num_simd_work_items(4)]] - [[intel::reqd_work_group_size(64, 64, 64)]] + [[intel::reqd_work_group_size(5, 5, 64)]] void operator()() const {} }; struct bar { - [[intel::reqd_work_group_size(64, 64, 64)]] + [[intel::reqd_work_group_size(5, 5, 64)]] [[intel::num_simd_work_items(4)]] void operator()() const {} }; +If the ``cl::reqd_work_group_size`` or ``__attribute__((reqd_work_group_size()))`` +attribute is specified on a declaration along with a ``intel::num_simd_work_items`` +attribute, the work group size (the first argument) must be evenly divisible by +the argument specified in the ``intel::num_simd_work_items`` attribute. +GNU and ``cl::reqd_work_group_size`` spelling of ReqdWorkGroupSizeAttr maps to +the OpenCL semantic. The first and last argument are only swapped for the Intel +attributes in SYCL and not the OpenCL ones. + +.. code-block:: c++ + + struct func1 { + [[intel::num_simd_work_items(4)]] + [[cl::reqd_work_group_size(4, 5, 5)]] + void operator()() const {} + }; + + [[intel::num_simd_work_items(2)]] + __attribute__((reqd_work_group_size(4,3,3))) void bar(); + }]; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 806f8062e5c70..34d8cd873f15c 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3152,20 +3152,28 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { ZDimExpr = ZDim.get(); // If the declaration has an [[intel::num_simd_work_items()]] attribute, - // check to see if the first argument (OpenCL spelling) or last argument - // (SYCL spelling) can be evenly divided by the num_simd_work_items - // attribute since first and last argument are only swapped for the - // Intel SYCL attributes and not the OpenCL ones. + // check to see if the first argument of [[cl::reqd_work_group_size()]] + // or __attribute__((reqd_work_group_size)) attribute and last argument + // of [intel::reqd_work_group_size()]] attribute can be evenly divided by + // the num_simd_work_items attribute. GNU and [[cl::reqd_work_group_size]] + // spelling of ReqdWorkGroupSizeAttr maps to the OpenCL + // semantics. First and last argument are only swapped for the Intel + // atributes in SYCL and not the OpenCL ones. if (const auto *A = D->getAttr()) { int64_t NumSimdWorkItems = A->getValue()->getIntegerConstantExpr(Ctx)->getSExtValue(); - unsigned checkWorkGroupSize = - AL.getSyntax() == AttributeCommonInfo::AS_GNU - ? XDimVal.getZExtValue() - : ZDimVal.getZExtValue(); + bool usesOpenCLArgOrdering = + ((AL.getSyntax() == AttributeCommonInfo::AS_CXX11 || + AL.getSyntax() == AttributeCommonInfo::AS_C2x) && + AL.hasScope() && AL.getScopeName()->isStr("cl")) || + AL.getSyntax() == AttributeCommonInfo::AS_GNU; - if (checkWorkGroupSize % NumSimdWorkItems != 0) { + unsigned WorkGroupSize = usesOpenCLArgOrdering + ? XDimVal.getZExtValue() + : ZDimVal.getZExtValue(); + + if (WorkGroupSize % NumSimdWorkItems != 0) { S.Diag(A->getLocation(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) << A << AL; S.Diag(AL.getLoc(), diag::note_conflicting_attribute); @@ -3311,22 +3319,22 @@ void Sema::AddSYCLIntelNumSimdWorkItemsAttr(Decl *D, return; } } - // If the declaration has a [[intel::reqd_work_group_size()]] or - // [[cl::reqd_work_group_size()]] attribute, check to see if the - // last argument can be evenly divided by the - // num_simd_work_items attribute. - // If the declaration has a __attribute__((reqd_work_group_size)) - // attribute, check to see if the first argument can be evenly + // If the declaration has a [[intel::reqd_work_group_size()]] + // attribute, check to see if the last argument can be evenly // divided by the num_simd_work_items attribute. - // First and last argument are only swapped for the Intel attributes - // and not the OpenCL ones. + // If the declaration has a __attribute__((reqd_work_group_size)) + // or [[cl::reqd_work_group_size()]] attribute, check to see if the + // first argument can be evenly divided by the num_simd_work_items + // attribute. GNU and [[cl::reqd_work_group_size()]] spelling of + // ReqdWorkGroupSizeAttr maps to the OpenCL semantics. First and last + // argument are only swapped for the Intel atributes in SYCL and not + // the OpenCL ones. if (const auto *DeclAttr = D->getAttr()) { Optional XDimVal = DeclAttr->getXDimVal(Context); Optional ZDimVal = DeclAttr->getZDimVal(Context); llvm::APSInt WorkGroupSize = - DeclAttr->getSyntax() == AttributeCommonInfo::AS_GNU ? *XDimVal - : *ZDimVal; + DeclAttr->usesOpenCLArgOrdering() ? *XDimVal : *ZDimVal; if (WorkGroupSize % ArgVal != 0) { Diag(CI.getLoc(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) @@ -3354,6 +3362,32 @@ SYCLIntelNumSimdWorkItemsAttr *Sema::MergeSYCLIntelNumSimdWorkItemsAttr( return nullptr; } } + // If the declaration has a [[intel::reqd_work_group_size()]] + // attribute, check to see if the last argument can be evenly + // divided by the num_simd_work_items attribute. + // If the declaration has a __attribute__((reqd_work_group_size)) + // or [[cl::reqd_work_group_size()]] attribute, check to see if the + // first argument can be evenly divided by the num_simd_work_items + // attribute. GNU and [[cl::reqd_work_group_size()]] spelling of + // ReqdWorkGroupSizeAttr maps to the OpenCL semantics. First and last + // argument are only swapped for the Intel atributes in SYCL and not + // the OpenCL ones. + if (const auto *DeclAttr = D->getAttr()) { + const auto *MergeExpr = dyn_cast(A.getValue()); + const auto *DeclXExpr = dyn_cast(DeclAttr->getXDim()); + const auto *DeclZExpr = dyn_cast(DeclAttr->getZDim()); + + llvm::APSInt WorkGroupSize = + DeclAttr->usesOpenCLArgOrdering() ? DeclXExpr->getResultAsAPSInt() + : DeclZExpr->getResultAsAPSInt(); + + if (WorkGroupSize % MergeExpr->getResultAsAPSInt() != 0) { + Diag(A.getLoc(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) + << &A << DeclAttr; + Diag(DeclAttr->getLocation(), diag::note_conflicting_attribute); + return nullptr; + } + } return ::new (Context) SYCLIntelNumSimdWorkItemsAttr(Context, A, A.getValue()); } diff --git a/clang/test/SemaSYCL/num_simd_work_items_device.cpp b/clang/test/SemaSYCL/num_simd_work_items_device.cpp index 2641ff5297809..7c5b9ded42643 100644 --- a/clang/test/SemaSYCL/num_simd_work_items_device.cpp +++ b/clang/test/SemaSYCL/num_simd_work_items_device.cpp @@ -40,10 +40,10 @@ struct FuncObj { }; #ifdef TRIGGER_ERROR -// If the declaration has an [[intel::reqd_work_group_size]] or -// [[cl::reqd_work_group_size]] attribute, tests that check if -// the work group size attribute argument (the last argument) -// can be evenly divided by the num_simd_work_items attribute. +// If the declaration has a [[intel::reqd_work_group_size]] +// attribute, tests that check if the work group size attribute +// argument (the last argument) can be evenly divided by the +// num_simd_work_items attribute. struct TRIFuncObjBad1 { [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} [[intel::reqd_work_group_size(3, 3, 5)]] // expected-note{{conflicting attribute is here}} @@ -53,53 +53,70 @@ struct TRIFuncObjBad1 { struct TRIFuncObjBad2 { [[intel::reqd_work_group_size(3, 3, 5)]] // expected-note{{conflicting attribute is here}} - [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} void operator()() const {} }; struct TRIFuncObjBad3 { - [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} - [[cl::reqd_work_group_size(3, 3, 5)]] // expected-note{{conflicting attribute is here}} + [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + [[intel::reqd_work_group_size(3)]] //expected-note{{conflicting attribute is here}} void operator()() const {} }; struct TRIFuncObjBad4 { - [[cl::reqd_work_group_size(3, 3, 5)]] // expected-note{{conflicting attribute is here}} - [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + [[intel::reqd_work_group_size(3)]] // expected-note{{conflicting attribute is here}} + [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} void operator()() const {} }; struct TRIFuncObjBad5 { - [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} - [[intel::reqd_work_group_size(3)]] //expected-note{{conflicting attribute is here}} + [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + [[intel::reqd_work_group_size(3, 64)]] // expected-note{{conflicting attribute is here}} void operator()() const {} }; struct TRIFuncObjBad6 { - [[intel::reqd_work_group_size(3)]] // expected-note{{conflicting attribute is here}} - [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + [[intel::reqd_work_group_size(3, 64)]] // expected-note{{conflicting attribute is here}} + [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} void operator()() const {} }; +[[intel::num_simd_work_items(2)]] void func1(); // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} +[[intel::reqd_work_group_size(4, 3, 3)]] void func1(); // expected-note{{conflicting attribute is here}} + +// If the declaration has a [[cl::reqd_work_group_size]] +// or __attribute__((reqd_work_group_size())) attribute, +// tests that check if the work group size attribute argument +// (the first argument) can be evenly divided by the num_simd_work_items +// attribute. GNU and [[cl::reqd_work_group_size]] spelling of +// ReqdWorkGroupSizeAttr maps to the OpenCL semantics. +// First and last argument are only swapped for the Intel atributes in +// SYCL and not the OpenCL ones. struct TRIFuncObjBad7 { - [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} - [[intel::reqd_work_group_size(3, 64)]] // expected-note{{conflicting attribute is here}} + [[cl::reqd_work_group_size(5, 3, 3)]] // expected-note{{conflicting attribute is here}} + [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} void operator()() const {} }; struct TRIFuncObjBad8 { - [[intel::reqd_work_group_size(3, 64)]] // expected-note{{conflicting attribute is here}} - [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + [[intel::num_simd_work_items(3)]] // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + [[cl::reqd_work_group_size(5, 3, 3)]] // expected-note{{conflicting attribute is here}} void operator()() const {} }; +[[intel::num_simd_work_items(2)]] void func2(); // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} +__attribute__((reqd_work_group_size(3,4,4))) void func2(); // expected-note{{conflicting attribute is here}} + +[[intel::num_simd_work_items(2)]] void func3(); // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} +[[cl::reqd_work_group_size(5, 3, 3)]] void func3(); // expected-note{{conflicting attribute is here}} + // Tests for incorrect argument values for Intel FPGA num_simd_work_items and reqd_work_group_size function attributes struct TRIFuncObjBad9 { [[intel::reqd_work_group_size(3, 3, 5)]] @@ -162,10 +179,16 @@ struct TRIFuncObjBad18 { }; #endif // TRIGGER_ERROR -// If the declaration has an [[intel::reqd_work_group_size]] or -// [[cl::reqd_work_group_size]] attribute, tests that check if -// the work group size attribute argument (the last argument) -// can be evenly divided by the num_simd_work_items attribute. +// If the declaration has a [[intel::reqd_work_group_size()]] +// attribute, check to see if the last argument can be evenly +// divided by the num_simd_work_items attribute. +// If the declaration has a __attribute__((reqd_work_group_size)) +// or [[cl::reqd_work_group_size()]] attribute, check to see if the +// first argument can be evenly divided by the num_simd_work_items +// attribute. GNU and [[cl::reqd_work_group_size()]] spelling of +// ReqdWorkGroupSizeAttr maps to the OpenCL semantics. First and last +// argument are only swapped for the Intel atributes in SYCL and not +// the OpenCL ones. struct TRIFuncObjGood1 { [[intel::num_simd_work_items(4)]] [[intel::reqd_work_group_size(3, 3, 64)]] void @@ -179,17 +202,20 @@ struct TRIFuncObjGood2 { }; struct TRIFuncObjGood3 { - [[intel::num_simd_work_items(4)]] - [[cl::reqd_work_group_size(3, 3, 64)]] void + [[intel::num_simd_work_items(2)]] + [[cl::reqd_work_group_size(4, 3, 3)]] void operator()() const {} }; struct TRIFuncObjGood4 { - [[cl::reqd_work_group_size(3, 3, 64)]] - [[intel::num_simd_work_items(4)]] void + [[cl::reqd_work_group_size(4, 3, 3)]] + [[intel::num_simd_work_items(2)]] void operator()() const {} }; +[[intel::num_simd_work_items(2)]] +__attribute__((reqd_work_group_size(4,3,3))) void func4(); //OK + int main() { q.submit([&](handler &h) { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel1 @@ -255,35 +281,35 @@ int main() { // CHECK-LABEL: FunctionDecl {{.*}}test_kernel6 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 4 + // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} + // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 3 // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 3 // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} + // CHECK-NEXT: value: Int 2 + // CHECK-NEXT: IntegerLiteral{{.*}}2{{$}} h.single_task(TRIFuncObjGood4()); // CHECK-LABEL: FunctionDecl {{.*}}test_kernel7 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 4 + // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} + // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 3 // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 3 // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} + // CHECK-NEXT: value: Int 2 + // CHECK-NEXT: IntegerLiteral{{.*}}2{{$}} #ifdef TRIGGER_ERROR [[intel::num_simd_work_items(0)]] int Var = 0; // expected-error{{'num_simd_work_items' attribute only applies to functions}} diff --git a/clang/test/SemaSYCL/sycl-device-num_simd_work_items-template.cpp b/clang/test/SemaSYCL/sycl-device-num_simd_work_items-template.cpp index 3ed44721314e4..2e5b97ec7d9a8 100644 --- a/clang/test/SemaSYCL/sycl-device-num_simd_work_items-template.cpp +++ b/clang/test/SemaSYCL/sycl-device-num_simd_work_items-template.cpp @@ -66,14 +66,35 @@ template template [[intel::num_simd_work_items(N)]] void func4() {} // expected-warning {{attribute 'num_simd_work_items' is already applied with different arguments}} +// Tests for num_simd_work_items and reqd_work_group_size arguments check. +template +__attribute__((reqd_work_group_size(3, 4, 4))) void func5(); // expected-note{{conflicting attribute is here}} +template +[[intel::num_simd_work_items(N)]] void func5(); // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + +template +[[cl::reqd_work_group_size(4, 3, 3)]] void func6(); // expected-note{{conflicting attribute is here}} +template +[[intel::num_simd_work_items(N)]] void func6(); // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + +template +[[intel::reqd_work_group_size(8, 4, 5)]] void func7(); // expected-note{{conflicting attribute is here}} +template +[[intel::num_simd_work_items(N)]] void func7(); // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + int check() { // no error expected func3<8>(); //expected-note@+1{{in instantiation of function template specialization 'func3<-1>' requested here}} func3<-1>(); - - func4<6>(); //expected-note {{in instantiation of function template specialization 'func4<6>' requested here}} - + //expected-note@+1{{in instantiation of function template specialization 'func4<6>' requested here}} + func4<6>(); + //expected-note@+1{{in instantiation of function template specialization 'func5<2>' requested here}} + func5<2>(); + //expected-note@+1{{in instantiation of function template specialization 'func6<3>' requested here}} + func6<3>(); + //expected-note@+1{{in instantiation of function template specialization 'func7<4>' requested here}} + func7<4>(); return 0; } From 5dd9786400983c80e183fa21d3ddfa85294bfe02 Mon Sep 17 00:00:00 2001 From: Soumi Manna Date: Sat, 13 Mar 2021 17:55:30 -0800 Subject: [PATCH 7/8] Fix errors Signed-off-by: Soumi Manna --- clang/lib/Sema/SemaDeclAttr.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 34d8cd873f15c..d90f05f18262c 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3164,14 +3164,13 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { A->getValue()->getIntegerConstantExpr(Ctx)->getSExtValue(); bool usesOpenCLArgOrdering = - ((AL.getSyntax() == AttributeCommonInfo::AS_CXX11 || - AL.getSyntax() == AttributeCommonInfo::AS_C2x) && - AL.hasScope() && AL.getScopeName()->isStr("cl")) || - AL.getSyntax() == AttributeCommonInfo::AS_GNU; + ((AL.getSyntax() == AttributeCommonInfo::AS_CXX11 || + AL.getSyntax() == AttributeCommonInfo::AS_C2x) && + AL.hasScope() && AL.getScopeName()->isStr("cl")) || + AL.getSyntax() == AttributeCommonInfo::AS_GNU; - unsigned WorkGroupSize = usesOpenCLArgOrdering - ? XDimVal.getZExtValue() - : ZDimVal.getZExtValue(); + unsigned WorkGroupSize = usesOpenCLArgOrdering ? XDimVal.getZExtValue() + : ZDimVal.getZExtValue(); if (WorkGroupSize % NumSimdWorkItems != 0) { S.Diag(A->getLocation(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) @@ -3377,9 +3376,9 @@ SYCLIntelNumSimdWorkItemsAttr *Sema::MergeSYCLIntelNumSimdWorkItemsAttr( const auto *DeclXExpr = dyn_cast(DeclAttr->getXDim()); const auto *DeclZExpr = dyn_cast(DeclAttr->getZDim()); - llvm::APSInt WorkGroupSize = - DeclAttr->usesOpenCLArgOrdering() ? DeclXExpr->getResultAsAPSInt() - : DeclZExpr->getResultAsAPSInt(); + llvm::APSInt WorkGroupSize = DeclAttr->usesOpenCLArgOrdering() + ? DeclXExpr->getResultAsAPSInt() + : DeclZExpr->getResultAsAPSInt(); if (WorkGroupSize % MergeExpr->getResultAsAPSInt() != 0) { Diag(A.getLoc(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) From 895e3bc43011227dbc218a80867312b68008a361 Mon Sep 17 00:00:00 2001 From: Soumi Manna Date: Sat, 13 Mar 2021 17:58:24 -0800 Subject: [PATCH 8/8] update var name Signed-off-by: Soumi Manna --- clang/lib/Sema/SemaDeclAttr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index d90f05f18262c..73ca5bba23c9a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3163,13 +3163,13 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { int64_t NumSimdWorkItems = A->getValue()->getIntegerConstantExpr(Ctx)->getSExtValue(); - bool usesOpenCLArgOrdering = + bool UsesOpenCLArgOrdering = ((AL.getSyntax() == AttributeCommonInfo::AS_CXX11 || AL.getSyntax() == AttributeCommonInfo::AS_C2x) && AL.hasScope() && AL.getScopeName()->isStr("cl")) || AL.getSyntax() == AttributeCommonInfo::AS_GNU; - unsigned WorkGroupSize = usesOpenCLArgOrdering ? XDimVal.getZExtValue() + unsigned WorkGroupSize = UsesOpenCLArgOrdering ? XDimVal.getZExtValue() : ZDimVal.getZExtValue(); if (WorkGroupSize % NumSimdWorkItems != 0) {