forked from OSchip/llvm-project
Refine vcall/vbase ordering with vtable construction.
llvm-svn: 85677
This commit is contained in:
parent
6ef6fe1c31
commit
75ce573815
|
@ -95,8 +95,10 @@ public:
|
|||
return llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
|
||||
}
|
||||
|
||||
void GenerateVBaseOffsets(std::vector<llvm::Constant *> &offsets,
|
||||
const CXXRecordDecl *RD, uint64_t Offset,
|
||||
#define D1(x)
|
||||
//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0)
|
||||
|
||||
void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
|
||||
bool updateVBIndex, Index_t current_vbindex) {
|
||||
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
|
||||
e = RD->bases_end(); i != e; ++i) {
|
||||
|
@ -105,22 +107,24 @@ public:
|
|||
Index_t next_vbindex = current_vbindex;
|
||||
if (i->isVirtual() && !SeenVBase.count(Base)) {
|
||||
SeenVBase.insert(Base);
|
||||
int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8;
|
||||
llvm::Constant *m = wrap(BaseOffset);
|
||||
m = wrap((0?700:0) + BaseOffset);
|
||||
if (updateVBIndex) {
|
||||
next_vbindex = (ssize_t)(-(offsets.size()*LLVMPointerWidth/8)
|
||||
next_vbindex = (ssize_t)(-(VCalls.size()*LLVMPointerWidth/8)
|
||||
- 3*LLVMPointerWidth/8);
|
||||
VBIndex[Base] = next_vbindex;
|
||||
}
|
||||
offsets.push_back(m);
|
||||
int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8;
|
||||
VCalls.push_back((0?700:0) + BaseOffset);
|
||||
D1(printf(" vbase for %s at %d delta %d most derived %s\n",
|
||||
Base->getNameAsCString(),
|
||||
(int)-VCalls.size()-3, (int)BaseOffset,
|
||||
Class->getNameAsCString()));
|
||||
}
|
||||
// We also record offsets for non-virtual bases to closest enclosing
|
||||
// virtual base. We do this so that we don't have to search
|
||||
// for the nearst virtual base class when generating thunks.
|
||||
if (updateVBIndex && VBIndex.count(Base) == 0)
|
||||
VBIndex[Base] = next_vbindex;
|
||||
GenerateVBaseOffsets(offsets, Base, Offset, updateVBIndex, next_vbindex);
|
||||
GenerateVBaseOffsets(Base, Offset, updateVBIndex, next_vbindex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,9 +241,17 @@ public:
|
|||
VCallOffset[MD] = OverrideOffset/8;
|
||||
idx = VCalls.size()+1;
|
||||
VCalls.push_back(0);
|
||||
D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
|
||||
MD->getNameAsCString(),
|
||||
(int)-VCalls.size()-3, (int)VCallOffset[MD],
|
||||
Class->getNameAsCString()));
|
||||
} else {
|
||||
VCallOffset[MD] = VCallOffset[OMD];
|
||||
VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8;
|
||||
D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n",
|
||||
MD->getNameAsCString(),
|
||||
(int)-VCalls.size()-3, (int)VCallOffset[MD],
|
||||
Class->getNameAsCString()));
|
||||
}
|
||||
VCall[MD] = idx;
|
||||
CallOffset ThisOffset;
|
||||
|
@ -340,7 +352,8 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset) {
|
||||
void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset,
|
||||
bool ForVirtualBase) {
|
||||
llvm::Constant *m = WrapAddrOf(MD);
|
||||
|
||||
// If we can find a previously allocated slot for this, reuse it.
|
||||
|
@ -350,6 +363,7 @@ public:
|
|||
// else allocate a new slot.
|
||||
Index[MD] = submethods.size();
|
||||
submethods.push_back(m);
|
||||
D1(printf(" vfn for %s at %d\n", MD->getNameAsCString(), (int)Index[MD]));
|
||||
if (MD->isPure())
|
||||
Pures[MD] = 1;
|
||||
if (MorallyVirtual) {
|
||||
|
@ -359,16 +373,19 @@ public:
|
|||
if (idx == 0) {
|
||||
idx = VCalls.size()+1;
|
||||
VCalls.push_back(0);
|
||||
D1(printf(" vcall for %s at %d with delta %d\n",
|
||||
MD->getNameAsCString(), (int)-VCalls.size()-3,
|
||||
(int)VCallOffset[MD]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual,
|
||||
Index_t Offset) {
|
||||
Index_t Offset, bool RDisVirtualBase) {
|
||||
for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
|
||||
++mi)
|
||||
if (mi->isVirtual())
|
||||
AddMethod(*mi, MorallyVirtual, Offset);
|
||||
AddMethod(*mi, MorallyVirtual, Offset, RDisVirtualBase);
|
||||
}
|
||||
|
||||
void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
|
||||
|
@ -397,6 +414,7 @@ public:
|
|||
|
||||
void insertVCalls(int InsertionPoint) {
|
||||
llvm::Constant *e = 0;
|
||||
D1(printf("============= combining vbase/vcall\n"));
|
||||
D(VCalls.insert(VCalls.begin(), 673));
|
||||
D(VCalls.push_back(672));
|
||||
methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e);
|
||||
|
@ -408,11 +426,10 @@ public:
|
|||
VCalls.clear();
|
||||
}
|
||||
|
||||
Index_t end(const CXXRecordDecl *RD, std::vector<llvm::Constant *> &offsets,
|
||||
const ASTRecordLayout &Layout,
|
||||
const CXXRecordDecl *PrimaryBase,
|
||||
bool PrimaryBaseWasVirtual, bool MorallyVirtual,
|
||||
int64_t Offset, bool ForVirtualBase, Path_t *Path) {
|
||||
Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
|
||||
const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual,
|
||||
bool MorallyVirtual, int64_t Offset, bool ForVirtualBase,
|
||||
Path_t *Path) {
|
||||
bool alloc = false;
|
||||
if (Path == 0) {
|
||||
alloc = true;
|
||||
|
@ -421,16 +438,6 @@ public:
|
|||
|
||||
StartNewTable();
|
||||
extra = 0;
|
||||
// FIXME: Cleanup.
|
||||
if (!ForVirtualBase) {
|
||||
D(methods.push_back(wrap(666)));
|
||||
// then virtual base offsets...
|
||||
for (std::vector<llvm::Constant *>::reverse_iterator i = offsets.rbegin(),
|
||||
e = offsets.rend(); i != e; ++i)
|
||||
methods.push_back(*i);
|
||||
D(methods.push_back(wrap(667)));
|
||||
}
|
||||
|
||||
bool DeferVCalls = MorallyVirtual || ForVirtualBase;
|
||||
int VCallInsertionPoint = methods.size();
|
||||
if (!DeferVCalls) {
|
||||
|
@ -439,20 +446,12 @@ public:
|
|||
// FIXME: just for extra, or for all uses of VCalls.size post this?
|
||||
extra = -VCalls.size();
|
||||
|
||||
if (ForVirtualBase) {
|
||||
D(methods.push_back(wrap(668)));
|
||||
// then virtual base offsets...
|
||||
for (std::vector<llvm::Constant *>::reverse_iterator i = offsets.rbegin(),
|
||||
e = offsets.rend(); i != e; ++i)
|
||||
methods.push_back(*i);
|
||||
D(methods.push_back(wrap(669)));
|
||||
}
|
||||
|
||||
methods.push_back(wrap(-(Offset/8)));
|
||||
methods.push_back(rtti);
|
||||
Index_t AddressPoint = methods.size();
|
||||
|
||||
InstallThunks();
|
||||
D1(printf("============= combining methods\n"));
|
||||
methods.insert(methods.end(), submethods.begin(), submethods.end());
|
||||
submethods.clear();
|
||||
|
||||
|
@ -461,10 +460,8 @@ public:
|
|||
MorallyVirtual, Offset, Path);
|
||||
|
||||
if (ForVirtualBase) {
|
||||
D(methods.push_back(wrap(670)));
|
||||
insertVCalls(VCallInsertionPoint);
|
||||
AddressPoint += VCalls.size();
|
||||
D(methods.push_back(wrap(671)));
|
||||
}
|
||||
|
||||
if (alloc) {
|
||||
|
@ -473,7 +470,36 @@ public:
|
|||
return AddressPoint;
|
||||
}
|
||||
|
||||
void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset) {
|
||||
void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
|
||||
bool updateVBIndex, Index_t current_vbindex,
|
||||
bool RDisVirtualBase) {
|
||||
if (!RD->isDynamicClass())
|
||||
return;
|
||||
|
||||
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
|
||||
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
|
||||
const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
|
||||
|
||||
// vtables are composed from the chain of primaries.
|
||||
if (PrimaryBase) {
|
||||
D1(printf(" doing primaries for %s most derived %s\n",
|
||||
RD->getNameAsCString(), Class->getNameAsCString()));
|
||||
|
||||
if (!PrimaryBaseWasVirtual)
|
||||
Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
|
||||
updateVBIndex, current_vbindex, PrimaryBaseWasVirtual);
|
||||
}
|
||||
|
||||
D1(printf(" doing vcall entries for %s most derived %s\n",
|
||||
RD->getNameAsCString(), Class->getNameAsCString()));
|
||||
|
||||
// And add the virtuals for the class to the primary vtable.
|
||||
AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase);
|
||||
}
|
||||
|
||||
void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
|
||||
bool updateVBIndex, Index_t current_vbindex,
|
||||
bool RDisVirtualBase, bool bottom=false) {
|
||||
if (!RD->isDynamicClass())
|
||||
return;
|
||||
|
||||
|
@ -485,11 +511,22 @@ public:
|
|||
if (PrimaryBase) {
|
||||
if (PrimaryBaseWasVirtual)
|
||||
IndirectPrimary.insert(PrimaryBase);
|
||||
Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset);
|
||||
|
||||
D1(printf(" doing primaries for %s most derived %s\n",
|
||||
RD->getNameAsCString(), Class->getNameAsCString()));
|
||||
|
||||
VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
|
||||
updateVBIndex, current_vbindex, PrimaryBaseWasVirtual);
|
||||
}
|
||||
|
||||
// And add the virtuals for the class to the primary vtable.
|
||||
AddMethods(RD, MorallyVirtual, Offset);
|
||||
D1(printf(" doing vbase entries for %s most derived %s\n",
|
||||
RD->getNameAsCString(), Class->getNameAsCString()));
|
||||
GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex);
|
||||
|
||||
if (RDisVirtualBase || bottom) {
|
||||
Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex,
|
||||
RDisVirtualBase);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t GenerateVtableForBase(const CXXRecordDecl *RD,
|
||||
|
@ -503,19 +540,21 @@ public:
|
|||
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
|
||||
const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
|
||||
|
||||
std::vector<llvm::Constant *> offsets;
|
||||
extra = 0;
|
||||
GenerateVBaseOffsets(offsets, RD, Offset, !ForVirtualBase, 0);
|
||||
if (ForVirtualBase)
|
||||
extra = offsets.size();
|
||||
D1(printf("building entries for base %s most derived %s\n",
|
||||
RD->getNameAsCString(), Class->getNameAsCString()));
|
||||
|
||||
Primaries(RD, MorallyVirtual, Offset);
|
||||
if (ForVirtualBase)
|
||||
extra = VCalls.size();
|
||||
|
||||
VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase,
|
||||
true);
|
||||
|
||||
if (Path)
|
||||
OverrideMethods(Path, MorallyVirtual, Offset);
|
||||
|
||||
return end(RD, offsets, Layout, PrimaryBase, PrimaryBaseWasVirtual,
|
||||
MorallyVirtual, Offset, ForVirtualBase, Path);
|
||||
return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual,
|
||||
Offset, ForVirtualBase, Path);
|
||||
}
|
||||
|
||||
void GenerateVtableForVBases(const CXXRecordDecl *RD,
|
||||
|
@ -540,6 +579,8 @@ public:
|
|||
VCall.clear();
|
||||
int64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
|
||||
CurrentVBaseOffset = BaseOffset;
|
||||
D1(printf("vtable %s virtual base %s\n",
|
||||
Class->getNameAsCString(), Base->getNameAsCString()));
|
||||
GenerateVtableForBase(Base, true, BaseOffset, true, Path);
|
||||
}
|
||||
int64_t BaseOffset = Offset;
|
||||
|
@ -575,6 +616,7 @@ int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) {
|
|||
// FIXME: This seems expensive. Can we do a partial job to get
|
||||
// just this data.
|
||||
VtableBuilder b(methods, RD, CGM);
|
||||
D1(printf("vtable %s\n", RD->getNameAsCString()));
|
||||
b.GenerateVtableForBase(RD);
|
||||
b.GenerateVtableForVBases(RD);
|
||||
|
||||
|
@ -599,6 +641,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
|
|||
// FIXME: This seems expensive. Can we do a partial job to get
|
||||
// just this data.
|
||||
VtableBuilder b(methods, RD, CGM);
|
||||
D1(printf("vtable %s\n", RD->getNameAsCString()));
|
||||
b.GenerateVtableForBase(RD);
|
||||
b.GenerateVtableForVBases(RD);
|
||||
|
||||
|
@ -629,6 +672,7 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) {
|
|||
|
||||
VtableBuilder b(methods, RD, CGM);
|
||||
|
||||
D1(printf("vtable %s\n", RD->getNameAsCString()));
|
||||
// First comes the vtables for all the non-virtual bases...
|
||||
AddressPoint = b.GenerateVtableForBase(RD);
|
||||
|
||||
|
|
|
@ -306,10 +306,10 @@ struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 {
|
|||
// CHECK-LP32-NEXT: .long __ZN9test5_B227funcB22Ev
|
||||
// CHECK-LP32-NEXT: .long __ZN9test5_B217funcB21Ev
|
||||
// CHECK-LP32-NEXT: .space 4
|
||||
// CHECK-LP32: .long 8
|
||||
// CHECK-LP32 .space 4
|
||||
// CHECK-LP32 .space 4 FIXME
|
||||
// CHECK-LP32: .long 4
|
||||
// CHECK-LP32-NEXT: .long 8
|
||||
// CHECK-LP32-NEXT: .space 4
|
||||
// CHECK-LP32-NEXT: .space 4
|
||||
// CHECK-LP32-NEXT: .long 4
|
||||
// CHECK-LP32-NEXT: .space 4
|
||||
// CHECK-LP32-NEXT: .space 4
|
||||
// CHECK-LP32-NEXT: .long 4294967288
|
||||
|
@ -358,10 +358,10 @@ struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 {
|
|||
// CHECK-LP64-NEXT: .quad __ZN9test5_B227funcB22Ev
|
||||
// CHECK-LP64-NEXT: .quad __ZN9test5_B217funcB21Ev
|
||||
// CHECK-LP64-NEXT: .space 8
|
||||
// CHECK-LP64: .quad 16
|
||||
// CHECK-LP64 .space 8
|
||||
// CHECK-LP64 .space 8
|
||||
// CHECK-LP64: .quad 8
|
||||
// CHECK-LP64-NEXT: .quad 16
|
||||
// CHECK-LP64-NEXT: .space 8
|
||||
// CHECK-LP64-NEXT: .space 8
|
||||
// CHECK-LP64-NEXT: .quad 8
|
||||
// CHECK-LP64-NEXT: .space 8
|
||||
// CHECK-LP64-NEXT: .space 8
|
||||
// CHECK-LP64-NEXT: .quad 18446744073709551600
|
||||
|
|
Loading…
Reference in New Issue