diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f28918fb0963..e7d10d707bb3 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1564,8 +1564,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // Apply any type attributes from the decl spec. This may cause the // list of type attributes to be temporarily saved while the type // attributes are pushed around. - if (AttributeList *attrs = DS.getAttributes().getList()) - processTypeAttrs(state, Result, TAL_DeclSpec, attrs); + processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes().getList()); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -2596,8 +2595,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // Constructors and destructors don't have return types. Use // "void" instead. T = SemaRef.Context.VoidTy; - if (AttributeList *attrs = D.getDeclSpec().getAttributes().getList()) - processTypeAttrs(state, T, TAL_DeclSpec, attrs); + processTypeAttrs(state, T, TAL_DeclSpec, + D.getDeclSpec().getAttributes().getList()); break; case UnqualifiedId::IK_ConversionFunctionId: @@ -4112,8 +4111,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } // See if there are any attributes on this declarator chunk. - if (AttributeList *attrs = const_cast(DeclType.getAttrs())) - processTypeAttrs(state, T, TAL_DeclChunk, attrs); + processTypeAttrs(state, T, TAL_DeclChunk, + const_cast(DeclType.getAttrs())); } assert(!T.isNull() && "T must not be null after this point"); @@ -4206,8 +4205,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } // Apply any undistributed attributes from the declarator. - if (AttributeList *attrs = D.getAttributes()) - processTypeAttrs(state, T, TAL_DeclName, attrs); + processTypeAttrs(state, T, TAL_DeclName, D.getAttributes()); // Diagnose any ignored type attributes. state.diagnoseIgnoredTypeAttrs(T); @@ -6176,10 +6174,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // type, but others can be present in the type specifiers even though they // apply to the decl. Here we apply type attributes and ignore the rest. - AttributeList *next; - do { + bool hasOpenCLAddressSpace = false; + while (attrs) { AttributeList &attr = *attrs; - next = attr.getNext(); + attrs = attr.getNext(); // reset to the next here due to early loop continue + // stmts // Skip attributes that were marked to be invalid. if (attr.isInvalid()) @@ -6238,6 +6237,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case AttributeList::AT_AddressSpace: HandleAddressSpaceTypeAttribute(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); + hasOpenCLAddressSpace = true; break; OBJC_POINTER_TYPE_ATTRS_CASELIST: if (!handleObjCPointerTypeAttr(state, attr, type)) @@ -6332,7 +6332,39 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, distributeFunctionTypeAttr(state, attr, type); break; } - } while ((attrs = next)); + } + + // If address space is not set, OpenCL 2.0 defines non private default + // address spaces for some cases: + // OpenCL 2.0, section 6.5: + // The address space for a variable at program scope or a static variable + // inside a function can either be __global or __constant, but defaults to + // __global if not specified. + // (...) + // Pointers that are declared without pointing to a named address space point + // to the generic address space. + if (state.getSema().getLangOpts().OpenCLVersion >= 200 && + !hasOpenCLAddressSpace && type.getAddressSpace() == 0 && + (TAL == TAL_DeclSpec || TAL == TAL_DeclChunk)) { + Declarator &D = state.getDeclarator(); + if (state.getCurrentChunkIndex() > 0 && + D.getTypeObject(state.getCurrentChunkIndex() - 1).Kind == + DeclaratorChunk::Pointer) { + type = state.getSema().Context.getAddrSpaceQualType( + type, LangAS::opencl_generic); + } else if (state.getCurrentChunkIndex() == 0 && + D.getContext() == Declarator::FileContext && + !D.isFunctionDeclarator() && !D.isFunctionDefinition() && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + !type->isSamplerT()) + type = state.getSema().Context.getAddrSpaceQualType( + type, LangAS::opencl_global); + else if (state.getCurrentChunkIndex() == 0 && + D.getContext() == Declarator::BlockContext && + D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) + type = state.getSema().Context.getAddrSpaceQualType( + type, LangAS::opencl_global); + } } /// \brief Ensure that the type of the given expression is complete. diff --git a/clang/test/CodeGenOpenCL/address-spaces.cl b/clang/test/CodeGenOpenCL/address-spaces.cl index e030c77d3e01..68fa02dadb26 100644 --- a/clang/test/CodeGenOpenCL/address-spaces.cl +++ b/clang/test/CodeGenOpenCL/address-spaces.cl @@ -1,27 +1,47 @@ -// RUN: %clang_cc1 %s -ffake-address-space-map -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -O0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -O0 -DCL20 -cl-std=CL2.0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefix=CL20 -void f__p(__private int *arg) { } -// CHECK: i32* nocapture %arg +// CHECK: i32* %arg +void f__p(__private int *arg) {} -void f__g(__global int *arg) { } -// CHECK: i32 addrspace(1)* nocapture %arg +// CHECK: i32 addrspace(1)* %arg +void f__g(__global int *arg) {} -void f__l(__local int *arg) { } -// CHECK: i32 addrspace(2)* nocapture %arg +// CHECK: i32 addrspace(2)* %arg +void f__l(__local int *arg) {} -void f__c(__constant int *arg) { } -// CHECK: i32 addrspace(3)* nocapture %arg +// CHECK: i32 addrspace(3)* %arg +void f__c(__constant int *arg) {} +// CHECK: i32* %arg +void fp(private int *arg) {} -void fp(private int *arg) { } -// CHECK: i32* nocapture %arg +// CHECK: i32 addrspace(1)* %arg +void fg(global int *arg) {} -void fg(global int *arg) { } -// CHECK: i32 addrspace(1)* nocapture %arg +// CHECK: i32 addrspace(2)* %arg +void fl(local int *arg) {} -void fl(local int *arg) { } -// CHECK: i32 addrspace(2)* nocapture %arg +// CHECK: i32 addrspace(3)* %arg +void fc(constant int *arg) {} -void fc(constant int *arg) { } -// CHECK: i32 addrspace(3)* nocapture %arg +#ifdef CL20 +int i; +// CL20-DAG: @i = common addrspace(1) global i32 0 +int *ptr; +// CL20-DAG: @ptr = common addrspace(1) global i32 addrspace(4)* null +#endif +// CHECK: i32* %arg +// CL20-DAG: i32 addrspace(4)* %arg +void f(int *arg) { + + int i; +// CHECK: %i = alloca i32, +// CL20-DAG: %i = alloca i32, + +#ifdef CL20 + static int ii; +// CL20-DAG: @f.ii = internal addrspace(1) global i32 0 +#endif +} diff --git a/clang/test/SemaOpenCL/storageclass-cl20.cl b/clang/test/SemaOpenCL/storageclass-cl20.cl index f379d59b7fd7..c8e7faa208f1 100644 --- a/clang/test/SemaOpenCL/storageclass-cl20.cl +++ b/clang/test/SemaOpenCL/storageclass-cl20.cl @@ -1,12 +1,12 @@ // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -DCL20 -cl-std=CL2.0 static constant int G1 = 0; -int G2 = 0;// expected-error{{program scope variable must reside in global or constant address space}} +int G2 = 0; global int G3 = 0; local int G4 = 0;// expected-error{{program scope variable must reside in global or constant address space}} void kernel foo() { - static int S1 = 5;// expected-error{{program scope variable must reside in global or constant address space}} + static int S1 = 5; static global int S2 = 5; static private int S3 = 5;// expected-error{{program scope variable must reside in global or constant address space}}