Skip to content

Commit abdbf89

Browse files
committed
Add sycl_external attribute
1 parent e7547b2 commit abdbf89

File tree

8 files changed

+109
-1
lines changed

8 files changed

+109
-1
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ def SharedVar : SubsetSubject<Var,
143143
def GlobalVar : SubsetSubject<Var,
144144
[{S->hasGlobalStorage()}], "global variables">;
145145

146+
146147
def ExternalGlobalVar : SubsetSubject<Var,
147148
[{S->hasGlobalStorage() &&
148149
S->getStorageClass()!=StorageClass::SC_Static &&
@@ -408,10 +409,14 @@ class SubjectList<list<AttrSubject> subjects, SubjectDiag diag = WarnDiag,
408409
string CustomDiag = customDiag;
409410
}
410411

411-
class LangOpt<string name, code customCode = [{}]> {
412+
class LangOpt<string name, code customCode = [{}], bit silentlyIgnore = 0> {
412413
// The language option to test; ignored when custom code is supplied.
413414
string Name = name;
414415

416+
// If set to 1, the attribute is accepted but is silently ignored. This is
417+
// useful in multi-compilation situations like SYCL.
418+
bit SilentlyIgnore = silentlyIgnore;
419+
415420
// A custom predicate, written as an expression evaluated in a context with
416421
// "LangOpts" bound.
417422
code CustomCode = customCode;
@@ -422,6 +427,7 @@ def CUDA : LangOpt<"CUDA">;
422427
def HIP : LangOpt<"HIP">;
423428
def SYCLHost : LangOpt<"SYCLIsHost">;
424429
def SYCLDevice : LangOpt<"SYCLIsDevice">;
430+
def SilentlyIgnoreSYCLHost : LangOpt<"SYCLIsHost", "", 1>;
425431
def COnly : LangOpt<"", "!LangOpts.CPlusPlus">;
426432
def CPlusPlus : LangOpt<"CPlusPlus">;
427433
def OpenCL : LangOpt<"OpenCL">;
@@ -1545,6 +1551,18 @@ def SYCLKernel : InheritableAttr {
15451551
let Documentation = [SYCLKernelDocs];
15461552
}
15471553

1554+
def GlobalStorageNonLocalVar : SubsetSubject<Var,
1555+
[{S->hasGlobalStorage() &&
1556+
!S->isLocalVarDeclOrParm()}],
1557+
"global variables">;
1558+
1559+
def SYCLExternal : InheritableAttr {
1560+
let Spellings = [GNU<"sycl_external">];
1561+
let Subjects = SubjectList<[Function, GlobalStorageNonLocalVar]>;
1562+
let LangOpts = [SYCLDevice, SilentlyIgnoreSYCLHost];
1563+
let Documentation = [SYCLExternalDocs];
1564+
}
1565+
15481566
def SYCLKernelEntryPoint : InheritableAttr {
15491567
let Spellings = [Clang<"sycl_kernel_entry_point">];
15501568
let Args = [

clang/include/clang/Basic/AttrDocs.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,17 @@ The SYCL kernel in the previous code sample meets these expectations.
472472
}];
473473
}
474474

475+
def SYCLExternalDocs : Documentation {
476+
let Category = DocCatFunction;
477+
let Heading = "sycl_external";
478+
let Content = [{
479+
The ``sycl_external`` attribute (or the ``SYCL_EXTERNAL`` macro) can only be applied to
480+
functions, and indicates that the function must be treated as a device function and
481+
must be emitted even if it has no direct uses from other device functions.
482+
All ``sycl_external`` function callees implicitly inherit this attribute.
483+
}];
484+
}
485+
475486
def SYCLKernelEntryPointDocs : Documentation {
476487
let Category = DocCatFunction;
477488
let Content = [{

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12746,6 +12746,11 @@ def err_sycl_special_type_num_init_method : Error<
1274612746
"types with 'sycl_special_class' attribute must have one and only one '__init' "
1274712747
"method defined">;
1274812748

12749+
//SYCL external attribute diagnostics
12750+
def err_sycl_attribute_internal_decl
12751+
: Error<"%0 attribute cannot be applied to a %select{function|variable}1"
12752+
" without external linkage">;
12753+
1274912754
// SYCL kernel entry point diagnostics
1275012755
def err_sycl_entry_point_invalid : Error<
1275112756
"'sycl_kernel_entry_point' attribute cannot be applied to a"

clang/include/clang/Sema/SemaSYCL.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class SemaSYCL : public SemaBase {
6262
ParsedType ParsedTy);
6363

6464
void handleKernelAttr(Decl *D, const ParsedAttr &AL);
65+
void handleSYCLExternalAttr(Decl *D, const ParsedAttr &AL);
6566
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
6667

6768
void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD);

clang/lib/AST/ASTContext.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12909,6 +12909,9 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
1290912909
if (D->hasAttr<WeakRefAttr>())
1291012910
return false;
1291112911

12912+
if (LangOpts.SYCLIsDevice && !D->hasAttr<SYCLKernelEntryPointAttr>())
12913+
return false;
12914+
1291212915
// Aliases and used decls are required.
1291312916
if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>())
1291412917
return true;
@@ -12926,6 +12929,10 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
1292612929

1292712930
// FIXME: Functions declared with SYCL_EXTERNAL are required during
1292812931
// device compilation.
12932+
// Functions definitions with sycl_external attribute are required during
12933+
// device compilation.
12934+
if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLExternalAttr>())
12935+
return true;
1292912936

1293012937
// Constructors and destructors are required.
1293112938
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7113,6 +7113,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
71137113
case ParsedAttr::AT_SYCLKernel:
71147114
S.SYCL().handleKernelAttr(D, AL);
71157115
break;
7116+
case ParsedAttr::AT_SYCLExternal:
7117+
S.SYCL().handleSYCLExternalAttr(D, AL);
7118+
break;
71167119
case ParsedAttr::AT_SYCLKernelEntryPoint:
71177120
S.SYCL().handleKernelEntryPointAttr(D, AL);
71187121
break;

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,17 @@ void SemaSYCL::handleKernelAttr(Decl *D, const ParsedAttr &AL) {
202202
handleSimpleAttribute<SYCLKernelAttr>(*this, D, AL);
203203
}
204204

205+
void SemaSYCL::handleSYCLExternalAttr(Decl *D, const ParsedAttr &AL) {
206+
auto *ND = cast<NamedDecl>(D);
207+
if (!ND->isExternallyVisible()) {
208+
Diag(AL.getLoc(), diag::err_sycl_attribute_internal_decl)
209+
<< AL << !isa<FunctionDecl>(ND);
210+
return;
211+
}
212+
213+
handleSimpleAttribute<SYCLExternalAttr>(*this, D, AL);
214+
}
215+
205216
void SemaSYCL::handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL) {
206217
ParsedType PT = AL.getTypeArg();
207218
TypeSourceInfo *TSI = nullptr;
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %clang_cc1 -fsycl-is-device -fsyntax-only -verify -DSYCL %s
2+
// RUN: %clang_cc1 -fsycl-is-host -fsyntax-only -verify -DHOST %s
3+
// RUN: %clang_cc1 -verify %s
4+
5+
// Semantic tests for sycl_external attribute
6+
7+
#ifdef SYCL
8+
9+
__attribute__((sycl_external(3))) // expected-error {{'sycl_external' attribute takes no arguments}}
10+
void bar() {}
11+
12+
__attribute__((sycl_external)) // expected-error {{'sycl_external' attribute cannot be applied to a function without external linkage}}
13+
static void func1() {}
14+
15+
namespace {
16+
__attribute__((sycl_external)) // expected-error {{'sycl_external' attribute cannot be applied to a function without external linkage}}
17+
void func2() {}
18+
19+
struct UnnX {};
20+
}
21+
22+
__attribute__((sycl_external)) // expected-error {{'sycl_external' attribute cannot be applied to a function without external linkage}}
23+
void func4(UnnX) {}
24+
25+
class A {
26+
__attribute__((sycl_external))
27+
A() {}
28+
29+
__attribute__((sycl_external)) void func3() {}
30+
};
31+
32+
class B {
33+
public:
34+
__attribute__((sycl_external)) virtual void foo() {}
35+
36+
__attribute__((sycl_external)) virtual void bar() = 0;
37+
};
38+
39+
__attribute__((sycl_external)) int *func0() { return nullptr; }
40+
41+
__attribute__((sycl_external)) void func2(int *) {}
42+
43+
#elif defined(HOST)
44+
45+
// expected-no-diagnostics
46+
__attribute__((sycl_external)) void func3() {}
47+
48+
#else
49+
__attribute__((sycl_external)) // expected-warning {{'sycl_external' attribute ignored}}
50+
void baz() {}
51+
52+
#endif

0 commit comments

Comments
 (0)