Reland 192220 "Abstract out parts of thunk emission code, add support for simple thunks when using -cxx-abi microsoft" with relaxed assertions
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192285 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index ab0db1a..2c37709 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -1405,7 +1406,8 @@
// ::= Z # global far
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
switch (MD->getAccess()) {
- default:
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
case AS_private:
if (MD->isStatic())
Out << 'C';
@@ -1858,36 +1860,70 @@
return Mangler.mangle(D);
}
+static void mangleThunkThisAdjustment(const CXXMethodDecl *MD,
+ const ThisAdjustment &Adjustment,
+ MicrosoftCXXNameMangler &Mangler,
+ raw_ostream &Out) {
+ // FIXME: add support for vtordisp thunks.
+ if (Adjustment.NonVirtual != 0) {
+ switch (MD->getAccess()) {
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
+ case AS_private:
+ Out << 'G';
+ break;
+ case AS_protected:
+ Out << 'O';
+ break;
+ case AS_public:
+ Out << 'W';
+ }
+ llvm::APSInt APSNumber(/*BitWidth=*/32, /*isUnsigned=*/true);
+ APSNumber = -Adjustment.NonVirtual;
+ Mangler.mangleNumber(APSNumber);
+ } else {
+ switch (MD->getAccess()) {
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
+ case AS_private:
+ Out << 'A';
+ break;
+ case AS_protected:
+ Out << 'I';
+ break;
+ case AS_public:
+ Out << 'Q';
+ }
+ }
+}
+
void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &Out) {
- // FIXME: this is not yet a complete implementation, but merely a
- // reasonably-working stub to avoid crashing when required to emit a thunk.
MicrosoftCXXNameMangler Mangler(*this, Out);
Out << "\01?";
Mangler.mangleName(MD);
- if (Thunk.This.NonVirtual != 0) {
- // FIXME: add support for protected/private or use mangleFunctionClass.
- Out << "W";
- llvm::APSInt APSNumber(/*BitWidth=*/32 /*FIXME: check on x64*/,
- /*isUnsigned=*/true);
- APSNumber = -Thunk.This.NonVirtual;
- Mangler.mangleNumber(APSNumber);
- } else {
- // FIXME: add support for protected/private or use mangleFunctionClass.
- Out << "Q";
- }
- // FIXME: mangle return adjustment? Most likely includes using an overridee FPT?
- Mangler.mangleFunctionType(MD->getType()->castAs<FunctionProtoType>(), MD);
+ mangleThunkThisAdjustment(MD, Thunk.This, Mangler, Out);
+ if (!Thunk.Return.isEmpty())
+ assert(Thunk.Method != 0 && "Thunk info should hold the overridee decl");
+
+ const CXXMethodDecl *DeclForFPT = Thunk.Method ? Thunk.Method : MD;
+ Mangler.mangleFunctionType(
+ DeclForFPT->getType()->castAs<FunctionProtoType>(), MD);
}
-void MicrosoftMangleContextImpl::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- const ThisAdjustment &,
- raw_ostream &) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle thunk for this destructor yet");
- getDiags().Report(DD->getLocation(), DiagID);
+void MicrosoftMangleContextImpl::mangleCXXDtorThunk(
+ const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &Adjustment, raw_ostream &Out) {
+ // FIXME: Actually, the dtor thunk should be emitted for vector deleting
+ // dtors rather than scalar deleting dtors. Just use the vector deleting dtor
+ // mangling manually until we support both deleting dtor types.
+ assert(Type == Dtor_Deleting);
+ MicrosoftCXXNameMangler Mangler(*this, Out, DD, Type);
+ Out << "\01??_E";
+ Mangler.mangleName(DD->getParent());
+ mangleThunkThisAdjustment(DD, Adjustment, Mangler, Out);
+ Mangler.mangleFunctionType(DD->getType()->castAs<FunctionProtoType>(), DD);
}
void MicrosoftMangleContextImpl::mangleCXXVFTable(
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 9aad711..e0b737c 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -992,6 +992,7 @@
MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
+ assert(!Context.getTargetInfo().getCXXABI().isMicrosoft());
LayoutVTable();
@@ -1904,6 +1905,21 @@
}
}
+struct ItaniumThunkInfoComparator {
+ bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ assert(LHS.Method == 0);
+ assert(RHS.Method == 0);
+
+ if (LHS.This != RHS.This)
+ return LHS.This < RHS.This;
+
+ if (LHS.Return != RHS.Return)
+ return LHS.Return < RHS.Return;
+
+ return false;
+ }
+};
+
/// dumpLayout - Dump the vtable layout.
void VTableBuilder::dumpLayout(raw_ostream& Out) {
// FIXME: write more tests that actually use the dumpLayout output to prevent
@@ -2146,7 +2162,8 @@
const CXXMethodDecl *MD = I->second;
ThunkInfoVectorTy ThunksVector = Thunks[MD];
- std::sort(ThunksVector.begin(), ThunksVector.end());
+ std::sort(ThunksVector.begin(), ThunksVector.end(),
+ ItaniumThunkInfoComparator());
Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
@@ -2233,7 +2250,17 @@
Out << '\n';
}
-
+
+struct VTableThunksComparator {
+ bool operator()(const VTableLayout::VTableThunkTy &LHS,
+ const VTableLayout::VTableThunkTy &RHS) {
+ if (LHS.first == RHS.first) {
+ assert(LHS.second == RHS.second &&
+ "Different thunks should have unique indices!");
+ }
+ return LHS.first < RHS.first;
+ }
+};
}
VTableLayout::VTableLayout(uint64_t NumVTableComponents,
@@ -2252,6 +2279,9 @@
this->VTableComponents.get());
std::copy(VTableThunks, VTableThunks+NumVTableThunks,
this->VTableThunks.get());
+ std::sort(this->VTableThunks.get(),
+ this->VTableThunks.get() + NumVTableThunks,
+ VTableThunksComparator());
}
VTableLayout::~VTableLayout() { }
@@ -2312,7 +2342,6 @@
static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) {
SmallVector<VTableLayout::VTableThunkTy, 1>
VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
- std::sort(VTableThunks.begin(), VTableThunks.end());
return new VTableLayout(Builder.getNumVTableComponents(),
Builder.vtable_component_begin(),
@@ -2520,18 +2549,14 @@
/// AddMethod - Add a single virtual member function to the vftable
/// components vector.
- void AddMethod(const CXXMethodDecl *MD, ThisAdjustment ThisAdjustment,
- ReturnAdjustment ReturnAdjustment) {
+ void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) {
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- assert(ReturnAdjustment.isEmpty() &&
+ assert(TI.Return.isEmpty() &&
"Destructor can't have return adjustment!");
Components.push_back(VTableComponent::MakeDeletingDtor(DD));
} else {
- // Add the return adjustment if necessary.
- if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) {
- VTableThunks[Components.size()].Return = ReturnAdjustment;
- VTableThunks[Components.size()].This = ThisAdjustment;
- }
+ if (!TI.isEmpty())
+ VTableThunks[Components.size()] = TI;
Components.push_back(VTableComponent::MakeFunction(MD));
}
}
@@ -2816,6 +2841,7 @@
FinalOverriders::OverriderInfo Overrider =
Overriders.getOverrider(MD, Base.getBaseOffset());
ThisAdjustment ThisAdjustmentOffset;
+ bool ForceThunk = false;
// Check if this virtual member function overrides
// a method in one of the visited bases.
@@ -2840,8 +2866,7 @@
AddThunk(MD, VTableThunks[OverriddenMethodInfo.VFTableIndex]);
}
- if (ComputeReturnAdjustmentBaseOffset(Context, MD, OverriddenMD)
- .isEmpty()) {
+ if (MD->getResultType() == OverriddenMD->getResultType()) {
// No return adjustment needed - just replace the overridden method info
// with the current info.
MethodInfo MI(OverriddenMethodInfo.VBTableIndex,
@@ -2859,6 +2884,7 @@
// method was in the vftable.
// For now, just mark the overriden method as shadowed by a new slot.
OverriddenMethodInfo.Shadowed = true;
+ ForceThunk = true;
// Also apply this adjustment to the shadowed slots.
if (!ThisAdjustmentOffset.isEmpty()) {
@@ -2907,6 +2933,7 @@
ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
}
if (!ReturnAdjustmentOffset.isEmpty()) {
+ ForceThunk = true;
ReturnAdjustment.NonVirtual =
ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
if (ReturnAdjustmentOffset.VirtualBase) {
@@ -2918,7 +2945,8 @@
}
}
- AddMethod(Overrider.Method, ThisAdjustmentOffset, ReturnAdjustment);
+ AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
+ ForceThunk ? MD : 0));
}
}
@@ -2929,6 +2957,20 @@
}
}
+struct MicrosoftThunkInfoStableSortComparator {
+ bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ if (LHS.This != RHS.This)
+ return LHS.This < RHS.This;
+
+ if (LHS.Return != RHS.Return)
+ return LHS.Return < RHS.Return;
+
+ // Keep different thunks with the same adjustments in the order they
+ // were put into the vector.
+ return false;
+ }
+};
+
void VFTableBuilder::dumpLayout(raw_ostream &Out) {
Out << "VFTable for ";
PrintBasePath(WhichVFPtr.PathToBaseWithVFPtr, Out);
@@ -3042,7 +3084,8 @@
const CXXMethodDecl *MD = I->second;
ThunkInfoVectorTy ThunksVector = Thunks[MD];
- std::sort(ThunksVector.begin(), ThunksVector.end());
+ std::stable_sort(ThunksVector.begin(), ThunksVector.end(),
+ MicrosoftThunkInfoStableSortComparator());
Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
@@ -3218,7 +3261,6 @@
assert(VFTableLayouts.count(id) == 0);
SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(
Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
- std::sort(VTableThunks.begin(), VTableThunks.end());
VFTableLayouts[id] = new VTableLayout(
Builder.getNumVTableComponents(), Builder.vtable_component_begin(),
VTableThunks.size(), VTableThunks.data(), EmptyAddressPointsMap, true);
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 3a1c8d1..eaeb971 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -339,11 +339,17 @@
SourceLocation CallLoc,
llvm::Value *This) = 0;
+ virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ CallArgList &CallArgs) {}
+
/// Emit any tables needed to implement virtual inheritance. For Itanium,
/// this emits virtual table tables. For the MSVC++ ABI, this emits virtual
/// base tables.
virtual void emitVirtualInheritanceTables(const CXXRecordDecl *RD) = 0;
+ virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) = 0;
+
virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
RValue RV, QualType ResultType);
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index b987eb4..5ede565 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -333,6 +333,9 @@
// Add our adjusted 'this' pointer.
CallArgs.add(RValue::get(AdjustedThisPtr), ThisType);
+ if (isa<CXXDestructorDecl>(MD))
+ CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, GD, CallArgs);
+
// Add the rest of the parameters.
for (FunctionDecl::param_const_iterator I = MD->param_begin(),
E = MD->param_end(); I != E; ++I) {
@@ -390,14 +393,8 @@
setThunkVisibility(CGM, MD, Thunk, Fn);
}
-void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
- bool UseAvailableExternallyLinkage)
-{
- if (CGM.getTarget().getCXXABI().isMicrosoft()) {
- // Emission of thunks is not supported yet in Microsoft ABI.
- return;
- }
-
+void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
+ bool ForVTable) {
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(GD);
// FIXME: re-use FnInfo in this computation.
@@ -435,9 +432,11 @@
}
llvm::Function *ThunkFn = cast<llvm::Function>(Entry);
+ bool ABIHasKeyFunctions = CGM.getTarget().getCXXABI().hasKeyFunctions();
+ bool UseAvailableExternallyLinkage = ForVTable && ABIHasKeyFunctions;
if (!ThunkFn->isDeclaration()) {
- if (UseAvailableExternallyLinkage) {
+ if (!ABIHasKeyFunctions || UseAvailableExternallyLinkage) {
// There is already a thunk emitted for this function, do nothing.
return;
}
@@ -466,14 +465,17 @@
CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
}
- if (UseAvailableExternallyLinkage)
- ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
+ CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable);
}
-void CodeGenVTables::MaybeEmitThunkAvailableExternally(GlobalDecl GD,
- const ThunkInfo &Thunk) {
- // We only want to do this when building with optimizations.
- if (!CGM.getCodeGenOpts().OptimizationLevel)
+void CodeGenVTables::maybeEmitThunkForVTable(GlobalDecl GD,
+ const ThunkInfo &Thunk) {
+ // If the ABI has key functions, only the TU with the key function should emit
+ // the thunk. However, we can allow inlining of thunks if we emit them with
+ // available_externally linkage together with vtables when optimizations are
+ // enabled.
+ if (CGM.getTarget().getCXXABI().hasKeyFunctions() &&
+ !CGM.getCodeGenOpts().OptimizationLevel)
return;
// We can't emit thunks for member functions with incomplete types.
@@ -482,7 +484,7 @@
cast<FunctionType>(MD->getType().getTypePtr())))
return;
- EmitThunk(GD, Thunk, /*UseAvailableExternallyLinkage=*/true);
+ emitThunk(GD, Thunk, /*ForVTable=*/true);
}
void CodeGenVTables::EmitThunks(GlobalDecl GD)
@@ -494,21 +496,18 @@
if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
return;
+ const VTableContext::ThunkInfoVectorTy *ThunkInfoVector;
if (VFTContext.isValid()) {
- // FIXME: This is a temporary solution to force generation of vftables in
- // Microsoft ABI. Remove when we thread VFTableContext through CodeGen.
- VFTContext->getVFPtrOffsets(MD->getParent());
- return;
+ ThunkInfoVector = VFTContext->getThunkInfo(GD);
+ } else {
+ ThunkInfoVector = VTContext.getThunkInfo(GD);
}
- const VTableContext::ThunkInfoVectorTy *ThunkInfoVector =
- VTContext.getThunkInfo(MD);
if (!ThunkInfoVector)
return;
for (unsigned I = 0, E = ThunkInfoVector->size(); I != E; ++I)
- EmitThunk(GD, (*ThunkInfoVector)[I],
- /*UseAvailableExternallyLinkage=*/false);
+ emitThunk(GD, (*ThunkInfoVector)[I], /*ForVTable=*/false);
}
llvm::Constant *
@@ -603,7 +602,7 @@
VTableThunks[NextVTableThunkIndex].first == I) {
const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second;
- MaybeEmitThunkAvailableExternally(GD, Thunk);
+ maybeEmitThunkForVTable(GD, Thunk);
Init = CGM.GetAddrOfThunk(GD, Thunk);
NextVTableThunkIndex++;
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index 9b95952..e17ad89 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -52,15 +52,12 @@
/// indices.
SecondaryVirtualPointerIndicesMapTy SecondaryVirtualPointerIndices;
- /// EmitThunk - Emit a single thunk.
- void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
- bool UseAvailableExternallyLinkage);
+ /// emitThunk - Emit a single thunk.
+ void emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool ForVTable);
- /// MaybeEmitThunkAvailableExternally - Try to emit the given thunk with
- /// available_externally linkage to allow for inlining of thunks.
- /// This will be done iff optimizations are enabled and the member function
- /// doesn't contain any incomplete types.
- void MaybeEmitThunkAvailableExternally(GlobalDecl GD, const ThunkInfo &Thunk);
+ /// maybeEmitThunkForVTable - Emit the given thunk for the vtable if needed by
+ /// the ABI.
+ void maybeEmitThunkForVTable(GlobalDecl GD, const ThunkInfo &Thunk);
public:
/// CreateVTableInitializer - Create a vtable initializer for the given record
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index ecf5d57..1e34a16 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -173,6 +173,13 @@
void emitVirtualInheritanceTables(const CXXRecordDecl *RD);
+ void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) {
+ // Allow inlining of thunks by emitting them with available_externally
+ // linkage together with vtables when needed.
+ if (ForVTable)
+ Thunk->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
+ }
+
StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 1d73b21..7452c86 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -173,8 +173,20 @@
CXXDtorType DtorType, SourceLocation CallLoc,
llvm::Value *This);
+ void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF, GlobalDecl GD,
+ CallArgList &CallArgs) {
+ assert(GD.getDtorType() == Dtor_Deleting &&
+ "Only deleting destructor thunks are available in this ABI");
+ CallArgs.add(RValue::get(getStructorImplicitParamValue(CGF)),
+ CGM.getContext().IntTy);
+ }
+
void emitVirtualInheritanceTables(const CXXRecordDecl *RD);
+ void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) {
+ Thunk->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
+ }
+
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr,
bool PerformInit);