Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@ class LangOptions : public LangOptionsBase {
/// SYCL integration footer to be generated by the device compiler
std::string SYCLIntFooter;

/// A driver-provided unique string for this translation unit that is used to
/// generate unique names for SYCL names. This is provided by the driver so
/// that the case of multiple-offload can have each device compilation share a
/// name.
std::string SYCLUniquePrefix;

LangOptions();

// Define accessors/mutators for language options of enumeration type.
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -5690,6 +5690,11 @@ def fsycl_int_footer : Separate<["-"], "fsycl-int-footer">,
MarshallingInfoString<LangOpts<"SYCLIntFooter">>;
def fsycl_int_footer_EQ : Joined<["-"], "fsycl-int-footer=">,
Alias<fsycl_int_footer>;
def fsycl_unique_prefix_EQ
: Joined<["-"], "fsycl-unique-prefix=">,
HelpText<"A unique prefix for this translation unit across devices, used "
"to generate a unique name for local variables">,
MarshallingInfoString<LangOpts<"SYCLUniquePrefix">>;
def fsycl_std_layout_kernel_params: Flag<["-"], "fsycl-std-layout-kernel-params">,
HelpText<"Enable standard layout requirement for SYCL kernel parameters.">,
MarshallingInfoFlag<LangOpts<"SYCLStdLayoutKernelParams">>;
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,13 @@ class SYCLIntegrationFooter {
public:
SYCLIntegrationFooter(Sema &S) : S(S) {}
bool emit(StringRef MainSrc);
void addVarDecl(VarDecl *);

private:
bool emit(raw_ostream &O);
Sema &S;
llvm::SmallVector<VarDecl *> SpecConstants;
void emitSpecIDName(raw_ostream &O, const VarDecl *VD);
};

/// Tracks expected type during expression parsing, for use in code completion.
Expand Down Expand Up @@ -13153,6 +13156,11 @@ class Sema final {
return *SyclIntFooter.get();
}

void addSyclVarDecl(VarDecl *VD) {
if (LangOpts.SYCLIsDevice && !LangOpts.SYCLIntFooter.empty())
getSyclIntegrationFooter().addVarDecl(VD);
}

enum SYCLRestrictKind {
KernelGlobalVariable,
KernelRTTI,
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7528,6 +7528,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (IsMemberSpecialization && !NewVD->isInvalidDecl())
CompleteMemberSpecialization(NewVD, Previous);

addSyclVarDecl(NewVD);
return NewVD;
}

Expand Down
63 changes: 62 additions & 1 deletion clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ class Util {
/// specialization constant class.
static bool isSyclSpecConstantType(const QualType &Ty);

/// Checks whether given clang type is a full specialization of the SYCL
/// specialization id class.
static bool isSyclSpecIdType(const QualType &Ty);

/// Checks whether given clang type is a full specialization of the SYCL
/// kernel_handler class.
static bool isSyclKernelHandlerType(const QualType &Ty);
Expand Down Expand Up @@ -4245,6 +4249,22 @@ SYCLIntegrationHeader::SYCLIntegrationHeader(bool _UnnamedLambdaSupport,
Sema &_S)
: UnnamedLambdaSupport(_UnnamedLambdaSupport), S(_S) {}

void SYCLIntegrationFooter::addVarDecl(VarDecl *VD) {
// Step 1: ensure that this is of the correct type(spec-constant template
// specialization).
if (!Util::isSyclSpecIdType(VD->getType()))
return;
// Step 2: ensure that this is a static member, or a namespace-scope.
// Note that the isLocalVarDeclorParm excludes thread-local and static-local
// intentionally, as there is no way to 'spell' one of those in the
// specialization. We just don't generate the specialization for those, and
// let an error happen during host compilation.
if (!VD->hasGlobalStorage() || VD->isLocalVarDeclOrParm())
return;
// Step 3: Add to SpecConstants collection.
SpecConstants.push_back(VD);
}

// Post-compile integration header support.
bool SYCLIntegrationFooter::emit(StringRef IntHeaderName) {
if (IntHeaderName.empty())
Expand All @@ -4261,8 +4281,40 @@ bool SYCLIntegrationFooter::emit(StringRef IntHeaderName) {
return emit(Out);
}

void SYCLIntegrationFooter::emitSpecIDName(raw_ostream &O, const VarDecl *VD) {
// FIXME: Figure out the spec-constant unique name here.
// Note that this changes based on the linkage of the variable.
// We typically want to use the __builtin_unique_stable_name for the variable
// (or the newer-equivilent for values, see the JIRA), but we also have to
// figure out if this has internal or external linkage. In external-case this
// should be the same as the the unique-name. However, this isn't the case
// with local-linkage, where we want to put the driver-provided random-value
// ahead of it, so that we make sure it is unique across translation units.
// This name should come from the yet implemented__builtin_unique_stable_name
// feature that accepts variables and gives the mangling for that.
O << "";
}

bool SYCLIntegrationFooter::emit(raw_ostream &O) {
O << "// Integration Footer contents to go here.\n";
PrintingPolicy Policy{S.getLangOpts()};
Policy.adjustForCPlusPlusFwdDecl();
Policy.SuppressTypedefs = true;
Policy.SuppressUnwrittenScope = true;

for (const VarDecl *D : SpecConstants) {
O << "template<>\n";
O << "inline const char *get_spec_constant_symbolic_ID<";
// Emit the FQN for this, but we probably need to do some funny-business for
// anonymous namespaces.
D->printQualifiedName(O, Policy);
O << ">() {\n";
O << " return \"";
emitSpecIDName(O, D);
O << "\";\n";
O << "}\n";
}

O << "#include <CL/sycl/detail/spec_const_integration.hpp>\n";
return true;
}

Expand Down Expand Up @@ -4304,6 +4356,15 @@ bool Util::isSyclSpecConstantType(const QualType &Ty) {
return matchQualifiedTypeName(Ty, Scopes);
}

bool Util::isSyclSpecIdType(const QualType &Ty) {
llvm::StringLiteral Name = "specialization_id";
std::array<DeclContextDesc, 3> Scopes = {
Util::DeclContextDesc{clang::Decl::Kind::Namespace, "cl"},
Util::DeclContextDesc{clang::Decl::Kind::Namespace, "sycl"},
Util::DeclContextDesc{Decl::Kind::ClassTemplateSpecialization, Name}};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 minor questions here:
does this not need the clang:: namespace prefix?
can we not use the "specialization_id" literal here directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess none of these need 'clang::'. I just copy/pasted from above :) Same as the using specialization_id here directly. I actually don't have a good reason for it being separate. I'll do some cleanup in THIS patch for this function, then do the rest in the other patch (#3504) for the rest.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So hold off on merging this, i want #3504 to go first. THEN I need to merge with that and do a touch of refactoring of this part.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, #3504 is in now, and has been merged with this. The changes you requested here have been done.

This patch should be ready for review (and presumably approval :) )?

return matchQualifiedTypeName(Ty, Scopes);
}

bool Util::isSyclKernelHandlerType(const QualType &Ty) {
const StringRef &Name = "kernel_handler";
std::array<DeclContextDesc, 3> Scopes = {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
if (Var->isStaticLocal())
SemaRef.CheckStaticLocalForDllExport(Var);

SemaRef.addSyclVarDecl(Var);
return Var;
}

Expand Down
17 changes: 17 additions & 0 deletions clang/test/CodeGenSYCL/Inputs/sycl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,23 @@ class kernel_handler {
void __init_specialization_constants_buffer(char *specialization_constants_buffer) {}
};

template <typename T> class specialization_id {
public:
using value_type = T;

template <class... Args>
explicit constexpr specialization_id(Args &&...args)
: MDefaultValue(args...) {}

specialization_id(const specialization_id &rhs) = delete;
specialization_id(specialization_id &&rhs) = delete;
specialization_id &operator=(const specialization_id &rhs) = delete;
specialization_id &operator=(specialization_id &&rhs) = delete;

private:
T MDefaultValue;
};

#define ATTR_SYCL_KERNEL __attribute__((sycl_kernel))
template <typename KernelName = auto_name, typename KernelType>
ATTR_SYCL_KERNEL void kernel_single_task(const KernelType &kernelFunc) { // #KernelSingleTask
Expand Down
86 changes: 84 additions & 2 deletions clang/test/CodeGenSYCL/integration_footer.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,92 @@
// RUN: %clang_cc1 -fsycl-is-device -triple spir64-unknown-unknown-sycldevice -fsycl-int-footer=%t.h %s -emit-llvm -o %t.ll
// RUN: FileCheck -input-file=%t.h %s

// CHECK: // Integration Footer contents to go here.

#include "Inputs/sycl.hpp"

int main() {
cl::sycl::kernel_single_task<class first_kernel>([]() {});
}

using namespace cl::sycl;

cl::sycl::specialization_id<int> GlobalSpecID;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<GlobalSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }

struct Wrapper {
static specialization_id<int> WrapperSpecID;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Wrapper::WrapperSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }
};

template <typename T>
struct WrapperTemplate {
static specialization_id<T> WrapperSpecID;
};
template class WrapperTemplate<int>;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<WrapperTemplate<int>::WrapperSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }
template class WrapperTemplate<double>;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<WrapperTemplate<double>::WrapperSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }

namespace Foo {
specialization_id<int> NSSpecID;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::NSSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }
inline namespace Bar {
specialization_id<int> InlineNSSpecID;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::InlineNSSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }
specialization_id<int> NSSpecID;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::Bar::NSSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }

struct Wrapper {
static specialization_id<int> WrapperSpecID;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::Wrapper::WrapperSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }
};

template <typename T>
struct WrapperTemplate {
static specialization_id<T> WrapperSpecID;
};
template class WrapperTemplate<int>;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::WrapperTemplate<int>::WrapperSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }
template class WrapperTemplate<double>;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::WrapperTemplate<double>::WrapperSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }
} // namespace Bar
namespace {
specialization_id<int> AnonNSSpecID;
// CHECK: template<>
// CHECK-NEXT: inline const char *get_spec_constant_symbolic_ID<Foo::AnonNSSpecID>() {
// CHECK-NEXT: return "";
// CHECK-NEXT: }
} // namespace

} // namespace Foo

// CHECK: #include <CL/sycl/detail/spec_const_integration.hpp>