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
This commit is contained in:
Douglas Gregor 2010-12-10 17:03:06 +00:00
parent 924a8f3573
commit 0cdc832077
8 changed files with 73 additions and 27 deletions

View File

@ -66,7 +66,16 @@ public:
/// \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 @@ public:
/// @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 @@ template<typename T>
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>

View File

@ -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; }

View File

@ -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:

View File

@ -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<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 @@ namespace llvm {
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 @@ 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;

View File

@ -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 {

View File

@ -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;

View File

@ -167,7 +167,7 @@ void ASTDeclReader::Visit(Decl *D) {
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::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<ObjCInterfaceDecl>
(Reader.GetDecl(Record[Idx++])));

View File

@ -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<ElaboratedType>(TP)->getNamedType().getTypePtr();
TP = cast<ElaboratedType>(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<FunctionType>())
@ -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;
}