[OpenCL] Add LangAS::opencl_private to represent private address space in AST
Currently Clang uses default address space (0) to represent private address space for OpenCL
in AST. There are two issues with this:
Multiple address spaces including private address space cannot be diagnosed.
There is no mangling for default address space. For example, if private int* is emitted as
i32 addrspace(5)* in IR. It is supposed to be mangled as PUAS5i but it is mangled as
Pi instead.
This patch attempts to represent OpenCL private address space explicitly in AST. It adds
a new enum LangAS::opencl_private and adds it to the variable types which are implicitly
private:
automatic variables without address space qualifier
function parameter
pointee type without address space qualifier (OpenCL 1.2 and below)
Differential Revision: https://reviews.llvm.org/D35082
llvm-svn: 315668
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 9a94900..37f2ff3 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -340,7 +340,7 @@
// First argument is an ndrange_t type.
Expr *NDRangeArg = TheCall->getArg(0);
- if (NDRangeArg->getType().getAsString() != "ndrange_t") {
+ if (NDRangeArg->getType().getUnqualifiedType().getAsString() != "ndrange_t") {
S.Diag(NDRangeArg->getLocStart(),
diag::err_opencl_builtin_expected_type)
<< TheCall->getDirectCallee() << "'ndrange_t'";
@@ -784,8 +784,11 @@
case Builtin::BIto_local:
Qual.setAddressSpace(LangAS::opencl_local);
break;
+ case Builtin::BIto_private:
+ Qual.setAddressSpace(LangAS::opencl_private);
+ break;
default:
- Qual.removeAddressSpace();
+ llvm_unreachable("Invalid builtin function");
}
Call->setType(S.Context.getPointerType(S.Context.getQualifiedType(
RT.getUnqualifiedType(), Qual)));
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 8f93d5c..31abdfa 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -6324,7 +6324,7 @@
// The event type cannot be used with the __local, __constant and __global
// address space qualifiers.
if (R->isEventT()) {
- if (R.getAddressSpace()) {
+ if (R.getAddressSpace() != LangAS::opencl_private) {
Diag(D.getLocStart(), diag::err_event_t_addr_space_qual);
D.setInvalidType();
}
@@ -7427,7 +7427,7 @@
return;
}
}
- } else if (T.getAddressSpace() != LangAS::Default) {
+ } else if (T.getAddressSpace() != LangAS::opencl_private) {
// Do not allow other address spaces on automatic variable.
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 1;
NewVD->setInvalidDecl();
@@ -8062,7 +8062,8 @@
if (PointeeType->isPointerType())
return PtrPtrKernelParam;
if (PointeeType.getAddressSpace() == LangAS::opencl_generic ||
- PointeeType.getAddressSpace() == 0)
+ PointeeType.getAddressSpace() == LangAS::opencl_private ||
+ PointeeType.getAddressSpace() == LangAS::Default)
return InvalidAddrSpacePtrKernelParam;
return PtrKernelParam;
}
@@ -8832,9 +8833,7 @@
// OpenCL v1.1 s6.5: Using an address space qualifier in a function return
// type declaration will generate a compilation error.
unsigned AddressSpace = NewFD->getReturnType().getAddressSpace();
- if (AddressSpace == LangAS::opencl_local ||
- AddressSpace == LangAS::opencl_global ||
- AddressSpace == LangAS::opencl_constant) {
+ if (AddressSpace != LangAS::Default) {
Diag(NewFD->getLocation(),
diag::err_opencl_return_value_with_address_space);
NewFD->setInvalidDecl();
@@ -11939,13 +11938,13 @@
// duration shall not be qualified by an address-space qualifier."
// Since all parameters have automatic store duration, they can not have
// an address space.
- if (T.getAddressSpace() != 0) {
- // OpenCL allows function arguments declared to be an array of a type
- // to be qualified with an address space.
- if (!(getLangOpts().OpenCL && T->isArrayType())) {
- Diag(NameLoc, diag::err_arg_with_address_space);
- New->setInvalidDecl();
- }
+ if (T.getAddressSpace() != LangAS::Default &&
+ // OpenCL allows function arguments declared to be an array of a type
+ // to be qualified with an address space.
+ !(getLangOpts().OpenCL &&
+ (T->isArrayType() || T.getAddressSpace() == LangAS::opencl_private))) {
+ Diag(NameLoc, diag::err_arg_with_address_space);
+ New->setInvalidDecl();
}
return New;
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 8623ab0..c741f84 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -4938,7 +4938,6 @@
TypeSourceInfo *ReturnTypeInfo = nullptr;
QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo);
-
if (D.isPrototypeContext() && getLangOpts().ObjCAutoRefCount)
inferARCWriteback(state, T);
@@ -5752,9 +5751,10 @@
ASIdx = LangAS::opencl_constant; break;
case AttributeList::AT_OpenCLGenericAddressSpace:
ASIdx = LangAS::opencl_generic; break;
+ case AttributeList::AT_OpenCLPrivateAddressSpace:
+ ASIdx = LangAS::opencl_private; break;
default:
- assert(Attr.getKind() == AttributeList::AT_OpenCLPrivateAddressSpace);
- ASIdx = 0; break;
+ llvm_unreachable("Invalid address space");
}
Type = S.Context.getAddrSpaceQualType(Type, ASIdx);
@@ -6986,6 +6986,92 @@
}
}
+static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
+ QualType &T, TypeAttrLocation TAL) {
+ Declarator &D = State.getDeclarator();
+
+ // Handle the cases where address space should not be deduced.
+ //
+ // The pointee type of a pointer type is alwasy deduced since a pointer always
+ // points to some memory location which should has an address space.
+ //
+ // There are situations that at the point of certain declarations, the address
+ // space may be unknown and better to be left as default. For example, when
+ // definining a typedef or struct type, they are not associated with any
+ // specific address space. Later on, they may be used with any address space
+ // to declare a variable.
+ //
+ // The return value of a function is r-value, therefore should not have
+ // address space.
+ //
+ // The void type does not occupy memory, therefore should not have address
+ // space, except when it is used as a pointee type.
+ //
+ // Since LLVM assumes function type is in default address space, it should not
+ // have address space.
+ auto ChunkIndex = State.getCurrentChunkIndex();
+ bool IsPointee =
+ ChunkIndex > 0 &&
+ (D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer ||
+ D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer);
+ bool IsFuncReturnType =
+ ChunkIndex > 0 &&
+ D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Function;
+ bool IsFuncType =
+ ChunkIndex < D.getNumTypeObjects() &&
+ D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function;
+ if ( // Do not deduce addr space for function return type and function type,
+ // otherwise it will fail some sema check.
+ IsFuncReturnType || IsFuncType ||
+ // Do not deduce addr space for member types of struct, except the pointee
+ // type of a pointer member type.
+ (D.getContext() == Declarator::MemberContext && !IsPointee) ||
+ // Do not deduce addr space for types used to define a typedef and the
+ // typedef itself, except the pointee type of a pointer type which is used
+ // to define the typedef.
+ (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef &&
+ !IsPointee) ||
+ // Do not deduce addr space of the void type, e.g. in f(void), otherwise
+ // it will fail some sema check.
+ (T->isVoidType() && !IsPointee))
+ return;
+
+ unsigned ImpAddr;
+ // Put OpenCL automatic variable in private address space.
+ // OpenCL v1.2 s6.5:
+ // The default address space name for arguments to a function in a
+ // program, or local variables of a function is __private. All function
+ // arguments shall be in the __private address space.
+ if (State.getSema().getLangOpts().OpenCLVersion <= 120) {
+ ImpAddr = LangAS::opencl_private;
+ } else {
+ // 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 (IsPointee) {
+ ImpAddr = LangAS::opencl_generic;
+ } else {
+ if (D.getContext() == Declarator::FileContext) {
+ ImpAddr = LangAS::opencl_global;
+ } else {
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
+ D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) {
+ ImpAddr = LangAS::opencl_global;
+ } else {
+ ImpAddr = LangAS::opencl_private;
+ }
+ }
+ }
+ }
+ T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr);
+}
+
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
TypeAttrLocation TAL, AttributeList *attrs) {
// Scan through and apply attributes to this type where it makes sense. Some
@@ -7157,39 +7243,11 @@
}
}
- // 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 ||
- D.getTypeObject(state.getCurrentChunkIndex() - 1).Kind ==
- DeclaratorChunk::BlockPointer)) {
- 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);
- }
+ if (!state.getSema().getLangOpts().OpenCL ||
+ type.getAddressSpace() != LangAS::Default)
+ return;
+
+ deduceOpenCLImplicitAddrSpace(state, type, TAL);
}
void Sema::completeExprArrayBound(Expr *E) {