Skip to content

Commit 66e207e

Browse files
authored
[SYCL] Fix device code outlining for static local variables (#5915)
When static variable was declared in host code and used from device code that forced emission of parent host function. It could cause emission of the code that is not valid for device (but still valid for host). This change makes sure that doesn't happen anymore.
1 parent c16412b commit 66e207e

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

clang/lib/CodeGen/CGDecl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,11 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
296296

297297
setStaticLocalDeclAddress(&D, Addr);
298298

299+
// Do not force emission of the parent funtion since it can be a host function
300+
// that contains illegal code for SYCL device.
301+
if (getLangOpts().SYCLIsDevice)
302+
return Addr;
303+
299304
// Ensure that the static local gets initialized by making sure the parent
300305
// function gets emitted eventually.
301306
const Decl *DC = cast<Decl>(D.getDeclContext());

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2840,6 +2840,14 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
28402840
} else if (VD->isStaticLocal()) {
28412841
llvm::Constant *var = CGM.getOrCreateStaticVarDecl(
28422842
*VD, CGM.getLLVMLinkageVarDefinition(VD, /*IsConstant=*/false));
2843+
2844+
// Force completion of static variable for SYCL since if it wasn't emitted
2845+
// already that means it is defined in host code and its parent function
2846+
// won't be emitted.
2847+
if (getLangOpts().SYCLIsDevice)
2848+
EmitStaticVarDecl(
2849+
*VD, CGM.getLLVMLinkageVarDefinition(VD, /*IsConstant=*/false));
2850+
28432851
addr = Address(
28442852
var, ConvertTypeForMem(VD->getType()), getContext().getDeclAlign(VD));
28452853

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: %clang_cc1 -internal-isystem %S/Inputs -fsycl-is-device -triple spir64-unknown-unknown -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s
2+
3+
// This test checks that static variables defined in host code and used in
4+
// device code do not force emission of their parent host functions.
5+
6+
#include "sycl.hpp"
7+
8+
// CHECK-NOT: class.cl::sycl::queue
9+
10+
// CHECK: @_ZZ4mainE3Loc = internal addrspace(1) constant i32 42, align 4
11+
// CHECK: @_ZZ4mainE6Struct = internal addrspace(1) constant %struct.S { i32 38 }, align 4
12+
// CHECK: @_ZL4Glob = internal addrspace(1) constant i64 100500, align 8
13+
// CHECK: @_ZZZZ4mainENKUlRN2cl4sycl7handlerEE_clES2_ENKUlvE_clEvE6InKern = internal addrspace(1) constant i32 2022, align 4
14+
// CHECK: @_ZN1SIiE6MemberE = available_externally addrspace(1) constant i32 1, align 4
15+
// CHECK: @_ZZ3fooiE5InFoo = internal addrspace(1) constant i32 300, align 4
16+
17+
// CHECK: define{{.*}}@_Z3fooi(i32 noundef %In)
18+
// CHECK-NOT: define{{.*}}@main()
19+
20+
template <class T> struct S {
21+
static const T Member = 1;
22+
int Parrots = 38;
23+
};
24+
25+
static constexpr unsigned long Glob = 100500;
26+
int foo(const int In) {
27+
static constexpr int InFoo = 300;
28+
return InFoo + In;
29+
}
30+
31+
int main() {
32+
sycl::queue q;
33+
static constexpr int Loc = 42;
34+
static const S<int> Struct;
35+
q.submit([&](sycl::handler &cgh) {
36+
cgh.single_task<class TheKernel>([=]() {
37+
(void)Loc;
38+
(void)Struct;
39+
40+
// Make sure other use cases with statics are not broken by the change.
41+
(void)Glob;
42+
static const int InKern = 2022;
43+
foo(Loc);
44+
(void)S<int>::Member;
45+
});
46+
});
47+
48+
return 0;
49+
}

0 commit comments

Comments
 (0)