[cfe-dev] CGRecordLayoutBuilder for MS ABI
John McCall
rjmccall at apple.com
Fri Nov 4 11:30:12 PDT 2011
On Nov 4, 2011, at 9:45 AM, r4start wrote:
> Sorry, at first time i didn't include MSLayoutVirtBases for codegen.
- if (Base->isDynamicClass()) {
+ // In the MS ABI, we need a vfptr if this class defines new virtual
+ // functions but has no primary base. The AST doesn't tell us
+ // directly that a class has new virtual functions, and checking for it
+ // is a bit expensive, but we can avoid the full check in some important
+ // cases: non-polymorphic classes have no virtual functions by
+ // definition, whereas polymorphic classes must either declare new
+ // virtual functions or inherit them from some base, and if that base
+ // were non-virtual then there would be a primary base.
+ if ((Base->isDynamicClass() &&
+ Context.getTargetInfo().getCXXABI() != CXXABI_Microsoft) ||
+ (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
+ BaseHasVFPtr(Base))) {
I actually meant this comment to go right before this line:
+ } else if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
+ !PrimaryBase && RD->isPolymorphic() &&
+ (RD->getNumVBases() == 0 || HasNewVirtualFunction(RD))) {
+
+ CharUnits PtrWidth =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+
+ VFPtrOffset = getSize();
+ setSize(getSize() + PtrWidth);
+ setDataSize(getSize());
}
Also, this condition:
+ if ((Base->isDynamicClass() &&
+ Context.getTargetInfo().getCXXABI() != CXXABI_Microsoft) ||
+ (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
+ BaseHasVFPtr(Base))) {
You've actually lost the isPolymorphic() test. I suggest pulling this out as
a separate function:
bool isPossiblePrimaryBase(const CXXRecordDecl *Base) {
if (Context.getTargetInfo().getCXXABI() != CXXABI_Microsoft)
return Base->isDynamicClass();
return Base->isPolymorphic() && BaseHasVFPtr(Base);
}
Also, I know this isn't new to your patch, but BaseHasVFPtr can be
significantly optimized. Here's a rewrite. :)
/// BaseHasVFPtr - Returns true if the given class has a vfptr we can
/// re-use when laid out as a base-class subobject.
bool
RecordLayoutBuilder::BaseHasVFPtr(const CXXRecordDecl *Base) const {
assert(Base->isPolymorphic() && "asking about a non-polymorphic class?");
// Polymorphic classes without virtual bases must have a vfptr we can use.
if (!Base->getNumVBases()) return true;
// In the MS ABI, primary bases always have vfptrs by definition.
if (Context.getASTRecordLayout(Base).getPrimaryBase()) return true;
// Okay, none of its non-virtual base classes has a vfptr. The class itself
// only gets a vfptr if it defines a new virtual function.
return HasNewVirtualFunction(Base);
}
+ // In MS ABI we must reuse vbtable from base class.
+ const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
+ if (BaseLayout.getVBPtrOffset() != CharUnits::fromQuantity(-1))
+ UseBaseVBTable = true;
This doesn't handle the case of a base class with indirect virtual bases, e.g.:
struct A { int a; };
struct B : virtual A { int b; };
struct C : B { int c; }; // C's layout has no VBPtrOffset, but it does have a vbptr from B
struct D : C { int d; };
So I think we should use this condition, which is incidentally much faster:
if (BaseDecl->getNumVBases())
bool
RecordLayoutBuilder::HasNewVirtualFunction(const CXXRecordDecl *RD) const {
+ if (!RD->getNumBases() && RD->isPolymorphic())
+ return true;
I would just assert on isPolymorphic() here, but if you think it's
convenient to call this on non-polymorphic classes, I would suggest:
if (!RD->isPolymorphic()) return false;
if (!RD->getNumBases()) return true;
Over to the CG world:
+ CharUnits VBPtrOffset = Layout.getVBPtrOffset();
+ if (NextFieldOffset < VBPtrOffset) {
+ AppendBytes(VBPtrOffset - NextFieldOffset);
+ }
+ llvm::Type *Vbptr = llvm::Type::getInt32PtrTy(Types.getLLVMContext());
+ AppendField(VBPtrOffset, Vbptr);
This can just be:
llvm::Type *Vbptr = llvm::Type::getInt32PtrTy(Types.getLLVMContext());
AppendPadding(VBPtrOffset, getTypeAlignment(Vbptr));
AppendField(VBPtrOffset, Vbptr);
+/// MSLayoutVirtualBases - layout the virtual bases of a record decl, like MSVC.
+void
+CGRecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD,
+ const ASTRecordLayout &Layout) {
+ if (!RD->getNumVBases())
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ CharUnits vbaseOffset = Layout.getVBaseClassOffset(BaseDecl);
+ LayoutVirtualBase(BaseDecl, vbaseOffset);
+ }
+}
Please put a comment in here like:
// The vbases list is ordered using a depth-first traversal, which is precisely
// what we need.
Otherwise looks good!
John.
More information about the cfe-dev
mailing list