Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
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
7 changes: 4 additions & 3 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,15 +283,16 @@ class NamedDecl : public Decl {
/// Creating this name is expensive, so it should be called only when
/// performance doesn't matter.
void printQualifiedName(raw_ostream &OS) const;
void printQualifiedName(raw_ostream &OS, const PrintingPolicy &Policy) const;
void printQualifiedName(raw_ostream &OS, const PrintingPolicy &Policy,
bool WithGlobalNsPrefix = false) const;

/// Print only the nested name specifier part of a fully-qualified name,
/// including the '::' at the end. E.g.
/// when `printQualifiedName(D)` prints "A::B::i",
/// this function prints "A::B::".
void printNestedNameSpecifier(raw_ostream &OS) const;
void printNestedNameSpecifier(raw_ostream &OS,
const PrintingPolicy &Policy) const;
void printNestedNameSpecifier(raw_ostream &OS, const PrintingPolicy &Policy,
bool WithGlobalNsPrefix = false) const;

// FIXME: Remove string version.
std::string getQualifiedNameAsString() const;
Expand Down
18 changes: 13 additions & 5 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1538,14 +1538,14 @@ void NamedDecl::printQualifiedName(raw_ostream &OS) const {
printQualifiedName(OS, getASTContext().getPrintingPolicy());
}

void NamedDecl::printQualifiedName(raw_ostream &OS,
const PrintingPolicy &P) const {
void NamedDecl::printQualifiedName(raw_ostream &OS, const PrintingPolicy &P,
bool WithGlobalNsPrefix) const {
if (getDeclContext()->isFunctionOrMethod()) {
// We do not print '(anonymous)' for function parameters without name.
printName(OS);
return;
}
printNestedNameSpecifier(OS, P);
printNestedNameSpecifier(OS, P, WithGlobalNsPrefix);
if (getDeclName())
OS << *this;
else {
Expand All @@ -1566,7 +1566,8 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS) const {
}

void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
const PrintingPolicy &P) const {
const PrintingPolicy &P,
bool WithGlobalNsPrefix) const {
const DeclContext *Ctx = getDeclContext();

// For ObjC methods and properties, look through categories and use the
Expand All @@ -1593,6 +1594,11 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
Ctx = Ctx->getParent();
}

if (Contexts.empty() && WithGlobalNsPrefix) {
if (getDeclContext()->isTranslationUnit())
OS << "::";
}

for (const DeclContext *DC : llvm::reverse(Contexts)) {
if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
OS << Spec->getName();
Expand All @@ -1605,7 +1611,9 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
if (ND->isAnonymousNamespace()) {
OS << (P.MSVCFormatting ? "`anonymous namespace\'"
: "(anonymous namespace)");
}
} else if (WithGlobalNsPrefix &&
ND->getDeclContext()->isTranslationUnit())
OS << "::" << *ND;
else
OS << *ND;
} else if (const auto *RD = dyn_cast<RecordDecl>(DC)) {
Expand Down
107 changes: 104 additions & 3 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1690,10 +1690,17 @@ void SYCLIntegrationHeader::emitFwdDecl(raw_ostream &O, const Decl *D,
PrintingPolicy P(D->getASTContext().getLangOpts());
P.adjustForCPlusPlusFwdDecl();
P.SuppressTypedefs = true;
P.SuppressUnwrittenScope = true;
std::string S;
llvm::raw_string_ostream SO(S);
D->print(SO, P);
O << SO.str() << ";\n";
O << SO.str();

if (const auto *ED = dyn_cast<EnumDecl>(D)) {
QualType T = ED->getIntegerType();
O << " : " << T.getAsString() << ";\n";
} else
O << ";\n";

// print closing braces for namespaces if needed
for (unsigned I = 0; I < NamespaceCnt; ++I)
Expand Down Expand Up @@ -1796,6 +1803,15 @@ void SYCLIntegrationHeader::emitForwardClassDecls(
}
break;
}
case TemplateArgument::ArgKind::Integral: {
// Handle Kernel Name Type templated using enum.
QualType T = Arg.getIntegralType();
if (const EnumType *ET = T->getAs<EnumType>()) {
const EnumDecl *ED = ET->getDecl();
emitFwdDecl(O, ED, KernelLocation);
}
break;
}
default:
break; // nop
}
Expand All @@ -1822,6 +1838,90 @@ static std::string getCPPTypeString(QualType Ty) {
return eraseAnonNamespace(Ty.getAsString(P));
}

static void printArguments(ASTContext &Ctx, raw_ostream &ArgOS,
ArrayRef<TemplateArgument> Args,
const PrintingPolicy &P, bool ParameterPack) {

if (!ParameterPack)
ArgOS << "<";

bool FirstArg = true;
const char *Comma = ", ";

for (unsigned I = 0; I < Args.size(); I++) {
const TemplateArgument &Arg = Args[I];
if (Arg.getKind() == TemplateArgument::ArgKind::Pack) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems a lot like a few of the other places we emit arguments based on their kind. Is there a way to dispatch the body of much of this instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maaaaybe. But I think the function body is not similar enough to make this efficient. Both functions are looping over arguments to emit 'something' but what is being emitted is different.

if (Arg.pack_size() && !FirstArg)
ArgOS << Comma;
printArguments(Ctx, ArgOS, Arg.getPackAsArray(), P, true);
} else if (Arg.getKind() == TemplateArgument::ArgKind::Integral) {
if (!FirstArg)
ArgOS << Comma;

QualType T = Arg.getIntegralType();
const EnumType *ET = T->getAs<EnumType>();

if (ET) {
const llvm::APSInt &Val = Arg.getAsIntegral();
ArgOS << "(" << ET->getDecl()->getQualifiedNameAsString() << ")" << Val;
} else {
Arg.print(P, ArgOS);
}
} else if (Arg.getKind() == TemplateArgument::ArgKind::Type) {
if (!FirstArg)
ArgOS << Comma;
LangOptions LO;
PrintingPolicy TypePolicy(LO);
TypePolicy.SuppressTypedefs = true;
TypePolicy.SuppressTagKeyword = true;
QualType T = Arg.getAsType();
QualType FullyQualifiedType =
TypeName::getFullyQualifiedType(T, Ctx, true);
ArgOS << FullyQualifiedType.getAsString(TypePolicy);
} else {
if (!FirstArg)
ArgOS << Comma;
Arg.print(P, ArgOS);
}
FirstArg = false;
}

if (!ParameterPack)
ArgOS << ">";
}

static std::string getKernelNameTypeString(QualType T) {

const CXXRecordDecl *RD = T->getAsCXXRecordDecl();

if (!RD)
return getCPPTypeString(T);

// If kernel name type is a template specialization with enum type
// template parameters, enumerators in name type string should be
// replaced with their underlying value since the enum definition
// is not visible in integration header.
if (const auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
LangOptions LO;
PrintingPolicy P(LO);
P.SuppressTypedefs = true;
SmallString<64> Buf;
llvm::raw_svector_ostream ArgOS(Buf);

// Print template class name
TSD->printQualifiedName(ArgOS, P, true);

// Print template arguments substituting enumerators
ASTContext &Ctx = RD->getASTContext();
const TemplateArgumentList &Args = TSD->getTemplateArgs();
printArguments(Ctx, ArgOS, Args.asArray(), P, false);

return eraseAnonNamespace(ArgOS.str().str());
}

return getCPPTypeString(T);
}

void SYCLIntegrationHeader::emit(raw_ostream &O) {
O << "// This is auto-generated SYCL integration header.\n";
O << "\n";
Expand Down Expand Up @@ -1938,8 +2038,9 @@ void SYCLIntegrationHeader::emit(raw_ostream &O) {
O << "', '" << c;
O << "'> {\n";
} else {
O << "template <> struct KernelInfo<" << getCPPTypeString(K.NameType)
<< "> {\n";

O << "template <> struct KernelInfo<"
<< getKernelNameTypeString(K.NameType) << "> {\n";
}
O << " DLL_LOCAL\n";
O << " static constexpr const char* getName() { return \"" << K.Name
Expand Down
12 changes: 6 additions & 6 deletions clang/test/CodeGenSYCL/int_header1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
// CHECK:template <> struct KernelInfo<class KernelName> {
// CHECK:template <> struct KernelInfo<::nm1::nm2::KernelName0> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName1> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName3< ::nm1::nm2::KernelName0>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName3< ::nm1::KernelName1>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName4< ::nm1::nm2::KernelName0>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName4< ::nm1::KernelName1>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName3<::nm1::nm2::KernelName0>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName3<::nm1::KernelName1>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName4<::nm1::nm2::KernelName0>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName4<::nm1::KernelName1>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName3<KernelName5>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName4<KernelName7>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName8< ::nm1::nm2::C>> {
// CHECK:template <> struct KernelInfo<class TmplClassInAnonNS<class ClassInAnonNS>> {
// CHECK:template <> struct KernelInfo<::nm1::KernelName8<::nm1::nm2::C>> {
// CHECK:template <> struct KernelInfo<TmplClassInAnonNS<ClassInAnonNS>> {

// This test checks if the SYCL device compiler is able to generate correct
// integration header when the kernel name class is expressed in different
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGenSYCL/integration_header.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@
//
// CHECK: template <> struct KernelInfo<class first_kernel> {
// CHECK: template <> struct KernelInfo<::second_namespace::second_kernel<char>> {
// CHECK: template <> struct KernelInfo<::third_kernel<1, int, ::point<X> >> {
// CHECK: template <> struct KernelInfo<::fourth_kernel< ::template_arg_ns::namespaced_arg<1> >> {
// CHECK: template <> struct KernelInfo<::third_kernel<1, int, ::point<X>>> {
// CHECK: template <> struct KernelInfo<::fourth_kernel<::template_arg_ns::namespaced_arg<1>>> {

#include "sycl.hpp"

Expand Down
8 changes: 4 additions & 4 deletions clang/test/CodeGenSYCL/kernel_name_with_typedefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,16 @@ int main() {
single_task<kernel_name2<const space::long_t, space::a_t>>(f);
// CHECK: template <> struct KernelInfo<::kernel_name2<const volatile long, const ::space::B>> {
single_task<kernel_name2<volatile space::clong_t, const space::b_t>>(f);
// CHECK: template <> struct KernelInfo<::kernel_name2< ::A, long>> {
// CHECK: template <> struct KernelInfo<::kernel_name2<::A, long>> {
single_task<kernel_name2<space::a_t, space::long_t>>(f);
// CHECK: template <> struct KernelInfo<::kernel_name2< ::space::B, int>> {
// CHECK: template <> struct KernelInfo<::kernel_name2<::space::B, int>> {
single_task<kernel_name2<space::b_t, int_t>>(f);
// full template specialization
// CHECK: template <> struct KernelInfo<::kernel_name2<int, const unsigned int>> {
single_task<kernel_name2<int_t, const uint_t>>(f);
// CHECK: template <> struct KernelInfo<::kernel_name2<const long, volatile const unsigned long>> {
// CHECK: template <> struct KernelInfo<::kernel_name2<const long, const volatile unsigned long>> {
single_task<kernel_name2<space::clong_t, volatile space::culong_t>>(f);
// CHECK: template <> struct KernelInfo<::kernel_name2< ::A, volatile ::space::B>> {
// CHECK: template <> struct KernelInfo<::kernel_name2<::A, volatile ::space::B>> {
single_task<kernel_name2<space::a_t, volatile space::b_t>>(f);
// CHECK: template <> struct KernelInfo<::kernel_name3<1>> {
single_task<kernel_name3<1>>(f);
Expand Down
119 changes: 119 additions & 0 deletions clang/test/CodeGenSYCL/kernelname-enum.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// RUN: %clang_cc1 -I %S/Inputs -fsycl -fsycl-is-device -triple spir64-unknown-unknown-sycldevice -fsycl-int-header=%t.h %s -fsyntax-only
// RUN: FileCheck -input-file=%t.h %s

#include "sycl.hpp"

enum class no_namespace_int : int {
val_1,
val_2
};

enum class no_namespace_short : short {
val_1,
val_2
};

namespace internal {
enum class namespace_short : short {
val_1,
val_2
};
}

namespace {
enum class enum_in_anonNS : short {
val_1,
val_2
};
}

enum class no_type_set {
val_1,
val_2
};

template <no_namespace_int EnumType>
class dummy_functor_1 {
public:
void operator()() {}
};

template <no_namespace_short EnumType>
class dummy_functor_2 {
public:
void operator()() {}
};

template <internal::namespace_short EnumType>
class dummy_functor_3 {
public:
void operator()() {}
};

template <enum_in_anonNS EnumType>
class dummy_functor_4 {
public:
void operator()() {}
};

template <no_type_set EnumType>
class dummy_functor_5 {
public:
void operator()() {}
};

int main() {

dummy_functor_1<no_namespace_int::val_1> f1;
dummy_functor_2<no_namespace_short::val_2> f2;
dummy_functor_3<internal::namespace_short::val_2> f3;
dummy_functor_4<enum_in_anonNS::val_2> f4;
dummy_functor_5<no_type_set::val_1> f5;

cl::sycl::queue q;

q.submit([&](cl::sycl::handler &cgh) {
cgh.single_task(f1);
});

q.submit([&](cl::sycl::handler &cgh) {
cgh.single_task(f2);
});

q.submit([&](cl::sycl::handler &cgh) {
cgh.single_task(f3);
});

q.submit([&](cl::sycl::handler &cgh) {
cgh.single_task(f4);
});

q.submit([&](cl::sycl::handler &cgh) {
cgh.single_task(f5);
});

return 0;
}

// CHECK: Forward declarations of templated kernel function types:
// CHECK: enum class no_namespace_int : int;
// CHECK: template <no_namespace_int EnumType> class dummy_functor_1;
// CHECK: enum class no_namespace_short : short;
// CHECK: template <no_namespace_short EnumType> class dummy_functor_2;
// CHECK: namespace internal {
// CHECK-NEXT: enum class namespace_short : short;
// CHECK-NEXT: }
// CHECK: template <internal::namespace_short EnumType> class dummy_functor_3;
// CHECK: namespace {
// CHECK-NEXT: enum class enum_in_anonNS : short;
// CHECK-NEXT: }
// CHECK: template <enum_in_anonNS EnumType> class dummy_functor_4;
// CHECK: enum class no_type_set : int;
// CHECK: template <no_type_set EnumType> class dummy_functor_5;

// CHECK: Specializations of KernelInfo for kernel function types:
// CHECK: template <> struct KernelInfo<::dummy_functor_1<(no_namespace_int)0>>
// CHECK: template <> struct KernelInfo<::dummy_functor_2<(no_namespace_short)1>>
// CHECK: template <> struct KernelInfo<::dummy_functor_3<(internal::namespace_short)1>>
// CHECK: template <> struct KernelInfo<::dummy_functor_4<(enum_in_anonNS)1>>
// CHECK: template <> struct KernelInfo<::dummy_functor_5<(no_type_set)0>>