diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index cae44fb274a4a..fbf00ac7d660d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1144,6 +1144,15 @@ def SYCLIntelMaxGlobalWorkDim : InheritableAttr { let PragmaAttributeSupport = 0; } +def SYCLIntelUsesGlobalWorkOffset : InheritableAttr { + let Spellings = [CXX11<"intelfpga","uses_global_work_offset">]; + let Args = [BoolArgument<"Enabled">]; + let LangOpts = [SYCLIsDevice, SYCLIsHost]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [SYCLIntelUsesGlobalWorkOffsetDocs]; + let PragmaAttributeSupport = 0; +} + def C11NoReturn : InheritableAttr { let Spellings = [Keyword<"_Noreturn">]; let Subjects = SubjectList<[Function], ErrorDiag>; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 9dce8a98b864e..175e1560ba4e9 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2009,6 +2009,16 @@ device kernel, the attribute is ignored and it is not propagated to a kernel. }]; } +def SYCLIntelUsesGlobalWorkOffsetDocs : Documentation { + let Category = DocCatFunction; + let Heading = "uses_global_work_offset (IntelFPGA)"; + let Content = [{ +Applies to a device function/lambda function or function call operator (of a +function object). If 0, compiler doesn't use the global work offset values for +the device function. Valid values are 0 and 1. + }]; +} + def SYCLFPGAPipeDocs : Documentation { let Category = DocCatStmt; let Heading = "pipe (read_only, write_only)"; diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h index 1ffcb1474b6d4..f2ea62e9f9fd2 100644 --- a/clang/include/clang/Basic/AttributeCommonInfo.h +++ b/clang/include/clang/Basic/AttributeCommonInfo.h @@ -158,7 +158,8 @@ class AttributeCommonInfo { (ParsedAttr == AT_IntelReqdSubGroupSize && isCXX11Attribute()) || ParsedAttr == AT_SYCLIntelNumSimdWorkItems || ParsedAttr == AT_SYCLIntelMaxWorkGroupSize || - ParsedAttr == AT_SYCLIntelMaxGlobalWorkDim) + ParsedAttr == AT_SYCLIntelMaxGlobalWorkDim || + ParsedAttr == AT_SYCLIntelUsesGlobalWorkOffset) return true; return false; diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 8b4c18a5c4f9c..b5d3dd3e3b72f 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -637,8 +637,10 @@ def NSReturnsMismatch : DiagGroup<"nsreturns-mismatch">; def IndependentClassAttribute : DiagGroup<"IndependentClass-attribute">; def UnknownAttributes : DiagGroup<"unknown-attributes">; def IgnoredAttributes : DiagGroup<"ignored-attributes">; +def AdjustedAttributes : DiagGroup<"adjusted-attributes">; def Attributes : DiagGroup<"attributes", [UnknownAttributes, - IgnoredAttributes]>; + IgnoredAttributes, + AdjustedAttributes]>; def UnknownSanitizers : DiagGroup<"unknown-sanitizers">; def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args", [CXX98CompatUnnamedTypeTemplateArgs]>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f82cdadd9ff47..86bb123137432 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10324,6 +10324,9 @@ def err_sycl_x_y_z_arguments_must_be_one : Error< "%0 X-, Y- and Z- sizes must be 1 when %1 attribute is used with value 0">; def err_intel_attribute_argument_is_not_in_range: Error< "The value of %0 attribute must be in range from 0 to 3">; +def warn_boolean_attribute_argument_is_not_valid: Warning< + "The value of %0 attribute should be 0 or 1. Adjusted to 1">, + InGroup; def err_sycl_attibute_cannot_be_applied_here : Error<"%0 attribute cannot be applied to a " "%select{static function or function in an anonymous namespace" diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 612594c28bc14..3e52589f7c636 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -668,6 +668,17 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD, Fn->setMetadata("max_global_work_dim", llvm::MDNode::get(Context, AttrMDArgs)); } + + if (const SYCLIntelUsesGlobalWorkOffsetAttr *A = + FD->getAttr()) { + bool IsEnabled = A->getEnabled(); + if (!IsEnabled) { + llvm::Metadata *AttrMDArgs[] = { + llvm::ConstantAsMetadata::get(Builder.getInt32(IsEnabled))}; + Fn->setMetadata("uses_global_work_offset", + llvm::MDNode::get(Context, AttrMDArgs)); + } + } } /// Determine whether the function F ends with a return stmt. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 1b156bdfc9a4f..5f6a155045923 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5166,6 +5166,26 @@ static bool checkForDuplicateAttribute(Sema &S, Decl *D, return false; } +static void handleUsesGlobalWorkOffsetAttr(Sema &S, Decl *D, + const ParsedAttr &Attr) { + if (S.LangOpts.SYCLIsHost) + return; + + checkForDuplicateAttribute(S, D, Attr); + + uint32_t Enabled; + const Expr *E = Attr.getArgAsExpr(0); + if (!checkUInt32Argument(S, Attr, E, Enabled, 0, + /*StrictlyUnsigned=*/true)) + return; + if (Enabled > 1) + S.Diag(Attr.getLoc(), diag::warn_boolean_attribute_argument_is_not_valid) + << Attr; + + D->addAttr(::new (S.Context) + SYCLIntelUsesGlobalWorkOffsetAttr(S.Context, Attr, Enabled)); +} + /// Handle the [[intelfpga::doublepump]] and [[intelfpga::singlepump]] attributes. /// One but not both can be specified /// Both are incompatible with the __register__ attribute. @@ -7599,6 +7619,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_SYCLIntelMaxGlobalWorkDim: handleMaxGlobalWorkDimAttr(S, D, AL); break; + case ParsedAttr::AT_SYCLIntelUsesGlobalWorkOffset: + handleUsesGlobalWorkOffsetAttr(S, D, AL); + break; case ParsedAttr::AT_VecTypeHint: handleVecTypeHint(S, D, AL); break; @@ -8082,6 +8105,10 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } else if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); + } else if (const auto *A = + D->getAttr()) { + Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; + D->setInvalidDecl(); } else if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 477ec98b4d48f..acab9ea043040 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -469,6 +469,14 @@ class MarkDeviceFunction : public RecursiveASTVisitor { FD->dropAttr(); } } + if (auto *A = FD->getAttr()) { + if (ParentFD == SYCLKernel) { + Attrs.insert(A); + } else { + SemaRef.Diag(A->getLocation(), diag::warn_attribute_ignored) << A; + FD->dropAttr(); + } + } // TODO: vec_len_hint should be handled here @@ -1357,7 +1365,8 @@ void Sema::MarkDevice(void) { case attr::Kind::SYCLIntelKernelArgsRestrict: case attr::Kind::SYCLIntelNumSimdWorkItems: case attr::Kind::SYCLIntelMaxGlobalWorkDim: - case attr::Kind::SYCLIntelMaxWorkGroupSize: { + case attr::Kind::SYCLIntelMaxWorkGroupSize: + case attr::Kind::SYCLIntelUsesGlobalWorkOffset: { SYCLKernel->addAttr(A); break; } diff --git a/clang/test/CodeGenSYCL/intel-fpga-uses-global-work-offset.cpp b/clang/test/CodeGenSYCL/intel-fpga-uses-global-work-offset.cpp new file mode 100644 index 0000000000000..2107f214df8be --- /dev/null +++ b/clang/test/CodeGenSYCL/intel-fpga-uses-global-work-offset.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple spir64-unknown-unknown-sycldevice -disable-llvm-passes -fsycl-is-device -emit-llvm -o - %s | FileCheck %s + +class Foo { +public: + [[intelfpga::uses_global_work_offset(0)]] void operator()() {} +}; + +template +__attribute__((sycl_kernel)) void kernel(Func kernelFunc) { + kernelFunc(); +} + +void bar() { + Foo boo; + kernel(boo); + + kernel( + []() [[intelfpga::uses_global_work_offset(0)]]{}); + + kernel( + []() [[intelfpga::uses_global_work_offset(1)]]{}); +} + +// CHECK: define spir_kernel void @{{.*}}kernel_name1() {{.*}} !uses_global_work_offset ![[NUM5:[0-9]+]] +// CHECK: define spir_kernel void @{{.*}}kernel_name2() {{.*}} !uses_global_work_offset ![[NUM5]] +// CHECK: define spir_kernel void @{{.*}}kernel_name3() {{.*}} ![[NUM4:[0-9]+]] +// CHECK-NOT: ![[NUM4]] = !{i32 1} +// CHECK: ![[NUM5]] = !{i32 0} diff --git a/clang/test/SemaSYCL/intel-fpga-uses-global-work-offset.cpp b/clang/test/SemaSYCL/intel-fpga-uses-global-work-offset.cpp new file mode 100644 index 0000000000000..f4063a8999dd2 --- /dev/null +++ b/clang/test/SemaSYCL/intel-fpga-uses-global-work-offset.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -Wno-return-type -fsycl-is-device -fcxx-exceptions -fsyntax-only -ast-dump -verify -pedantic %s | FileCheck %s + +struct FuncObj { + [[intelfpga::uses_global_work_offset(1)]] void operator()() {} +}; + +template +void kernel(Func kernelFunc) { + kernelFunc(); +} + +int main() { + // CHECK: SYCLIntelUsesGlobalWorkOffsetAttr{{.*}}Enabled + kernel([]() { + FuncObj(); + }); + + // CHECK: SYCLIntelUsesGlobalWorkOffsetAttr + // CHECK-NOT: Enabled + kernel( + []() [[intelfpga::uses_global_work_offset(0)]]{}); + + // CHECK: SYCLIntelUsesGlobalWorkOffsetAttr{{.*}}Enabled + // expected-warning@+2{{'uses_global_work_offset' attribute should be 0 or 1. Adjusted to 1}} + kernel( + []() [[intelfpga::uses_global_work_offset(42)]]{}); + + // expected-error@+2{{'uses_global_work_offset' attribute requires a non-negative integral compile time constant expression}} + kernel( + []() [[intelfpga::uses_global_work_offset(-1)]]{}); + + // expected-error@+2{{'uses_global_work_offset' attribute requires parameter 0 to be an integer constant}} + kernel( + []() [[intelfpga::uses_global_work_offset("foo")]]{}); + + kernel([]() { + // expected-error@+1{{'uses_global_work_offset' attribute only applies to functions}} + [[intelfpga::uses_global_work_offset(1)]] int a; + }); + + // CHECK: SYCLIntelUsesGlobalWorkOffsetAttr{{.*}} + // CHECK-NOT: Enabled + // CHECK: SYCLIntelUsesGlobalWorkOffsetAttr{{.*}}Enabled + // expected-warning@+2{{attribute 'uses_global_work_offset' is already applied}} + kernel( + []() [[intelfpga::uses_global_work_offset(0), intelfpga::uses_global_work_offset(1)]]{}); + + return 0; +}