eliminate the std::vector from StructLayout, allocating the elements immediately

after the StructLayout object in memory.  This marginally improves locality,
speeding up -load-vn -gcse by ~0.8%.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@34158 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2007-02-10 20:15:41 +00:00
parent b0c39a3b4d
commit 9182e3f205
2 changed files with 61 additions and 46 deletions

View File

@ -275,9 +275,10 @@ public:
/// target machine, based on the TargetData structure.
///
class StructLayout {
std::vector<uint64_t> MemberOffsets;
unsigned StructAlignment;
uint64_t StructSize;
unsigned StructAlignment;
unsigned NumElements;
uint64_t MemberOffsets[1]; // variable sized array!
public:
uint64_t getSizeInBytes() const {
@ -294,7 +295,7 @@ public:
unsigned getElementContainingOffset(uint64_t Offset) const;
uint64_t getElementOffset(unsigned Idx) const {
assert(Idx < MemberOffsets.size() && "Invalid element idx!");
assert(Idx < NumElements && "Invalid element idx!");
return MemberOffsets[Idx];
}

View File

@ -48,11 +48,11 @@ static inline void getTypeInfoPref(const Type *Ty, const TargetData *TD,
StructLayout::StructLayout(const StructType *ST, const TargetData &TD) {
StructAlignment = 0;
StructSize = 0;
NumElements = ST->getNumElements();
// Loop over each of the elements, placing them in memory...
for (StructType::element_iterator TI = ST->element_begin(),
TE = ST->element_end(); TI != TE; ++TI) {
const Type *Ty = *TI;
for (unsigned i = 0, e = NumElements; i != e; ++i) {
const Type *Ty = ST->getElementType(i);
unsigned char A;
unsigned TyAlign;
uint64_t TySize;
@ -66,7 +66,7 @@ StructLayout::StructLayout(const StructType *ST, const TargetData &TD) {
// Keep track of maximum alignment constraint
StructAlignment = std::max(TyAlign, StructAlignment);
MemberOffsets.push_back(StructSize);
MemberOffsets[i] = StructSize;
StructSize += TySize; // Consume space for this data item
}
@ -83,15 +83,15 @@ StructLayout::StructLayout(const StructType *ST, const TargetData &TD) {
/// getElementContainingOffset - Given a valid offset into the structure,
/// return the structure index that contains it.
unsigned StructLayout::getElementContainingOffset(uint64_t Offset) const {
std::vector<uint64_t>::const_iterator SI =
std::upper_bound(MemberOffsets.begin(), MemberOffsets.end(), Offset);
assert(SI != MemberOffsets.begin() && "Offset not in structure type!");
const uint64_t *SI =
std::upper_bound(&MemberOffsets[0], &MemberOffsets[NumElements], Offset);
assert(SI != &MemberOffsets[0] && "Offset not in structure type!");
--SI;
assert(*SI <= Offset && "upper_bound didn't work");
assert((SI == MemberOffsets.begin() || *(SI-1) < Offset) &&
(SI+1 == MemberOffsets.end() || *(SI+1) > Offset) &&
assert((SI == &MemberOffsets[0] || *(SI-1) < Offset) &&
(SI+1 == &MemberOffsets[NumElements] || *(SI+1) > Offset) &&
"Upper bound didn't work!");
return SI-MemberOffsets.begin();
return SI-&MemberOffsets[0];
}
//===----------------------------------------------------------------------===//
@ -203,25 +203,66 @@ TargetData::TargetData(const Module *M) {
}
/// LayoutInfo - The lazy cache of structure layout information maintained by
/// TargetData.
/// TargetData. Note that the struct types must have been free'd before
/// llvm_shutdown is called (and thus this is deallocated) because all the
/// targets with cached elements should have been destroyed.
///
typedef std::pair<const TargetData*,const StructType*> LayoutKey;
static ManagedStatic<std::map<LayoutKey, StructLayout> > LayoutInfo;
static ManagedStatic<std::map<LayoutKey, StructLayout*> > LayoutInfo;
TargetData::~TargetData() {
if (LayoutInfo.isConstructed()) {
// Remove any layouts for this TD.
std::map<LayoutKey, StructLayout> &TheMap = *LayoutInfo;
std::map<LayoutKey, StructLayout>::iterator
std::map<LayoutKey, StructLayout*> &TheMap = *LayoutInfo;
std::map<LayoutKey, StructLayout*>::iterator
I = TheMap.lower_bound(LayoutKey(this, (const StructType*)0));
for (std::map<LayoutKey, StructLayout>::iterator E = TheMap.end();
I != E && I->first.first == this; )
for (std::map<LayoutKey, StructLayout*>::iterator E = TheMap.end();
I != E && I->first.first == this; ) {
I->second->~StructLayout();
free(I->second);
TheMap.erase(I++);
}
}
}
const StructLayout *TargetData::getStructLayout(const StructType *Ty) const {
std::map<LayoutKey, StructLayout*> &TheMap = *LayoutInfo;
std::map<LayoutKey, StructLayout*>::iterator
I = TheMap.lower_bound(LayoutKey(this, Ty));
if (I != TheMap.end() && I->first.first == this && I->first.second == Ty)
return I->second;
// Otherwise, create the struct layout. Because it is variable length, we
// malloc it, then use placement new.
unsigned NumElts = Ty->getNumElements();
StructLayout *L =
(StructLayout *)malloc(sizeof(StructLayout)+(NumElts-1)*sizeof(uint64_t));
new (L) StructLayout(Ty, *this);
TheMap.insert(I, std::make_pair(LayoutKey(this, Ty), L));
return L;
}
/// InvalidateStructLayoutInfo - TargetData speculatively caches StructLayout
/// objects. If a TargetData object is alive when types are being refined and
/// removed, this method must be called whenever a StructType is removed to
/// avoid a dangling pointer in this cache.
void TargetData::InvalidateStructLayoutInfo(const StructType *Ty) const {
if (!LayoutInfo.isConstructed()) return; // No cache.
std::map<LayoutKey, StructLayout*>::iterator I =
LayoutInfo->find(LayoutKey(this, Ty));
if (I != LayoutInfo->end()) {
I->second->~StructLayout();
free(I->second);
LayoutInfo->erase(I);
}
}
std::string TargetData::getStringRepresentation() const {
std::stringstream repr;
@ -250,33 +291,6 @@ std::string TargetData::getStringRepresentation() const {
return repr.str();
}
const StructLayout *TargetData::getStructLayout(const StructType *Ty) const {
std::map<LayoutKey, StructLayout> &TheMap = *LayoutInfo;
std::map<LayoutKey, StructLayout>::iterator
I = TheMap.lower_bound(LayoutKey(this, Ty));
if (I != TheMap.end() && I->first.first == this && I->first.second == Ty)
return &I->second;
else {
return &TheMap.insert(I, std::make_pair(LayoutKey(this, Ty),
StructLayout(Ty, *this)))->second;
}
}
/// InvalidateStructLayoutInfo - TargetData speculatively caches StructLayout
/// objects. If a TargetData object is alive when types are being refined and
/// removed, this method must be called whenever a StructType is removed to
/// avoid a dangling pointer in this cache.
void TargetData::InvalidateStructLayoutInfo(const StructType *Ty) const {
if (!LayoutInfo.isConstructed()) return; // No cache.
std::map<LayoutKey, StructLayout>::iterator I =
LayoutInfo->find(std::make_pair(this, Ty));
if (I != LayoutInfo->end())
LayoutInfo->erase(I);
}
static inline void getTypeInfoABI(const Type *Ty, const TargetData *TD,
uint64_t &Size, unsigned char &Alignment) {