forked from OSchip/llvm-project
Make thunk this/return adjustment ABI-specific. Also, fix the return adjustment when using -cxx-abi microsoft
Reviewed at http://llvm-reviews.chandlerc.com/D2026 llvm-svn: 193679
This commit is contained in:
parent
580da27616
commit
0201432a5e
|
@ -39,19 +39,52 @@ struct ReturnAdjustment {
|
|||
/// \brief The non-virtual adjustment from the derived object to its
|
||||
/// nearest virtual base.
|
||||
int64_t NonVirtual;
|
||||
|
||||
/// \brief Holds the ABI-specific information about the virtual return
|
||||
/// adjustment, if needed.
|
||||
union VirtualAdjustment {
|
||||
// Itanium ABI
|
||||
struct {
|
||||
/// \brief The offset (in bytes), relative to the address point
|
||||
/// of the virtual base class offset.
|
||||
int64_t VBaseOffsetOffset;
|
||||
} Itanium;
|
||||
|
||||
// Microsoft ABI
|
||||
struct {
|
||||
/// \brief The offset (in bytes) of the vbptr, relative to the beginning
|
||||
/// of the derived class.
|
||||
uint32_t VBPtrOffset;
|
||||
|
||||
/// \brief Index of the virtual base in the vbtable.
|
||||
uint32_t VBIndex;
|
||||
} Microsoft;
|
||||
|
||||
VirtualAdjustment() {
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
bool Equals(const VirtualAdjustment &Other) const {
|
||||
return memcmp(this, &Other, sizeof(Other)) == 0;
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
VirtualAdjustment Zero;
|
||||
return Equals(Zero);
|
||||
}
|
||||
|
||||
bool Less(const VirtualAdjustment &RHS) const {
|
||||
return memcmp(this, &RHS, sizeof(RHS)) < 0;
|
||||
}
|
||||
} Virtual;
|
||||
|
||||
/// \brief The offset (in bytes), relative to the address point
|
||||
/// of the virtual base class offset.
|
||||
int64_t VBaseOffsetOffset;
|
||||
ReturnAdjustment() : NonVirtual(0) {}
|
||||
|
||||
ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { }
|
||||
|
||||
bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; }
|
||||
bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); }
|
||||
|
||||
friend bool operator==(const ReturnAdjustment &LHS,
|
||||
const ReturnAdjustment &RHS) {
|
||||
return LHS.NonVirtual == RHS.NonVirtual &&
|
||||
LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset;
|
||||
return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(RHS.Virtual);
|
||||
}
|
||||
|
||||
friend bool operator!=(const ReturnAdjustment &LHS, const ReturnAdjustment &RHS) {
|
||||
|
@ -62,9 +95,8 @@ struct ReturnAdjustment {
|
|||
const ReturnAdjustment &RHS) {
|
||||
if (LHS.NonVirtual < RHS.NonVirtual)
|
||||
return true;
|
||||
|
||||
return LHS.NonVirtual == RHS.NonVirtual &&
|
||||
LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset;
|
||||
|
||||
return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS.Virtual);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -3657,8 +3657,8 @@ void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
|
|||
// Mangle the return pointer adjustment if there is one.
|
||||
if (!Thunk.Return.isEmpty())
|
||||
Mangler.mangleCallOffset(Thunk.Return.NonVirtual,
|
||||
Thunk.Return.VBaseOffsetOffset);
|
||||
|
||||
Thunk.Return.Virtual.Itanium.VBaseOffsetOffset);
|
||||
|
||||
Mangler.mangleFunctionEncoding(MD);
|
||||
}
|
||||
|
||||
|
|
|
@ -1203,10 +1203,10 @@ ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
|
|||
// Get the virtual base offset offset.
|
||||
if (Offset.DerivedClass == MostDerivedClass) {
|
||||
// We can get the offset offset directly from our map.
|
||||
Adjustment.VBaseOffsetOffset =
|
||||
Adjustment.Virtual.Itanium.VBaseOffsetOffset =
|
||||
VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
|
||||
} else {
|
||||
Adjustment.VBaseOffsetOffset =
|
||||
Adjustment.Virtual.Itanium.VBaseOffsetOffset =
|
||||
VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
|
||||
Offset.VirtualBase).getQuantity();
|
||||
}
|
||||
|
@ -1304,7 +1304,7 @@ ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment(
|
|||
VCallOffsets = Builder.getVCallOffsets();
|
||||
}
|
||||
|
||||
Adjustment.VCallOffsetOffset =
|
||||
Adjustment.VCallOffsetOffset =
|
||||
VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
|
||||
}
|
||||
|
||||
|
@ -1996,8 +1996,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
|
|||
Out << "\n [return adjustment: ";
|
||||
Out << Thunk.Return.NonVirtual << " non-virtual";
|
||||
|
||||
if (Thunk.Return.VBaseOffsetOffset) {
|
||||
Out << ", " << Thunk.Return.VBaseOffsetOffset;
|
||||
if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) {
|
||||
Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset;
|
||||
Out << " vbase offset offset";
|
||||
}
|
||||
|
||||
|
@ -2172,8 +2172,8 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
|
|||
if (!Thunk.Return.isEmpty()) {
|
||||
Out << "return adjustment: " << Thunk.Return.NonVirtual;
|
||||
Out << " non-virtual";
|
||||
if (Thunk.Return.VBaseOffsetOffset) {
|
||||
Out << ", " << Thunk.Return.VBaseOffsetOffset;
|
||||
if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) {
|
||||
Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset;
|
||||
Out << " vbase offset offset";
|
||||
}
|
||||
|
||||
|
@ -2911,9 +2911,11 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
|
|||
ReturnAdjustment.NonVirtual =
|
||||
ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
|
||||
if (ReturnAdjustmentOffset.VirtualBase) {
|
||||
// FIXME: We might want to create a VBIndex alias for VBaseOffsetOffset
|
||||
// in the ReturnAdjustment struct.
|
||||
ReturnAdjustment.VBaseOffsetOffset =
|
||||
const ASTRecordLayout &DerivedLayout =
|
||||
Context.getASTRecordLayout(ReturnAdjustmentOffset.DerivedClass);
|
||||
ReturnAdjustment.Virtual.Microsoft.VBPtrOffset =
|
||||
DerivedLayout.getVBPtrOffset().getQuantity();
|
||||
ReturnAdjustment.Virtual.Microsoft.VBIndex =
|
||||
GetVBTableIndex(ReturnAdjustmentOffset.DerivedClass,
|
||||
ReturnAdjustmentOffset.VirtualBase);
|
||||
}
|
||||
|
@ -2945,6 +2947,34 @@ struct MicrosoftThunkInfoStableSortComparator {
|
|||
}
|
||||
};
|
||||
|
||||
static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out,
|
||||
bool ContinueFirstLine) {
|
||||
const ReturnAdjustment &R = TI.Return;
|
||||
bool Multiline = false;
|
||||
const char *LinePrefix = "\n ";
|
||||
if (!R.isEmpty()) {
|
||||
if (!ContinueFirstLine)
|
||||
Out << LinePrefix;
|
||||
Out << "[return adjustment: ";
|
||||
if (R.Virtual.Microsoft.VBPtrOffset)
|
||||
Out << "vbptr at offset " << R.Virtual.Microsoft.VBPtrOffset << ", ";
|
||||
if (R.Virtual.Microsoft.VBIndex)
|
||||
Out << "vbase #" << R.Virtual.Microsoft.VBIndex << ", ";
|
||||
Out << R.NonVirtual << " non-virtual]";
|
||||
Multiline = true;
|
||||
}
|
||||
|
||||
const ThisAdjustment &T = TI.This;
|
||||
if (!T.isEmpty()) {
|
||||
if (Multiline || !ContinueFirstLine)
|
||||
Out << LinePrefix;
|
||||
Out << "[this adjustment: ";
|
||||
assert(TI.This.VCallOffsetOffset == 0 &&
|
||||
"VtorDisp adjustment is not supported yet");
|
||||
Out << T.NonVirtual << " non-virtual]";
|
||||
}
|
||||
}
|
||||
|
||||
void VFTableBuilder::dumpLayout(raw_ostream &Out) {
|
||||
Out << "VFTable for ";
|
||||
PrintBasePath(WhichVFPtr.PathToBaseWithVFPtr, Out);
|
||||
|
@ -2977,23 +3007,8 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
|
|||
}
|
||||
|
||||
ThunkInfo Thunk = VTableThunks.lookup(I);
|
||||
if (!Thunk.isEmpty()) {
|
||||
// If this function pointer has a return adjustment, dump it.
|
||||
if (!Thunk.Return.isEmpty()) {
|
||||
Out << "\n [return adjustment: ";
|
||||
if (Thunk.Return.VBaseOffsetOffset)
|
||||
Out << "vbase #" << Thunk.Return.VBaseOffsetOffset << ", ";
|
||||
Out << Thunk.Return.NonVirtual << " non-virtual]";
|
||||
}
|
||||
|
||||
// If this function pointer has a 'this' pointer adjustment, dump it.
|
||||
if (!Thunk.This.isEmpty()) {
|
||||
assert(!Thunk.This.VCallOffsetOffset &&
|
||||
"No virtual this adjustment in this ABI");
|
||||
Out << "\n [this adjustment: " << Thunk.This.NonVirtual
|
||||
<< " non-virtual]";
|
||||
}
|
||||
}
|
||||
if (!Thunk.isEmpty())
|
||||
dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -3011,13 +3026,7 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
|
|||
if (!Thunk.isEmpty()) {
|
||||
assert(Thunk.Return.isEmpty() &&
|
||||
"No return adjustment needed for destructors!");
|
||||
// If this destructor has a 'this' pointer adjustment, dump it.
|
||||
if (!Thunk.This.isEmpty()) {
|
||||
assert(!Thunk.This.VCallOffsetOffset &&
|
||||
"No virtual this adjustment in this ABI");
|
||||
Out << "\n [this adjustment: " << Thunk.This.NonVirtual
|
||||
<< " non-virtual]";
|
||||
}
|
||||
dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -3068,26 +3077,7 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) {
|
|||
const ThunkInfo &Thunk = ThunksVector[I];
|
||||
|
||||
Out << llvm::format("%4d | ", I);
|
||||
|
||||
// If this function pointer has a return pointer adjustment, dump it.
|
||||
if (!Thunk.Return.isEmpty()) {
|
||||
Out << "return adjustment: ";
|
||||
if (Thunk.Return.VBaseOffsetOffset)
|
||||
Out << "vbase #" << Thunk.Return.VBaseOffsetOffset << ", ";
|
||||
Out << Thunk.Return.NonVirtual << " non-virtual";
|
||||
|
||||
if (!Thunk.This.isEmpty())
|
||||
Out << "\n ";
|
||||
}
|
||||
|
||||
// If this function pointer has a 'this' pointer adjustment, dump it.
|
||||
if (!Thunk.This.isEmpty()) {
|
||||
assert(!Thunk.This.VCallOffsetOffset &&
|
||||
"No virtual this adjustment in this ABI");
|
||||
Out << "this adjustment: ";
|
||||
Out << Thunk.This.NonVirtual << " non-virtual";
|
||||
}
|
||||
|
||||
dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/true);
|
||||
Out << '\n';
|
||||
}
|
||||
|
||||
|
|
|
@ -356,6 +356,14 @@ public:
|
|||
|
||||
virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) = 0;
|
||||
|
||||
virtual llvm::Value *performThisAdjustment(CodeGenFunction &CGF,
|
||||
llvm::Value *This,
|
||||
const ThisAdjustment &TA) = 0;
|
||||
|
||||
virtual llvm::Value *performReturnAdjustment(CodeGenFunction &CGF,
|
||||
llvm::Value *Ret,
|
||||
const ReturnAdjustment &RA) = 0;
|
||||
|
||||
virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
|
||||
RValue RV, QualType ResultType);
|
||||
|
||||
|
|
|
@ -56,53 +56,6 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
|
|||
return GetOrCreateLLVMFunction(Name, Ty, GD, /*ForVTable=*/true);
|
||||
}
|
||||
|
||||
static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF,
|
||||
llvm::Value *Ptr,
|
||||
int64_t NonVirtualAdjustment,
|
||||
int64_t VirtualAdjustment,
|
||||
bool IsReturnAdjustment) {
|
||||
if (!NonVirtualAdjustment && !VirtualAdjustment)
|
||||
return Ptr;
|
||||
|
||||
llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
|
||||
llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
|
||||
|
||||
if (NonVirtualAdjustment && !IsReturnAdjustment) {
|
||||
// Perform the non-virtual adjustment for a base-to-derived cast.
|
||||
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
|
||||
}
|
||||
|
||||
if (VirtualAdjustment) {
|
||||
llvm::Type *PtrDiffTy =
|
||||
CGF.ConvertType(CGF.getContext().getPointerDiffType());
|
||||
|
||||
// Perform the virtual adjustment.
|
||||
llvm::Value *VTablePtrPtr =
|
||||
CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
|
||||
|
||||
llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr);
|
||||
|
||||
llvm::Value *OffsetPtr =
|
||||
CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
|
||||
|
||||
OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo());
|
||||
|
||||
// Load the adjustment offset from the vtable.
|
||||
llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr);
|
||||
|
||||
// Adjust our pointer.
|
||||
V = CGF.Builder.CreateInBoundsGEP(V, Offset);
|
||||
}
|
||||
|
||||
if (NonVirtualAdjustment && IsReturnAdjustment) {
|
||||
// Perform the non-virtual adjustment for a derived-to-base cast.
|
||||
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
|
||||
}
|
||||
|
||||
// Cast back to the original type.
|
||||
return CGF.Builder.CreateBitCast(V, Ptr->getType());
|
||||
}
|
||||
|
||||
static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
|
||||
const ThunkInfo &Thunk, llvm::Function *Fn) {
|
||||
CGM.setGlobalVisibility(Fn, MD);
|
||||
|
@ -181,12 +134,10 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
|
|||
CGF.Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull);
|
||||
CGF.EmitBlock(AdjustNotNull);
|
||||
}
|
||||
|
||||
ReturnValue = PerformTypeAdjustment(CGF, ReturnValue,
|
||||
Thunk.Return.NonVirtual,
|
||||
Thunk.Return.VBaseOffsetOffset,
|
||||
/*IsReturnAdjustment*/true);
|
||||
|
||||
|
||||
ReturnValue = CGF.CGM.getCXXABI().performReturnAdjustment(CGF, ReturnValue,
|
||||
Thunk.Return);
|
||||
|
||||
if (NullCheckValue) {
|
||||
CGF.Builder.CreateBr(AdjustEnd);
|
||||
CGF.EmitBlock(AdjustNull);
|
||||
|
@ -266,11 +217,8 @@ void CodeGenFunction::GenerateVarArgsThunk(
|
|||
assert(ThisStore && "Store of this should be in entry block?");
|
||||
// Adjust "this", if necessary.
|
||||
Builder.SetInsertPoint(ThisStore);
|
||||
llvm::Value *AdjustedThisPtr =
|
||||
PerformTypeAdjustment(*this, ThisPtr,
|
||||
Thunk.This.NonVirtual,
|
||||
Thunk.This.VCallOffsetOffset,
|
||||
/*IsReturnAdjustment*/false);
|
||||
llvm::Value *AdjustedThisPtr =
|
||||
CGM.getCXXABI().performThisAdjustment(*this, ThisPtr, Thunk.This);
|
||||
ThisStore->setOperand(0, AdjustedThisPtr);
|
||||
|
||||
if (!Thunk.Return.isEmpty()) {
|
||||
|
@ -322,12 +270,9 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
|
|||
CXXThisValue = CXXABIThisValue;
|
||||
|
||||
// Adjust the 'this' pointer if necessary.
|
||||
llvm::Value *AdjustedThisPtr =
|
||||
PerformTypeAdjustment(*this, LoadCXXThis(),
|
||||
Thunk.This.NonVirtual,
|
||||
Thunk.This.VCallOffsetOffset,
|
||||
/*IsReturnAdjustment*/false);
|
||||
|
||||
llvm::Value *AdjustedThisPtr =
|
||||
CGM.getCXXABI().performThisAdjustment(*this, LoadCXXThis(), Thunk.This);
|
||||
|
||||
CallArgList CallArgs;
|
||||
|
||||
// Add our adjusted 'this' pointer.
|
||||
|
|
|
@ -180,6 +180,12 @@ public:
|
|||
Thunk->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
|
||||
}
|
||||
|
||||
llvm::Value *performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This,
|
||||
const ThisAdjustment &TA);
|
||||
|
||||
llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
|
||||
const ReturnAdjustment &RA);
|
||||
|
||||
StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
|
||||
StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
|
||||
|
||||
|
@ -1059,6 +1065,68 @@ void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
|
|||
VTables.EmitVTTDefinition(VTT, CGM.getVTableLinkage(RD), RD);
|
||||
}
|
||||
|
||||
static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
|
||||
llvm::Value *Ptr,
|
||||
int64_t NonVirtualAdjustment,
|
||||
int64_t VirtualAdjustment,
|
||||
bool IsReturnAdjustment) {
|
||||
if (!NonVirtualAdjustment && !VirtualAdjustment)
|
||||
return Ptr;
|
||||
|
||||
llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
|
||||
llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
|
||||
|
||||
if (NonVirtualAdjustment && !IsReturnAdjustment) {
|
||||
// Perform the non-virtual adjustment for a base-to-derived cast.
|
||||
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
|
||||
}
|
||||
|
||||
if (VirtualAdjustment) {
|
||||
llvm::Type *PtrDiffTy =
|
||||
CGF.ConvertType(CGF.getContext().getPointerDiffType());
|
||||
|
||||
// Perform the virtual adjustment.
|
||||
llvm::Value *VTablePtrPtr =
|
||||
CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo());
|
||||
|
||||
llvm::Value *VTablePtr = CGF.Builder.CreateLoad(VTablePtrPtr);
|
||||
|
||||
llvm::Value *OffsetPtr =
|
||||
CGF.Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
|
||||
|
||||
OffsetPtr = CGF.Builder.CreateBitCast(OffsetPtr, PtrDiffTy->getPointerTo());
|
||||
|
||||
// Load the adjustment offset from the vtable.
|
||||
llvm::Value *Offset = CGF.Builder.CreateLoad(OffsetPtr);
|
||||
|
||||
// Adjust our pointer.
|
||||
V = CGF.Builder.CreateInBoundsGEP(V, Offset);
|
||||
}
|
||||
|
||||
if (NonVirtualAdjustment && IsReturnAdjustment) {
|
||||
// Perform the non-virtual adjustment for a derived-to-base cast.
|
||||
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment);
|
||||
}
|
||||
|
||||
// Cast back to the original type.
|
||||
return CGF.Builder.CreateBitCast(V, Ptr->getType());
|
||||
}
|
||||
|
||||
llvm::Value *ItaniumCXXABI::performThisAdjustment(CodeGenFunction &CGF,
|
||||
llvm::Value *This,
|
||||
const ThisAdjustment &TA) {
|
||||
return performTypeAdjustment(CGF, This, TA.NonVirtual, TA.VCallOffsetOffset,
|
||||
/*IsReturnAdjustment=*/false);
|
||||
}
|
||||
|
||||
llvm::Value *
|
||||
ItaniumCXXABI::performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
|
||||
const ReturnAdjustment &RA) {
|
||||
return performTypeAdjustment(CGF, Ret, RA.NonVirtual,
|
||||
RA.Virtual.Itanium.VBaseOffsetOffset,
|
||||
/*IsReturnAdjustment=*/true);
|
||||
}
|
||||
|
||||
void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
|
||||
RValue RV, QualType ResultType) {
|
||||
if (!isa<CXXDestructorDecl>(CGF.CurGD.getDecl()))
|
||||
|
|
|
@ -190,6 +190,12 @@ public:
|
|||
Thunk->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
|
||||
}
|
||||
|
||||
llvm::Value *performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This,
|
||||
const ThisAdjustment &TA);
|
||||
|
||||
llvm::Value *performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
|
||||
const ReturnAdjustment &RA);
|
||||
|
||||
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
|
||||
llvm::GlobalVariable *DeclPtr,
|
||||
bool PerformInit);
|
||||
|
@ -268,6 +274,16 @@ private:
|
|||
llvm::Value *VBTableOffset,
|
||||
llvm::Value **VBPtr = 0);
|
||||
|
||||
llvm::Value *GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF,
|
||||
llvm::Value *Base,
|
||||
int32_t VBPtrOffset,
|
||||
int32_t VBTableOffset,
|
||||
llvm::Value **VBPtr = 0) {
|
||||
llvm::Value *VBPOffset = llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset),
|
||||
*VBTOffset = llvm::ConstantInt::get(CGM.IntTy, VBTableOffset);
|
||||
return GetVBaseOffsetFromVBPtr(CGF, Base, VBPOffset, VBTOffset, VBPtr);
|
||||
}
|
||||
|
||||
/// \brief Performs a full virtual base adjustment. Used to dereference
|
||||
/// pointers to members of virtual bases.
|
||||
llvm::Value *AdjustVirtualBase(CodeGenFunction &CGF, const CXXRecordDecl *RD,
|
||||
|
@ -962,6 +978,54 @@ void MicrosoftCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
|
|||
}
|
||||
}
|
||||
|
||||
llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF,
|
||||
llvm::Value *This,
|
||||
const ThisAdjustment &TA) {
|
||||
if (TA.isEmpty())
|
||||
return This;
|
||||
|
||||
llvm::Value *V = CGF.Builder.CreateBitCast(This, CGF.Int8PtrTy);
|
||||
|
||||
assert(TA.VCallOffsetOffset == 0 &&
|
||||
"VtorDisp adjustment is not supported yet");
|
||||
|
||||
if (TA.NonVirtual) {
|
||||
// Non-virtual adjustment might result in a pointer outside the allocated
|
||||
// object, e.g. if the final overrider class is laid out after the virtual
|
||||
// base that declares a method in the most derived class.
|
||||
V = CGF.Builder.CreateConstGEP1_32(V, TA.NonVirtual);
|
||||
}
|
||||
|
||||
// Don't need to bitcast back, the call CodeGen will handle this.
|
||||
return V;
|
||||
}
|
||||
|
||||
llvm::Value *
|
||||
MicrosoftCXXABI::performReturnAdjustment(CodeGenFunction &CGF, llvm::Value *Ret,
|
||||
const ReturnAdjustment &RA) {
|
||||
if (RA.isEmpty())
|
||||
return Ret;
|
||||
|
||||
llvm::Value *V = CGF.Builder.CreateBitCast(Ret, CGF.Int8PtrTy);
|
||||
|
||||
if (RA.Virtual.Microsoft.VBIndex) {
|
||||
assert(RA.Virtual.Microsoft.VBIndex > 0);
|
||||
int32_t IntSize =
|
||||
getContext().getTypeSizeInChars(getContext().IntTy).getQuantity();
|
||||
llvm::Value *VBPtr;
|
||||
llvm::Value *VBaseOffset =
|
||||
GetVBaseOffsetFromVBPtr(CGF, V, RA.Virtual.Microsoft.VBPtrOffset,
|
||||
IntSize * RA.Virtual.Microsoft.VBIndex, &VBPtr);
|
||||
V = CGF.Builder.CreateInBoundsGEP(VBPtr, VBaseOffset);
|
||||
}
|
||||
|
||||
if (RA.NonVirtual)
|
||||
V = CGF.Builder.CreateConstInBoundsGEP1_32(V, RA.NonVirtual);
|
||||
|
||||
// Cast back to the original type.
|
||||
return CGF.Builder.CreateBitCast(V, Ret->getType());
|
||||
}
|
||||
|
||||
bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
|
||||
QualType elementType) {
|
||||
// Microsoft seems to completely ignore the possibility of a
|
||||
|
|
|
@ -61,14 +61,14 @@ struct C : A, B {
|
|||
|
||||
C::C() {} // Emits vftable and forces thunk generation.
|
||||
|
||||
// CODEGEN: define weak x86_thiscallcc void @"\01??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete)
|
||||
// CODEGEN: getelementptr inbounds i8* {{.*}}, i64 -4
|
||||
// CODEGEN-LABEL: define weak x86_thiscallcc void @"\01??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete)
|
||||
// CODEGEN: getelementptr i8* {{.*}}, i32 -4
|
||||
// FIXME: should actually call _EC, not _GC.
|
||||
// CODEGEN: call x86_thiscallcc void @"\01??_GC@@UAEPAXI@Z"
|
||||
// CODEGEN: ret
|
||||
|
||||
// CODEGEN: define weak x86_thiscallcc void @"\01?public_f@C@@W3AEXXZ"(%struct.C*
|
||||
// CODEGEN: getelementptr inbounds i8* {{.*}}, i64 -4
|
||||
// CODEGEN-LABEL: define weak x86_thiscallcc void @"\01?public_f@C@@W3AEXXZ"(%struct.C*
|
||||
// CODEGEN: getelementptr i8* {{.*}}, i32 -4
|
||||
// CODEGEN: call x86_thiscallcc void @"\01?public_f@C@@UAEXXZ"(%struct.C*
|
||||
// CODEGEN: ret
|
||||
|
||||
|
@ -81,6 +81,7 @@ struct D {
|
|||
};
|
||||
|
||||
struct E : D {
|
||||
E();
|
||||
virtual C* goo();
|
||||
// MANGLING-DAG: @"\01?goo@E@@UAEPAUC@@XZ"
|
||||
// MANGLING-DAG: @"\01?goo@E@@QAEPAUB@@XZ"
|
||||
|
@ -88,14 +89,15 @@ struct E : D {
|
|||
// MANGLING-X64-DAG: @"\01?goo@E@@QEAAPEAUB@@XZ"
|
||||
};
|
||||
|
||||
E e; // Emits vftable and forces thunk generation.
|
||||
E::E() {} // Emits vftable and forces thunk generation.
|
||||
|
||||
// CODEGEN: define weak x86_thiscallcc %struct.C* @"\01?goo@E@@QAEPAUB@@XZ"
|
||||
// CODEGEN-LABEL: define weak x86_thiscallcc %struct.C* @"\01?goo@E@@QAEPAUB@@XZ"
|
||||
// CODEGEN: call x86_thiscallcc %struct.C* @"\01?goo@E@@UAEPAUC@@XZ"
|
||||
// CODEGEN: getelementptr inbounds i8* {{.*}}, i64 4
|
||||
// CODEGEN: getelementptr inbounds i8* {{.*}}, i32 4
|
||||
// CODEGEN: ret
|
||||
|
||||
struct F : virtual A, virtual B {
|
||||
virtual void own_method();
|
||||
virtual ~F();
|
||||
};
|
||||
|
||||
|
@ -115,6 +117,27 @@ struct H : E {
|
|||
|
||||
H h;
|
||||
|
||||
struct I : D {
|
||||
I();
|
||||
virtual F* goo();
|
||||
};
|
||||
|
||||
I::I() {} // Emits vftable and forces thunk generation.
|
||||
|
||||
// CODEGEN-LABEL: define weak x86_thiscallcc %struct.{{[BF]}}* @"\01?goo@I@@QAEPAUB@@XZ"
|
||||
// CODEGEN: %[[ORIG_RET:.*]] = call x86_thiscallcc %struct.F* @"\01?goo@I@@UAEPAUF@@XZ"
|
||||
// CODEGEN: %[[ORIG_RET_i8:.*]] = bitcast %struct.F* %[[ORIG_RET]] to i8*
|
||||
// CODEGEN: %[[VBPTR_i8:.*]] = getelementptr inbounds i8* %[[ORIG_RET_i8]], i32 4
|
||||
// CODEGEN: %[[VBPTR:.*]] = bitcast i8* %[[VBPTR_i8]] to i8**
|
||||
// CODEGEN: %[[VBTABLE:.*]] = load i8** %[[VBPTR]]
|
||||
// CODEGEN: %[[VBASE_OFFSET_PTR_i8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 8
|
||||
// CODEGEN: %[[VBASE_OFFSET_PTR:.*]] = bitcast i8* %[[VBASE_OFFSET_PTR_i8]] to i32*
|
||||
// CODEGEN: %[[VBASE_OFFSET:.*]] = load i32* %[[VBASE_OFFSET_PTR]]
|
||||
// CODEGEN: %[[RES_i8:.*]] = getelementptr inbounds i8* %[[VBPTR_i8]], i32 %[[VBASE_OFFSET]]
|
||||
// CODEGEN: %[[RES:.*]] = bitcast i8* %[[RES_i8]] to %struct.F*
|
||||
// CODEGEN: phi %struct.F* {{.*}} %[[RES]]
|
||||
// CODEGEN: ret %struct.{{[BF]}}*
|
||||
|
||||
// FIXME: Write vtordisp adjusting thunk tests
|
||||
|
||||
namespace CrashOnThunksForAttributedType {
|
||||
|
|
|
@ -275,7 +275,7 @@ struct Test1 : B, C {
|
|||
// THIS-THUNKS-Test1-NEXT: [this adjustment: -4 non-virtual]
|
||||
|
||||
// THIS-THUNKS-Test1: Thunks for 'void this_adjustment::Test1::g()' (1 entry).
|
||||
// THIS-THUNKS-Test1-NEXT: 0 | this adjustment: -4 non-virtual
|
||||
// THIS-THUNKS-Test1-NEXT: 0 | [this adjustment: -4 non-virtual]
|
||||
|
||||
// THIS-THUNKS-Test1: VFTable indices for 'this_adjustment::Test1' (1 entries).
|
||||
// THIS-THUNKS-Test1-NEXT: 0 | void this_adjustment::Test1::g()
|
||||
|
@ -301,7 +301,7 @@ struct Test2 : A, B, C {
|
|||
// THIS-THUNKS-Test2-NEXT: [this adjustment: -4 non-virtual]
|
||||
|
||||
// THIS-THUNKS-Test2: Thunks for 'void this_adjustment::Test2::g()' (1 entry).
|
||||
// THIS-THUNKS-Test2-NEXT: 0 | this adjustment: -4 non-virtual
|
||||
// THIS-THUNKS-Test2-NEXT: 0 | [this adjustment: -4 non-virtual]
|
||||
|
||||
// THIS-THUNKS-Test2: VFTable indices for 'this_adjustment::Test2' (1 entries).
|
||||
// THIS-THUNKS-Test2-NEXT: via vfptr at offset 4
|
||||
|
@ -327,18 +327,18 @@ struct Test3: no_thunks::Test1, no_thunks::Test2 {
|
|||
|
||||
// THIS-THUNKS-Test3: VFTable for 'A' in 'no_thunks::Test2' in 'this_adjustment::Test3' (1 entries).
|
||||
// THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::f()
|
||||
// THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual]
|
||||
// THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual]
|
||||
|
||||
// THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::f()' (1 entry).
|
||||
// THIS-THUNKS-Test3-NEXT: 0 | this adjustment: -8 non-virtual
|
||||
// THIS-THUNKS-Test3-NEXT: 0 | [this adjustment: -8 non-virtual]
|
||||
|
||||
// THIS-THUNKS-Test3: VFTable for 'B' in 'no_thunks::Test2' in 'this_adjustment::Test3' (2 entries).
|
||||
// THIS-THUNKS-Test3-NEXT: 0 | void this_adjustment::Test3::g()
|
||||
// THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual]
|
||||
// THIS-THUNKS-Test3-NEXT: [this adjustment: -8 non-virtual]
|
||||
// THIS-THUNKS-Test3-NEXT: 1 | void B::h()
|
||||
|
||||
// THIS-THUNKS-Test3: Thunks for 'void this_adjustment::Test3::g()' (1 entry).
|
||||
// THIS-THUNKS-Test3-NEXT: 0 | this adjustment: -8 non-virtual
|
||||
// THIS-THUNKS-Test3-NEXT: 0 | [this adjustment: -8 non-virtual]
|
||||
|
||||
// THIS-THUNKS-Test3: VFTable indices for 'this_adjustment::Test3' (2 entries).
|
||||
// THIS-THUNKS-Test3-NEXT: via vfptr at offset 0
|
||||
|
@ -373,7 +373,7 @@ struct Test3 : Test1, Test2 {
|
|||
// VDTOR-THUNKS-Test3-NEXT: [this adjustment: -4 non-virtual]
|
||||
|
||||
// VDTOR-THUNKS-Test3: Thunks for 'vdtor::Test3::~Test3()' (1 entry).
|
||||
// VDTOR-THUNKS-Test3-NEXT: 0 | this adjustment: -4 non-virtual
|
||||
// VDTOR-THUNKS-Test3-NEXT: 0 | [this adjustment: -4 non-virtual]
|
||||
|
||||
// VDTOR-THUNKS-Test3: VFTable indices for 'vdtor::Test3' (1 entries).
|
||||
// VDTOR-THUNKS-Test3-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
|
||||
|
@ -398,7 +398,7 @@ struct Test5 : Test4, Test2 {
|
|||
// VDTOR-THUNKS-Test5-NEXT: [this adjustment: -4 non-virtual]
|
||||
|
||||
// VDTOR-THUNKS-Test5: Thunks for 'vdtor::Test5::~Test5()' (1 entry).
|
||||
// VDTOR-THUNKS-Test5-NEXT: 0 | this adjustment: -4 non-virtual
|
||||
// VDTOR-THUNKS-Test5-NEXT: 0 | [this adjustment: -4 non-virtual]
|
||||
|
||||
// VDTOR-THUNKS-Test5: VFTable indices for 'vdtor::Test5' (1 entries).
|
||||
// VDTOR-THUNKS-Test5-NEXT: -- accessible via vfptr at offset 4 --
|
||||
|
@ -418,7 +418,7 @@ struct Test6 : Test4, Test2 {
|
|||
// VDTOR-THUNKS-Test6-NEXT: [this adjustment: -4 non-virtual]
|
||||
|
||||
// VDTOR-THUNKS-Test6: Thunks for 'vdtor::Test6::~Test6()' (1 entry).
|
||||
// VDTOR-THUNKS-Test6-NEXT: 0 | this adjustment: -4 non-virtual
|
||||
// VDTOR-THUNKS-Test6-NEXT: 0 | [this adjustment: -4 non-virtual]
|
||||
|
||||
// VDTOR-THUNKS-Test6: VFTable indices for 'vdtor::Test6' (1 entries).
|
||||
// VDTOR-THUNKS-Test6-NEXT: -- accessible via vfptr at offset 4 --
|
||||
|
@ -436,7 +436,7 @@ struct Test7 : Test5 {
|
|||
// VDTOR-THUNKS-Test7-NEXT: [this adjustment: -4 non-virtual]
|
||||
|
||||
// VDTOR-THUNKS-Test7: Thunks for 'vdtor::Test7::~Test7()' (1 entry).
|
||||
// VDTOR-THUNKS-Test7-NEXT: 0 | this adjustment: -4 non-virtual
|
||||
// VDTOR-THUNKS-Test7-NEXT: 0 | [this adjustment: -4 non-virtual]
|
||||
|
||||
// VDTOR-THUNKS-Test7: VFTable indices for 'vdtor::Test7' (1 entries).
|
||||
// VDTOR-THUNKS-Test7-NEXT: -- accessible via vfptr at offset 4 --
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
// RUN: FileCheck --check-prefix=VDTORS-P %s < %t
|
||||
// RUN: FileCheck --check-prefix=RET-W %s < %t
|
||||
// RUN: FileCheck --check-prefix=RET-T %s < %t
|
||||
// RUN: FileCheck --check-prefix=RET-V %s < %t
|
||||
|
||||
// RUN: FileCheck --check-prefix=MANGLING %s < %t
|
||||
|
||||
|
@ -152,7 +153,7 @@ struct X: virtual C {
|
|||
|
||||
// TEST4: VFTable for 'A' in 'C' in 'Test4::X' (2 entries).
|
||||
// TEST4-NEXT: 0 | void C::f()
|
||||
// TEST4-NEXT: [this adjustment: 8 non-virtual]
|
||||
// TEST4-NEXT: [this adjustment: 8 non-virtual]
|
||||
// TEST4-NEXT: 1 | void A::z()
|
||||
|
||||
// TEST4-NOT: VFTable indices for 'Test4::X'
|
||||
|
@ -223,7 +224,7 @@ struct Y : virtual X {
|
|||
// TEST7-NEXT: 1 | void A::z()
|
||||
|
||||
// TEST7: Thunks for 'void C::f()' (1 entry).
|
||||
// TEST7-NEXT: 0 | this adjustment: 8 non-virtual
|
||||
// TEST7-NEXT: 0 | [this adjustment: 8 non-virtual]
|
||||
|
||||
// TEST7-NOT: VFTable indices for 'Test7::Y'
|
||||
|
||||
|
@ -338,7 +339,7 @@ struct W : Z, D, virtual A, virtual B {
|
|||
// TEST9-W-NEXT: 1 | void A::z()
|
||||
|
||||
// TEST9-W: Thunks for 'void D::f()' (1 entry).
|
||||
// TEST9-W-NEXT: 0 | this adjustment: -8 non-virtual
|
||||
// TEST9-W-NEXT: 0 | [this adjustment: -8 non-virtual]
|
||||
|
||||
// TEST9-W-NOT: VFTable indices for 'Test9::W'
|
||||
|
||||
|
@ -371,7 +372,7 @@ struct T : Z, D, virtual A, virtual B {
|
|||
// TEST9-T-NEXT: [this adjustment: -8 non-virtual]
|
||||
|
||||
// TEST9-T: Thunks for 'void Test9::T::h()' (1 entry).
|
||||
// TEST9-T-NEXT: 0 | this adjustment: -8 non-virtual
|
||||
// TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual]
|
||||
|
||||
// TEST9-T: VFTable for 'A' in 'D' in 'Test9::T' (2 entries).
|
||||
// TEST9-T-NEXT: 0 | void Test9::T::f()
|
||||
|
@ -380,10 +381,10 @@ struct T : Z, D, virtual A, virtual B {
|
|||
// TEST9-T-NEXT: [this adjustment: -8 non-virtual]
|
||||
|
||||
// TEST9-T: Thunks for 'void Test9::T::f()' (1 entry).
|
||||
// TEST9-T-NEXT: 0 | this adjustment: -8 non-virtual
|
||||
// TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual]
|
||||
|
||||
// TEST9-T: Thunks for 'void Test9::T::z()' (1 entry).
|
||||
// TEST9-T-NEXT: 0 | this adjustment: -8 non-virtual
|
||||
// TEST9-T-NEXT: 0 | [this adjustment: -8 non-virtual]
|
||||
|
||||
// TEST9-T: VFTable indices for 'Test9::T' (4 entries).
|
||||
// TEST9-T-NEXT: via vfptr at offset 0
|
||||
|
@ -464,7 +465,7 @@ struct U : virtual W {
|
|||
// VDTORS-U-NEXT: 1 | void vdtors::X::zzz()
|
||||
|
||||
// VDTORS-U: Thunks for 'vdtors::W::~W()' (1 entry).
|
||||
// VDTORS-U-NEXT: 0 | this adjustment: -4 non-virtual
|
||||
// VDTORS-U-NEXT: 0 | [this adjustment: -4 non-virtual]
|
||||
|
||||
// VDTORS-U: VFTable indices for 'vdtors::U' (1 entries).
|
||||
// VDTORS-U-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 --
|
||||
|
@ -484,7 +485,7 @@ struct V : virtual W {
|
|||
// VDTORS-V-NEXT: 1 | void vdtors::X::zzz()
|
||||
|
||||
// VDTORS-V: Thunks for 'vdtors::W::~W()' (1 entry).
|
||||
// VDTORS-V-NEXT: 0 | this adjustment: -4 non-virtual
|
||||
// VDTORS-V-NEXT: 0 | [this adjustment: -4 non-virtual]
|
||||
|
||||
// VDTORS-V: VFTable indices for 'vdtors::V' (1 entries).
|
||||
// VDTORS-V-NEXT: -- accessible via vbtable index 1, vfptr at offset 4 --
|
||||
|
@ -553,4 +554,22 @@ struct T : W {
|
|||
};
|
||||
|
||||
T t;
|
||||
|
||||
struct U : virtual A {
|
||||
virtual void g(); // adds a vfptr
|
||||
};
|
||||
|
||||
struct V : Z {
|
||||
// RET-V: VFTable for 'return_adjustment::Z' in 'return_adjustment::V' (2 entries).
|
||||
// RET-V-NEXT: 0 | return_adjustment::U *return_adjustment::V::foo()
|
||||
// RET-V-NEXT: [return adjustment: vbptr at offset 4, vbase #1, 0 non-virtual]
|
||||
// RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo()
|
||||
|
||||
// RET-V: VFTable indices for 'return_adjustment::V' (1 entries).
|
||||
// RET-V-NEXT: 1 | return_adjustment::U *return_adjustment::V::foo()
|
||||
|
||||
virtual U* foo();
|
||||
};
|
||||
|
||||
V v;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue