Eliminate the branching in QualType::getTypePtr() by providing a
common base for ExtQuals and Type that stores the underlying type
pointer. This results in a 2% performance win for -emit-llvm on a
typical C file, with 1% memory growth in the AST.
Note that there is an API change in this optimization:
QualType::getTypePtr() can no longer be invoked on a NULL
QualType. If the QualType might be NULL, use
QualType::getTypePtrOrNull(). I've audited all uses of getTypePtr() in
the code base and changed the appropriate uses over to
getTypePtrOrNull().
A future optimization opportunity would be to distinguish between
cast/dyn_cast and cast_or_null/dyn_cast_or_null; for the former, we
could use getTypePtr() rather than getTypePtrOrNull(), to take another
branch out of the cast/dyn_cast implementation.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121489 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index dad4dfc..b1962b7 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -66,7 +66,16 @@
/// \brief Retrieve the underlying type pointer, which refers to a
/// canonical type.
- T *getTypePtr() const { return cast_or_null<T>(Stored.getTypePtr()); }
+ ///
+ /// The underlying pointer must not be NULL.
+ T *getTypePtr() const { return cast<T>(Stored.getTypePtr()); }
+
+ /// \brief Retrieve the underlying type pointer, which refers to a
+ /// canonical type, or NULL.
+ ///
+ T *getTypePtrOrNull() const {
+ return cast_or_null<T>(Stored.getTypePtrOrNull());
+ }
/// \brief Implicit conversion to a qualified type.
operator QualType() const { return Stored; }
@@ -225,7 +234,7 @@
/// @code
/// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... }
/// @endcode
- operator const T*() const { return this->Stored.getTypePtr(); }
+ operator const T*() const { return this->Stored.getTypePtrOrNull(); }
/// \brief Try to convert the given canonical type to a specific structural
/// type.
@@ -338,7 +347,7 @@
struct simplify_type<const ::clang::CanQual<T> > {
typedef T* SimpleType;
static SimpleType getSimplifiedValue(const ::clang::CanQual<T> &Val) {
- return Val.getTypePtr();
+ return Val.getTypePtrOrNull();
}
};
template<typename T>
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 2a3bf85..98b20c1 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -2259,7 +2259,7 @@
}
/// \brief Set the underlying integer type.
- void setIntegerType(QualType T) { IntegerType = T.getTypePtr(); }
+ void setIntegerType(QualType T) { IntegerType = T.getTypePtrOrNull(); }
/// \brief Set the underlying integer type source info.
void setIntegerTypeSourceInfo(TypeSourceInfo* TInfo) { IntegerType = TInfo; }
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index bde2e24..6e79bad 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -910,7 +910,7 @@
bool Typename, QualType Type, bool ParameterPack)
: TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename),
InheritedDefault(false), ParameterPack(ParameterPack), DefaultArgument() {
- TypeForDecl = Type.getTypePtr();
+ TypeForDecl = Type.getTypePtrOrNull();
}
public:
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 19f7f47..5c67dd8 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -326,7 +326,24 @@
static const uint32_t AddressSpaceShift = 5;
};
-
+/// \brief Base class that is common to both the \c ExtQuals and \c Type
+/// classes, which allows \c QualType to access the common fields between the
+/// two.
+///
+class ExtQualsTypeCommonBase {
+protected:
+ ExtQualsTypeCommonBase(const Type *BaseType) : BaseType(BaseType) { }
+
+ /// \brief The "base" type of an extended qualifiers type (\c ExtQuals) or
+ /// a self-referential pointer (for \c Type).
+ ///
+ /// This pointer allows an efficient mapping from a QualType to its
+ /// underlying type pointer.
+ const Type *BaseType;
+
+ friend class QualType;
+};
+
/// ExtQuals - We can encode up to four bits in the low bits of a
/// type pointer, but there are many more type qualifiers that we want
/// to be able to apply to an arbitrary type. Therefore we have this
@@ -337,7 +354,7 @@
/// in three low bits on the QualType pointer; a fourth bit records whether
/// the pointer is an ExtQuals node. The extended qualifiers (address spaces,
/// Objective-C GC attributes) are much more rare.
-class ExtQuals : public llvm::FoldingSetNode {
+class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode {
// NOTE: changing the fast qualifiers should be straightforward as
// long as you don't make 'const' non-fast.
// 1. Qualifiers:
@@ -351,15 +368,13 @@
// 3. ASTContext:
// a) Update get{Volatile,Restrict}Type.
- /// BaseType - the underlying type that this qualifies
- const Type *BaseType;
-
/// Quals - the immutable set of qualifiers applied by this
/// node; always contains extended qualifiers.
Qualifiers Quals;
public:
- ExtQuals(const Type *Base, Qualifiers Quals) : BaseType(Base), Quals(Quals)
+ ExtQuals(const Type *Base, Qualifiers Quals)
+ : ExtQualsTypeCommonBase(Base), Quals(Quals)
{
assert(Quals.hasNonFastQualifiers()
&& "ExtQuals created with no fast qualifiers");
@@ -444,10 +459,25 @@
/// Retrieves a pointer to the underlying (unqualified) type.
/// This should really return a const Type, but it's not worth
/// changing all the users right now.
+ ///
+ /// This function requires that the type not be NULL. If the type might be
+ /// NULL, use the (slightly less efficient) \c getTypePtrOrNull().
Type *getTypePtr() const {
- if (hasLocalNonFastQualifiers())
- return const_cast<Type*>(getExtQualsUnsafe()->getBaseType());
- return const_cast<Type*>(getTypePtrUnsafe());
+ assert(!isNull() && "Cannot retrieve a NULL type pointer");
+ uintptr_t CommonPtrVal
+ = reinterpret_cast<uintptr_t>(Value.getOpaqueValue());
+ CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1);
+ ExtQualsTypeCommonBase *CommonPtr
+ = reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal);
+ return const_cast<Type *>(CommonPtr->BaseType);
+ }
+
+ Type *getTypePtrOrNull() const {
+ uintptr_t TypePtrPtrVal
+ = reinterpret_cast<uintptr_t>(Value.getOpaqueValue());
+ TypePtrPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1);
+ Type **TypePtrPtr = reinterpret_cast<Type**>(TypePtrPtrVal);
+ return TypePtrPtr? *TypePtrPtr : 0;
}
/// Divides a QualType into its unqualified type and a set of local
@@ -741,7 +771,7 @@
template<> struct simplify_type<const ::clang::QualType> {
typedef ::clang::Type* SimpleType;
static SimpleType getSimplifiedValue(const ::clang::QualType &Val) {
- return Val.getTypePtr();
+ return Val.getTypePtrOrNull();
}
};
template<> struct simplify_type< ::clang::QualType>
@@ -790,7 +820,7 @@
///
/// Types, once created, are immutable.
///
-class Type {
+class Type : public ExtQualsTypeCommonBase {
public:
enum TypeClass {
#define TYPE(Class, Base) Class,
@@ -981,7 +1011,8 @@
// silence VC++ warning C4355: 'this' : used in base member initializer list
Type *this_() { return this; }
Type(TypeClass tc, QualType Canonical, bool Dependent, bool VariablyModified)
- : CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical) {
+ : ExtQualsTypeCommonBase(this),
+ CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical) {
TypeBits.TC = tc;
TypeBits.Dependent = Dependent;
TypeBits.VariablyModified = VariablyModified;
diff --git a/include/clang/Checker/PathSensitive/MemRegion.h b/include/clang/Checker/PathSensitive/MemRegion.h
index 33793e6..ac44944 100644
--- a/include/clang/Checker/PathSensitive/MemRegion.h
+++ b/include/clang/Checker/PathSensitive/MemRegion.h
@@ -359,7 +359,7 @@
QualType getDesugaredValueType(ASTContext &Context) const {
QualType T = getValueType();
- return T.getTypePtr() ? T.getDesugaredType(Context) : T;
+ return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T;
}
QualType getDesugaredLocationType(ASTContext &Context) const {
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 4e0a7b7..5fe95bf 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -2772,6 +2772,9 @@
}
QualType PointeeType = GetType(Record[0]);
QualType ClassType = GetType(Record[1]);
+ if (PointeeType.isNull() || ClassType.isNull())
+ return QualType();
+
return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr());
}
@@ -4368,7 +4371,10 @@
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
- Type *T = GetType(Record[Idx++]).getTypePtr();
+ Type *T = GetType(Record[Idx++]).getTypePtrOrNull();
+ if (!T)
+ return 0;
+
bool Template = Record[Idx++];
NNS = NestedNameSpecifier::Create(*Context, Prev, Template, T);
break;
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 8506f0b..6100d65 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -167,7 +167,7 @@
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
// if we have a fully initialized TypeDecl, we can safely read its type now.
- TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtr());
+ TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// FunctionDecl's body was written last after all other Stmts/Exprs.
if (Record[Idx++])
@@ -443,7 +443,7 @@
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
VisitObjCContainerDecl(ID);
- ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr());
+ ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtrOrNull());
ID->setSuperClass(cast_or_null<ObjCInterfaceDecl>
(Reader.GetDecl(Record[Idx++])));
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index a42f009..2fe360b 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -63,7 +63,7 @@
}
static CXTypeKind GetTypeKind(QualType T) {
- Type *TP = T.getTypePtr();
+ Type *TP = T.getTypePtrOrNull();
if (!TP)
return CXType_Invalid;
@@ -186,7 +186,7 @@
CXType clang_getPointeeType(CXType CT) {
QualType T = GetQualType(CT);
- Type *TP = T.getTypePtr();
+ Type *TP = T.getTypePtrOrNull();
if (!TP)
return MakeCXType(QualType(), GetTU(CT));
@@ -217,7 +217,7 @@
return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
QualType T = GetQualType(CT);
- Type *TP = T.getTypePtr();
+ Type *TP = T.getTypePtrOrNull();
if (!TP)
return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound);
@@ -254,7 +254,7 @@
// FIXME: Template type parameters!
case Type::Elaborated:
- TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtr();
+ TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull();
goto try_again;
default:
@@ -324,7 +324,7 @@
CXType clang_getResultType(CXType X) {
QualType T = GetQualType(X);
- if (!T.getTypePtr())
+ if (!T.getTypePtrOrNull())
return MakeCXType(QualType(), GetTU(X));
if (const FunctionType *FD = T->getAs<FunctionType>())
@@ -347,7 +347,7 @@
unsigned clang_isPODType(CXType X) {
QualType T = GetQualType(X);
- if (!T.getTypePtr())
+ if (!T.getTypePtrOrNull())
return 0;
return T->isPODType() ? 1 : 0;
}