From 0cdc8320779058553b48b3c14875ad44632091d3 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 10 Dec 2010 17:03:06 +0000 Subject: [PATCH] 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. llvm-svn: 121489 --- clang/include/clang/AST/CanonicalType.h | 15 ++++- clang/include/clang/AST/Decl.h | 2 +- clang/include/clang/AST/DeclTemplate.h | 2 +- clang/include/clang/AST/Type.h | 55 +++++++++++++++---- .../clang/Checker/PathSensitive/MemRegion.h | 2 +- clang/lib/Serialization/ASTReader.cpp | 8 ++- clang/lib/Serialization/ASTReaderDecl.cpp | 4 +- clang/tools/libclang/CXType.cpp | 12 ++-- 8 files changed, 73 insertions(+), 27 deletions(-) diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index dad4dfc926e1..b1962b7b9e4d 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -66,7 +66,16 @@ public: /// \brief Retrieve the underlying type pointer, which refers to a /// canonical type. - T *getTypePtr() const { return cast_or_null(Stored.getTypePtr()); } + /// + /// The underlying pointer must not be NULL. + T *getTypePtr() const { return cast(Stored.getTypePtr()); } + + /// \brief Retrieve the underlying type pointer, which refers to a + /// canonical type, or NULL. + /// + T *getTypePtrOrNull() const { + return cast_or_null(Stored.getTypePtrOrNull()); + } /// \brief Implicit conversion to a qualified type. operator QualType() const { return Stored; } @@ -225,7 +234,7 @@ public: /// @code /// if (CanQual Ptr = T->getAs()) { ... } /// @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 @@ template struct simplify_type > { typedef T* SimpleType; static SimpleType getSimplifiedValue(const ::clang::CanQual &Val) { - return Val.getTypePtr(); + return Val.getTypePtrOrNull(); } }; template diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 2a3bf8591191..98b20c1ae1de 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2259,7 +2259,7 @@ public: } /// \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/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index bde2e24e198f..6e79bad6823e 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -910,7 +910,7 @@ class TemplateTypeParmDecl : public TypeDecl { 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/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 19f7f4783773..5c67dd8b4f8b 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -326,7 +326,24 @@ private: 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 @@ private: /// 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 @@ class ExtQuals : public llvm::FoldingSetNode { // 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 @@ public: /// 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(getExtQualsUnsafe()->getBaseType()); - return const_cast(getTypePtrUnsafe()); + assert(!isNull() && "Cannot retrieve a NULL type pointer"); + uintptr_t CommonPtrVal + = reinterpret_cast(Value.getOpaqueValue()); + CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); + ExtQualsTypeCommonBase *CommonPtr + = reinterpret_cast(CommonPtrVal); + return const_cast(CommonPtr->BaseType); + } + + Type *getTypePtrOrNull() const { + uintptr_t TypePtrPtrVal + = reinterpret_cast(Value.getOpaqueValue()); + TypePtrPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); + Type **TypePtrPtr = reinterpret_cast(TypePtrPtrVal); + return TypePtrPtr? *TypePtrPtr : 0; } /// Divides a QualType into its unqualified type and a set of local @@ -741,7 +771,7 @@ namespace llvm { template<> struct simplify_type { 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 @@ namespace clang { /// /// Types, once created, are immutable. /// -class Type { +class Type : public ExtQualsTypeCommonBase { public: enum TypeClass { #define TYPE(Class, Base) Class, @@ -981,7 +1011,8 @@ protected: // 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/clang/include/clang/Checker/PathSensitive/MemRegion.h b/clang/include/clang/Checker/PathSensitive/MemRegion.h index 33793e66e305..ac44944c50a5 100644 --- a/clang/include/clang/Checker/PathSensitive/MemRegion.h +++ b/clang/include/clang/Checker/PathSensitive/MemRegion.h @@ -359,7 +359,7 @@ public: 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/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 4e0a7b783b42..5fe95bfed465 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -2772,6 +2772,9 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { } 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 @@ ASTReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) { 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/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 8506f0bdd61c..6100d65757cc 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -167,7 +167,7 @@ void ASTDeclReader::Visit(Decl *D) { if (TypeDecl *TD = dyn_cast(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(D)) { // FunctionDecl's body was written last after all other Stmts/Exprs. if (Record[Idx++]) @@ -443,7 +443,7 @@ void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { 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 (Reader.GetDecl(Record[Idx++]))); diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp index a42f009de2d1..2fe360b31999 100644 --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -63,7 +63,7 @@ static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) { } static CXTypeKind GetTypeKind(QualType T) { - Type *TP = T.getTypePtr(); + Type *TP = T.getTypePtrOrNull(); if (!TP) return CXType_Invalid; @@ -186,7 +186,7 @@ CXType clang_getCanonicalType(CXType CT) { 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 @@ CXCursor clang_getTypeDeclaration(CXType CT) { 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 @@ try_again: // FIXME: Template type parameters! case Type::Elaborated: - TP = cast(TP)->getNamedType().getTypePtr(); + TP = cast(TP)->getNamedType().getTypePtrOrNull(); goto try_again; default: @@ -324,7 +324,7 @@ unsigned clang_equalTypes(CXType A, CXType B) { 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()) @@ -347,7 +347,7 @@ CXType clang_getCursorResultType(CXCursor C) { unsigned clang_isPODType(CXType X) { QualType T = GetQualType(X); - if (!T.getTypePtr()) + if (!T.getTypePtrOrNull()) return 0; return T->isPODType() ? 1 : 0; }