[OpenCL] Generic address space has been added in OpenCL v2.0.

To support it in the frontend, the following has been added:  
- generic address space type attribute;
- documentation for the OpenCL address space attributes;
- parsing of __generic(generic) keyword;
- test code for the parser and diagnostics.

llvm-svn: 222831
This commit is contained in:
Anastasia Stulova 2014-11-26 14:10:06 +00:00
parent c53ead03ce
commit 2c8dcfbae6
11 changed files with 143 additions and 11 deletions

View File

@ -30,6 +30,7 @@ enum ID {
opencl_global = Offset,
opencl_local,
opencl_constant,
opencl_generic,
cuda_device,
cuda_constant,

View File

@ -624,22 +624,27 @@ def OpenCLImageAccess : Attr {
def OpenCLPrivateAddressSpace : TypeAttr {
let Spellings = [Keyword<"__private">, Keyword<"private">];
let Documentation = [Undocumented];
let Documentation = [OpenCLAddressSpacePrivateDocs];
}
def OpenCLGlobalAddressSpace : TypeAttr {
let Spellings = [Keyword<"__global">, Keyword<"global">];
let Documentation = [Undocumented];
let Documentation = [OpenCLAddressSpaceGlobalDocs];
}
def OpenCLLocalAddressSpace : TypeAttr {
let Spellings = [Keyword<"__local">, Keyword<"local">];
let Documentation = [Undocumented];
let Documentation = [OpenCLAddressSpaceLocalDocs];
}
def OpenCLConstantAddressSpace : TypeAttr {
let Spellings = [Keyword<"__constant">, Keyword<"constant">];
let Documentation = [Undocumented];
let Documentation = [OpenCLAddressSpaceConstantDocs];
}
def OpenCLGenericAddressSpace : TypeAttr {
let Spellings = [Keyword<"__generic">, Keyword<"generic">];
let Documentation = [OpenCLAddressSpaceGenericDocs];
}
def Deprecated : InheritableAttr {

View File

@ -1265,3 +1265,88 @@ for further details including limitations of the unroll hints.
}];
}
def DocOpenCLAddressSpaces : DocumentationCategory<"OpenCL Address Spaces"> {
let Content = [{
The address space qualifier may be used to specify the region of memory that is
used to allocate the object. OpenCL supports the following address spaces:
__generic(generic), __global(global), __local(local), __private(private),
__constant(constant).
.. code-block:: opencl
__constant int c = ...;
__generic int* foo(global int* g) {
__local int* l;
private int p;
...
return l;
}
More details can be found in the OpenCL C language Spec v2.0, Section 6.5.
}];
}
def OpenCLAddressSpaceGenericDocs : Documentation {
let Category = DocOpenCLAddressSpaces;
let Heading = "__generic(generic)";
let Content = [{
The generic address space attribute is only available with OpenCL v2.0 and later.
It can be used with pointer types. Variables in global and local scope and
function parameters in non-kernel functions can have the generic address space
type attribute. It is intended to be a placeholder for any other address space
except for '__constant' in OpenCL code which can be used with multiple address
spaces.
}];
}
def OpenCLAddressSpaceConstantDocs : Documentation {
let Category = DocOpenCLAddressSpaces;
let Heading = "__constant(constant)";
let Content = [{
The constant address space attribute signals that an object is located in
a constant (non-modifiable) memory region. It is available to all work items.
Any type can be annotated with the constant address space attribute. Objects
with the constant address space qualifier can be declared in any scope and must
have an initializer.
}];
}
def OpenCLAddressSpaceGlobalDocs : Documentation {
let Category = DocOpenCLAddressSpaces;
let Heading = "__global(global)";
let Content = [{
The global address space attribute specifies that an object is allocated in
global memory, which is accessible by all work items. The content stored in this
memory area persists between kernel executions. Pointer types to the global
address space are allowed as function parameters or local variables. Starting
with OpenCL v2.0, the global address space can be used with global (program
scope) variables and static local variable as well.
}];
}
def OpenCLAddressSpaceLocalDocs : Documentation {
let Category = DocOpenCLAddressSpaces;
let Heading = "__local(local)";
let Content = [{
The local address space specifies that an object is allocated in the local (work
group) memory area, which is accessible to all work items in the same work
group. The content stored in this memory region is not accessible after
the kernel execution ends. In a kernel function scope, any variable can be in
the local address space. In other scopes, only pointer types to the local address
space are allowed. Local address space variables cannot have an initializer.
}];
}
def OpenCLAddressSpacePrivateDocs : Documentation {
let Category = DocOpenCLAddressSpaces;
let Heading = "__private(private)";
let Content = [{
The private address space specifies that an object is allocated in the private
(work item) memory. Other work items cannot access the same memory area and its
content is destroyed after work item execution ends. Local variables can be
declared in the private address space. Function arguments are always in the
private address space. Kernel function arguments of a pointer or an array type
cannot point to the private address space.
}];
}

View File

@ -934,8 +934,8 @@ def err_pragma_optimize_extra_argument : Error<
"unexpected extra argument '%0' to '#pragma clang optimize'">;
// OpenCL Section 6.8.g
def err_not_opencl_storage_class_specifier : Error<
"OpenCL does not support the '%0' storage class specifier">;
def err_opencl_unknown_type_specifier : Error<
"OpenCL does not support the '%0' %select{type qualifier|storage class specifier}1">;
// OpenCL EXTENSION pragma (OpenCL 1.1 [9.1])
def warn_pragma_expected_colon : Warning<

View File

@ -471,10 +471,12 @@ KEYWORD(__global , KEYOPENCL)
KEYWORD(__local , KEYOPENCL)
KEYWORD(__constant , KEYOPENCL)
KEYWORD(__private , KEYOPENCL)
KEYWORD(__generic , KEYOPENCL)
ALIAS("global", __global , KEYOPENCL)
ALIAS("local", __local , KEYOPENCL)
ALIAS("constant", __constant , KEYOPENCL)
ALIAS("private", __private , KEYOPENCL)
ALIAS("generic", __generic , KEYOPENCL)
// OpenCL function qualifiers
KEYWORD(__kernel , KEYOPENCL)
ALIAS("kernel", __kernel , KEYOPENCL)

View File

@ -699,9 +699,10 @@ static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T,
1, // opencl_global
2, // opencl_local
3, // opencl_constant
4, // cuda_device
5, // cuda_constant
6 // cuda_shared
4, // opencl_generic
5, // cuda_device
6, // cuda_constant
7 // cuda_shared
};
return &FakeAddrSpaceMap;
} else {

View File

@ -1490,6 +1490,9 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
case LangAS::opencl_constant:
OS << "__constant";
break;
case LangAS::opencl_generic:
OS << "__generic";
break;
default:
OS << "__attribute__((address_space(";
OS << addrspace;

View File

@ -1368,6 +1368,8 @@ namespace {
1, // opencl_global
3, // opencl_local
4, // opencl_constant
// FIXME: generic has to be added to the target
0, // opencl_generic
1, // cuda_device
4, // cuda_constant
3, // cuda_shared
@ -1487,6 +1489,8 @@ static const unsigned R600AddrSpaceMap[] = {
1, // opencl_global
3, // opencl_local
2, // opencl_constant
// FIXME: generic has to be added to the target
0, // opencl_generic
1, // cuda_device
2, // cuda_constant
3 // cuda_shared
@ -5381,6 +5385,8 @@ namespace {
3, // opencl_global
4, // opencl_local
5, // opencl_constant
// FIXME: generic has to be added to the target
0, // opencl_generic
0, // cuda_device
0, // cuda_constant
0 // cuda_shared
@ -6104,6 +6110,7 @@ namespace {
1, // opencl_global
3, // opencl_local
2, // opencl_constant
4, // opencl_generic
0, // cuda_device
0, // cuda_constant
0 // cuda_shared

View File

@ -2520,6 +2520,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
const PrintingPolicy &Policy = Actions.getASTContext().getPrintingPolicy();
while (1) {
bool isInvalid = false;
bool isStorageClass = false;
const char *PrevSpec = nullptr;
unsigned DiagID = 0;
@ -2943,22 +2944,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw_typedef:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_typedef, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw_extern:
if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "extern";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_extern, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw___private_extern__:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_private_extern,
Loc, PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw_static:
if (DS.getThreadStorageClassSpec() == DeclSpec::TSCS___thread)
Diag(Tok, diag::ext_thread_before) << "static";
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_static, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw_auto:
if (getLangOpts().CPlusPlus11) {
@ -2974,18 +2979,22 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
} else
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw_register:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw_mutable:
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_mutable, Loc,
PrevSpec, DiagID, Policy);
isStorageClass = true;
break;
case tok::kw___thread:
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS___thread, Loc,
PrevSpec, DiagID);
isStorageClass = true;
break;
case tok::kw_thread_local:
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc,
@ -2994,6 +3003,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw__Thread_local:
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local,
Loc, PrevSpec, DiagID);
isStorageClass = true;
break;
// function-specifier
@ -3232,6 +3242,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
break;
// OpenCL qualifiers:
case tok::kw___generic:
// generic address space is introduced only in OpenCL v2.0
// see OpenCL C Spec v2.0 s6.5.5
if (Actions.getLangOpts().OpenCLVersion < 200) {
DiagID = diag::err_opencl_unknown_type_specifier;
PrevSpec = Tok.getIdentifierInfo()->getNameStart();
isInvalid = true;
break;
};
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@ -3266,6 +3285,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (DiagID == diag::ext_duplicate_declspec)
Diag(Tok, DiagID)
<< PrevSpec << FixItHint::CreateRemoval(Tok.getLocation());
else if (DiagID == diag::err_opencl_unknown_type_specifier)
Diag(Tok, DiagID) << PrevSpec << isStorageClass;
else
Diag(Tok, DiagID) << PrevSpec;
}
@ -3982,6 +4003,7 @@ bool Parser::isTypeQualifier() const {
case tok::kw___local:
case tok::kw___global:
case tok::kw___constant:
case tok::kw___generic:
case tok::kw___read_only:
case tok::kw___read_write:
case tok::kw___write_only:
@ -4131,6 +4153,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw___local:
case tok::kw___global:
case tok::kw___constant:
case tok::kw___generic:
case tok::kw___read_only:
case tok::kw___read_write:
case tok::kw___write_only:
@ -4303,6 +4326,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw___local:
case tok::kw___global:
case tok::kw___constant:
case tok::kw___generic:
case tok::kw___read_only:
case tok::kw___read_write:
case tok::kw___write_only:
@ -4491,6 +4515,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, unsigned AttrReqs,
case tok::kw___global:
case tok::kw___local:
case tok::kw___constant:
case tok::kw___generic:
case tok::kw___read_only:
case tok::kw___write_only:
case tok::kw___read_write:

View File

@ -508,14 +508,14 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc,
case SCS_private_extern:
case SCS_static:
if (S.getLangOpts().OpenCLVersion < 120) {
DiagID = diag::err_not_opencl_storage_class_specifier;
DiagID = diag::err_opencl_unknown_type_specifier;
PrevSpec = getSpecifierName(SC);
return true;
}
break;
case SCS_auto:
case SCS_register:
DiagID = diag::err_not_opencl_storage_class_specifier;
DiagID = diag::err_opencl_unknown_type_specifier;
PrevSpec = getSpecifierName(SC);
return true;
default:

View File

@ -3981,6 +3981,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
ASIdx = LangAS::opencl_local; break;
case AttributeList::AT_OpenCLConstantAddressSpace:
ASIdx = LangAS::opencl_constant; break;
case AttributeList::AT_OpenCLGenericAddressSpace:
ASIdx = LangAS::opencl_generic; break;
default:
assert(Attr.getKind() == AttributeList::AT_OpenCLPrivateAddressSpace);
ASIdx = 0; break;
@ -4892,6 +4894,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case AttributeList::AT_OpenCLGlobalAddressSpace:
case AttributeList::AT_OpenCLLocalAddressSpace:
case AttributeList::AT_OpenCLConstantAddressSpace:
case AttributeList::AT_OpenCLGenericAddressSpace:
case AttributeList::AT_AddressSpace:
HandleAddressSpaceTypeAttribute(type, attr, state.getSema());
attr.setUsedAsTypeAttr();