From 4410489163931892b568f0a43bd49c430a3aa3f5 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 2 Apr 2013 16:23:57 +0000 Subject: [PATCH] [ms-cxxabi] Move MS inheritance model calculation into MemberPointerType Summary: This makes it possible to share code between lib/AST/MicrosoftCXXABI.cpp and lib/CodeGen/MicrosoftCXXABI.cpp. No functionality change. Also adds comments about the layout of the member pointer structs as I currently understand them. Reviewers: rjmccall CC: timurrrr, cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D590 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178548 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclCXX.h | 3 + include/clang/AST/Type.h | 12 ++++ lib/AST/MicrosoftCXXABI.cpp | 120 +++++++++++++++++++++++++----------- 3 files changed, 98 insertions(+), 37 deletions(-) diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 0d24b0822a..430e6d8cc5 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1532,6 +1532,9 @@ public: getLambdaData().ContextDecl = ContextDecl; } + /// \brief Returns the inheritance model used for this record. + MSInheritanceModel getMSInheritanceModel() const; + /// \brief Determine whether this lambda expression was known to be dependent /// at the time it was created, even if its context does not appear to be /// dependent. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index e0402148b5..ec736688b1 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2092,6 +2092,14 @@ public: } }; +/// The inheritance model to use for this member pointer. +enum MSInheritanceModel { + IHM_Single, + IHM_Multiple, + IHM_Virtual, + IHM_Unspecified +}; + /// MemberPointerType - C++ 8.3.3 - Pointers to members /// class MemberPointerType : public Type, public llvm::FoldingSetNode { @@ -2127,6 +2135,10 @@ public: return !PointeeType->isFunctionProtoType(); } + /// Returns the number of pointer and integer slots used to represent this + /// member pointer in the MS C++ ABI. + std::pair getMSMemberPointerSlots() const; + const Type *getClass() const { return Class; } bool isSugared() const { return false; } diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index 2f41cec718..d5a1504219 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -57,7 +57,7 @@ public: // getNumBases() seems to only give us the number of direct bases, and not the // total. This function tells us if we inherit from anybody that uses MI, or if // we have a non-primary base class, which uses the multiple inheritance model. -static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) { +bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) { while (RD->getNumBases() > 0) { if (RD->getNumBases() > 1) return true; @@ -70,60 +70,106 @@ static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) { return false; } -std::pair -MicrosoftCXXABI::getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const { - const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); - const TargetInfo &Target = Context.getTargetInfo(); - - assert(Target.getTriple().getArch() == llvm::Triple::x86 || - Target.getTriple().getArch() == llvm::Triple::x86_64); - - Attr *IA = RD->getAttr(); - attr::Kind Inheritance; - if (IA) { - Inheritance = IA->getKind(); - } else if (RD->getNumVBases() > 0) { - Inheritance = attr::VirtualInheritance; - } else if (MPT->getPointeeType()->isFunctionType() && - usesMultipleInheritanceModel(RD)) { - Inheritance = attr::MultipleInheritance; - } else { - Inheritance = attr::SingleInheritance; +MSInheritanceModel MSInheritanceAttrToModel(attr::Kind Kind) { + switch (Kind) { + default: llvm_unreachable("expected MS inheritance attribute"); + case attr::SingleInheritance: return IHM_Single; + case attr::MultipleInheritance: return IHM_Multiple; + case attr::VirtualInheritance: return IHM_Virtual; + case attr::UnspecifiedInheritance: return IHM_Unspecified; } +} - unsigned PtrSize = Target.getPointerWidth(0); - unsigned IntSize = Target.getIntWidth(); - uint64_t Width; - unsigned Align; - if (MPT->getPointeeType()->isFunctionType()) { +MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const { + Attr *IA = this->getAttr(); + if (IA) + return MSInheritanceAttrToModel(IA->getKind()); + // If there was no explicit attribute, the record must be defined already, and + // we can figure out the inheritance model from its other properties. + if (this->getNumVBases() > 0) + return IHM_Virtual; + if (usesMultipleInheritanceModel(this)) + return IHM_Multiple; + return IHM_Single; +} + +// Returns the number of pointer and integer slots used to represent a member +// pointer in the MS C++ ABI. +// +// Member function pointers have the following general form; however, fields +// are dropped as permitted (under the MSVC interpretation) by the inheritance +// model of the actual class. +// +// struct { +// // A pointer to the member function to call. If the member function is +// // virtual, this will be a thunk that forwards to the appropriate vftable +// // slot. +// void *FunctionPointerOrVirtualThunk; +// +// // An offset to add to the address of the vbtable pointer after (possibly) +// // selecting the virtual base but before resolving and calling the function. +// // Only needed if the class has any virtual bases or bases at a non-zero +// // offset. +// int NonVirtualBaseAdjustment; +// +// // An offset within the vb-table that selects the virtual base containing +// // the member. Loading from this offset produces a new offset that is +// // added to the address of the vb-table pointer to produce the base. +// int VirtualBaseAdjustmentOffset; +// +// // The offset of the vb-table pointer within the object. Only needed for +// // incomplete types. +// int VBTableOffset; +// }; +std::pair MemberPointerType::getMSMemberPointerSlots() const { + const CXXRecordDecl *RD = this->getClass()->getAsCXXRecordDecl(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + unsigned Ptrs; + unsigned Ints = 0; + if (this->isMemberFunctionPointer()) { // Member function pointers are a struct of a function pointer followed by a // variable number of ints depending on the inheritance model used. The // function pointer is a real function if it is non-virtual and a vftable // slot thunk if it is virtual. The ints select the object base passed for // the 'this' pointer. - Align = Target.getPointerAlign(0); + Ptrs = 1; // First slot is always a function pointer. switch (Inheritance) { - case attr::SingleInheritance: Width = PtrSize; break; - case attr::MultipleInheritance: Width = PtrSize + 1 * IntSize; break; - case attr::VirtualInheritance: Width = PtrSize + 2 * IntSize; break; - case attr::UnspecifiedInheritance: Width = PtrSize + 3 * IntSize; break; default: llvm_unreachable("unknown inheritance model"); + case IHM_Unspecified: ++Ints; // VBTableOffset + case IHM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset + case IHM_Multiple: ++Ints; // NonVirtualBaseAdjustment + case IHM_Single: break; // Nothing } } else { // Data pointers are an aggregate of ints. The first int is an offset // followed by vbtable-related offsets. - Align = Target.getIntAlign(); + Ptrs = 0; switch (Inheritance) { - case attr::SingleInheritance: // Same as multiple inheritance. - case attr::MultipleInheritance: Width = 1 * IntSize; break; - case attr::VirtualInheritance: Width = 2 * IntSize; break; - case attr::UnspecifiedInheritance: Width = 3 * IntSize; break; default: llvm_unreachable("unknown inheritance model"); + case IHM_Unspecified: ++Ints; // VBTableOffset + case IHM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset + case IHM_Multiple: // Nothing + case IHM_Single: ++Ints; // Field offset } } - Width = llvm::RoundUpToAlignment(Width, Align); + return std::make_pair(Ptrs, Ints); +} - // FIXME: Verify that our alignment matches MSVC. +std::pair +MicrosoftCXXABI::getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const { + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + const TargetInfo &Target = Context.getTargetInfo(); + assert(Target.getTriple().getArch() == llvm::Triple::x86 || + Target.getTriple().getArch() == llvm::Triple::x86_64); + unsigned Ptrs, Ints; + llvm::tie(Ptrs, Ints) = MPT->getMSMemberPointerSlots(); + // The nominal struct is laid out with pointers followed by ints and aligned + // to a pointer width if any are present and an int width otherwise. + unsigned PtrSize = Target.getPointerWidth(0); + unsigned IntSize = Target.getIntWidth(); + uint64_t Width = Ptrs * PtrSize + Ints * IntSize; + unsigned Align = Ptrs > 0 ? Target.getPointerAlign(0) : Target.getIntAlign(); + Width = llvm::RoundUpToAlignment(Width, Align); return std::make_pair(Width, Align); } -- 2.40.0