[PATCH] D102801: [CUDA][HIP] Fix device variables used by host

2021-05-20 Thread Yaxun Liu via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG4cb42564ec4b: [CUDA][HIP] Fix device variables used by host 
(authored by yaxunl).
Herald added a project: clang.

Changed prior to commit:
  https://reviews.llvm.org/D102801?vs=346831=346851#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102801/new/

https://reviews.llvm.org/D102801

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGDeclCXX.cpp
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/Sema/SemaCUDA.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/test/AST/ast-dump-constant-var.cu
  clang/test/CodeGenCUDA/host-used-device-var.cu
  clang/test/SemaCUDA/static-device-var.cu

Index: clang/test/SemaCUDA/static-device-var.cu
===
--- clang/test/SemaCUDA/static-device-var.cu
+++ clang/test/SemaCUDA/static-device-var.cu
@@ -1,16 +1,14 @@
 // REQUIRES: x86-registered-target
 // REQUIRES: amdgpu-registered-target
 
-// RUN: %clang_cc1 -triple nvptx -fcuda-is-device \
-// RUN:-emit-llvm -o - %s -fsyntax-only -verify=dev
+// RUN: %clang_cc1 -triple nvptx -fcuda-is-device -std=c++11 \
+// RUN:-emit-llvm -o - %s -fsyntax-only -verify=dev,com
 
-// RUN: %clang_cc1 -triple x86_64-gnu-linux \
-// RUN:-emit-llvm -o - %s -fsyntax-only -verify=host
+// RUN: %clang_cc1 -triple x86_64-gnu-linux -std=c++11 \
+// RUN:-emit-llvm -o - %s -fsyntax-only -verify=host,com
 
 // Checks allowed usage of file-scope and function-scope static variables.
 
-// host-no-diagnostics
-
 #include "Inputs/cuda.h"
 
 // Checks static variables are allowed in device functions.
@@ -42,6 +40,28 @@
   // dev-error@-1 {{reference to __host__ variable 'z' in __global__ function}}
 }
 
+// Check dynamic initialization of static device variable is not allowed.
+
+namespace TestStaticVarInLambda {
+class A {
+public:
+  A(char *);
+};
+class B {
+public:
+  __device__ B(char *);
+};
+void fun() {
+  (void) [](char *c) {
+static A var1(c);
+static __device__ B var2(c);
+// com-error@-1 {{dynamic initialization is not supported for __device__, __constant__, __shared__, and __managed__ variables}}
+(void) var1;
+(void) var2;
+  };
+}
+}
+
 int* getDeviceSymbol(int *x);
 
 void foo() {
Index: clang/test/CodeGenCUDA/host-used-device-var.cu
===
--- clang/test/CodeGenCUDA/host-used-device-var.cu
+++ clang/test/CodeGenCUDA/host-used-device-var.cu
@@ -66,30 +66,148 @@
 template 
 __device__ func_t p_add_func = add_func;
 
+// Check non-constant constexpr variables ODR-used by host code only is not emitted.
+// DEV-NEG-NOT: constexpr_var1a
+// DEV-NEG-NOT: constexpr_var1b
+constexpr int constexpr_var1a = 1;
+inline constexpr int constexpr_var1b = 1;
+
+// Check constant constexpr variables ODR-used by host code only.
+// Non-inline constexpr variable has internal linkage, therefore it is not accessible by host and not kept.
+// Inline constexpr variable has linkonce_ord linkage, therefore it can be accessed by host and kept.
+// DEV-NEG-NOT: constexpr_var2a
+// DEV-DAG: @constexpr_var2b = linkonce_odr addrspace(4) externally_initialized constant i32 2
+__constant__ constexpr int constexpr_var2a = 2;
+inline __constant__ constexpr int constexpr_var2b = 2;
+
 void use(func_t p);
-void use(int *p);
+__host__ __device__ void use(const int *p);
 
+// Check static device variable in host function.
+// DEV-DAG:  @_ZZ4fun1vE11static_var1 = addrspace(1) externally_initialized global i32 3
 void fun1() {
+  static __device__ int static_var1 = 3;
   use();
   use();
   use();
   use(_var);
   use(_var);
   use(p_add_func);
+  use(_var1a);
+  use(_var1b);
+  use(_var2a);
+  use(_var2b);
+  use(_var1);
+}
+
+// Check static variable in host device function.
+// DEV-DAG:  @_ZZ4fun2vE11static_var2 = internal addrspace(1) global i32 4
+// DEV-DAG:  @_ZZ4fun2vE11static_var3 = addrspace(1) global i32 4
+__host__ __device__ void fun2() {
+  static int static_var2 = 4;
+  static __device__ int static_var3 = 4;
+  use(_var2);
+  use(_var3);
 }
 
 __global__ void kern1(int **x) {
   *x = 
+  fun2();
+}
+
+// Check static variables of lambda functions.
+
+// Lambda functions are implicit host device functions.
+// Default static variables in lambda functions should be treated
+// as host variables on host side, therefore should not be forced
+// to be emitted on device.
+
+// DEV-DAG: @_ZZZN21TestStaticVarInLambda3funEvENKUlPcE_clES0_E4var2 = addrspace(1) externally_initialized global i32 5
+// DEV-NEG-NOT: @_ZZZN21TestStaticVarInLambda3funEvENKUlPcE_clES0_E4var1
+namespace TestStaticVarInLambda {
+class A {
+public:
+  A(char *);
+};
+void fun() {
+  (void) [](char *c) {
+static A var1(c);
+static __device__ int var2 = 5;
+(void) var1;
+(void) var2;
+  };
+}
+}
+
+// 

[PATCH] D102801: [CUDA][HIP] Fix device variables used by host

2021-05-20 Thread Artem Belevich via Phabricator via cfe-commits
tra accepted this revision.
tra added a comment.
This revision is now accepted and ready to land.

LGTM.

I've verified that Tensorflow still builds with this patch and that the patch 
does fix the regressions we've seen.
If you could land this patch soon, that would be appreciated.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102801/new/

https://reviews.llvm.org/D102801

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D102801: [CUDA][HIP] Fix device variables used by host

2021-05-20 Thread Yaxun Liu via Phabricator via cfe-commits
yaxunl updated this revision to Diff 346831.
yaxunl marked 3 inline comments as done.
yaxunl added a comment.

revised by Artem's comments


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102801/new/

https://reviews.llvm.org/D102801

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGDeclCXX.cpp
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/Sema/SemaCUDA.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/test/AST/ast-dump-constant-var.cu
  clang/test/CodeGenCUDA/host-used-device-var.cu
  clang/test/SemaCUDA/static-device-var.cu

Index: clang/test/SemaCUDA/static-device-var.cu
===
--- clang/test/SemaCUDA/static-device-var.cu
+++ clang/test/SemaCUDA/static-device-var.cu
@@ -1,16 +1,14 @@
 // REQUIRES: x86-registered-target
 // REQUIRES: amdgpu-registered-target
 
-// RUN: %clang_cc1 -triple nvptx -fcuda-is-device \
-// RUN:-emit-llvm -o - %s -fsyntax-only -verify=dev
+// RUN: %clang_cc1 -triple nvptx -fcuda-is-device -std=c++11 \
+// RUN:-emit-llvm -o - %s -fsyntax-only -verify=dev,com
 
-// RUN: %clang_cc1 -triple x86_64-gnu-linux \
-// RUN:-emit-llvm -o - %s -fsyntax-only -verify=host
+// RUN: %clang_cc1 -triple x86_64-gnu-linux -std=c++11 \
+// RUN:-emit-llvm -o - %s -fsyntax-only -verify=host,com
 
 // Checks allowed usage of file-scope and function-scope static variables.
 
-// host-no-diagnostics
-
 #include "Inputs/cuda.h"
 
 // Checks static variables are allowed in device functions.
@@ -42,6 +40,28 @@
   // dev-error@-1 {{reference to __host__ variable 'z' in __global__ function}}
 }
 
+// Check dynamic initialization of static device variable is not allowed.
+
+namespace TestStaticVarInLambda {
+class A {
+public:
+  A(char *);
+};
+class B {
+public:
+  __device__ B(char *);
+};
+void fun() {
+  (void) [](char *c) {
+static A var1(c);
+static __device__ B var2(c);
+// com-error@-1 {{dynamic initialization is not supported for __device__, __constant__, __shared__, and __managed__ variables}}
+(void) var1;
+(void) var2;
+  };
+}
+}
+
 int* getDeviceSymbol(int *x);
 
 void foo() {
Index: clang/test/CodeGenCUDA/host-used-device-var.cu
===
--- clang/test/CodeGenCUDA/host-used-device-var.cu
+++ clang/test/CodeGenCUDA/host-used-device-var.cu
@@ -66,30 +66,148 @@
 template 
 __device__ func_t p_add_func = add_func;
 
+// Check non-constant constexpr variables ODR-used by host code only is not emitted.
+// DEV-NEG-NOT: constexpr_var1a
+// DEV-NEG-NOT: constexpr_var1b
+constexpr int constexpr_var1a = 1;
+inline constexpr int constexpr_var1b = 1;
+
+// Check constant constexpr variables ODR-used by host code only.
+// Non-inline constexpr variable has internal linkage, therefore it is not accessible by host and not kept.
+// Inline constexpr variable has linkonce_ord linkage, therefore it can be accessed by host and kept.
+// DEV-NEG-NOT: constexpr_var2a
+// DEV-DAG: @constexpr_var2b = linkonce_odr addrspace(4) externally_initialized constant i32 2
+__constant__ constexpr int constexpr_var2a = 2;
+inline __constant__ constexpr int constexpr_var2b = 2;
+
 void use(func_t p);
-void use(int *p);
+__host__ __device__ void use(const int *p);
 
+// Check static device variable in host function.
+// DEV-DAG:  @_ZZ4fun1vE11static_var1 = dso_local addrspace(1) externally_initialized global i32 3
 void fun1() {
+  static __device__ int static_var1 = 3;
   use();
   use();
   use();
   use(_var);
   use(_var);
   use(p_add_func);
+  use(_var1a);
+  use(_var1b);
+  use(_var2a);
+  use(_var2b);
+  use(_var1);
+}
+
+// Check static variable in host device function.
+// DEV-DAG:  @_ZZ4fun2vE11static_var2 = internal addrspace(1) global i32 4
+// DEV-DAG:  @_ZZ4fun2vE11static_var3 = dso_local addrspace(1) global i32 4
+__host__ __device__ void fun2() {
+  static int static_var2 = 4;
+  static __device__ int static_var3 = 4;
+  use(_var2);
+  use(_var3);
 }
 
 __global__ void kern1(int **x) {
   *x = 
+  fun2();
+}
+
+// Check static variables of lambda functions.
+
+// Lambda functions are implicit host device functions.
+// Default static variables in lambda functions should be treated
+// as host variables on host side, therefore should not be forced
+// to be emitted on device.
+
+// DEV-DAG: @_ZZZN21TestStaticVarInLambda3funEvENKUlPcE_clES0_E4var2 = dso_local addrspace(1) externally_initialized global i32 5
+// DEV-NEG-NOT: @_ZZZN21TestStaticVarInLambda3funEvENKUlPcE_clES0_E4var1
+namespace TestStaticVarInLambda {
+class A {
+public:
+  A(char *);
+};
+void fun() {
+  (void) [](char *c) {
+static A var1(c);
+static __device__ int var2 = 5;
+(void) var1;
+(void) var2;
+  };
+}
+}
+
+// Check implicit constant variable ODR-used by host code is not emitted.
+
+// AST contains instantiation of al, which triggers AST instantiation
+// of x::al::am, which triggers AST instatiation of x::ap,
+// which 

[PATCH] D102801: [CUDA][HIP] Fix device variables used by host

2021-05-20 Thread Yaxun Liu via Phabricator via cfe-commits
yaxunl marked 3 inline comments as done.
yaxunl added inline comments.



Comment at: clang/include/clang/Sema/Sema.h:12066
 
+  enum CUDAVariableTarget {
+CVT_Device,  /// Device only

tra wrote:
> Wasn't there another kind, where the variable is emitted on the host with 
> device-side shadow? I vaguely recall it had something to do with textures.
That was the first implementation, which was similar to managed var but used 
pinned host memory as a common memory shared by device and host.

However, that implementation was later replaced by a different implementation 
which is similar to nvcc. In the new implementation textures and surfaces are 
like usual device variables. So far I do not see the necessity to differentiate 
them from usual device variables.



Comment at: clang/include/clang/Sema/Sema.h:12067
+  enum CUDAVariableTarget {
+CVT_Device,  /// Device only
+CVT_Host,/// Host only

tra wrote:
> I think we should mention the host-side shadows, too.
will do



Comment at: clang/lib/Sema/SemaCUDA.cpp:148-149
+return CVT_Unified;
+  if (hasImplicitAttr(Var))
+return CVT_Both;
+  if (Var->hasAttr() || Var->hasAttr() ||

tra wrote:
> I'm still not a fan of relying on a implicit __constant__.
> Can we change it to more direct `is-a-constexpr && 
> !has-explicit-device-side-attr` ?
> We may eventually consider relaxing this to `can-be-const-evaluated` and 
> allow const vars with known values.
> 
will do. agree we should relax this for const var in the future


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102801/new/

https://reviews.llvm.org/D102801

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D102801: [CUDA][HIP] Fix device variables used by host

2021-05-20 Thread Artem Belevich via Phabricator via cfe-commits
tra added a comment.

In D102801#2771664 , @yaxunl wrote:

> In the updated patch I have a simpler solution which is easier to explain to 
> the users. Basically we classify variables by how they are emitted: device 
> side only, host side only, both sides as different entities (e.g. default 
> constexpr var), and both sides as unified entity (e.g. managed var). For 
> variables emitted on both sides as separate entities, we have limited 
> knowledge and we limit what we can do for them. I think users should 
> understand the compiler's limitation in such cases. And they can easily 
> workaround that by making the variable explicitly device variable.

This is really nice.

Let me test it internally and see if anything breaks.




Comment at: clang/include/clang/Sema/Sema.h:12066
 
+  enum CUDAVariableTarget {
+CVT_Device,  /// Device only

Wasn't there another kind, where the variable is emitted on the host with 
device-side shadow? I vaguely recall it had something to do with textures.



Comment at: clang/include/clang/Sema/Sema.h:12067
+  enum CUDAVariableTarget {
+CVT_Device,  /// Device only
+CVT_Host,/// Host only

I think we should mention the host-side shadows, too.



Comment at: clang/lib/Sema/SemaCUDA.cpp:148-149
+return CVT_Unified;
+  if (hasImplicitAttr(Var))
+return CVT_Both;
+  if (Var->hasAttr() || Var->hasAttr() ||

I'm still not a fan of relying on a implicit __constant__.
Can we change it to more direct `is-a-constexpr && 
!has-explicit-device-side-attr` ?
We may eventually consider relaxing this to `can-be-const-evaluated` and allow 
const vars with known values.



CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102801/new/

https://reviews.llvm.org/D102801

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D102801: [CUDA][HIP] Fix device variables used by host

2021-05-20 Thread Yaxun Liu via Phabricator via cfe-commits
yaxunl marked 2 inline comments as done.
yaxunl added a comment.

In D102801#2769619 , @tra wrote:

> Tentative LGTM as we need it to fix the regression soon.
>
> Summoning @rsmith for the 'big picture' opinion. 
> While the patch may fix this particular regression, I wonder if there's a 
> better way to deal with this. We're growing a bit too many nuances that would 
> be hard to explain and may cause more corner cases to appear.

In the updated patch I have a simpler solution which is easier to explain to 
the users. Basically we classify variables by how they are emitted: device side 
only, host side only, both sides as different entities (e.g. default constexpr 
var), and both sides as unified entity (e.g. managed var). For variables 
emitted on both sides as separate entities, we have limited knowledge and we 
limit what we can do for them. I think users should understand the compiler's 
limitation in such cases. And they can easily workaround that by making the 
variable explicitly device variable.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102801/new/

https://reviews.llvm.org/D102801

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D102801: [CUDA][HIP] Fix device variables used by host

2021-05-20 Thread Yaxun Liu via Phabricator via cfe-commits
yaxunl marked 2 inline comments as done.
yaxunl added a comment.

In D102801#2769936 , @tra wrote:

> This patch does not appear to fix the second regression introduced by the 
> D102237 .
>
> Trying to compile the following code triggers an assertion in CGExpr.cpp:
>
>   class a {
>   public:
> a(char *);
>   };
>   void b() {
> [](char *c) {
>   static a d(c);
>   d;
> };
>   }
>
> With assertions disabled it eventually leads to a different error: 
> `Module has a nontrivial global ctor, which NVPTX does not support.`
> https://godbolt.org/z/sYE1dKr1W

The root cause is similar to the last regression. Basically when a variable is 
emitted on both sides but as different entities, we should not treat it as a 
device variable on host side. I have updated the patch to fix both regressions.




Comment at: clang/lib/CodeGen/CodeGenModule.cpp:2386
+  };
+  if (!HasImplicitConstantAttr(V))
+DeferredDeclsToEmit.push_back(V);

tra wrote:
> IIUIC, The idea here is that we do not want to emit `constexpr int foo;` on 
> device, even if we happen to ODR-use it there.
> And the way we detect this is by checking for implicit `__constant__` we 
> happen to add to constexpr variables.
> 
> I think this may be relying on the implementation details too much. It also 
> makes compiler's behavior somewhat surprising -- we would potentially emit 
> other variables that do not get any device attributes attribute, but would 
> not emit the variables with implicit `__constant__`, which is a device 
> attribute.
> 
> I'm not sure if we have any good options here. This may be an acceptable 
> compromise, but I wonder if there's a better way to deal with this.
> 
> That said, this patch is OK to fix the regression we have now, but we may 
> need to revisit this.
> 
we need to differentiate `constexpr int a` and `__constant__ constexpr int a`, 
since the former is emitted on both sides, and the later is only emitted on 
device side. It seems the only way to differentiate them is to check whether 
the constant attribute is explicit or not.



Comment at: clang/test/CodeGenCUDA/host-used-device-var.cu:103-131
+// Check implicit constant variable ODR-used by host code is not emitted.
+// DEV-NEG-NOT: _ZN16TestConstexprVar1oE
+namespace TestConstexprVar {
+char o;
+class ou {
+public:
+  ou(char) { __builtin_strlen(); }

tra wrote:
> This definitely needs some comments. Otherwise this is nearly 
> incomprehensible and it's impossible to tell what's going on.
done


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102801/new/

https://reviews.llvm.org/D102801

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D102801: [CUDA][HIP] Fix device variables used by host

2021-05-20 Thread Yaxun Liu via Phabricator via cfe-commits
yaxunl updated this revision to Diff 346796.
yaxunl retitled this revision from "[CUDA][HIP] Fix implicit constant variable" 
to "[CUDA][HIP] Fix device variables used by host".
yaxunl edited the summary of this revision.
yaxunl added a comment.

Fix the other regression


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D102801/new/

https://reviews.llvm.org/D102801

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGDeclCXX.cpp
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/Sema/SemaCUDA.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/test/AST/ast-dump-constant-var.cu
  clang/test/CodeGenCUDA/host-used-device-var.cu
  clang/test/SemaCUDA/static-device-var.cu

Index: clang/test/SemaCUDA/static-device-var.cu
===
--- clang/test/SemaCUDA/static-device-var.cu
+++ clang/test/SemaCUDA/static-device-var.cu
@@ -1,16 +1,14 @@
 // REQUIRES: x86-registered-target
 // REQUIRES: amdgpu-registered-target
 
-// RUN: %clang_cc1 -triple nvptx -fcuda-is-device \
-// RUN:-emit-llvm -o - %s -fsyntax-only -verify=dev
+// RUN: %clang_cc1 -triple nvptx -fcuda-is-device -std=c++11 \
+// RUN:-emit-llvm -o - %s -fsyntax-only -verify=dev,com
 
-// RUN: %clang_cc1 -triple x86_64-gnu-linux \
-// RUN:-emit-llvm -o - %s -fsyntax-only -verify=host
+// RUN: %clang_cc1 -triple x86_64-gnu-linux -std=c++11 \
+// RUN:-emit-llvm -o - %s -fsyntax-only -verify=host,com
 
 // Checks allowed usage of file-scope and function-scope static variables.
 
-// host-no-diagnostics
-
 #include "Inputs/cuda.h"
 
 // Checks static variables are allowed in device functions.
@@ -42,6 +40,28 @@
   // dev-error@-1 {{reference to __host__ variable 'z' in __global__ function}}
 }
 
+// Check dynamic initialization of static device variable is not allowed.
+
+namespace TestStaticVarInLambda {
+class A {
+public:
+  A(char *);
+};
+class B {
+public:
+  __device__ B(char *);
+};
+void fun() {
+  (void) [](char *c) {
+static A var1(c);
+static __device__ B var2(c);
+// com-error@-1 {{dynamic initialization is not supported for __device__, __constant__, __shared__, and __managed__ variables}}
+(void) var1;
+(void) var2;
+  };
+}
+}
+
 int* getDeviceSymbol(int *x);
 
 void foo() {
Index: clang/test/CodeGenCUDA/host-used-device-var.cu
===
--- clang/test/CodeGenCUDA/host-used-device-var.cu
+++ clang/test/CodeGenCUDA/host-used-device-var.cu
@@ -66,30 +66,148 @@
 template 
 __device__ func_t p_add_func = add_func;
 
+// Check non-constant constexpr variables ODR-used by host code only is not emitted.
+// DEV-NEG-NOT: constexpr_var1a
+// DEV-NEG-NOT: constexpr_var1b
+constexpr int constexpr_var1a = 1;
+inline constexpr int constexpr_var1b = 1;
+
+// Check constant constexpr variables ODR-used by host code only.
+// Non-inline constexpr variable has internal linkage, therefore it is not accessible by host and not kept.
+// Inline constexpr variable has linkonce_ord linkage, therefore it can be accessed by host and kept.
+// DEV-NEG-NOT: constexpr_var2a
+// DEV-DAG: @constexpr_var2b = linkonce_odr addrspace(4) externally_initialized constant i32 2
+__constant__ constexpr int constexpr_var2a = 2;
+inline __constant__ constexpr int constexpr_var2b = 2;
+
 void use(func_t p);
-void use(int *p);
+__host__ __device__ void use(const int *p);
 
+// Check static device variable in host function.
+// DEV-DAG:  @_ZZ4fun1vE11static_var1 = dso_local addrspace(1) externally_initialized global i32 3
 void fun1() {
+  static __device__ int static_var1 = 3;
   use();
   use();
   use();
   use(_var);
   use(_var);
   use(p_add_func);
+  use(_var1a);
+  use(_var1b);
+  use(_var2a);
+  use(_var2b);
+  use(_var1);
+}
+
+// Check static variable in host device function.
+// DEV-DAG:  @_ZZ4fun2vE11static_var2 = internal addrspace(1) global i32 4
+// DEV-DAG:  @_ZZ4fun2vE11static_var3 = dso_local addrspace(1) global i32 4
+__host__ __device__ void fun2() {
+  static int static_var2 = 4;
+  static __device__ int static_var3 = 4;
+  use(_var2);
+  use(_var3);
 }
 
 __global__ void kern1(int **x) {
   *x = 
+  fun2();
+}
+
+// Check static variables of lambda functions.
+
+// Lambda functions are implicit host device functions.
+// Default static variables in lambda functions should be treated
+// as host variables on host side, therefore should not be forced
+// to be emitted on device.
+
+// DEV-DAG: @_ZZZN21TestStaticVarInLambda3funEvENKUlPcE_clES0_E4var2 = dso_local addrspace(1) externally_initialized global i32 5
+// DEV-NEG-NOT: @_ZZZN21TestStaticVarInLambda3funEvENKUlPcE_clES0_E4var1
+namespace TestStaticVarInLambda {
+class A {
+public:
+  A(char *);
+};
+void fun() {
+  (void) [](char *c) {
+static A var1(c);
+static __device__ int var2 = 5;
+(void) var1;
+(void) var2;
+  };
+}
+}
+
+// Check implicit constant variable ODR-used by host code is not emitted.
+
+// AST