From 6e34f0e735bc955840f3b90b53a7be1b64186f90 Mon Sep 17 00:00:00 2001 From: Yaxun Liu Date: Mon, 15 May 2017 14:47:47 +0000 Subject: [PATCH] [OpenCL] Emit function-scope variable in constant address space as static variable Differential Revision: https://reviews.llvm.org/D32977 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303072 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 9 ++++- lib/CodeGen/CGDecl.cpp | 13 ++++--- lib/Sema/SemaDecl.cpp | 35 +++++++++++++------ ...amdgpu-debug-info-pointer-address-space.cl | 20 +++++------ .../amdgpu-debug-info-variable-expression.cl | 30 ++++++++-------- .../constant-addr-space-globals.cl | 8 +++-- test/SemaOpenCL/storageclass.cl | 11 +++++- 7 files changed, 81 insertions(+), 45 deletions(-) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index bba40e56b0..facef8e55f 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -966,9 +966,16 @@ public: /// 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()) diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 10a0b46d90..0fa8eeb1c3 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -152,7 +152,14 @@ void CodeGenFunction::EmitDecl(const Decl &D) { /// EmitVarDecl - This method handles emission of any variable declaration /// inside a function, including static vars etc. void CodeGenFunction::EmitVarDecl(const VarDecl &D) { - if (D.isStaticLocal()) { + if (D.hasExternalStorage()) + // Don't emit it now, allow it to be emitted lazily on its first use. + return; + + // Some function-scope variable does not have static storage but still + // needs to be emitted like a static variable, e.g. a function-scope + // variable in constant address space in OpenCL. + if (D.getStorageDuration() != SD_Automatic) { llvm::GlobalValue::LinkageTypes Linkage = CGM.getLLVMLinkageVarDefinition(&D, /*isConstant=*/false); @@ -163,10 +170,6 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) { return EmitStaticVarDecl(D, Linkage); } - if (D.hasExternalStorage()) - // Don't emit it now, allow it to be emitted lazily on its first use. - return; - if (D.getType().getAddressSpace() == LangAS::opencl_local) return CGM.getOpenCLRuntime().EmitWorkGroupLocalVarDecl(*this, D); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index fb5f56e052..2e069a9def 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -10394,23 +10394,36 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { VDecl->setInit(Init); if (VDecl->isLocalVarDecl()) { + // Don't check the initializer if the declaration is malformed. + if (VDecl->isInvalidDecl()) { + // do nothing + + // OpenCL v1.2 s6.5.3: __constant locals must be constant-initialized. + // This is true even in OpenCL C++. + } else if (VDecl->getType().getAddressSpace() == LangAS::opencl_constant) { + CheckForConstantInitializer(Init, DclT); + + // Otherwise, C++ does not restrict the initializer. + } else if (getLangOpts().CPlusPlus) { + // do nothing + // C99 6.7.8p4: All the expressions in an initializer for an object that has // static storage duration shall be constant expressions or string literals. - // C++ does not have this restriction. - if (!getLangOpts().CPlusPlus && !VDecl->isInvalidDecl()) { + } else if (VDecl->getStorageClass() == SC_Static) { + CheckForConstantInitializer(Init, DclT); + + // C89 is stricter than C99 for aggregate initializers. + // C89 6.5.7p3: All the expressions [...] in an initializer list + // for an object that has aggregate or union type shall be + // constant expressions. + } else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() && + isa(Init)) { const Expr *Culprit; - if (VDecl->getStorageClass() == SC_Static) - CheckForConstantInitializer(Init, DclT); - // C89 is stricter than C99 for non-static aggregate types. - // C89 6.5.7p3: All the expressions [...] in an initializer list - // for an object that has aggregate or union type shall be - // constant expressions. - else if (!getLangOpts().C99 && VDecl->getType()->isAggregateType() && - isa(Init) && - !Init->isConstantInitializer(Context, false, &Culprit)) + if (!Init->isConstantInitializer(Context, false, &Culprit)) { Diag(Culprit->getExprLoc(), diag::ext_aggregate_init_not_constant) << Culprit->getSourceRange(); + } } } else if (VDecl->isStaticDataMember() && !VDecl->isInline() && VDecl->getLexicalDeclContext()->isRecord()) { diff --git a/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl b/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl index c0b30095a6..7baee5eee3 100644 --- a/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl +++ b/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl @@ -58,16 +58,16 @@ kernel void kernel1( // 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; diff --git a/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl b/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl index a962d3c75a..c0a4c21ce7 100644 --- a/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl +++ b/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl @@ -80,21 +80,21 @@ kernel void kernel1( // 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]]) diff --git a/test/CodeGenOpenCL/constant-addr-space-globals.cl b/test/CodeGenOpenCL/constant-addr-space-globals.cl index 4f0d1ea23e..7bb970527c 100644 --- a/test/CodeGenOpenCL/constant-addr-space-globals.cl +++ b/test/CodeGenOpenCL/constant-addr-space-globals.cl @@ -11,10 +11,11 @@ kernel void test(global float *out) { // 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}; @@ -23,5 +24,8 @@ kernel void k(void) { // 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); } diff --git a/test/SemaOpenCL/storageclass.cl b/test/SemaOpenCL/storageclass.cl index a93f8244dc..f457cfd1d3 100644 --- a/test/SemaOpenCL/storageclass.cl +++ b/test/SemaOpenCL/storageclass.cl @@ -5,7 +5,7 @@ constant int G2 = 0; 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 @@ void kernel foo() { 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 @@ void f() { } 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}} } -- 2.40.0