== Introduction ==
During the work that Anastasia has been doing on enabling OpenCL C++,
points have been raised about the state of address space support in
Clang. Currently, this support is rather ad-hoc. The representation of
address spaces in qualifiers and the lowering of Clang address spaces
to their LLVM counterparts are sound, but the behavioral semantics of
address spaces given by the Embedded C TR are not really sufficient to
model address space behaviors for arbitrary target architectures.
Here are some of the reviews in which this has come up:
Many address space semantics are locked behind the OpenCL language
option, even though those semantics would likely be applicable to
non-OpenCL cases as well. This means that, when not using any
particular address space-using language dialect, the address space
semantics are far too loosely defined. When using address spaces
outside of the ones defined in LangAS (the ‘target’ address spaces),
you can convert between any two address spaces explicitly, even though
this might not make sense on a particular target. There is no way for a
target to define which address spaces are compatible with each other.
Technically, this behavior is in accordance with the Embedded-C TR
(explicitly converting between all address spaces is allowed, but
undefined if they aren’t compatible), but I do not believe this
behavior is meaningful. If a target’s address spaces are disjoint,
there is no reason to let a user convert between them, even with a
In order to make the support for address spaces more complete, general
and also useful for targets with a need to define more specific rules
for their address spaces, a generalization of the conversion semantics
for address spaces is needed.
== Current implementation ==
Currently, address space compatibility is defined in terms of
superspaces. An address space can encompass others, in which case it
would be considered a superset/superspace of the other address spaces.
Given two address spaces, Super and Sub, where Super is a superspace of
Sub, then it is valid to implicitly convert a
Sub T* to a
as all pointers to Sub are encompassed by pointers to Super. It is not
necessarily safe to implicitly convert in the other direction. Also, an
address space is a superspace of itself.
This is currently implemented in Qualifiers::isAddressSpaceSupersetOf.
The OpenCL __generic address space is the superspace of all other
address spaces except for the OpenCL __constant address space. This
method is used when checking pointer compatibility during assignment
(and other forms of initialization).
Explicitly converting (casting) between two address spaces is permitted
if either of them is a superspace of the other. This is implemented in
Qualifiers::isAddressSpaceOverlapping. This check is only done in
OpenCL mode; when using address spaces in regular C, explicit
conversion is always permitted.
== Issues ==
The problem with modeling the address space conversion semantics on
superspaces and subspaces is that these two concepts are orthogonal. A
target or language could have address spaces which ‘overlap’ in some
way, yet disallow implicit or explicit conversion between them. It
could also have address spaces which do not overlap, but for which
explicit or implicit conversion is permitted.
== Suggestion ==
The suggestion in this RFC to improve the way targets and languages in
Clang can express the semantics of address space conversions is to add
a mechanism to ASTContext and TargetInfo which lets us query if a
conversion from one address space to another address space is either:
- valid implicitly
- valid explicitly
A suggestion for the interface on ASTContext would be
bool isAddressSpaceConvertible(LangAS From, LangAS To, bool Explicit)
The method would initially consult any language address space
conversion rules (such as conversion rules in OpenCL), and if no such
rules apply, proceed to fall back on a TargetInfo hook.
The TargetInfo hook would have the same format as the ASTContext
method, but would return the validity of the conversion for the
particular compilation target. The default behavior of this hook would
be that all implicit address space conversions are disallowed, and all
explicit conversions are permitted.
(An alternative setup here would be that the ASTContext method queries
the TargetInfo directly, and have the language semantics be defined in
the TargetInfo base method instead. This would let targets override
language semantics. I don’t know if this is necessary, or desirable.)
It’s important to point out that implicit validity should imply the
explicit one. If a call to this ASTContext method is made as below, and
Ctx.isAddressSpaceConvertible(From, To, false)
then the following should also return true:
Ctx.isAddressSpaceConvertible(From, To, true)
If it did not, then
To T* p = from_ptr would be permitted, but
To T* p = (To T*)from_ptr would not be, which is rather
== Necessary work ==
The steps to implement this RFC should be as follows:
A patch which adds the aforementioned methods to ASTContext and
TargetInfo, and defines the necessary semantics for the default and
language-specific conversions in them.
A patch which replaces the currently used methods for address space
compatibility mentioned earlier (isAddressSpaceSupersetOf,
isAddressSpaceOverlapping) with calls to the new methods in ASTContext.
There are some other users of these methods, such as
Qualifiers::compatiblyIncludes, but it’s not entirely clear how to
update these as a Qualifiers does not have access to ASTContext.
- Possibly a patch to remove the old address space compatibility
methods, if it can be determined that they are no longer needed.
Thank you for reading!