Skip to content

Commit bc21ab2

Browse files
author
Erich Keane
authored
[SYCL] Implement some dependencies for SYCL 2020 Spec constant design (#3499)
The Spec-constant design (#3331) has a few dependencies on the CFE, including generating unique names for reachable specialization_id variables and putting the results in the integration footer. This patch helps with this effort in 2 ways: First, it creates a command line option that will be used eventually to ensure that types with internal linkage have names unique to this translation unit. This will eventually be used by the unique-id/unique-stable-name implementation, but is required as a CC1 option to unblock the Driver implementation. Second, it generates the integration footer sans the generated names (which will be added when we have the unique-id/unique-stable-name implementation in place). This is necessary to unblock library implementation of this feature.
1 parent c1ddf86 commit bc21ab2

File tree

8 files changed

+184
-3
lines changed

8 files changed

+184
-3
lines changed

clang/include/clang/Basic/LangOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,12 @@ class LangOptions : public LangOptionsBase {
354354
/// SYCL integration footer to be generated by the device compiler
355355
std::string SYCLIntFooter;
356356

357+
/// A driver-provided unique string for this translation unit that is used to
358+
/// generate unique names for SYCL names. This is provided by the driver so
359+
/// that the case of multiple-offload can have each device compilation share a
360+
/// name.
361+
std::string SYCLUniquePrefix;
362+
357363
LangOptions();
358364

359365
// Define accessors/mutators for language options of enumeration type.

clang/include/clang/Driver/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5698,6 +5698,11 @@ def fsycl_int_footer : Separate<["-"], "fsycl-int-footer">,
56985698
MarshallingInfoString<LangOpts<"SYCLIntFooter">>;
56995699
def fsycl_int_footer_EQ : Joined<["-"], "fsycl-int-footer=">,
57005700
Alias<fsycl_int_footer>;
5701+
def fsycl_unique_prefix_EQ
5702+
: Joined<["-"], "fsycl-unique-prefix=">,
5703+
HelpText<"A unique prefix for this translation unit across devices, used "
5704+
"to generate a unique name for local variables.">,
5705+
MarshallingInfoString<LangOpts<"SYCLUniquePrefix">>;
57015706
def fsycl_std_layout_kernel_params: Flag<["-"], "fsycl-std-layout-kernel-params">,
57025707
HelpText<"Enable standard layout requirement for SYCL kernel parameters.">,
57035708
MarshallingInfoFlag<LangOpts<"SYCLStdLayoutKernelParams">>;

clang/include/clang/Sema/Sema.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,10 +434,13 @@ class SYCLIntegrationFooter {
434434
public:
435435
SYCLIntegrationFooter(Sema &S) : S(S) {}
436436
bool emit(StringRef MainSrc);
437+
void addVarDecl(const VarDecl *VD);
437438

438439
private:
439440
bool emit(raw_ostream &O);
440441
Sema &S;
442+
llvm::SmallVector<const VarDecl *> SpecConstants;
443+
void emitSpecIDName(raw_ostream &O, const VarDecl *VD);
441444
};
442445

443446
/// Tracks expected type during expression parsing, for use in code completion.
@@ -13162,6 +13165,11 @@ class Sema final {
1316213165
return *SyclIntFooter.get();
1316313166
}
1316413167

13168+
void addSyclVarDecl(VarDecl *VD) {
13169+
if (LangOpts.SYCLIsDevice && !LangOpts.SYCLIntFooter.empty())
13170+
getSyclIntegrationFooter().addVarDecl(VD);
13171+
}
13172+
1316513173
enum SYCLRestrictKind {
1316613174
KernelGlobalVariable,
1316713175
KernelRTTI,

clang/lib/Sema/SemaDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7532,6 +7532,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
75327532
if (IsMemberSpecialization && !NewVD->isInvalidDecl())
75337533
CompleteMemberSpecialization(NewVD, Previous);
75347534

7535+
addSyclVarDecl(NewVD);
75357536
return NewVD;
75367537
}
75377538

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ class Util {
122122
/// specialization constant class.
123123
static bool isSyclSpecConstantType(QualType Ty);
124124

125+
/// Checks whether given clang type is a full specialization of the SYCL
126+
/// specialization id class.
127+
static bool isSyclSpecIdType(QualType Ty);
128+
125129
/// Checks whether given clang type is a full specialization of the SYCL
126130
/// kernel_handler class.
127131
static bool isSyclKernelHandlerType(QualType Ty);
@@ -4292,6 +4296,22 @@ SYCLIntegrationHeader::SYCLIntegrationHeader(bool _UnnamedLambdaSupport,
42924296
Sema &_S)
42934297
: UnnamedLambdaSupport(_UnnamedLambdaSupport), S(_S) {}
42944298

4299+
void SYCLIntegrationFooter::addVarDecl(const VarDecl *VD) {
4300+
// Step 1: ensure that this is of the correct type-spec-constant template
4301+
// specialization).
4302+
if (!Util::isSyclSpecIdType(VD->getType()))
4303+
return;
4304+
// Step 2: ensure that this is a static member, or a namespace-scope.
4305+
// Note that isLocalVarDeclorParm excludes thread-local and static-local
4306+
// intentionally, as there is no way to 'spell' one of those in the
4307+
// specialization. We just don't generate the specialization for those, and
4308+
// let an error happen during host compilation.
4309+
if (!VD->hasGlobalStorage() || VD->isLocalVarDeclOrParm())
4310+
return;
4311+
// Step 3: Add to SpecConstants collection.
4312+
SpecConstants.push_back(VD);
4313+
}
4314+
42954315
// Post-compile integration header support.
42964316
bool SYCLIntegrationFooter::emit(StringRef IntHeaderName) {
42974317
if (IntHeaderName.empty())
@@ -4308,8 +4328,40 @@ bool SYCLIntegrationFooter::emit(StringRef IntHeaderName) {
43084328
return emit(Out);
43094329
}
43104330

4331+
void SYCLIntegrationFooter::emitSpecIDName(raw_ostream &O, const VarDecl *VD) {
4332+
// FIXME: Figure out the spec-constant unique name here.
4333+
// Note that this changes based on the linkage of the variable.
4334+
// We typically want to use the __builtin_unique_stable_name for the variable
4335+
// (or the newer-equivilent for values, see the JIRA), but we also have to
4336+
// figure out if this has internal or external linkage. In external-case this
4337+
// should be the same as the the unique-name. However, this isn't the case
4338+
// with local-linkage, where we want to put the driver-provided random-value
4339+
// ahead of it, so that we make sure it is unique across translation units.
4340+
// This name should come from the yet implemented__builtin_unique_stable_name
4341+
// feature that accepts variables and gives the mangling for that.
4342+
O << "";
4343+
}
4344+
43114345
bool SYCLIntegrationFooter::emit(raw_ostream &O) {
4312-
O << "// Integration Footer contents to go here.\n";
4346+
PrintingPolicy Policy{S.getLangOpts()};
4347+
Policy.adjustForCPlusPlusFwdDecl();
4348+
Policy.SuppressTypedefs = true;
4349+
Policy.SuppressUnwrittenScope = true;
4350+
4351+
for (const VarDecl *D : SpecConstants) {
4352+
O << "template<>\n";
4353+
O << "inline const char *get_spec_constant_symbolic_ID<";
4354+
// Emit the FQN for this, but we probably need to do some funny-business for
4355+
// anonymous namespaces.
4356+
D->printQualifiedName(O, Policy);
4357+
O << ">() {\n";
4358+
O << " return \"";
4359+
emitSpecIDName(O, D);
4360+
O << "\";\n";
4361+
O << "}\n";
4362+
}
4363+
4364+
O << "#include <CL/sycl/detail/spec_const_integration.hpp>\n";
43134365
return true;
43144366
}
43154367

@@ -4346,6 +4398,15 @@ bool Util::isSyclSpecConstantType(QualType Ty) {
43464398
return matchQualifiedTypeName(Ty, Scopes);
43474399
}
43484400

4401+
bool Util::isSyclSpecIdType(QualType Ty) {
4402+
std::array<DeclContextDesc, 3> Scopes = {
4403+
Util::MakeDeclContextDesc(clang::Decl::Kind::Namespace, "cl"),
4404+
Util::MakeDeclContextDesc(clang::Decl::Kind::Namespace, "sycl"),
4405+
Util::MakeDeclContextDesc(Decl::Kind::ClassTemplateSpecialization,
4406+
"specialization_id")};
4407+
return matchQualifiedTypeName(Ty, Scopes);
4408+
}
4409+
43494410
bool Util::isSyclKernelHandlerType(QualType Ty) {
43504411
std::array<DeclContextDesc, 3> Scopes = {
43514412
Util::MakeDeclContextDesc(Decl::Kind::Namespace, "cl"),

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
13411341
if (Var->isStaticLocal())
13421342
SemaRef.CheckStaticLocalForDllExport(Var);
13431343

1344+
SemaRef.addSyclVarDecl(Var);
13441345
return Var;
13451346
}
13461347

clang/test/CodeGenSYCL/Inputs/sycl.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,23 @@ class kernel_handler {
295295
void __init_specialization_constants_buffer(char *specialization_constants_buffer) {}
296296
};
297297

298+
template <typename T> class specialization_id {
299+
public:
300+
using value_type = T;
301+
302+
template <class... Args>
303+
explicit constexpr specialization_id(Args &&...args)
304+
: MDefaultValue(args...) {}
305+
306+
specialization_id(const specialization_id &rhs) = delete;
307+
specialization_id(specialization_id &&rhs) = delete;
308+
specialization_id &operator=(const specialization_id &rhs) = delete;
309+
specialization_id &operator=(specialization_id &&rhs) = delete;
310+
311+
private:
312+
T MDefaultValue;
313+
};
314+
298315
#define ATTR_SYCL_KERNEL __attribute__((sycl_kernel))
299316
template <typename KernelName = auto_name, typename KernelType>
300317
ATTR_SYCL_KERNEL void kernel_single_task(const KernelType &kernelFunc) { // #KernelSingleTask
Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,92 @@
11
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown-sycldevice -fsycl-int-footer=%t.h %s -emit-llvm -o %t.ll
22
// RUN: FileCheck -input-file=%t.h %s
33

4-
// CHECK: // Integration Footer contents to go here.
5-
64
#include "Inputs/sycl.hpp"
75

86
int main() {
97
cl::sycl::kernel_single_task<class first_kernel>([]() {});
108
}
9+
10+
using namespace cl::sycl;
11+
12+
cl::sycl::specialization_id<int> GlobalSpecID;
13+
// CHECK: template<>
14+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<GlobalSpecID>() {
15+
// CHECK-NEXT: return "";
16+
// CHECK-NEXT: }
17+
18+
struct Wrapper {
19+
static specialization_id<int> WrapperSpecID;
20+
// CHECK: template<>
21+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Wrapper::WrapperSpecID>() {
22+
// CHECK-NEXT: return "";
23+
// CHECK-NEXT: }
24+
};
25+
26+
template <typename T>
27+
struct WrapperTemplate {
28+
static specialization_id<T> WrapperSpecID;
29+
};
30+
template class WrapperTemplate<int>;
31+
// CHECK: template<>
32+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<WrapperTemplate<int>::WrapperSpecID>() {
33+
// CHECK-NEXT: return "";
34+
// CHECK-NEXT: }
35+
template class WrapperTemplate<double>;
36+
// CHECK: template<>
37+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<WrapperTemplate<double>::WrapperSpecID>() {
38+
// CHECK-NEXT: return "";
39+
// CHECK-NEXT: }
40+
41+
namespace Foo {
42+
specialization_id<int> NSSpecID;
43+
// CHECK: template<>
44+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::NSSpecID>() {
45+
// CHECK-NEXT: return "";
46+
// CHECK-NEXT: }
47+
inline namespace Bar {
48+
specialization_id<int> InlineNSSpecID;
49+
// CHECK: template<>
50+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::InlineNSSpecID>() {
51+
// CHECK-NEXT: return "";
52+
// CHECK-NEXT: }
53+
specialization_id<int> NSSpecID;
54+
// CHECK: template<>
55+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::Bar::NSSpecID>() {
56+
// CHECK-NEXT: return "";
57+
// CHECK-NEXT: }
58+
59+
struct Wrapper {
60+
static specialization_id<int> WrapperSpecID;
61+
// CHECK: template<>
62+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::Wrapper::WrapperSpecID>() {
63+
// CHECK-NEXT: return "";
64+
// CHECK-NEXT: }
65+
};
66+
67+
template <typename T>
68+
struct WrapperTemplate {
69+
static specialization_id<T> WrapperSpecID;
70+
};
71+
template class WrapperTemplate<int>;
72+
// CHECK: template<>
73+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::WrapperTemplate<int>::WrapperSpecID>() {
74+
// CHECK-NEXT: return "";
75+
// CHECK-NEXT: }
76+
template class WrapperTemplate<double>;
77+
// CHECK: template<>
78+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::WrapperTemplate<double>::WrapperSpecID>() {
79+
// CHECK-NEXT: return "";
80+
// CHECK-NEXT: }
81+
} // namespace Bar
82+
namespace {
83+
specialization_id<int> AnonNSSpecID;
84+
// CHECK: template<>
85+
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::AnonNSSpecID>() {
86+
// CHECK-NEXT: return "";
87+
// CHECK-NEXT: }
88+
} // namespace
89+
90+
} // namespace Foo
91+
92+
// CHECK: #include <CL/sycl/detail/spec_const_integration.hpp>

0 commit comments

Comments
 (0)