diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 6e033f9e083b2..e75eb8e9be1b3 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2503,26 +2503,77 @@ 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 first argument) must be evenly divisible by the argument specified -in the ``intel::num_simd_work_items`` attribute. +If the ``reqd_work_group_size`` attribute is specified on a declaration along +with ``num_simd_work_items``, the required work group size specified +by ``num_simd_work_items`` attribute must evenly divide the index that +increments fastest in the ``reqd_work_group_size`` attribute. + +The arguments to ``reqd_work_group_size`` are ordered based on which index +increments the fastest. In OpenCL, the first argument is the index that +increments the fastest, and in SYCL, the last argument is the index that +increments the fastest. + +In OpenCL, all three arguments are required. + +In SYCL, the attribute accepts either one, two, or three arguments; in each +form, the last (or only) argument is the index that increments fastest. +The number of arguments passed to the attribute must match the dimensionality +of the kernel the attribute is applied to. .. code-block:: c++ + // Note, '64' is evenly divisible by '4'; in SYCL, the last + // argument to the attribute is the one which increments fastest. struct func { [[intel::num_simd_work_items(4)]] - [[intel::reqd_work_group_size(64, 64, 64)]] + [[intel::reqd_work_group_size(7, 4, 64)]] void operator()() const {} }; + // Note, '8' is evenly divisible by '8'; in SYCL, the last + // argument to the attribute is the one which increments fastest. struct bar { - [[intel::reqd_work_group_size(64, 64, 64)]] + [[intel::reqd_work_group_size(1, 1, 8)]] + [[intel::num_simd_work_items(8)]] + void operator()() const {} + }; + + // Note, '10' is evenly divisible by '5'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + [[cl::reqd_work_group_size(7, 5, 10)]] + [[intel::num_simd_work_items(5)]] void fun2() {} + + // Note, '8' is evenly divisible by '4'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + [[intel::num_simd_work_items(4)]] + [[cl::reqd_work_group_size(5, 4, 8)]] void fun3() {} + + // Note, '8' is evenly divisible by '8'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + struct func1 { + [[intel::num_simd_work_items(8)]] + [[cl::reqd_work_group_size(1, 1, 8)]] + void operator()() const {} + }; + + // Note, '8' is evenly divisible by '4'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + struct bar1 { + [[cl::reqd_work_group_size(7, 4, 8)]] [[intel::num_simd_work_items(4)]] void operator()() const {} }; + // Note, '4' is evenly divisible by '2'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + [[intel::num_simd_work_items(2)]] + __attribute__((reqd_work_group_size(3, 2, 4))) void test(); + + // Note, '8' is evenly divisible by '2'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + __attribute__((reqd_work_group_size(3, 2, 8))) + [intel::num_simd_work_items(2)]] void test(); + }]; } @@ -2636,6 +2687,77 @@ In OpenCL C, this attribute is available in GNU spelling __kernel __attribute__((reqd_work_group_size(8, 16, 32))) void test() {} +The arguments to ``reqd_work_group_size`` are ordered based on which index +increments the fastest. In OpenCL, the first argument is the index that +increments the fastest, and in SYCL, the last argument is the index that +increments the fastest. + +In OpenCL, all three arguments are required. + +In SYCL, the attribute accepts either one, two, or three arguments; in each +form, the last (or only) argument is the index that increments fastest. The +number of arguments passed to the attribute must match the dimensionality of +the kernel the attribute is applied to. + +If the ``reqd_work_group_size attribute`` is specified on a declaration along +with ``num_simd_work_items``, the required work group size specified by +``num_simd_work_items`` must evenly divide the index that increments fastest +in the ``reqd_work_group_size`` attribute. + +.. code-block:: c++ + + // Note, '64' is evenly divisible by '4'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + struct func { + [[intel::num_simd_work_items(4)]] + [[intel::reqd_work_group_size(7, 4, 64)]] + void operator()() const {} + }; + + // Note, '8' is evenly divisible by '8'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + struct bar { + [[intel::reqd_work_group_size(1, 1, 8)]] + [[intel::num_simd_work_items(8)]] + void operator()() const {} + }; + + // Note, '10' is evenly divisible by '5'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + [[cl::reqd_work_group_size(7, 5, 10)]] + [[intel::num_simd_work_items(5)]] void fun2() {} + + // Note, '8' is evenly divisible by '4'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + [[intel::num_simd_work_items(4)]] + [[cl::reqd_work_group_size(5, 4, 8)]] void fun3() {} + + // Note, '8' is evenly divisible by '8'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + struct func1 { + [[intel::num_simd_work_items(8)]] + [[cl::reqd_work_group_size(1, 1, 8)]] + void operator()() const {} + }; + + // Note, '8' is evenly divisible by '4'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + struct bar1 { + [[cl::reqd_work_group_size(7, 4, 8)]] + [[intel::num_simd_work_items(4)]] + void operator()() const {} + }; + + // Note, '4' is evenly divisible by '2'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + [[intel::num_simd_work_items(2)]] + __attribute__((reqd_work_group_size(3, 2, 4))) void test(); + + // Note, '8' is evenly divisible by '2'; in SYCL, the last + // argument to the attribute is the one which increments fastest. + __attribute__((reqd_work_group_size(3, 2, 8))) + [intel::num_simd_work_items(2)]] void test(); + }]; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 548fa364d08d9..a4f8d0a8ce2b6 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3086,17 +3086,25 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) { return; ZDimExpr = ZDim.get(); + // If the num_simd_work_items attribute is specified on a declaration it + // must evenly divide the index that increments fastest in the + // reqd_work_group_size attribute. In OpenCL, the first argument increments + // the fastest, and in SYCL, the last argument increments the fastest. if (const auto *A = D->getAttr()) { int64_t NumSimdWorkItems = A->getValue()->getIntegerConstantExpr(Ctx)->getSExtValue(); - if (XDimVal.getZExtValue() % NumSimdWorkItems != 0) { + unsigned WorkGroupSize = S.getLangOpts().OpenCL ? 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); return; } } + if (const auto *ExistingAttr = D->getAttr()) { // Compare attribute arguments value and warn for a mismatch. if (ExistingAttr->getXDimVal(Ctx) != XDimVal || @@ -3280,17 +3288,38 @@ 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 - // num_simd_work_items attribute. + // If the reqd_work_group_size attribute is specified on a declaration + // along with num_simd_work_items, the required work group size specified + // by num_simd_work_items attribute must evenly divide the index that + // increments fastest in the reqd_work_group_size attribute. + // + // The arguments to reqd_work_group_size are ordered based on which index + // increments the fastest. In OpenCL, the first argument is the index that + // increments the fastest, and in SYCL, the last argument is the index that + // increments the fastest. if (const auto *DeclAttr = D->getAttr()) { - Optional XDimVal = DeclAttr->getXDimVal(Context); + Expr *XDimExpr = DeclAttr->getXDim(); + Expr *YDimExpr = DeclAttr->getYDim(); + Expr *ZDimExpr = DeclAttr->getZDim(); - if (*XDimVal % ArgVal != 0) { - Diag(CI.getLoc(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) - << CI << DeclAttr; - Diag(DeclAttr->getLocation(), diag::note_conflicting_attribute); - return; + if (!XDimExpr->isValueDependent() && !YDimExpr->isValueDependent() && + !ZDimExpr->isValueDependent()) { + llvm::APSInt XDimVal, ZDimVal; + ExprResult XDim = VerifyIntegerConstantExpression(XDimExpr, &XDimVal); + ExprResult ZDim = VerifyIntegerConstantExpression(ZDimExpr, &ZDimVal); + + if (XDim.isInvalid() || ZDim.isInvalid()) + return; + + unsigned WorkGroupSize = getLangOpts().OpenCL ? XDimVal.getZExtValue() + : ZDimVal.getZExtValue(); + + if (WorkGroupSize % ArgVal.getSExtValue() != 0) { + Diag(CI.getLoc(), diag::err_sycl_num_kernel_wrong_reqd_wg_size) + << CI << DeclAttr; + Diag(DeclAttr->getLocation(), diag::note_conflicting_attribute); + return; + } } } } diff --git a/clang/test/SemaSYCL/num_simd_work_items_device.cpp b/clang/test/SemaSYCL/num_simd_work_items_device.cpp index c0a378a34c04c..6e573353894a7 100644 --- a/clang/test/SemaSYCL/num_simd_work_items_device.cpp +++ b/clang/test/SemaSYCL/num_simd_work_items_device.cpp @@ -42,66 +42,111 @@ 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) -// can be evenly divided by the num_simd_work_items attribute. +// If the declaration has a [[intel::reqd_work_group_size]] +// [[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 [[intel::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(3, 6, 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(3, 6, 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 {} }; +// Tests for the default values of [[intel::reqd_work_group_size()]]. + +// FIXME: This should be accepted instead of error which turns out to be +// an implementation bug that shouldn't be visible to the user as there +// aren't really any default values. The dimensionality of the attribute +// must match the kernel, so three different forms of the attribute +// (one, two, and three argument) can be used instead of assuming default +// values. This will prevent to redeclare the function with a different dimensionality. 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}} + [[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 {} }; +// FIXME: This should be accepted instead of error which turns out to be +// an implementation bug that shouldn't be visible to the user as there +// aren't really any default values. The dimensionality of the attribute +// must match the kernel, so three different forms of the attribute +// (one, two, and three argument) can be used instead of assuming default +// values. This will prevent to redeclare the function with a different dimensionality. struct TRIFuncObjBad4 { - [[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}} + [[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 {} }; +// FIXME: This should be accepted instead of error which turns out to be +// an implementation bug that shouldn't be visible to the user as there +// aren't really any default values. The dimensionality of the attribute +// must match the kernel, so three different forms of the attribute +// (one, two, and three argument) can be used instead of assuming default +// values. This will prevent to redeclare the function with a different dimensionality. 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::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::reqd_work_group_size(4, 64)]] // expected-note{{conflicting attribute is here}} void operator()() const {} }; +// FIXME: This should be accepted instead of error which turns out to be +// an implementation bug that shouldn't be visible to the user as there +// aren't really any default values. The dimensionality of the attribute +// must match the kernel, so three different forms of the attribute +// (one, two, and three argument) can be used instead of assuming default +// values. This will prevent to redeclare the function with a different dimensionality. struct TRIFuncObjBad6 { - [[intel::reqd_work_group_size(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(4, 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}} void operator()() const {} }; 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::reqd_work_group_size(3, 64)]] // expected-note{{conflicting attribute is here}} + [[cl::reqd_work_group_size(6, 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 {} }; 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}} + [[cl::reqd_work_group_size(6, 3, 5)]] // expected-note{{conflicting attribute is here}} void operator()() const {} }; +[[intel::num_simd_work_items(2)]] // 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, 2, 3)]] void func1(); // expected-note{{conflicting attribute is here}} + +[[intel::reqd_work_group_size(4, 2, 3)]] // expected-note{{conflicting attribute is here}} +[[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}} + +[[intel::num_simd_work_items(2)]] // 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(4, 2, 3)]] void func3(); // expected-note{{conflicting attribute is here}} + +[[cl::reqd_work_group_size(4, 2, 3)]] // expected-note{{conflicting attribute is here}} +[[intel::num_simd_work_items(2)]] void func4(); // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + +// If the declaration has a __attribute__((reqd_work_group_size())) +// attribute, tests that check if the work group size attribute argument +// (the last argument) can be evenly divided by the [[intel::num_simd_work_items()]] +// attribute. +[[intel::num_simd_work_items(2)]] // 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(4, 2, 5))) void func5(); // 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(5, 5, 5)]] @@ -164,57 +209,37 @@ 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) -// can be evenly divided by the num_simd_work_items attribute. +// If the declaration has a [[intel::reqd_work_group_size()]] +// or [[cl::reqd_work_group_size()]] or +// __attribute__((reqd_work_group_size)) attribute, check to see +// if the last argument can be evenly divided by the +// [[intel::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(3, 64, 4)]] void operator()() const {} }; struct TRIFuncObjGood2 { - [[intel::reqd_work_group_size(64, 64, 5)]] + [[intel::reqd_work_group_size(3, 64, 4)]] [[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(3, 64, 4)]] void operator()() const {} }; struct TRIFuncObjGood4 { - [[cl::reqd_work_group_size(64, 64, 5)]] + [[cl::reqd_work_group_size(3, 64, 4)]] [[intel::num_simd_work_items(4)]] void operator()() const {} }; -struct TRIFuncObjGood5 { - [[intel::num_simd_work_items(4)]] - [[intel::reqd_work_group_size(64)]] void - operator()() const {} -}; - -struct TRIFuncObjGood6 { - [[intel::reqd_work_group_size(64)]] - [[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 - operator()() const {} -}; - -struct TRIFuncObjGood8 { - [[intel::reqd_work_group_size(64, 5)]] - [[intel::num_simd_work_items(4)]] void - operator()() const {} -}; +[[intel::num_simd_work_items(2)]] +__attribute__((reqd_work_group_size(3, 2, 6))) void func6(); //OK int main() { q.submit([&](handler &h) { @@ -251,27 +276,27 @@ int main() { // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} // 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: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} + // CHECK-NEXT: value: Int 4 + // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} h.single_task(TRIFuncObjGood2()); // 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: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} + // CHECK-NEXT: value: Int 4 + // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 @@ -285,95 +310,27 @@ int main() { // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} // 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: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} - - h.single_task(TRIFuncObjGood4()); - // CHECK-LABEL: FunctionDecl {{.*}}test_kernel7 - // CHECK: ReqdWorkGroupSizeAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 5 - // CHECK-NEXT: IntegerLiteral{{.*}}5{{$}} - // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - h.single_task(TRIFuncObjGood5()); - // CHECK-LABEL: FunctionDecl {{.*}}test_kernel8 - // CHECK: SYCLIntelNumSimdWorkItemsAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} + h.single_task(TRIFuncObjGood4()); + // CHECK-LABEL: FunctionDecl {{.*}}test_kernel7 // CHECK: ReqdWorkGroupSizeAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 1 - // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 1 - // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} - - h.single_task(TRIFuncObjGood6()); - // CHECK-LABEL: FunctionDecl {{.*}}test_kernel9 - // CHECK: ReqdWorkGroupSizeAttr {{.*}} + // CHECK-NEXT: value: Int 3 + // CHECK-NEXT: IntegerLiteral{{.*}}3{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 64 // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 1 - // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 1 - // CHECK-NEXT: IntegerLiteral{{.*}}1{{$}} - // 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: SYCLIntelNumSimdWorkItemsAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 4 - // CHECK-NEXT: IntegerLiteral{{.*}}4{{$}} - // CHECK: ReqdWorkGroupSizeAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} - // 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{{$}} - - h.single_task(TRIFuncObjGood8()); - // CHECK-LABEL: FunctionDecl {{.*}}test_kernel11 - // CHECK: ReqdWorkGroupSizeAttr {{.*}} - // CHECK-NEXT: ConstantExpr{{.*}}'int' - // CHECK-NEXT: value: Int 64 - // CHECK-NEXT: IntegerLiteral{{.*}}64{{$}} - // 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: SYCLIntelNumSimdWorkItemsAttr {{.*}} // CHECK-NEXT: ConstantExpr{{.*}}'int' // CHECK-NEXT: value: Int 4 @@ -382,49 +339,49 @@ int main() { #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 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 b9445054752f8..ea43ce8631d13 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 @@ -93,3 +93,57 @@ int check() { // CHECK-NEXT: ConstantExpr {{.*}} 'int' // CHECK-NEXT: value: Int 2 // CHECK-NEXT: IntegerLiteral{{.*}}2{{$}} + +// Tests for num_simd_work_items and reqd_work_group_size arguments check. +template +__attribute__((reqd_work_group_size(8, 6, 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 +[[cl::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}} + +template +[[intel::reqd_work_group_size(N, N, N)]] void func8(); // expected-note{{conflicting attribute is here}} +template +[[intel::num_simd_work_items(3)]] void func8(); // 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(X, Y, Z)]] void func9(); // expected-note{{conflicting attribute is here}} +template +[[intel::num_simd_work_items(N)]] void func9(); // 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(X, Y, Z)]] void func10(); // expected-note{{conflicting attribute is here}} +template +[[intel::num_simd_work_items(3)]] void func10(); // 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(X, Y, Z)]] void func11(); // expected-note{{conflicting attribute is here}} +template +[[intel::num_simd_work_items(2)]] void func11(); // 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(N, N, N)]] void func12(); // expected-note{{conflicting attribute is here}} +template +[[intel::num_simd_work_items(2)]] void func12(); // expected-error{{'num_simd_work_items' attribute must evenly divide the work-group size for the 'reqd_work_group_size' attribute}} + +int check1() { + func6<3>(); // OK + func6<2>(); // expected-note {{in instantiation of function template specialization 'func6<2>' requested here}} + func7<4>(); // expected-note {{in instantiation of function template specialization 'func7<4>' requested here}} + func7<5>(); // OK + func8<5>(); // expected-note {{in instantiation of function template specialization 'func8<5>' requested here}} + func8<3>(); // OK + func9<6, 3, 5, 3>(); // expected-note {{in instantiation of function template specialization 'func9<6, 3, 5, 3>' requested here}} + func9<9, 6, 3, 3>(); // OK + func10<6, 3, 5>(); // expected-note {{in instantiation of function template specialization 'func10<6, 3, 5>' requested here}} + func10<9, 6, 3>(); // OK + func11<6, 4, 5>(); // expected-note {{in instantiation of function template specialization 'func11<6, 4, 5>' requested here}} + func11<8, 6, 2>(); // OK + func12<3>(); // expected-note {{in instantiation of function template specialization 'func12<3>' requested here}} + func12<2>(); // OK + return 0; +}