[clang] Add sycl_external attribute (PR #140282)
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 16 10:04:37 PDT 2025
https://github.com/schittir created https://github.com/llvm/llvm-project/pull/140282
None
>From abdbf8905d324f9b935b34bbc97c508ede5ac028 Mon Sep 17 00:00:00 2001
From: "Chittireddy, Sindhu" <sindhu.chittireddy at intel.com>
Date: Fri, 16 May 2025 08:51:06 -0700
Subject: [PATCH] Add sycl_external attribute
---
clang/include/clang/Basic/Attr.td | 20 ++++++-
clang/include/clang/Basic/AttrDocs.td | 11 ++++
.../clang/Basic/DiagnosticSemaKinds.td | 5 ++
clang/include/clang/Sema/SemaSYCL.h | 1 +
clang/lib/AST/ASTContext.cpp | 7 +++
clang/lib/Sema/SemaDeclAttr.cpp | 3 ++
clang/lib/Sema/SemaSYCL.cpp | 11 ++++
.../test/SemaSYCL/sycl-external-attribute.cpp | 52 +++++++++++++++++++
8 files changed, 109 insertions(+), 1 deletion(-)
create mode 100644 clang/test/SemaSYCL/sycl-external-attribute.cpp
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index ccd13a4cca4dd..1c13d0eb23f3b 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -143,6 +143,7 @@ def SharedVar : SubsetSubject<Var,
def GlobalVar : SubsetSubject<Var,
[{S->hasGlobalStorage()}], "global variables">;
+
def ExternalGlobalVar : SubsetSubject<Var,
[{S->hasGlobalStorage() &&
S->getStorageClass()!=StorageClass::SC_Static &&
@@ -408,10 +409,14 @@ class SubjectList<list<AttrSubject> subjects, SubjectDiag diag = WarnDiag,
string CustomDiag = customDiag;
}
-class LangOpt<string name, code customCode = [{}]> {
+class LangOpt<string name, code customCode = [{}], bit silentlyIgnore = 0> {
// The language option to test; ignored when custom code is supplied.
string Name = name;
+ // If set to 1, the attribute is accepted but is silently ignored. This is
+ // useful in multi-compilation situations like SYCL.
+ bit SilentlyIgnore = silentlyIgnore;
+
// A custom predicate, written as an expression evaluated in a context with
// "LangOpts" bound.
code CustomCode = customCode;
@@ -422,6 +427,7 @@ def CUDA : LangOpt<"CUDA">;
def HIP : LangOpt<"HIP">;
def SYCLHost : LangOpt<"SYCLIsHost">;
def SYCLDevice : LangOpt<"SYCLIsDevice">;
+def SilentlyIgnoreSYCLHost : LangOpt<"SYCLIsHost", "", 1>;
def COnly : LangOpt<"", "!LangOpts.CPlusPlus">;
def CPlusPlus : LangOpt<"CPlusPlus">;
def OpenCL : LangOpt<"OpenCL">;
@@ -1545,6 +1551,18 @@ def SYCLKernel : InheritableAttr {
let Documentation = [SYCLKernelDocs];
}
+def GlobalStorageNonLocalVar : SubsetSubject<Var,
+ [{S->hasGlobalStorage() &&
+ !S->isLocalVarDeclOrParm()}],
+ "global variables">;
+
+def SYCLExternal : InheritableAttr {
+ let Spellings = [GNU<"sycl_external">];
+ let Subjects = SubjectList<[Function, GlobalStorageNonLocalVar]>;
+ let LangOpts = [SYCLDevice, SilentlyIgnoreSYCLHost];
+ let Documentation = [SYCLExternalDocs];
+}
+
def SYCLKernelEntryPoint : InheritableAttr {
let Spellings = [Clang<"sycl_kernel_entry_point">];
let Args = [
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 5fb5f16680b41..2eef46a1348f3 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -472,6 +472,17 @@ The SYCL kernel in the previous code sample meets these expectations.
}];
}
+def SYCLExternalDocs : Documentation {
+ let Category = DocCatFunction;
+ let Heading = "sycl_external";
+ let Content = [{
+The ``sycl_external`` attribute (or the ``SYCL_EXTERNAL`` macro) can only be applied to
+functions, and indicates that the function must be treated as a device function and
+must be emitted even if it has no direct uses from other device functions.
+All ``sycl_external`` function callees implicitly inherit this attribute.
+ }];
+}
+
def SYCLKernelEntryPointDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3efe9593b8633..9228d388bc10b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12746,6 +12746,11 @@ def err_sycl_special_type_num_init_method : Error<
"types with 'sycl_special_class' attribute must have one and only one '__init' "
"method defined">;
+//SYCL external attribute diagnostics
+def err_sycl_attribute_internal_decl
+ : Error<"%0 attribute cannot be applied to a %select{function|variable}1"
+ " without external linkage">;
+
// SYCL kernel entry point diagnostics
def err_sycl_entry_point_invalid : Error<
"'sycl_kernel_entry_point' attribute cannot be applied to a"
diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h
index b47b2f155ef93..099cc56b0ef92 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -62,6 +62,7 @@ class SemaSYCL : public SemaBase {
ParsedType ParsedTy);
void handleKernelAttr(Decl *D, const ParsedAttr &AL);
+ void handleSYCLExternalAttr(Decl *D, const ParsedAttr &AL);
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index c58cd2c93fb60..e767b79d0b25f 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -12909,6 +12909,9 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (D->hasAttr<WeakRefAttr>())
return false;
+ if (LangOpts.SYCLIsDevice && !D->hasAttr<SYCLKernelEntryPointAttr>())
+ return false;
+
// Aliases and used decls are required.
if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>())
return true;
@@ -12926,6 +12929,10 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
// FIXME: Functions declared with SYCL_EXTERNAL are required during
// device compilation.
+ // Functions definitions with sycl_external attribute are required during
+ // device compilation.
+ if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLExternalAttr>())
+ return true;
// Constructors and destructors are required.
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 377595639bef1..271cf417a12f3 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7113,6 +7113,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_SYCLKernel:
S.SYCL().handleKernelAttr(D, AL);
break;
+ case ParsedAttr::AT_SYCLExternal:
+ S.SYCL().handleSYCLExternalAttr(D, AL);
+ break;
case ParsedAttr::AT_SYCLKernelEntryPoint:
S.SYCL().handleKernelEntryPointAttr(D, AL);
break;
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 1969d7b0ba837..a08e2f076fb12 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -202,6 +202,17 @@ void SemaSYCL::handleKernelAttr(Decl *D, const ParsedAttr &AL) {
handleSimpleAttribute<SYCLKernelAttr>(*this, D, AL);
}
+void SemaSYCL::handleSYCLExternalAttr(Decl *D, const ParsedAttr &AL) {
+ auto *ND = cast<NamedDecl>(D);
+ if (!ND->isExternallyVisible()) {
+ Diag(AL.getLoc(), diag::err_sycl_attribute_internal_decl)
+ << AL << !isa<FunctionDecl>(ND);
+ return;
+ }
+
+ handleSimpleAttribute<SYCLExternalAttr>(*this, D, AL);
+}
+
void SemaSYCL::handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL) {
ParsedType PT = AL.getTypeArg();
TypeSourceInfo *TSI = nullptr;
diff --git a/clang/test/SemaSYCL/sycl-external-attribute.cpp b/clang/test/SemaSYCL/sycl-external-attribute.cpp
new file mode 100644
index 0000000000000..2260dba386a73
--- /dev/null
+++ b/clang/test/SemaSYCL/sycl-external-attribute.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -verify -DSYCL %s
+// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -verify -DHOST %s
+// RUN: %clang_cc1 -verify %s
+
+// Semantic tests for sycl_external attribute
+
+#ifdef SYCL
+
+__attribute__((sycl_external(3))) // expected-error {{'sycl_external' attribute takes no arguments}}
+void bar() {}
+
+__attribute__((sycl_external)) // expected-error {{'sycl_external' attribute cannot be applied to a function without external linkage}}
+static void func1() {}
+
+namespace {
+ __attribute__((sycl_external)) // expected-error {{'sycl_external' attribute cannot be applied to a function without external linkage}}
+ void func2() {}
+
+ struct UnnX {};
+}
+
+__attribute__((sycl_external)) // expected-error {{'sycl_external' attribute cannot be applied to a function without external linkage}}
+ void func4(UnnX) {}
+
+class A {
+ __attribute__((sycl_external))
+ A() {}
+
+ __attribute__((sycl_external)) void func3() {}
+};
+
+class B {
+public:
+ __attribute__((sycl_external)) virtual void foo() {}
+
+ __attribute__((sycl_external)) virtual void bar() = 0;
+};
+
+__attribute__((sycl_external)) int *func0() { return nullptr; }
+
+__attribute__((sycl_external)) void func2(int *) {}
+
+#elif defined(HOST)
+
+// expected-no-diagnostics
+__attribute__((sycl_external)) void func3() {}
+
+#else
+__attribute__((sycl_external)) // expected-warning {{'sycl_external' attribute ignored}}
+void baz() {}
+
+#endif
More information about the cfe-commits
mailing list