Skip to content

Commit

Permalink
Convert clang::LangAS to a strongly typed enum
Browse files Browse the repository at this point in the history
Summary:
Convert clang::LangAS to a strongly typed enum

Currently both clang AST address spaces and target specific address spaces
are represented as unsigned which can lead to subtle errors if the wrong
type is passed. It is especially confusing in the CodeGen files as it is
not possible to see what kind of address space should be passed to a
function without looking at the implementation.
I originally made this change for our LLVM fork for the CHERI architecture
where we make extensive use of address spaces to differentiate between
capabilities and pointers. When merging the upstream changes I usually
run into some test failures or runtime crashes because the wrong kind of
address space is passed to a function. By converting the LangAS enum to a
C++11 we can catch these errors at compile time. Additionally, it is now
obvious from the function signature which kind of address space it expects.

I found the following errors while writing this patch:

- ItaniumRecordLayoutBuilder::LayoutField was passing a clang AST address
  space to  TargetInfo::getPointer{Width,Align}()
- TypePrinter::printAttributedAfter() prints the numeric value of the
  clang AST address space instead of the target address space.
  However, this code is not used so I kept the current behaviour
- initializeForBlockHeader() in CGBlocks.cpp was passing
  LangAS::opencl_generic to TargetInfo::getPointer{Width,Align}()
- CodeGenFunction::EmitBlockLiteral() was passing a AST address space to
  TargetInfo::getPointerWidth()
- CGOpenMPRuntimeNVPTX::translateParameter() passed a target address space
  to Qualifiers::addAddressSpace()
- CGOpenMPRuntimeNVPTX::getParameterAddress() was using
  llvm::Type::getPointerTo() with a AST address space
- clang_getAddressSpace() returns either a LangAS or a target address
  space. As this is exposed to C I have kept the current behaviour and
  added a comment stating that it is probably not correct.

Other than this the patch should not cause any functional changes.

Reviewers: yaxunl, pcc, bader

Reviewed By: yaxunl, bader

Subscribers: jlebar, jholewinski, nhaehnle, Anastasia, cfe-commits

Differential Revision: https://reviews.llvm.org/D38816

llvm-svn: 315871
  • Loading branch information
arichardson committed Oct 15, 2017
1 parent bc7f806 commit 6d98943
Show file tree
Hide file tree
Showing 32 changed files with 179 additions and 163 deletions.
10 changes: 5 additions & 5 deletions clang/include/clang/AST/ASTContext.h
Expand Up @@ -496,7 +496,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
CXXABI *createCXXABI(const TargetInfo &T);

/// \brief The logical -> physical address space map.
const LangAS::Map *AddrSpaceMap;
const LangASMap *AddrSpaceMap;

/// \brief Address space map mangling must be used with language specific
/// address spaces (e.g. OpenCL/CUDA)
Expand Down Expand Up @@ -1070,7 +1070,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// The resulting type has a union of the qualifiers from T and the address
/// space. If T already has an address space specifier, it is silently
/// replaced.
QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const;
QualType getAddrSpaceQualType(QualType T, LangAS AddressSpace) const;

/// \brief Remove any existing address space on the type and returns the type
/// with qualifiers intact (or that's the idea anyway)
Expand Down Expand Up @@ -2363,14 +2363,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
return getTargetAddressSpace(Q.getAddressSpace());
}

unsigned getTargetAddressSpace(unsigned AS) const;
unsigned getTargetAddressSpace(LangAS AS) const;

/// Get target-dependent integer value for null pointer which is used for
/// constant folding.
uint64_t getTargetNullPointerValue(QualType QT) const;

bool addressSpaceMapManglingFor(unsigned AS) const {
return AddrSpaceMapMangling || AS >= LangAS::FirstTargetAddressSpace;
bool addressSpaceMapManglingFor(LangAS AS) const {
return AddrSpaceMapMangling || isTargetAddressSpace(AS);
}

private:
Expand Down
28 changes: 15 additions & 13 deletions clang/include/clang/AST/Type.h
Expand Up @@ -328,32 +328,34 @@ class Qualifiers {
}

bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
LangAS getAddressSpace() const {
return static_cast<LangAS>(Mask >> AddressSpaceShift);
}
bool hasTargetSpecificAddressSpace() const {
return getAddressSpace() >= LangAS::FirstTargetAddressSpace;
return isTargetAddressSpace(getAddressSpace());
}
/// Get the address space attribute value to be printed by diagnostics.
unsigned getAddressSpaceAttributePrintValue() const {
auto Addr = getAddressSpace();
// This function is not supposed to be used with language specific
// address spaces. If that happens, the diagnostic message should consider
// printing the QualType instead of the address space value.
assert(Addr == 0 || hasTargetSpecificAddressSpace());
if (Addr)
return Addr - LangAS::FirstTargetAddressSpace;
assert(Addr == LangAS::Default || hasTargetSpecificAddressSpace());
if (Addr != LangAS::Default)
return toTargetAddressSpace(Addr);
// TODO: The diagnostic messages where Addr may be 0 should be fixed
// since it cannot differentiate the situation where 0 denotes the default
// address space or user specified __attribute__((address_space(0))).
return 0;
}
void setAddressSpace(unsigned space) {
assert(space <= MaxAddressSpace);
void setAddressSpace(LangAS space) {
assert((unsigned)space <= MaxAddressSpace);
Mask = (Mask & ~AddressSpaceMask)
| (((uint32_t) space) << AddressSpaceShift);
}
void removeAddressSpace() { setAddressSpace(0); }
void addAddressSpace(unsigned space) {
assert(space);
void removeAddressSpace() { setAddressSpace(LangAS::Default); }
void addAddressSpace(LangAS space) {
assert(space != LangAS::Default);
setAddressSpace(space);
}

Expand Down Expand Up @@ -1005,7 +1007,7 @@ class QualType {
}

/// Return the address space of this type.
inline unsigned getAddressSpace() const;
inline LangAS getAddressSpace() const;

/// Returns gc attribute of this type.
inline Qualifiers::GC getObjCGCAttr() const;
Expand Down Expand Up @@ -1230,7 +1232,7 @@ class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode {
}

bool hasAddressSpace() const { return Quals.hasAddressSpace(); }
unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
LangAS getAddressSpace() const { return Quals.getAddressSpace(); }

const Type *getBaseType() const { return BaseType; }

Expand Down Expand Up @@ -5654,7 +5656,7 @@ inline void QualType::removeLocalCVRQualifiers(unsigned Mask) {
}

/// Return the address space of this type.
inline unsigned QualType::getAddressSpace() const {
inline LangAS QualType::getAddressSpace() const {
return getQualifiers().getAddressSpace();
}

Expand Down
23 changes: 19 additions & 4 deletions clang/include/clang/Basic/AddressSpaces.h
Expand Up @@ -16,14 +16,14 @@
#ifndef LLVM_CLANG_BASIC_ADDRESSSPACES_H
#define LLVM_CLANG_BASIC_ADDRESSSPACES_H

namespace clang {
#include <assert.h>

namespace LangAS {
namespace clang {

/// \brief Defines the address space values used by the address space qualifier
/// of QualType.
///
enum ID {
enum class LangAS : unsigned {
// The default value 0 is the value used in QualType for the the situation
// where there is no address space qualifier.
Default = 0,
Expand Down Expand Up @@ -51,9 +51,24 @@ enum ID {

/// The type of a lookup table which maps from language-specific address spaces
/// to target-specific ones.
typedef unsigned Map[FirstTargetAddressSpace];
typedef unsigned LangASMap[(unsigned)LangAS::FirstTargetAddressSpace];

/// \return whether \p AS is a target-specific address space rather than a
/// clang AST address space
inline bool isTargetAddressSpace(LangAS AS) {
return (unsigned)AS >= (unsigned)LangAS::FirstTargetAddressSpace;
}

inline unsigned toTargetAddressSpace(LangAS AS) {
assert(isTargetAddressSpace(AS));
return (unsigned)AS - (unsigned)LangAS::FirstTargetAddressSpace;
}

inline LangAS getLangASFromTargetAS(unsigned TargetAS) {
return static_cast<LangAS>((TargetAS) +
(unsigned)LangAS::FirstTargetAddressSpace);
}

} // namespace clang

#endif
14 changes: 5 additions & 9 deletions clang/include/clang/Basic/TargetInfo.h
Expand Up @@ -86,7 +86,7 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
*LongDoubleFormat, *Float128Format;
unsigned char RegParmMax, SSERegParmMax;
TargetCXXABI TheCXXABI;
const LangAS::Map *AddrSpaceMap;
const LangASMap *AddrSpaceMap;

mutable StringRef PlatformName;
mutable VersionTuple PlatformMinVersion;
Expand Down Expand Up @@ -322,9 +322,7 @@ class TargetInfo : public RefCountedBase<TargetInfo> {

/// \brief Get integer value for null pointer.
/// \param AddrSpace address space of pointee in source language.
virtual uint64_t getNullPointerValue(unsigned AddrSpace) const {
return 0;
}
virtual uint64_t getNullPointerValue(LangAS AddrSpace) const { return 0; }

/// \brief Return the size of '_Bool' and C++ 'bool' for this target, in bits.
unsigned getBoolWidth() const { return BoolWidth; }
Expand Down Expand Up @@ -971,15 +969,13 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
return nullptr;
}

const LangAS::Map &getAddressSpaceMap() const {
return *AddrSpaceMap;
}
const LangASMap &getAddressSpaceMap() const { return *AddrSpaceMap; }

/// \brief Return an AST address space which can be used opportunistically
/// for constant global memory. It must be possible to convert pointers into
/// this address space to LangAS::Default. If no such address space exists,
/// this may return None, and such optimizations will be disabled.
virtual llvm::Optional<unsigned> getConstantAddressSpace() const {
virtual llvm::Optional<LangAS> getConstantAddressSpace() const {
return LangAS::Default;
}

Expand Down Expand Up @@ -1058,7 +1054,7 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
}

/// \brief Get address space for OpenCL type.
virtual LangAS::ID getOpenCLTypeAddrSpace(const Type *T) const;
virtual LangAS getOpenCLTypeAddrSpace(const Type *T) const;

/// \returns Target specific vtbl ptr address space.
virtual unsigned getVtblPtrAddressSpace() const {
Expand Down
24 changes: 12 additions & 12 deletions clang/lib/AST/ASTContext.cpp
Expand Up @@ -697,8 +697,8 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
llvm_unreachable("Invalid CXXABI type!");
}

static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T,
const LangOptions &LOpts) {
static const LangASMap *getAddressSpaceMap(const TargetInfo &T,
const LangOptions &LOpts) {
if (LOpts.FakeAddressSpaceMap) {
// The fake address space map must have a distinct entry for each
// language-specific address space.
Expand Down Expand Up @@ -2283,8 +2283,8 @@ ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const {
return QualType(eq, fastQuals);
}

QualType
ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) const {
QualType ASTContext::getAddrSpaceQualType(QualType T,
LangAS AddressSpace) const {
QualType CanT = getCanonicalType(T);
if (CanT.getAddressSpace() == AddressSpace)
return T;
Expand Down Expand Up @@ -8870,8 +8870,8 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
char *End;
unsigned AddrSpace = strtoul(Str, &End, 10);
if (End != Str && AddrSpace != 0) {
Type = Context.getAddrSpaceQualType(
Type, AddrSpace + LangAS::FirstTargetAddressSpace);
Type = Context.getAddrSpaceQualType(Type,
getLangASFromTargetAS(AddrSpace));
Str = End;
}
if (c == '*')
Expand Down Expand Up @@ -9694,20 +9694,20 @@ ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
}

uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const {
unsigned AS;
LangAS AS;
if (QT->getUnqualifiedDesugaredType()->isNullPtrType())
AS = 0;
AS = LangAS::Default;
else
AS = QT->getPointeeType().getAddressSpace();

return getTargetInfo().getNullPointerValue(AS);
}

unsigned ASTContext::getTargetAddressSpace(unsigned AS) const {
if (AS >= LangAS::FirstTargetAddressSpace)
return AS - LangAS::FirstTargetAddressSpace;
unsigned ASTContext::getTargetAddressSpace(LangAS AS) const {
if (isTargetAddressSpace(AS))
return toTargetAddressSpace(AS);
else
return (*AddrSpaceMap)[AS];
return (*AddrSpaceMap)[(unsigned)AS];
}

// Explicitly instantiate this in case a Redeclarable<T> is used from a TU that
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ItaniumMangle.cpp
Expand Up @@ -2222,7 +2222,7 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp
// <type> ::= U <CUDA-addrspace>

SmallString<64> ASString;
unsigned AS = Quals.getAddressSpace();
LangAS AS = Quals.getAddressSpace();

if (Context.getASTContext().addressSpaceMapManglingFor(AS)) {
// <target-addrspace> ::= "AS" <address-space-number>
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/RecordLayoutBuilder.cpp
Expand Up @@ -1731,7 +1731,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
const ArrayType* ATy = Context.getAsArrayType(D->getType());
FieldAlign = Context.getTypeAlignInChars(ATy->getElementType());
} else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
unsigned AS = RT->getPointeeType().getAddressSpace();
unsigned AS = Context.getTargetAddressSpace(RT->getPointeeType());
FieldSize =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(AS));
FieldAlign =
Expand Down
12 changes: 7 additions & 5 deletions clang/lib/AST/TypePrinter.cpp
Expand Up @@ -1320,7 +1320,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
default: llvm_unreachable("This attribute should have been handled already");
case AttributedType::attr_address_space:
OS << "address_space(";
OS << T->getEquivalentType().getAddressSpace();
// FIXME: printing the raw LangAS value is wrong. This should probably
// use the same code as Qualifiers::print()
OS << (unsigned)T->getEquivalentType().getAddressSpace();
OS << ')';
break;

Expand Down Expand Up @@ -1645,7 +1647,7 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const {
if (getCVRQualifiers())
return false;

if (getAddressSpace())
if (getAddressSpace() != LangAS::Default)
return false;

if (getObjCGCAttr())
Expand Down Expand Up @@ -1676,7 +1678,8 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
OS << "__unaligned";
addSpace = true;
}
if (unsigned addrspace = getAddressSpace()) {
LangAS addrspace = getAddressSpace();
if (addrspace != LangAS::Default) {
if (addrspace != LangAS::opencl_private) {
if (addSpace)
OS << ' ';
Expand Down Expand Up @@ -1704,9 +1707,8 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
OS << "__shared";
break;
default:
assert(addrspace >= LangAS::FirstTargetAddressSpace);
OS << "__attribute__((address_space(";
OS << addrspace - LangAS::FirstTargetAddressSpace;
OS << toTargetAddressSpace(addrspace);
OS << ")))";
}
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Basic/TargetInfo.cpp
Expand Up @@ -23,7 +23,7 @@
#include <cstdlib>
using namespace clang;

static const LangAS::Map DefaultAddrSpaceMap = { 0 };
static const LangASMap DefaultAddrSpaceMap = {0};

// TargetInfo Constructor.
TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
Expand Down Expand Up @@ -356,7 +356,7 @@ bool TargetInfo::initFeatureMap(
return true;
}

LangAS::ID TargetInfo::getOpenCLTypeAddrSpace(const Type *T) const {
LangAS TargetInfo::getOpenCLTypeAddrSpace(const Type *T) const {
auto BT = dyn_cast<BuiltinType>(T);

if (!BT) {
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Basic/Targets/AMDGPU.cpp
Expand Up @@ -42,7 +42,7 @@ static const char *const DataLayoutStringSIGenericIsZero =
"-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128"
"-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-A5";

static const LangAS::Map AMDGPUPrivIsZeroDefIsGenMap = {
static const LangASMap AMDGPUPrivIsZeroDefIsGenMap = {
4, // Default
1, // opencl_global
3, // opencl_local
Expand All @@ -54,7 +54,7 @@ static const LangAS::Map AMDGPUPrivIsZeroDefIsGenMap = {
3 // cuda_shared
};

static const LangAS::Map AMDGPUGenIsZeroDefIsGenMap = {
static const LangASMap AMDGPUGenIsZeroDefIsGenMap = {
0, // Default
1, // opencl_global
3, // opencl_local
Expand All @@ -66,7 +66,7 @@ static const LangAS::Map AMDGPUGenIsZeroDefIsGenMap = {
3 // cuda_shared
};

static const LangAS::Map AMDGPUPrivIsZeroDefIsPrivMap = {
static const LangASMap AMDGPUPrivIsZeroDefIsPrivMap = {
0, // Default
1, // opencl_global
3, // opencl_local
Expand All @@ -78,7 +78,7 @@ static const LangAS::Map AMDGPUPrivIsZeroDefIsPrivMap = {
3 // cuda_shared
};

static const LangAS::Map AMDGPUGenIsZeroDefIsPrivMap = {
static const LangASMap AMDGPUGenIsZeroDefIsPrivMap = {
5, // Default
1, // opencl_global
3, // opencl_local
Expand Down

0 comments on commit 6d98943

Please sign in to comment.