Skip to content

Commit 21d3a50

Browse files
elizabethandrewsFznamznon
authored andcommitted
Process builtin-sycl-kernel-name called before kernel invocation
Prior support for builtins depends on KernelInfo being available at the time of builtin call. This is not always the case. If a builtin is called prior to kernel invocation, KernelInfo is not populated and the builtin will be unable to retrieve the information it requires. In this case,a global variable is declared to hold the required information, which is populated later when kernel invocation is processed. This PR implements support for this case for builtin-sycl-kernel-name.
1 parent 9565308 commit 21d3a50

File tree

6 files changed

+167
-30
lines changed

6 files changed

+167
-30
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2527,17 +2527,61 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
25272527
return RValue::get(CGF->Builder.CreateCall(UBF, Args));
25282528
}
25292529

2530-
static const SYCLKernelInfo *GetSYCLKernelInfo(ASTContext &Ctx,
2531-
const CallExpr *E) {
2532-
// Argument to the builtin is a type trait which is used to retrieve the
2533-
// kernel name type.
2534-
// FIXME: Improve the comment.
2530+
static const CanQualType GetKernelNameType(ASTContext &Ctx, const CallExpr *E) {
2531+
// The first argument to the builtin is an object that designates
2532+
// the SYCL kernel. The argument is evaluated and its value is
2533+
// discarded; the SYCL kernel is identified based on the argument
2534+
// type. The argument type is required to be a class or structure
2535+
// with a member typedef or type alias named 'type'. The target
2536+
// type of the 'type' member is the SYCL kernel name type.
25352537
RecordDecl *RD = E->getArg(0)->getType()->castAs<RecordType>()->getDecl();
25362538
IdentifierTable &IdentTable = Ctx.Idents;
25372539
auto Name = DeclarationName(&(IdentTable.get("type")));
25382540
NamedDecl *ND = (RD->lookup(Name)).front();
25392541
TypedefNameDecl *TD = cast<TypedefNameDecl>(ND);
2540-
CanQualType KernelNameType = Ctx.getCanonicalType(TD->getUnderlyingType());
2542+
return Ctx.getCanonicalType(TD->getUnderlyingType());
2543+
}
2544+
2545+
static llvm::GlobalVariable *
2546+
EmitKernelNameGlobal(CodeGenModule &CGM, ASTContext &Ctx, const CallExpr *E) {
2547+
CanQualType KernelNameType = GetKernelNameType(Ctx, E);
2548+
2549+
// SmallString<256> KernelNameSymbol;
2550+
// llvm::raw_svector_ostream Out(KernelNameSymbol);
2551+
// The mangling used for the name of the global variable storing the offload
2552+
// kernel name is identical to the mangling of the offload kernel name.
2553+
// CGM.getCXXABI().getMangleContext().mangleSYCLKernelCallerName(KernelNameType,
2554+
// Out);
2555+
//
2556+
2557+
auto DeviceDiscriminatorOverrider =
2558+
[](ASTContext &Ctx, const NamedDecl *ND) -> UnsignedOrNone {
2559+
if (const auto *RD = dyn_cast<CXXRecordDecl>(ND))
2560+
if (RD->isLambda())
2561+
return RD->getDeviceLambdaManglingNumber();
2562+
return std::nullopt;
2563+
};
2564+
std::unique_ptr<MangleContext> MC{ItaniumMangleContext::create(
2565+
Ctx, Ctx.getDiagnostics(), DeviceDiscriminatorOverrider)};
2566+
2567+
SmallString<256> KernelNameSymbol;
2568+
llvm::raw_svector_ostream Out(KernelNameSymbol);
2569+
//llvm::raw_string_ostream Out(KernelNameSymbol);
2570+
MC->mangleCanonicalTypeName(KernelNameType, Out);
2571+
2572+
llvm::GlobalVariable *GV = new llvm::GlobalVariable(
2573+
CGM.getModule(), CGM.GlobalsInt8PtrTy,
2574+
/*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, nullptr,
2575+
KernelNameSymbol);
2576+
2577+
CGM.AddSYCLKernelNameSymbol(KernelNameType, GV);
2578+
2579+
return GV;
2580+
}
2581+
2582+
static const SYCLKernelInfo *GetSYCLKernelInfo(ASTContext &Ctx,
2583+
const CallExpr *E) {
2584+
CanQualType KernelNameType = GetKernelNameType(Ctx, E);
25412585

25422586
// Retrieve KernelInfo using the kernel name.
25432587
return Ctx.findSYCLKernelInfo(KernelNameType);
@@ -6237,21 +6281,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
62376281
return RValue::get(Str.getPointer());
62386282
}
62396283
case Builtin::BI__builtin_sycl_kernel_name: {
6240-
ASTContext &Ctx = getContext();
6241-
// Argument to the builtin is a kernel_id_t type trait which is used
6242-
// to retrieve the kernel name type.
6243-
RecordDecl *RD = E->getArg(0)->getType()->castAs<RecordType>()->getDecl();
6244-
IdentifierTable &IdentTable = Ctx.Idents;
6245-
auto Name = DeclarationName(&(IdentTable.get("type")));
6246-
NamedDecl *ND = (RD->lookup(Name)).front();
6247-
TypeAliasDecl *TD = cast<TypeAliasDecl>(ND);
6248-
QualType KernelNameType = TD->getUnderlyingType().getCanonicalType();
6249-
6250-
// Retrieve the mangled name corresponding to kernel name type.
6251-
const SYCLKernelInfo *KernelInfo = Ctx.findSYCLKernelInfo(KernelNameType);
6252-
assert(KernelInfo && "Type does not correspond to a SYCL kernel name.");
6253-
6254-
// Emit the mangled name.
6284+
// Retrieve the kernel info corresponding to kernel name type.
6285+
const SYCLKernelInfo *KernelInfo = GetSYCLKernelInfo(getContext(), E);
6286+
6287+
// This indicates that the builtin was called before the kernel was
6288+
// invoked. In this case, a global variable is declared, and returned
6289+
// as the result of the call to the builtin. This global variable is
6290+
// later initialized to hold the name of the offload kernel when kernel
6291+
// invocation is processed.
6292+
if (!KernelInfo)
6293+
return RValue::get(EmitKernelNameGlobal(CGM, getContext(), E));
6294+
6295+
// Emit the mangled name from KernelInfo if available.
62556296
auto Str = CGM.GetAddrOfConstantCString(KernelInfo->GetKernelName(), "");
62566297
return RValue::get(Str.getPointer());
62576298
}

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3319,16 +3319,20 @@ void CodeGenModule::EmitDeferred() {
33193319
// a SYCL kernel caller offload entry point function is generated and
33203320
// emitted in place of each of these functions.
33213321
if (const auto *FD = D.getDecl()->getAsFunction()) {
3322-
if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLKernelEntryPointAttr>() &&
3323-
FD->isDefined()) {
3322+
if (FD->hasAttr<SYCLKernelEntryPointAttr>() && FD->isDefined()) {
33243323
// Functions with an invalid sycl_kernel_entry_point attribute are
33253324
// ignored during device compilation.
3326-
if (!FD->getAttr<SYCLKernelEntryPointAttr>()->isInvalidAttr()) {
3325+
if (LangOpts.SYCLIsDevice &&
3326+
!FD->getAttr<SYCLKernelEntryPointAttr>()->isInvalidAttr()) {
33273327
// Generate and emit the SYCL kernel caller function.
33283328
EmitSYCLKernelCaller(FD, getContext());
33293329
// Recurse to emit any symbols directly or indirectly referenced
33303330
// by the SYCL kernel caller function.
33313331
EmitDeferred();
3332+
} else {
3333+
// Initialize the global variables corresponding to SYCL Builtins
3334+
// used to obtain information about the offload kernel.
3335+
InitSYCLKernelInfoSymbolsForBuiltins(FD, getContext());
33323336
}
33333337
// Do not emit the sycl_kernel_entry_point attributed function.
33343338
continue;

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ class CodeGenModule : public CodeGenTypeCache {
677677
computeVTPointerAuthentication(const CXXRecordDecl *ThisClass);
678678

679679
AtomicOptions AtomicOpts;
680+
llvm::DenseMap<CanQualType, llvm::GlobalVariable *> SYCLKernelNameSymbols;
680681

681682
public:
682683
CodeGenModule(ASTContext &C, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
@@ -1505,6 +1506,10 @@ class CodeGenModule : public CodeGenTypeCache {
15051506
/// annotations are emitted during finalization of the LLVM code.
15061507
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
15071508

1509+
void AddSYCLKernelNameSymbol(CanQualType, llvm::GlobalVariable *);
1510+
1511+
llvm::GlobalVariable *GetSYCLKernelNameSymbol(CanQualType);
1512+
15081513
bool isInNoSanitizeList(SanitizerMask Kind, llvm::Function *Fn,
15091514
SourceLocation Loc) const;
15101515

@@ -1975,6 +1980,12 @@ class CodeGenModule : public CodeGenTypeCache {
19751980
void EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
19761981
ASTContext &Ctx);
19771982

1983+
/// Initialize the global variables corresponding to SYCL Builtins used to
1984+
/// obtain information about the offload kernel.
1985+
void
1986+
InitSYCLKernelInfoSymbolsForBuiltins(const FunctionDecl *KernelEntryPointFn,
1987+
ASTContext &Ctx);
1988+
19781989
/// Determine whether the definition must be emitted; if this returns \c
19791990
/// false, the definition can be emitted lazily if it's used.
19801991
bool MustBeEmitted(const ValueDecl *D);

clang/lib/CodeGen/CodeGenSYCL.cpp

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,24 @@ static void SetSYCLKernelAttributes(llvm::Function *Fn, CodeGenFunction &CGF) {
2525
Fn->addFnAttr(llvm::Attribute::MustProgress);
2626
}
2727

28+
static CanQualType GetKernelNameType(const FunctionDecl *KernelEntryPointFn,
29+
ASTContext &Ctx) {
30+
const auto *KernelEntryPointAttr =
31+
KernelEntryPointFn->getAttr<SYCLKernelEntryPointAttr>();
32+
assert(KernelEntryPointAttr && "Missing sycl_kernel_entry_point attribute");
33+
CanQualType KernelNameType =
34+
Ctx.getCanonicalType(KernelEntryPointAttr->getKernelName());
35+
return KernelNameType;
36+
}
37+
38+
static const SYCLKernelInfo *
39+
GetKernelInfo(const FunctionDecl *KernelEntryPointFn, ASTContext &Ctx) {
40+
CanQualType KernelNameType = GetKernelNameType(KernelEntryPointFn, Ctx);
41+
const SYCLKernelInfo *KernelInfo = Ctx.findSYCLKernelInfo(KernelNameType);
42+
assert(KernelInfo && "Type does not correspond to a kernel name");
43+
return KernelInfo;
44+
}
45+
2846
void CodeGenModule::EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
2947
ASTContext &Ctx) {
3048
assert(Ctx.getLangOpts().SYCLIsDevice &&
@@ -52,12 +70,10 @@ void CodeGenModule::EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
5270
getTypes().arrangeSYCLKernelCallerDeclaration(Ctx.VoidTy, Args);
5371
llvm::FunctionType *FnTy = getTypes().GetFunctionType(FnInfo);
5472

55-
// Retrieve the generated name for the SYCL kernel caller function.
56-
CanQualType KernelNameType =
57-
Ctx.getCanonicalType(KernelEntryPointAttr->getKernelName());
58-
const SYCLKernelInfo &KernelInfo = Ctx.getSYCLKernelInfo(KernelNameType);
59-
auto *Fn = llvm::Function::Create(FnTy, llvm::Function::ExternalLinkage,
60-
KernelInfo.GetKernelName(), &getModule());
73+
// Retrieve the generated name for the SYCL kernel caller function
74+
const SYCLKernelInfo *KernelInfo = GetKernelInfo(KernelEntryPointFn, Ctx);
75+
auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalVariable::ExternalLinkage,
76+
KernelInfo->GetKernelName(), &getModule());
6177

6278
// Emit the SYCL kernel caller function.
6379
CodeGenFunction CGF(*this);
@@ -70,3 +86,34 @@ void CodeGenModule::EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
7086
SetLLVMFunctionAttributesForDefinition(cast<Decl>(OutlinedFnDecl), Fn);
7187
CGF.FinishFunction();
7288
}
89+
90+
void CodeGenModule::AddSYCLKernelNameSymbol(CanQualType KernelNameType,
91+
llvm::GlobalVariable *GV) {
92+
SYCLKernelNameSymbols[KernelNameType] = GV;
93+
}
94+
95+
llvm::GlobalVariable *
96+
CodeGenModule::GetSYCLKernelNameSymbol(CanQualType KernelNameType) {
97+
auto it = SYCLKernelNameSymbols.find(KernelNameType);
98+
if (it != SYCLKernelNameSymbols.end())
99+
return it->second;
100+
return nullptr;
101+
}
102+
103+
void CodeGenModule::InitSYCLKernelInfoSymbolsForBuiltins(
104+
const FunctionDecl *KernelEntryPointFn, ASTContext &Ctx) {
105+
CanQualType KernelNameType = GetKernelNameType(KernelEntryPointFn, Ctx);
106+
llvm::GlobalVariable *GV = GetSYCLKernelNameSymbol(KernelNameType);
107+
if (GV && !GV->hasInitializer()) {
108+
const SYCLKernelInfo *KernelInfo = GetKernelInfo(KernelEntryPointFn, Ctx);
109+
ConstantAddress KernelNameStrConstantAddr =
110+
GetAddrOfConstantCString(KernelInfo->GetKernelName(), "");
111+
llvm::Constant *KernelNameStr = KernelNameStrConstantAddr.getPointer();
112+
// FIXME: It is unclear to me whether the right API here is
113+
// replaceInitializer or setInitializer. Unfortunately since the branch I am
114+
// working on is outdated, my workspace does not have replaceInitializer
115+
// Hopefully the person continuing to work on builtins can check this out.
116+
GV->setInitializer(KernelNameStr);
117+
GV->setLinkage(llvm::GlobalValue::PrivateLinkage);
118+
}
119+
}

clang/test/CodeGenSYCL/builtin-sycl-kernel-name.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class kernel_name_3;
1010
class kernel_name_4;
1111
class kernel_name_5;
1212
typedef kernel_name_4 kernel_name_TD2;
13+
class kernel_name_6;
1314

1415
struct constexpr_kernel_name;
1516

@@ -56,13 +57,27 @@ void test() {
5657
test_template<kernel_name_5>();
5758
}
5859

60+
void testBuiltinBeforeKernelInvocation2();
61+
62+
void testBuiltinBeforeKernelInvocation1() {
63+
const char* testBefore1 = __builtin_sycl_kernel_name(kernel_id_t<kernel_name_6>());
64+
}
65+
66+
void testBuiltinBeforeKernelInvocation2() {
67+
SYCLKernel Obj;
68+
kernel_single_task<kernel_name_6>(Obj);
69+
testBuiltinBeforeKernelInvocation2();
70+
}
71+
5972
// Kernel names retrieved from KernelInfo map
6073
// CHECK: @0 = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_1Evv\00", align 1
6174
// CHECK: @1 = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_2Evv\00", align 1
6275
// CHECK: @2 = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_3Evv\00", align 1
6376
// CHECK: @3 = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_4Evv\00", align 1
6477
// CHECK: @.str = private unnamed_addr constant [52 x i8] c"_Z20__sycl_kernel_callerI21constexpr_kernel_nameEvv\00", align 1
78+
// CHECK: @_Z20__sycl_kernel_callerI13kernel_name_6Evv = private constant ptr @[[INIT:[0-9]+]]
6579
// CHECK: @4 = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_5Evv\00", align 1
80+
// CHECK: @[[INIT]] = private unnamed_addr constant [44 x i8] c"_Z20__sycl_kernel_callerI13kernel_name_6Evv\00", align 1
6681

6782
// CHECK: define dso_local void @_Z4testv()
6883
// CHECK: %test1 = alloca ptr, align 8
@@ -81,3 +96,7 @@ void test() {
8196
// CHECK: %test7 = alloca ptr, align 8
8297
// CHECK: store ptr @4, ptr %test6, align 8
8398
// CHECK: store ptr @4, ptr %test7, align 8
99+
100+
// CHECK: define dso_local void @_Z34testBuiltinBeforeKernelInvocation1v()
101+
// CHECK: %testBefore1 = alloca ptr, align 8
102+
// CHECK: store ptr @_Z20__sycl_kernel_callerI13kernel_name_6Evv, ptr %testBefore1, align 8

clang/test/SemaSYCL/builtin-sycl-kernel-name.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ class kernel_name_1;
44
class kernel_name_2;
55
class kernel_name_3;
66
typedef kernel_name_3 kernel_name_TD;
7+
class kernel_name_4;
8+
struct constexpr_kernel_name;
79

810
template<typename KN>
911
struct kernel_id_1 {
@@ -29,6 +31,19 @@ struct SYCLKernel {
2931
void operator()() const {}
3032
};
3133

34+
void testBuiltinBeforeKernelInvocation2();
35+
void testBuiltinBeforeKernelInvocation1() {
36+
const char* testBefore1 = __builtin_sycl_kernel_name(kernel_id_1<kernel_name_4>()); // Valid
37+
constexpr const char* testBefore2 = __builtin_sycl_kernel_name(kernel_id_1<constexpr_kernel_name>()); // expected-error {{constexpr variable 'testBefore2' must be initialized by a constant expression}}
38+
}
39+
40+
void testBuiltinBeforeKernelInvocation2() {
41+
SYCLKernel Obj;
42+
kernel_single_task<kernel_name_4>(Obj);
43+
kernel_single_task<constexpr_kernel_name>(Obj);
44+
testBuiltinBeforeKernelInvocation2();
45+
}
46+
3247
void test() {
3348
SYCLKernel Obj;
3449
kernel_single_task<kernel_name_1>(Obj);

0 commit comments

Comments
 (0)