Skip to content

Commit 4ba61d0

Browse files
authored
[SYCL] Match kernel's function types with actual types. (#1949)
Using getFullyQualifiedType to calculcate the kernel function's types makes the types in the kernel different from the actual type and that creates a type mismatch. getFullyQualifiedType's use is restricted to make type lookup correct in templates. This change, replacing the fully qualified type with the canonical one, fixes the issue, but will imply that the pretty-printer needs to be updated to print fully qualified names.
1 parent 7fa4f68 commit 4ba61d0

File tree

2 files changed

+68
-30
lines changed

2 files changed

+68
-30
lines changed

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -706,8 +706,7 @@ static QualType calculateKernelNameType(ASTContext &Ctx,
706706
const TemplateArgumentList *TAL =
707707
KernelCallerFunc->getTemplateSpecializationArgs();
708708
assert(TAL && "No template argument info");
709-
return TypeName::getFullyQualifiedType(TAL->get(0).getAsType(), Ctx,
710-
/*WithGlobalNSPrefix=*/true);
709+
return TAL->get(0).getAsType().getCanonicalType();
711710
}
712711

713712
// Gets a name for the OpenCL kernel function, calculated from the first
@@ -1761,10 +1760,7 @@ class SyclKernelIntHeaderCreator
17611760
"Incorrect template args for Accessor Type");
17621761
// Get specialization constant ID type, which is the second template
17631762
// argument.
1764-
QualType SpecConstIDTy =
1765-
TypeName::getFullyQualifiedType(TemplateArgs.get(1).getAsType(),
1766-
SemaRef.getASTContext(), true)
1767-
.getCanonicalType();
1763+
QualType SpecConstIDTy = TemplateArgs.get(1).getAsType().getCanonicalType();
17681764
const std::string SpecConstName = PredefinedExpr::ComputeName(
17691765
SemaRef.getASTContext(), PredefinedExpr::UniqueStableNameType,
17701766
SpecConstIDTy);
@@ -2446,40 +2442,42 @@ static void printTemplateArguments(ASTContext &Ctx, raw_ostream &ArgOS,
24462442
ArgOS << ">";
24472443
}
24482444

2449-
static std::string getKernelNameTypeString(QualType T, ASTContext &Ctx,
2450-
const PrintingPolicy &TypePolicy) {
2451-
2452-
QualType FullyQualifiedType = TypeName::getFullyQualifiedType(T, Ctx, true);
2453-
2454-
const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
2455-
2456-
if (!RD)
2457-
return eraseAnonNamespace(FullyQualifiedType.getAsString(TypePolicy));
2458-
2459-
// If kernel name type is a template specialization with enum type
2460-
// template parameters, enumerators in name type string should be
2461-
// replaced with their underlying value since the enum definition
2462-
// is not visible in integration header.
2463-
if (const auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
2464-
SmallString<64> Buf;
2465-
llvm::raw_svector_ostream ArgOS(Buf);
2466-
2467-
// Print the qualifiers for the type.
2468-
FullyQualifiedType.getQualifiers().print(ArgOS, TypePolicy,
2445+
static std::string printRecordType(QualType T, const CXXRecordDecl *RD,
2446+
const PrintingPolicy &TypePolicy) {
2447+
SmallString<64> Buf;
2448+
llvm::raw_svector_ostream OS(Buf);
2449+
T.getCanonicalType().getQualifiers().print(OS, TypePolicy,
24692450
/*appendSpaceIfNotEmpty*/ true);
2451+
if (const auto *TSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
24702452

24712453
// Print template class name
2472-
TSD->printQualifiedName(ArgOS, TypePolicy, /*WithGlobalNsPrefix*/ true);
2454+
TSD->printQualifiedName(OS, TypePolicy, /*WithGlobalNsPrefix*/ true);
24732455

24742456
// Print template arguments substituting enumerators
24752457
ASTContext &Ctx = RD->getASTContext();
24762458
const TemplateArgumentList &Args = TSD->getTemplateArgs();
2477-
printTemplateArguments(Ctx, ArgOS, Args.asArray(), TypePolicy);
2459+
printTemplateArguments(Ctx, OS, Args.asArray(), TypePolicy);
24782460

2479-
return eraseAnonNamespace(ArgOS.str().str());
2461+
return eraseAnonNamespace(OS.str().str());
24802462
}
2463+
if (RD->getDeclContext()->isFunctionOrMethod())
2464+
return eraseAnonNamespace(T.getCanonicalType().getAsString(TypePolicy));
2465+
const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(RD->getDeclContext());
2466+
RD->printQualifiedName(OS, TypePolicy, !(NS && NS->isAnonymousNamespace()));
2467+
return eraseAnonNamespace(OS.str().str());
2468+
}
24812469

2482-
return eraseAnonNamespace(FullyQualifiedType.getAsString(TypePolicy));
2470+
static std::string getKernelNameTypeString(QualType T, ASTContext &Ctx,
2471+
const PrintingPolicy &TypePolicy) {
2472+
if (T->isRecordType())
2473+
return printRecordType(T, T->getAsCXXRecordDecl(), TypePolicy);
2474+
if (T->isEnumeralType()) {
2475+
SmallString<64> Buf;
2476+
llvm::raw_svector_ostream OS(Buf);
2477+
OS << "::" << T.getCanonicalType().getAsString(TypePolicy);
2478+
return eraseAnonNamespace(OS.str().str());
2479+
}
2480+
return eraseAnonNamespace(T.getCanonicalType().getAsString(TypePolicy));
24832481
}
24842482

24852483
void SYCLIntegrationHeader::emit(raw_ostream &O) {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %clang_cc1 -fsycl -fsycl-is-device -fsyntax-only -verify %s
2+
// expected-no-diagnostics
3+
4+
// The kernel_single_task call is emitted as an OpenCL kernel function. The call
5+
// to getFullyQualifiedType caused a 2nd instantiation of zip_iterator<b,b> (the
6+
// first instantiation is on line 28 during phase 1).
7+
// Then, the call to 'foo' in 'main' causes 'foo' to be instantiated. The best
8+
// match for zip_iterator<j,d> is the one instantiated by the
9+
// kernel_single_task, which is now different from the one made in phase 1.
10+
// 'is_same<zip_iterator<b,b>' is instantiated during phase 1 at line 28, and
11+
// 'zip_iterator<b,b>' is instantiated by getFullyQualifiedName.
12+
// So 'is_same<zip_iterator<b,b>, zip_iterator<j,d>>::value' return false
13+
// even though zip_iterator<b,b> and zip_iterator<j,d> have the same type
14+
// 'zip_iterator<b,b>'.
15+
16+
struct b {};
17+
18+
template <typename T, typename U>
19+
struct is_same { static const bool value = false; };
20+
template <typename T>
21+
struct is_same<T, T> { static const bool value = true; };
22+
23+
template <typename... Ts>
24+
struct zip_iterator {};
25+
26+
template <class j, class d>
27+
void foo(j e, d k) {
28+
static_assert(is_same<zip_iterator<b, b>, zip_iterator<j, d>>::value, "device_iterator");
29+
}
30+
31+
template <typename name, typename Func>
32+
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
33+
kernelFunc();
34+
}
35+
36+
int main() {
37+
kernel_single_task<zip_iterator<b, b>>([] {});
38+
foo(b{}, b{});
39+
return 0;
40+
}

0 commit comments

Comments
 (0)