Cache the sized-ness of struct types, once we reach the steady state of

"is sized". This prevents every query to isSized() from recursing over
every sub-type of a struct type. This could get *very* slow for
extremely deep nesting of structs, as in 177.mesa.

This change is a 45% speedup for 'opt -O2' of 177.mesa.linked.bc, and
likely a significant speedup for other cases as well. It even impacts
-O0 cases because so many part of the code try to check whether a type
is sized.

Thanks for the review from Nick Lewycky and Benjamin Kramer on IRC.

llvm-svn: 152197
This commit is contained in:
Chandler Carruth 2012-03-07 02:33:09 +00:00
parent 0bb9044973
commit cee7a12d40
2 changed files with 27 additions and 12 deletions

View File

@ -195,9 +195,10 @@ class StructType : public CompositeType {
// This is the contents of the SubClassData field. // This is the contents of the SubClassData field.
SCDB_HasBody = 1, SCDB_HasBody = 1,
SCDB_Packed = 2, SCDB_Packed = 2,
SCDB_IsLiteral = 4 SCDB_IsLiteral = 4,
SCDB_IsSized = 8
}; };
/// SymbolTableEntry - For a named struct that actually has a name, this is a /// SymbolTableEntry - For a named struct that actually has a name, this is a
/// pointer to the symbol table entry (maintained by LLVMContext) for the /// pointer to the symbol table entry (maintained by LLVMContext) for the
/// struct. This is null if the type is an literal struct or if it is /// struct. This is null if the type is an literal struct or if it is
@ -248,6 +249,9 @@ public:
/// isOpaque - Return true if this is a type with an identity that has no body /// isOpaque - Return true if this is a type with an identity that has no body
/// specified yet. These prints as 'opaque' in .ll files. /// specified yet. These prints as 'opaque' in .ll files.
bool isOpaque() const { return (getSubclassData() & SCDB_HasBody) == 0; } bool isOpaque() const { return (getSubclassData() & SCDB_HasBody) == 0; }
/// isSized - Return true if this is a sized type.
bool isSized() const;
/// hasName - Return true if this is a named struct that has a non-empty name. /// hasName - Return true if this is a named struct that has a non-empty name.
bool hasName() const { return SymbolTableEntry != 0; } bool hasName() const { return SymbolTableEntry != 0; }

View File

@ -185,16 +185,7 @@ bool Type::isSizedDerivedType() const {
if (!this->isStructTy()) if (!this->isStructTy())
return false; return false;
// Opaque structs have no size. return cast<StructType>(this)->isSized();
if (cast<StructType>(this)->isOpaque())
return false;
// Okay, our struct is sized if all of the elements are.
for (subtype_iterator I = subtype_begin(), E = subtype_end(); I != E; ++I)
if (!(*I)->isSized())
return false;
return true;
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -579,6 +570,26 @@ StructType *StructType::create(StringRef Name, Type *type, ...) {
return llvm::StructType::create(Ctx, StructFields, Name); return llvm::StructType::create(Ctx, StructFields, Name);
} }
bool StructType::isSized() const {
if ((getSubclassData() & SCDB_IsSized) != 0)
return true;
if (isOpaque())
return false;
// Okay, our struct is sized if all of the elements are, but if one of the
// elements is opaque, the struct isn't sized *yet*, but may become sized in
// the future, so just bail out without caching.
for (element_iterator I = element_begin(), E = element_end(); I != E; ++I)
if (!(*I)->isSized())
return false;
// Here we cheat a bit and cast away const-ness. The goal is to memoize when
// we find a sized type, as types can only move from opaque to sized, not the
// other way.
const_cast<StructType*>(this)->setSubclassData(
getSubclassData() | SCDB_IsSized);
return true;
}
StringRef StructType::getName() const { StringRef StructType::getName() const {
assert(!isLiteral() && "Literal structs never have names"); assert(!isLiteral() && "Literal structs never have names");