yaxunl created this revision.
Herald added a subscriber: nhaehnle.

https://reviews.llvm.org/D32977

Files:
  include/clang/AST/Decl.h
  lib/Sema/SemaDecl.cpp
  test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
  test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
  test/CodeGenOpenCL/constant-addr-space-globals.cl
  test/SemaOpenCL/storageclass.cl

Index: test/SemaOpenCL/storageclass.cl
===================================================================
--- test/SemaOpenCL/storageclass.cl
+++ test/SemaOpenCL/storageclass.cl
@@ -5,7 +5,7 @@
 int G3 = 0;        // expected-error{{program scope variable must reside in constant address space}}
 global int G4 = 0; // expected-error{{program scope variable must reside in constant address space}}
 
-void kernel foo() {
+void kernel foo(int x) {
   // static is not allowed at local scope before CL2.0
   static int S1 = 5;          // expected-error{{variables in function scope cannot be declared static}}
   static constant int S2 = 5; // expected-error{{variables in function scope cannot be declared static}}
@@ -15,6 +15,12 @@
 
   auto int L3 = 7; // expected-error{{OpenCL version 1.2 does not support the 'auto' storage class specifier}}
   global int L4;   // expected-error{{function scope variable cannot be declared in global address space}}
+
+  constant int L5 = x; // expected-error {{initializer element is not a compile-time constant}}
+  global int *constant L6 = &G4;
+  private int *constant L7 = &x; // expected-error {{initializer element is not a compile-time constant}}
+  constant int *constant L8 = &L1;
+  local int *constant L9 = &L2; // expected-error {{initializer element is not a compile-time constant}}
 }
 
 static void kernel bar() { // expected-error{{kernel functions cannot be declared static}}
@@ -29,4 +35,7 @@
   }
   global int L3; // expected-error{{function scope variable cannot be declared in global address space}}
   extern constant float L4;
+  extern local float L5; // expected-error{{extern variable must reside in constant address space}}
+  static int L6 = 0;     // expected-error{{variables in function scope cannot be declared static}}
+  static int L7;         // expected-error{{variables in function scope cannot be declared static}}
 }
Index: test/CodeGenOpenCL/constant-addr-space-globals.cl
===================================================================
--- test/CodeGenOpenCL/constant-addr-space-globals.cl
+++ test/CodeGenOpenCL/constant-addr-space-globals.cl
@@ -11,17 +11,21 @@
 // but create a copy in the original address space (unless a variable itself is
 // in the constant address space).
 
-void foo(constant const int *p1, const int *p2, const int *p3);
+void foo(constant int* p, constant const int *p1, const int *p2, const int *p3);
 // CHECK: @k.arr1 = internal addrspace(2) constant [3 x i32] [i32 1, i32 2, i32 3]
 // CHECK: @k.arr2 = private unnamed_addr addrspace(2) constant [3 x i32] [i32 4, i32 5, i32 6]
 // CHECK: @k.arr3 = private unnamed_addr addrspace(2) constant [3 x i32] [i32 7, i32 8, i32 9]
+// CHECK: @k.var1 = internal addrspace(2) constant i32 1
 kernel void k(void) {
   // CHECK-NOT: %arr1 = alloca [3 x i32]
   constant const int arr1[] = {1, 2, 3};
   // CHECK: %arr2 = alloca [3 x i32]
   const int arr2[] = {4, 5, 6};
   // CHECK: %arr3 = alloca [3 x i32]
   int arr3[] = {7, 8, 9};
 
-  foo(arr1, arr2, arr3);
+  constant int var1 = 1;
+  
+  // CHECK: call spir_func void @foo(i32 addrspace(2)* @k.var1, i32 addrspace(2)* getelementptr inbounds ([3 x i32], [3 x i32] addrspace(2)* @k.arr1, i32 0, i32 0)
+  foo(&var1, arr1, arr2, arr3);
 }
Index: test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
===================================================================
--- test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
+++ test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
@@ -80,21 +80,21 @@
   // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(4)** {{.*}}, metadata ![[FUNCVAR4]], metadata ![[PRIVATE]]), !dbg !{{[0-9]+}}
   int *FuncVar4 = Tmp1;
 
-  // CHECK-DAG: ![[FUNCVAR5:[0-9]+]] = !DILocalVariable(name: "FuncVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(1)** {{.*}}, metadata ![[FUNCVAR5]], metadata ![[NONE:[0-9]+]]), !dbg !{{[0-9]+}}
-  global int *constant FuncVar5 = KernelArg0;
-  // CHECK-DAG: ![[FUNCVAR6:[0-9]+]] = !DILocalVariable(name: "FuncVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(2)** {{.*}}, metadata ![[FUNCVAR6]], metadata ![[NONE]]), !dbg !{{[0-9]+}}
-  constant int *constant FuncVar6 = KernelArg1;
-  // CHECK-DAG: ![[FUNCVAR7:[0-9]+]] = !DILocalVariable(name: "FuncVar7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(3)** {{.*}}, metadata ![[FUNCVAR7]], metadata ![[NONE]]), !dbg !{{[0-9]+}}
-  local int *constant FuncVar7 = KernelArg2;
-  // CHECK-DAG: ![[FUNCVAR8:[0-9]+]] = !DILocalVariable(name: "FuncVar8", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: call void @llvm.dbg.declare(metadata i32** {{.*}}, metadata ![[FUNCVAR8]], metadata ![[NONE]]), !dbg !{{[0-9]+}}
-  private int *constant FuncVar8 = Tmp0;
-  // CHECK-DAG: ![[FUNCVAR9:[0-9]+]] = !DILocalVariable(name: "FuncVar9", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: call void @llvm.dbg.declare(metadata i32 addrspace(4)** {{.*}}, metadata ![[FUNCVAR9]], metadata ![[NONE]]), !dbg !{{[0-9]+}}
-  int *constant FuncVar9 = Tmp1;
+  // CHECK-DAG: ![[FUNCVAR5:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR5]])
+  global int *constant FuncVar5 = 0;
+  // CHECK-DAG: ![[FUNCVAR6:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR6]])
+  constant int *constant FuncVar6 = 0;
+  // CHECK-DAG: ![[FUNCVAR7:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR7]])
+  local int *constant FuncVar7 = 0;
+  // CHECK-DAG: ![[FUNCVAR8:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar8", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR8]])
+  private int *constant FuncVar8 = 0;
+  // CHECK-DAG: ![[FUNCVAR9:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar9", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
+  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR9]])
+  int *constant FuncVar9 = 0;
 
   // CHECK-DAG: ![[FUNCVAR10:[0-9]+]] = distinct !DIGlobalVariable(name: "FuncVar10", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}}, isLocal: true, isDefinition: true)
   // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR10]], expr: ![[LOCAL]])
Index: test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
===================================================================
--- test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
+++ test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
@@ -58,16 +58,16 @@
   // CHECK-DAG: !DILocalVariable(name: "FuncVar4", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
   int *FuncVar4 = Tmp1;
 
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
-  global int *constant FuncVar5 = KernelArg0;
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
-  constant int *constant FuncVar6 = KernelArg1;
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]])
-  local int *constant FuncVar7 = KernelArg2;
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar8", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]])
-  private int *constant FuncVar8 = Tmp0;
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar9", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
-  int *constant FuncVar9 = Tmp1;
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+  global int *constant FuncVar5 = 0;
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+  constant int *constant FuncVar6 = 0;
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]], isLocal: true, isDefinition: true)
+  local int *constant FuncVar7 = 0;
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar8", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]], isLocal: true, isDefinition: true)
+  private int *constant FuncVar8 = 0;
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar9", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+  int *constant FuncVar9 = 0;
 
   // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar10", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
   global int *local FuncVar10; FuncVar10 = KernelArg0;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -7091,7 +7091,7 @@
   // scope.
   if (getLangOpts().OpenCLVersion == 120 &&
       !getOpenCLOptions().isEnabled("cl_clang_storage_class_specifiers") &&
-      NewVD->isStaticLocal()) {
+      NewVD->isStaticLocal() && NewVD->getStorageClass() == SC_Static) {
     Diag(NewVD->getLocation(), diag::err_static_function_scope);
     NewVD->setInvalidDecl();
     return;
@@ -7124,7 +7124,8 @@
     // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static
     // variables inside a function can also be declared in the global
     // address space.
-    if (NewVD->isFileVarDecl() || NewVD->isStaticLocal() ||
+    if (NewVD->isFileVarDecl() || (NewVD->isStaticLocal() &&
+        NewVD->getType().getAddressSpace() != LangAS::opencl_constant) ||
         NewVD->hasExternalStorage()) {
       if (!T->isSamplerT() &&
           !(T.getAddressSpace() == LangAS::opencl_constant ||
@@ -10278,7 +10279,11 @@
     // C++ does not have this restriction.
     if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) {
       const Expr *Culprit;
-      if (VDecl->getStorageClass() == SC_Static)
+      if (VDecl->getStorageClass() == SC_Static ||
+          // OpenCL v1.2 s6.5.3: Variables in constant address space are
+          // required to be initialized and the values used to initialize
+          // these variables must be a compile time constant.
+          VDecl->getType().getAddressSpace() == LangAS::opencl_constant)
         CheckForConstantInitializer(Init, DclT);
       // C89 is stricter than C99 for non-static aggregate types.
       // C89 6.5.7p3: All the expressions [...] in an initializer list
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -966,9 +966,16 @@
   /// hasLocalStorage - Returns true if a variable with function scope
   ///  is a non-static local variable.
   bool hasLocalStorage() const {
-    if (getStorageClass() == SC_None)
+    if (getStorageClass() == SC_None) {
+      // OpenCL v1.2 s6.5.3: The __constant or constant address space name is
+      // used to describe variables allocated in global memory and which are
+      // accessed inside a kernel(s) as read-only variables. As such, variables
+      // in constant address space cannot have local storage.
+      if (getType().getAddressSpace() == LangAS::opencl_constant)
+        return false;
       // Second check is for C++11 [dcl.stc]p4.
       return !isFileVarDecl() && getTSCSpec() == TSCS_unspecified;
+    }
 
     // Global Named Register (GNU extension)
     if (getStorageClass() == SC_Register && !isLocalVarDeclOrParm())
@@ -985,7 +992,15 @@
   bool isStaticLocal() const {
     return (getStorageClass() == SC_Static ||
             // C++11 [dcl.stc]p4
-            (getStorageClass() == SC_None && getTSCSpec() == TSCS_thread_local))
+            (getStorageClass() == SC_None &&
+             getTSCSpec() == TSCS_thread_local) ||
+
+            // OpenCL v1.2 s6.5.3: The __constant or constant address space
+            // name is used to describe variables allocated in global memory
+            // and which are accessed inside a kernel(s) as read-only variables.
+            // As such, function-scope variables in constant address space
+            // should have static storage instead of local storage.
+            getType().getAddressSpace() == LangAS::opencl_constant)
       && !isFileVarDecl();
   }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to