summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorTimur Iskhodzhanov <timurrrr@google.com>2013-11-06 06:24:31 +0000
committerTimur Iskhodzhanov <timurrrr@google.com>2013-11-06 06:24:31 +0000
commit053142a90d700c21e491444d6996bb1ff80fa0e2 (patch)
tree2e96d9574c342b5d807cbb69c39b23e6df2f9bb8 /clang/lib
parent67b277c34fc517ea9f17e5505d9c420485224239 (diff)
downloadbcm5719-llvm-053142a90d700c21e491444d6996bb1ff80fa0e2.tar.gz
bcm5719-llvm-053142a90d700c21e491444d6996bb1ff80fa0e2.zip
Fix PR17738 - add support for vtordisp thunks when using -cxx-abi microsoft
llvm-svn: 194132
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp7
-rw-r--r--clang/lib/AST/MicrosoftMangle.cpp71
-rw-r--r--clang/lib/AST/VTableBuilder.cpp109
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp3
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp25
5 files changed, 171 insertions, 44 deletions
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 953bff20ad6..3d0e7253d76 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -3657,8 +3657,9 @@ void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
Mangler.getStream() << 'c';
// Mangle the 'this' pointer adjustment.
- Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset);
-
+ Mangler.mangleCallOffset(Thunk.This.NonVirtual,
+ Thunk.This.Virtual.Itanium.VCallOffsetOffset);
+
// Mangle the return pointer adjustment if there is one.
if (!Thunk.Return.isEmpty())
Mangler.mangleCallOffset(Thunk.Return.NonVirtual,
@@ -3677,7 +3678,7 @@ void ItaniumMangleContextImpl::mangleCXXDtorThunk(
// Mangle the 'this' pointer adjustment.
Mangler.mangleCallOffset(ThisAdjustment.NonVirtual,
- ThisAdjustment.VCallOffsetOffset);
+ ThisAdjustment.Virtual.Itanium.VCallOffsetOffset);
Mangler.mangleFunctionEncoding(DD);
}
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 08d1eb07a32..c36c16745c0 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -121,7 +121,7 @@ public:
void mangleDeclaration(const NamedDecl *ND);
void mangleFunctionEncoding(const FunctionDecl *FD);
void mangleVariableEncoding(const VarDecl *VD);
- void mangleNumber(int64_t Number);
+ void mangleNumber(uint32_t Number);
void mangleNumber(const llvm::APSInt &Value);
void mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM = QMM_Mangle);
@@ -387,8 +387,8 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
Out << '@';
}
-void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
- llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false);
+void MicrosoftCXXNameMangler::mangleNumber(uint32_t Number) {
+ llvm::APSInt APSNumber(/*BitWidth=*/32, /*isUnsigned=*/true);
APSNumber = Number;
mangleNumber(APSNumber);
}
@@ -836,7 +836,7 @@ void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) {
// functions. You could have a method baz of class C inside a function bar
// inside a function foo, like so:
// ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ
- int NestLevel = getLocalNestingLevel(FD);
+ unsigned NestLevel = getLocalNestingLevel(FD);
Out << '?';
mangleNumber(NestLevel);
Out << '?';
@@ -1367,24 +1367,18 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
// ::= D # private: static far
// ::= E # private: virtual near
// ::= F # private: virtual far
- // ::= G # private: thunk near
- // ::= H # private: thunk far
// ::= I # protected: near
// ::= J # protected: far
// ::= K # protected: static near
// ::= L # protected: static far
// ::= M # protected: virtual near
// ::= N # protected: virtual far
- // ::= O # protected: thunk near
- // ::= P # protected: thunk far
// ::= Q # public: near
// ::= R # public: far
// ::= S # public: static near
// ::= T # public: static far
// ::= U # public: virtual near
// ::= V # public: virtual far
- // ::= W # public: thunk near
- // ::= X # public: thunk far
// <global-function> ::= Y # global near
// ::= Z # global far
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
@@ -1843,12 +1837,61 @@ void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D,
return Mangler.mangle(D);
}
+// <this-adjustment> ::= <no-adjustment> | <static-adjustment> |
+// <virtual-adjustment>
+// <no-adjustment> ::= A # private near
+// ::= B # private far
+// ::= I # protected near
+// ::= J # protected far
+// ::= Q # public near
+// ::= R # public far
+// <static-adjustment> ::= G <static-offset> # private near
+// ::= H <static-offset> # private far
+// ::= O <static-offset> # protected near
+// ::= P <static-offset> # protected far
+// ::= W <static-offset> # public near
+// ::= X <static-offset> # public far
+// <virtual-adjustment> ::= $0 <virtual-shift> <static-offset> # private near
+// ::= $1 <virtual-shift> <static-offset> # private far
+// ::= $2 <virtual-shift> <static-offset> # protected near
+// ::= $3 <virtual-shift> <static-offset> # protected far
+// ::= $4 <virtual-shift> <static-offset> # public near
+// ::= $5 <virtual-shift> <static-offset> # public far
+// <virtual-shift> ::= <vtordisp-shift> | <vtordispex-shift>
+// <vtordisp-shift> ::= <offset-to-vtordisp>
+// <vtordispex-shift> ::= <offset-to-vbptr> <vbase-offset-offset>
+// <offset-to-vtordisp>
static void mangleThunkThisAdjustment(const CXXMethodDecl *MD,
const ThisAdjustment &Adjustment,
MicrosoftCXXNameMangler &Mangler,
raw_ostream &Out) {
- // FIXME: add support for vtordisp thunks.
- if (Adjustment.NonVirtual != 0) {
+ if (!Adjustment.Virtual.isEmpty()) {
+ Out << '$';
+ char AccessSpec;
+ switch (MD->getAccess()) {
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
+ case AS_private:
+ AccessSpec = '0';
+ break;
+ case AS_protected:
+ AccessSpec = '2';
+ break;
+ case AS_public:
+ AccessSpec = '4';
+ }
+ if (Adjustment.Virtual.Microsoft.VBPtrOffset) {
+ Out << 'R' << AccessSpec;
+ Mangler.mangleNumber(Adjustment.Virtual.Microsoft.VBPtrOffset);
+ Mangler.mangleNumber(Adjustment.Virtual.Microsoft.VBOffsetOffset);
+ Mangler.mangleNumber(Adjustment.Virtual.Microsoft.VtordispOffset);
+ Mangler.mangleNumber(Adjustment.NonVirtual);
+ } else {
+ Out << AccessSpec;
+ Mangler.mangleNumber(Adjustment.Virtual.Microsoft.VtordispOffset);
+ Mangler.mangleNumber(-Adjustment.NonVirtual);
+ }
+ } else if (Adjustment.NonVirtual != 0) {
switch (MD->getAccess()) {
case AS_none:
llvm_unreachable("Unsupported access specifier");
@@ -1861,9 +1904,7 @@ static void mangleThunkThisAdjustment(const CXXMethodDecl *MD,
case AS_public:
Out << 'W';
}
- llvm::APSInt APSNumber(/*BitWidth=*/32, /*isUnsigned=*/true);
- APSNumber = -Adjustment.NonVirtual;
- Mangler.mangleNumber(APSNumber);
+ Mangler.mangleNumber(-Adjustment.NonVirtual);
} else {
switch (MD->getAccess()) {
case AS_none:
diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp
index 69a2fb2136f..efaa313a67b 100644
--- a/clang/lib/AST/VTableBuilder.cpp
+++ b/clang/lib/AST/VTableBuilder.cpp
@@ -1304,7 +1304,7 @@ ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment(
VCallOffsets = Builder.getVCallOffsets();
}
- Adjustment.VCallOffsetOffset =
+ Adjustment.Virtual.Itanium.VCallOffsetOffset =
VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
}
@@ -1552,7 +1552,7 @@ void ItaniumVTableBuilder::AddMethods(
ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
Overrider);
- if (ThisAdjustment.VCallOffsetOffset &&
+ if (ThisAdjustment.Virtual.Itanium.VCallOffsetOffset &&
Overrider.Method->getParent() == MostDerivedClass) {
// There's no return adjustment from OverriddenMD and MD,
@@ -2009,8 +2009,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
Out << "\n [this adjustment: ";
Out << Thunk.This.NonVirtual << " non-virtual";
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
+ if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
Out << " vcall offset offset";
}
@@ -2044,8 +2044,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
Out << "\n [this adjustment: ";
Out << Thunk.This.NonVirtual << " non-virtual";
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
+ if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
Out << " vcall offset offset";
}
@@ -2186,8 +2186,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
Out << "this adjustment: ";
Out << Thunk.This.NonVirtual << " non-virtual";
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
+ if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
Out << " vcall offset offset";
}
}
@@ -2527,6 +2527,9 @@ private:
BaseSubobject Base,
FinalOverriders::OverriderInfo Overrider);
+ void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider,
+ CharUnits ThisOffset, ThisAdjustment &TA);
+
/// AddMethod - Add a single virtual member function to the vftable
/// components vector.
void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) {
@@ -2672,7 +2675,7 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
I != E; ++I) {
const CXXBasePath &Path = (*I);
CharUnits ThisOffset = Base.getBaseOffset();
- bool SeenVBase = false;
+ CharUnits LastVBaseOffset;
// For each path from the overrider to the parents of the overridden methods,
// traverse the path, calculating the this offset in the most derived class.
@@ -2684,7 +2687,7 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD);
if (Element.Base->isVirtual()) {
- SeenVBase = true;
+ LastVBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD);
if (Overrider.Method->getParent() == PrevRD) {
// This one's interesting. If the final overrider is in a vbase B of the
// most derived class and it overrides a method of the B's own vbase A,
@@ -2695,23 +2698,25 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
// differently in the most derived class.
ThisOffset += Layout.getVBaseClassOffset(CurRD);
} else {
- ThisOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD);
+ ThisOffset = LastVBaseOffset;
}
-
- // A virtual destructor of a virtual base takes the address of the
- // virtual base subobject as the "this" argument.
- if (isa<CXXDestructorDecl>(MD))
- break;
} else {
ThisOffset += Layout.getBaseClassOffset(CurRD);
}
}
- // If a "Base" class has at least one non-virtual base with a virtual
- // destructor, the "Base" virtual destructor will take the address of the
- // "Base" subobject as the "this" argument.
- if (!SeenVBase && isa<CXXDestructorDecl>(MD))
- return Base.getBaseOffset();
+ if (isa<CXXDestructorDecl>(MD)) {
+ if (LastVBaseOffset.isZero()) {
+ // If a "Base" class has at least one non-virtual base with a virtual
+ // destructor, the "Base" virtual destructor will take the address
+ // of the "Base" subobject as the "this" argument.
+ return Base.getBaseOffset();
+ } else {
+ // A virtual destructor of a virtual base takes the address of the
+ // virtual base subobject as the "this" argument.
+ return LastVBaseOffset;
+ }
+ }
if (Ret > ThisOffset || First) {
First = false;
@@ -2723,6 +2728,49 @@ VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
return Ret;
}
+void VFTableBuilder::CalculateVtordispAdjustment(
+ FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset,
+ ThisAdjustment &TA) {
+ const ASTRecordLayout::VBaseOffsetsMapTy &VBaseMap =
+ MostDerivedClassLayout.getVBaseOffsetsMap();
+ const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry =
+ VBaseMap.find(WhichVFPtr.LastVBase);
+ assert(VBaseMapEntry != VBaseMap.end());
+
+ // Check if we need a vtordisp adjustment at all.
+ if (!VBaseMapEntry->second.hasVtorDisp())
+ return;
+
+ CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
+ // The implicit vtordisp field is located right before the vbase.
+ TA.Virtual.Microsoft.VtordispOffset =
+ (VFPtrVBaseOffset - WhichVFPtr.VFPtrFullOffset).getQuantity() - 4;
+
+ // If the final overrider is defined in either:
+ // - the most derived class or its non-virtual base or
+ // - the same vbase as the initial declaration,
+ // a simple vtordisp thunk will suffice.
+ const CXXRecordDecl *OverriderRD = Overrider.Method->getParent();
+ if (OverriderRD == MostDerivedClass)
+ return;
+
+ const CXXRecordDecl *OverriderVBase =
+ ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase;
+ if (!OverriderVBase || OverriderVBase == WhichVFPtr.LastVBase)
+ return;
+
+ // Otherwise, we need to do use the dynamic offset of the final overrider
+ // in order to get "this" adjustment right.
+ TA.Virtual.Microsoft.VBPtrOffset =
+ (VFPtrVBaseOffset + WhichVFPtr.VFPtrOffset -
+ MostDerivedClassLayout.getVBPtrOffset()).getQuantity();
+ TA.Virtual.Microsoft.VBOffsetOffset =
+ Context.getTypeSizeInChars(Context.IntTy).getQuantity() *
+ VTables.getVBTableIndex(MostDerivedClass, OverriderVBase);
+
+ TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity();
+}
+
static void GroupNewVirtualOverloads(
const CXXRecordDecl *RD,
SmallVector<const CXXMethodDecl *, 10> &VirtualMethods) {
@@ -2829,6 +2877,12 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
if (TI != WhichVFPtr.VFPtrFullOffset) {
ThisAdjustmentOffset.NonVirtual =
(TI - WhichVFPtr.VFPtrFullOffset).getQuantity();
+ }
+
+ if (WhichVFPtr.LastVBase)
+ CalculateVtordispAdjustment(Overrider, TI, ThisAdjustmentOffset);
+
+ if (!ThisAdjustmentOffset.isEmpty()) {
VTableThunks[OverriddenMethodInfo.VFTableIndex].This =
ThisAdjustmentOffset;
AddThunk(MD, VTableThunks[OverriddenMethodInfo.VFTableIndex]);
@@ -2962,8 +3016,17 @@ static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out,
if (Multiline || !ContinueFirstLine)
Out << LinePrefix;
Out << "[this adjustment: ";
- assert(TI.This.VCallOffsetOffset == 0 &&
- "VtorDisp adjustment is not supported yet");
+ if (!TI.This.Virtual.isEmpty()) {
+ assert(T.Virtual.Microsoft.VtordispOffset < 0);
+ Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", ";
+ if (T.Virtual.Microsoft.VBPtrOffset) {
+ Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset
+ << " to the left, ";
+ assert(T.Virtual.Microsoft.VBOffsetOffset > 0);
+ Out << LinePrefix << " vboffset at "
+ << T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, ";
+ }
+ }
Out << T.NonVirtual << " non-virtual]";
}
}
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 9b7cf17030a..0e8f31a4845 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -1118,7 +1118,8 @@ static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
llvm::Value *ItaniumCXXABI::performThisAdjustment(CodeGenFunction &CGF,
llvm::Value *This,
const ThisAdjustment &TA) {
- return performTypeAdjustment(CGF, This, TA.NonVirtual, TA.VCallOffsetOffset,
+ return performTypeAdjustment(CGF, This, TA.NonVirtual,
+ TA.Virtual.Itanium.VCallOffsetOffset,
/*IsReturnAdjustment=*/false);
}
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 7e3a47d9131..6415749e2df 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -988,8 +988,29 @@ llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF,
llvm::Value *V = CGF.Builder.CreateBitCast(This, CGF.Int8PtrTy);
- assert(TA.VCallOffsetOffset == 0 &&
- "VtorDisp adjustment is not supported yet");
+ if (!TA.Virtual.isEmpty()) {
+ assert(TA.Virtual.Microsoft.VtordispOffset < 0);
+ // Adjust the this argument based on the vtordisp value.
+ llvm::Value *VtorDispPtr =
+ CGF.Builder.CreateConstGEP1_32(V, TA.Virtual.Microsoft.VtordispOffset);
+ VtorDispPtr =
+ CGF.Builder.CreateBitCast(VtorDispPtr, CGF.Int32Ty->getPointerTo());
+ llvm::Value *VtorDisp = CGF.Builder.CreateLoad(VtorDispPtr, "vtordisp");
+ V = CGF.Builder.CreateGEP(V, CGF.Builder.CreateNeg(VtorDisp));
+
+ if (TA.Virtual.Microsoft.VBPtrOffset) {
+ // If the final overrider is defined in a virtual base other than the one
+ // that holds the vfptr, we have to use a vtordispex thunk which looks up
+ // the vbtable of the derived class.
+ assert(TA.Virtual.Microsoft.VBPtrOffset > 0);
+ assert(TA.Virtual.Microsoft.VBOffsetOffset >= 0);
+ llvm::Value *VBPtr;
+ llvm::Value *VBaseOffset =
+ GetVBaseOffsetFromVBPtr(CGF, V, -TA.Virtual.Microsoft.VBPtrOffset,
+ TA.Virtual.Microsoft.VBOffsetOffset, &VBPtr);
+ V = CGF.Builder.CreateInBoundsGEP(VBPtr, VBaseOffset);
+ }
+ }
if (TA.NonVirtual) {
// Non-virtual adjustment might result in a pointer outside the allocated
OpenPOWER on IntegriCloud