r188870 - Abstract out virtual calls and virtual function prologue code generation; implement them for -cxx-abi microsoft
Timur Iskhodzhanov
timurrrr at google.com
Tue Aug 20 23:25:04 PDT 2013
Author: timurrrr
Date: Wed Aug 21 01:25:03 2013
New Revision: 188870
URL: http://llvm.org/viewvc/llvm-project?rev=188870&view=rev
Log:
Abstract out virtual calls and virtual function prologue code generation; implement them for -cxx-abi microsoft
Added:
cfe/trunk/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp
Modified:
cfe/trunk/include/clang/AST/VTableBuilder.h
cfe/trunk/lib/AST/VTableBuilder.cpp
cfe/trunk/lib/CodeGen/CGCXX.cpp
cfe/trunk/lib/CodeGen/CGCXXABI.h
cfe/trunk/lib/CodeGen/CGCall.cpp
cfe/trunk/lib/CodeGen/CGClass.cpp
cfe/trunk/lib/CodeGen/CGExprCXX.cpp
cfe/trunk/lib/CodeGen/CGVTables.h
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/CodeGen/CodeGenModule.h
cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
Modified: cfe/trunk/include/clang/AST/VTableBuilder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/VTableBuilder.h?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/VTableBuilder.h (original)
+++ cfe/trunk/include/clang/AST/VTableBuilder.h Wed Aug 21 01:25:03 2013
@@ -417,6 +417,10 @@ public:
/// If nonzero, holds the vbtable index of the virtual base with the vfptr.
uint64_t VBTableIndex;
+ /// If nonnull, holds the last vbase which contains the vfptr that the
+ /// method definition is adjusted to.
+ const CXXRecordDecl *VBase;
+
/// This is the offset of the vfptr from the start of the last vbase, or the
/// complete type if there are no virtual bases.
CharUnits VFTableOffset;
@@ -425,19 +429,24 @@ public:
uint64_t Index;
MethodVFTableLocation()
- : VBTableIndex(0), VFTableOffset(CharUnits::Zero()), Index(0) {}
+ : VBTableIndex(0), VBase(0), VFTableOffset(CharUnits::Zero()),
+ Index(0) {}
- MethodVFTableLocation(uint64_t VBTableIndex, CharUnits VFTableOffset,
- uint64_t Index)
- : VBTableIndex(VBTableIndex), VFTableOffset(VFTableOffset),
- Index(Index) {}
+ MethodVFTableLocation(uint64_t VBTableIndex, const CXXRecordDecl *VBase,
+ CharUnits VFTableOffset, uint64_t Index)
+ : VBTableIndex(VBTableIndex), VBase(VBase),
+ VFTableOffset(VFTableOffset), Index(Index) {}
bool operator<(const MethodVFTableLocation &other) const {
- if (VBTableIndex != other.VBTableIndex)
+ if (VBTableIndex != other.VBTableIndex) {
+ assert(VBase != other.VBase);
return VBTableIndex < other.VBTableIndex;
+ }
if (VFTableOffset != other.VFTableOffset)
return VFTableOffset < other.VFTableOffset;
- return Index < other.Index;
+ if (Index != other.Index)
+ return Index < other.Index;
+ return false;
}
};
Modified: cfe/trunk/lib/AST/VTableBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/VTableBuilder.cpp?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/AST/VTableBuilder.cpp (original)
+++ cfe/trunk/lib/AST/VTableBuilder.cpp Wed Aug 21 01:25:03 2013
@@ -2490,6 +2490,10 @@ private:
/// this method's base has, or zero.
const uint64_t VBTableIndex;
+ /// VBase - If nonnull, holds the last vbase which contains the vfptr that
+ /// the method definition is adjusted to.
+ const CXXRecordDecl *VBase;
+
/// VFTableIndex - The index in the vftable that this method has.
const uint64_t VFTableIndex;
@@ -2498,11 +2502,13 @@ private:
/// or used for vcalls in the most derived class.
bool Shadowed;
- MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex)
- : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex),
+ MethodInfo(uint64_t VBTableIndex, const CXXRecordDecl *VBase,
+ uint64_t VFTableIndex)
+ : VBTableIndex(VBTableIndex), VBase(VBase), VFTableIndex(VFTableIndex),
Shadowed(false) {}
- MethodInfo() : VBTableIndex(0), VFTableIndex(0), Shadowed(false) {}
+ MethodInfo()
+ : VBTableIndex(0), VBase(0), VFTableIndex(0), Shadowed(false) {}
};
typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
@@ -2584,8 +2590,8 @@ private:
// and the entries shadowed by return adjusting thunks.
if (MD->getParent() != MostDerivedClass || MI.Shadowed)
continue;
- MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.VFPtrOffset,
- MI.VFTableIndex);
+ MethodVFTableLocation Loc(MI.VBTableIndex, MI.VBase,
+ WhichVFPtr.VFPtrOffset, MI.VFTableIndex);
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc;
} else {
@@ -2838,6 +2844,7 @@ void VFTableBuilder::AddMethods(BaseSubo
// No return adjustment needed - just replace the overridden method info
// with the current info.
MethodInfo MI(OverriddenMethodInfo.VBTableIndex,
+ OverriddenMethodInfo.VBase,
OverriddenMethodInfo.VFTableIndex);
MethodInfoMap.erase(OverriddenMDIterator);
@@ -2882,7 +2889,7 @@ void VFTableBuilder::AddMethods(BaseSubo
// it requires return adjustment. Insert the method info for this method.
unsigned VBIndex =
LastVBase ? GetVBTableIndex(MostDerivedClass, LastVBase) : 0;
- MethodInfo MI(VBIndex, Components.size());
+ MethodInfo MI(VBIndex, LastVBase, Components.size());
assert(!MethodInfoMap.count(MD) &&
"Should not have method info for this method yet!");
Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Wed Aug 21 01:25:03 2013
@@ -272,23 +272,12 @@ CodeGenModule::GetAddrOfCXXDestructor(co
/*ForVTable=*/false));
}
-llvm::Value *
-CodeGenFunction::BuildVirtualCall(GlobalDecl GD, llvm::Value *This,
- llvm::Type *Ty) {
- GD = GD.getCanonicalDecl();
- uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(GD);
-
- Ty = Ty->getPointerTo()->getPointerTo();
- llvm::Value *VTable = GetVTablePtr(This, Ty);
- llvm::Value *VFuncPtr =
- Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
- return Builder.CreateLoad(VFuncPtr);
-}
-
static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF,
GlobalDecl GD,
llvm::Type *Ty,
const CXXRecordDecl *RD) {
+ assert(!CGF.CGM.getTarget().getCXXABI().isMicrosoft() &&
+ "No kext in Microsoft ABI");
GD = GD.getCanonicalDecl();
CodeGenModule &CGM = CGF.CGM;
llvm::Value *VTable = CGM.getVTables().GetAddrOfVTable(RD);
Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Wed Aug 21 01:25:03 2013
@@ -256,6 +256,23 @@ public:
/// Emit destructor variants required by this ABI.
virtual void EmitCXXDestructors(const CXXDestructorDecl *D) = 0;
+ /// Get the type of the implicit "this" parameter used by a method. May return
+ /// zero if no specific type is applicable, e.g. if the ABI expects the "this"
+ /// parameter to point to some artificial offset in a complete object due to
+ /// vbases being reordered.
+ virtual const CXXRecordDecl *
+ getThisArgumentTypeForMethod(const CXXMethodDecl *MD) {
+ return MD->getParent();
+ }
+
+ /// Perform ABI-specific "this" argument adjustment required prior to
+ /// a virtual function call.
+ virtual llvm::Value *adjustThisArgumentForVirtualCall(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Value *This) {
+ return This;
+ }
+
/// Build the ABI-specific portion of the parameter list for a
/// function. This generally involves a 'this' parameter and
/// possibly some extra data for constructors and destructors.
@@ -267,6 +284,13 @@ public:
QualType &ResTy,
FunctionArgList &Params) = 0;
+ /// Perform ABI-specific "this" parameter adjustment in a virtual function
+ /// prologue.
+ virtual llvm::Value *adjustThisParameterInVirtualFunctionPrologue(
+ CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) {
+ return This;
+ }
+
/// Emit the ABI-specific prolog for the function.
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
@@ -279,6 +303,12 @@ public:
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) = 0;
+ /// Build a virtual function pointer in the ABI-specific way.
+ virtual llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Value *This,
+ llvm::Type *Ty) = 0;
+
/// Emit the ABI-specific virtual destructor call.
virtual void EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor,
Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Wed Aug 21 01:25:03 2013
@@ -160,6 +160,8 @@ static CallingConv getCallingConventionF
/// Arrange the argument and result information for a call to an
/// unknown C++ non-static member function of the given abstract type.
+/// (Zero value of RD means we don't have any meaningful "this" argument type,
+/// so fall back to a generic pointer type).
/// The member function must be an ordinary function, i.e. not a
/// constructor or destructor.
const CGFunctionInfo &
@@ -168,7 +170,10 @@ CodeGenTypes::arrangeCXXMethodType(const
SmallVector<CanQualType, 16> argTypes;
// Add the 'this' pointer.
- argTypes.push_back(GetThisType(Context, RD));
+ if (RD)
+ argTypes.push_back(GetThisType(Context, RD));
+ else
+ argTypes.push_back(Context.VoidPtrTy);
return ::arrangeCXXMethodType(*this, argTypes,
FTP->getCanonicalTypeUnqualified().getAs<FunctionProtoType>());
@@ -187,7 +192,9 @@ CodeGenTypes::arrangeCXXMethodDeclaratio
if (MD->isInstance()) {
// The abstract case is perfectly fine.
- return arrangeCXXMethodType(MD->getParent(), prototype.getTypePtr());
+ const CXXRecordDecl *ThisType =
+ CGM.getCXXABI().getThisArgumentTypeForMethod(MD);
+ return arrangeCXXMethodType(ThisType, prototype.getTypePtr());
}
return arrangeFreeFunctionType(prototype);
@@ -1341,6 +1348,11 @@ void CodeGenFunction::EmitFunctionProlog
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
+ if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(CurCodeDecl)) {
+ if (MD->isVirtual() && Arg == CXXABIThisDecl)
+ V = CGM.getCXXABI().adjustThisParameterInVirtualFunctionPrologue(*this, CurGD, V);
+ }
+
// Because of merging of function types from multiple decls it is
// possible for the type of an argument to not match the corresponding
// type in the function type. Since we are codegening the callee
Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Wed Aug 21 01:25:03 2013
@@ -2125,7 +2125,7 @@ CodeGenFunction::EmitCXXOperatorMemberCa
CGM.getTypes().arrangeCXXMethodDeclaration(MD));
if (UseVirtualCall(getContext(), E, MD))
- return BuildVirtualCall(MD, This, fnType);
+ return CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, fnType);
return CGM.GetAddrOfFunction(MD, fnType);
}
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Wed Aug 21 01:25:03 2013
@@ -299,7 +299,7 @@ RValue CodeGenFunction::EmitCXXMemberCal
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty);
} else if (UseVirtualCall) {
- Callee = BuildVirtualCall(MD, This, Ty);
+ Callee = CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, Ty);
} else {
if (getLangOpts().AppleKext &&
MD->isVirtual() &&
@@ -312,6 +312,9 @@ RValue CodeGenFunction::EmitCXXMemberCal
}
}
+ if (MD->isVirtual())
+ This = CGM.getCXXABI().adjustThisArgumentForVirtualCall(*this, MD, This);
+
return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
/*ImplicitParam=*/0, QualType(),
CE->arg_begin(), CE->arg_end());
Modified: cfe/trunk/lib/CodeGen/CGVTables.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.h?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVTables.h (original)
+++ cfe/trunk/lib/CodeGen/CGVTables.h Wed Aug 21 01:25:03 2013
@@ -31,6 +31,8 @@ namespace CodeGen {
class CodeGenVTables {
CodeGenModule &CGM;
+ // FIXME: Consider moving VTContext and VFTContext into respective CXXABI
+ // classes?
VTableContext VTContext;
OwningPtr<MicrosoftVFTableContext> VFTContext;
@@ -78,6 +80,8 @@ public:
VTableContext &getVTableContext() { return VTContext; }
+ MicrosoftVFTableContext &getVFTableContext() { return *VFTContext.get(); }
+
/// getSubVTTIndex - Return the index of the sub-VTT for the base class of the
/// given record decl.
uint64_t getSubVTTIndex(const CXXRecordDecl *RD, BaseSubobject Base);
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Aug 21 01:25:03 2013
@@ -2102,8 +2102,6 @@ public:
void EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
ArrayRef<llvm::Value*> args);
- llvm::Value *BuildVirtualCall(GlobalDecl GD, llvm::Value *This,
- llvm::Type *Ty);
llvm::Value *BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
NestedNameSpecifier *Qual,
llvm::Type *Ty);
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Wed Aug 21 01:25:03 2013
@@ -519,8 +519,13 @@ public:
CodeGenTypes &getTypes() { return Types; }
CodeGenVTables &getVTables() { return VTables; }
+
VTableContext &getVTableContext() { return VTables.getVTableContext(); }
+ MicrosoftVFTableContext &getVFTableContext() {
+ return VTables.getVFTableContext();
+ }
+
llvm::MDNode *getTBAAInfo(QualType QTy);
llvm::MDNode *getTBAAInfoForVTablePtr();
llvm::MDNode *getTBAAStructInfo(QualType QTy);
Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Wed Aug 21 01:25:03 2013
@@ -142,6 +142,9 @@ public:
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
+ llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD,
+ llvm::Value *This, llvm::Type *Ty);
+
void EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor,
CXXDtorType DtorType, SourceLocation CallLoc,
@@ -885,6 +888,20 @@ void ItaniumCXXABI::EmitConstructorCall(
This, VTT, VTTTy, ArgBeg, ArgEnd);
}
+llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Value *This,
+ llvm::Type *Ty) {
+ GD = GD.getCanonicalDecl();
+ Ty = Ty->getPointerTo()->getPointerTo();
+ llvm::Value *VTable = CGF.GetVTablePtr(This, Ty);
+
+ uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(GD);
+ llvm::Value *VFuncPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn");
+ return CGF.Builder.CreateLoad(VFuncPtr);
+}
+
void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor,
CXXDtorType DtorType,
@@ -895,8 +912,8 @@ void ItaniumCXXABI::EmitVirtualDestructo
const CGFunctionInfo *FInfo
= &CGM.getTypes().arrangeCXXDestructor(Dtor, DtorType);
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
- llvm::Value *Callee
- = CGF.BuildVirtualCall(GlobalDecl(Dtor, DtorType), This, Ty);
+ llvm::Value *Callee =
+ getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, DtorType), This, Ty);
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
/*ImplicitParam=*/0, QualType(), 0, 0);
Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Wed Aug 21 01:25:03 2013
@@ -113,10 +113,34 @@ public:
void EmitCXXDestructors(const CXXDestructorDecl *D);
+ const CXXRecordDecl *getThisArgumentTypeForMethod(const CXXMethodDecl *MD) {
+ MD = MD->getCanonicalDecl();
+ if (MD->isVirtual() && !isa<CXXDestructorDecl>(MD)) {
+ MicrosoftVFTableContext::MethodVFTableLocation ML =
+ CGM.getVFTableContext().getMethodVFTableLocation(MD);
+ // The vbases might be ordered differently in the final overrider object
+ // and the complete object, so the "this" argument may sometimes point to
+ // memory that has no particular type (e.g. past the complete object).
+ // In this case, we just use a generic pointer type.
+ // FIXME: might want to have a more precise type in the non-virtual
+ // multiple inheritance case.
+ if (ML.VBase || !ML.VFTableOffset.isZero())
+ return 0;
+ }
+ return MD->getParent();
+ }
+
+ llvm::Value *adjustThisArgumentForVirtualCall(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Value *This);
+
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params);
+ llvm::Value *adjustThisParameterInVirtualFunctionPrologue(
+ CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This);
+
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
void EmitConstructorCall(CodeGenFunction &CGF,
@@ -125,7 +149,10 @@ public:
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
-
+
+ llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD,
+ llvm::Value *This, llvm::Type *Ty);
+
void EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor,
CXXDtorType DtorType, SourceLocation CallLoc,
@@ -423,6 +450,34 @@ void MicrosoftCXXABI::EmitCXXDestructors
CGM.EmitGlobal(GlobalDecl(D, Dtor_Base));
}
+llvm::Value *MicrosoftCXXABI::adjustThisArgumentForVirtualCall(
+ CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) {
+ GD = GD.getCanonicalDecl();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ if (isa<CXXDestructorDecl>(MD))
+ return This;
+
+ MicrosoftVFTableContext::MethodVFTableLocation ML =
+ CGM.getVFTableContext().getMethodVFTableLocation(GD);
+
+ unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace();
+ llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS);
+ if (ML.VBase) {
+ This = CGF.Builder.CreateBitCast(This, charPtrTy);
+ llvm::Value *VBaseOffset = CGM.getCXXABI()
+ .GetVirtualBaseClassOffset(CGF, This, MD->getParent(), ML.VBase);
+ This = CGF.Builder.CreateInBoundsGEP(This, VBaseOffset);
+ }
+ CharUnits StaticOffset = ML.VFTableOffset;
+ if (!StaticOffset.isZero()) {
+ assert(StaticOffset.isPositive());
+ This = CGF.Builder.CreateBitCast(This, charPtrTy);
+ This = CGF.Builder
+ .CreateConstInBoundsGEP1_64(This, StaticOffset.getQuantity());
+ }
+ return This;
+}
+
static bool IsDeletingDtor(GlobalDecl GD) {
const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
if (isa<CXXDestructorDecl>(MD)) {
@@ -457,6 +512,41 @@ void MicrosoftCXXABI::BuildInstanceFunct
}
}
+llvm::Value *MicrosoftCXXABI::adjustThisParameterInVirtualFunctionPrologue(
+ CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) {
+ GD = GD.getCanonicalDecl();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ if (isa<CXXDestructorDecl>(MD))
+ return This;
+
+ // In this ABI, every virtual function takes a pointer to one of the
+ // subobjects that first defines it as the 'this' parameter, rather than a
+ // pointer to ther final overrider subobject. Thus, we need to adjust it back
+ // to the final overrider subobject before use.
+ // See comments in the MicrosoftVFTableContext implementation for the details.
+
+ MicrosoftVFTableContext::MethodVFTableLocation ML =
+ CGM.getVFTableContext().getMethodVFTableLocation(GD);
+ CharUnits Adjustment = ML.VFTableOffset;
+ if (ML.VBase) {
+ const ASTRecordLayout &DerivedLayout =
+ CGF.getContext().getASTRecordLayout(MD->getParent());
+ Adjustment += DerivedLayout.getVBaseClassOffset(ML.VBase);
+ }
+
+ if (Adjustment.isZero())
+ return This;
+
+ unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace();
+ llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS),
+ *thisTy = This->getType();
+
+ This = CGF.Builder.CreateBitCast(This, charPtrTy);
+ assert(Adjustment.isPositive());
+ This = CGF.Builder.CreateConstGEP1_64(This, -Adjustment.getQuantity());
+ return CGF.Builder.CreateBitCast(This, thisTy);
+}
+
void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
EmitThisParam(CGF);
@@ -514,6 +604,24 @@ void MicrosoftCXXABI::EmitConstructorCal
ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd);
}
+llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
+ GlobalDecl GD,
+ llvm::Value *This,
+ llvm::Type *Ty) {
+ GD = GD.getCanonicalDecl();
+ CGBuilderTy &Builder = CGF.Builder;
+
+ Ty = Ty->getPointerTo()->getPointerTo();
+ llvm::Value *VPtr = adjustThisArgumentForVirtualCall(CGF, GD, This);
+ llvm::Value *VTable = CGF.GetVTablePtr(VPtr, Ty);
+
+ MicrosoftVFTableContext::MethodVFTableLocation ML =
+ CGM.getVFTableContext().getMethodVFTableLocation(GD);
+ llvm::Value *VFuncPtr =
+ Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn");
+ return Builder.CreateLoad(VFuncPtr);
+}
+
void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
const CXXDestructorDecl *Dtor,
CXXDtorType DtorType,
@@ -523,15 +631,15 @@ void MicrosoftCXXABI::EmitVirtualDestruc
// We have only one destructor in the vftable but can get both behaviors
// by passing an implicit bool parameter.
- const CGFunctionInfo *FInfo
- = &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
+ const CGFunctionInfo *FInfo =
+ &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
- llvm::Value *Callee
- = CGF.BuildVirtualCall(GlobalDecl(Dtor, Dtor_Deleting), This, Ty);
+ llvm::Value *Callee =
+ getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, Dtor_Deleting), This, Ty);
ASTContext &Context = CGF.getContext();
- llvm::Value *ImplicitParam
- = llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()),
+ llvm::Value *ImplicitParam =
+ llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()),
DtorType == Dtor_Deleting);
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp?rev=188870&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp Wed Aug 21 01:25:03 2013
@@ -0,0 +1,147 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+struct Left {
+ virtual void left();
+};
+
+struct Right {
+ virtual void right();
+};
+
+struct ChildNoOverride : Left, Right {
+};
+
+struct ChildOverride : Left, Right {
+ virtual void left();
+ virtual void right();
+};
+
+extern "C" void foo(void *);
+
+void call_left_no_override(ChildNoOverride *child) {
+// CHECK: define void @"\01?call_left_no_override
+// CHECK: %[[CHILD:.*]] = load %struct.ChildNoOverride
+
+ child->left();
+// Only need to cast 'this' to Left*.
+// CHECK: %[[LEFT:.*]] = bitcast %struct.ChildNoOverride* %[[CHILD]] to %struct.Left*
+// CHECK: %[[VFPTR:.*]] = bitcast %struct.Left* %[[LEFT]] to void (%struct.Left*)***
+// CHECK: %[[VFTABLE:.*]] = load void (%struct.Left*)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.Left*)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.Left*)** %[[VFUN]]
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.Left* %[[LEFT]])
+// CHECK: ret
+}
+
+void ChildOverride::left() {
+// CHECK: define x86_thiscallcc void @"\01?left at ChildOverride@@UAEXXZ"(%struct.ChildOverride* %[[THIS:.*]])
+//
+// No need to adjust 'this' as the ChildOverride's layout begins with Left.
+// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.ChildOverride*, align 4
+// CHECK: store %struct.ChildOverride* %[[THIS]], %struct.ChildOverride** %[[THIS_ADDR]], align 4
+
+ foo(this);
+// CHECK: %[[THIS:.*]] = load %struct.ChildOverride** %[[THIS_ADDR]]
+// CHECK: %[[THIS_i8:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8*
+// CHECK: call void @foo(i8* %[[THIS_i8]])
+// CHECK: ret
+}
+
+void call_left_override(ChildOverride *child) {
+// CHECK: define void @"\01?call_left_override
+// CHECK: %[[CHILD:.*]] = load %struct.ChildOverride
+
+ child->left();
+// CHECK: %[[VFPTR:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to void (%struct.ChildOverride*)***
+// CHECK: %[[VFTABLE:.*]] = load void (%struct.ChildOverride*)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.ChildOverride*)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.ChildOverride*)** %[[VFUN]]
+//
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.ChildOverride* %[[CHILD]])
+// CHECK: ret
+}
+
+void call_right_no_override(ChildNoOverride *child) {
+// CHECK: define void @"\01?call_right_no_override
+// CHECK: %[[CHILD:.*]] = load %struct.ChildNoOverride
+
+ child->right();
+// When calling a right base's virtual method, one needs to adjust 'this' at
+// the caller site.
+//
+// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildNoOverride* %[[CHILD]] to i8*
+// CHECK: %[[RIGHT_i8:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i32 4
+// CHECK: %[[RIGHT:.*]] = bitcast i8* %[[RIGHT_i8]] to %struct.Right*
+//
+// CHECK: %[[VFPTR:.*]] = bitcast %struct.Right* %[[RIGHT]] to void (%struct.Right*)***
+// CHECK: %[[VFTABLE:.*]] = load void (%struct.Right*)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.Right*)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.Right*)** %[[VFUN]]
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.Right* %[[RIGHT]])
+// CHECK: ret
+}
+
+void ChildOverride::right() {
+// CHECK: define x86_thiscallcc void @"\01?right at ChildOverride@@UAEXXZ"(i8*
+//
+// ChildOverride::right gets 'this' cast to Right* in ECX (i.e. this+4) so we
+// need to adjust 'this' before use.
+//
+// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.ChildOverride*, align 4
+// CHECK: %[[THIS_i8:.*]] = getelementptr i8* %[[ECX:.*]], i64 -4
+// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.ChildOverride*
+// CHECK: store %struct.ChildOverride* %[[THIS]], %struct.ChildOverride** %[[THIS_ADDR]], align 4
+
+ foo(this);
+// CHECK: %[[THIS:.*]] = load %struct.ChildOverride** %[[THIS_ADDR]]
+// CHECK: %[[THIS_PARAM:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8*
+// CHECK: call void @foo(i8* %[[THIS_PARAM]])
+// CHECK: ret
+}
+
+void call_right_override(ChildOverride *child) {
+// CHECK: define void @"\01?call_right_override
+// CHECK: %[[CHILD:.*]] = load %struct.ChildOverride
+
+ child->right();
+// When calling a right child's virtual method, one needs to adjust 'this' at
+// the caller site.
+//
+// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8*
+//
+// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i64 4
+// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to void (i8*)***
+// CHECK: %[[VFTABLE:.*]] = load void (i8*)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)** %[[VFTABLE]], i64 0
+// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)** %[[VFUN]]
+//
+// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8*
+// CHECK: %[[RIGHT:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i64 4
+//
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](i8* %[[RIGHT]])
+// CHECK: ret
+}
+
+struct GrandchildOverride : ChildOverride {
+ virtual void right();
+};
+
+void GrandchildOverride::right() {
+// CHECK: define x86_thiscallcc void @"\01?right at GrandchildOverride@@UAEXXZ"(i8*
+//
+// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.GrandchildOverride*, align 4
+// CHECK: %[[THIS_i8:.*]] = getelementptr i8* %[[ECX:.*]], i64 -4
+// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.GrandchildOverride*
+// CHECK: store %struct.GrandchildOverride* %[[THIS]], %struct.GrandchildOverride** %[[THIS_ADDR]], align 4
+
+ foo(this);
+// CHECK: %[[THIS:.*]] = load %struct.GrandchildOverride** %[[THIS_ADDR]]
+// CHECK: %[[THIS_PARAM:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to i8*
+// CHECK: call void @foo(i8* %[[THIS_PARAM]])
+// CHECK: ret
+}
+
+void call_grandchild_right(GrandchildOverride *obj) {
+ // Just make sure we don't crash.
+ obj->right();
+}
Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp Wed Aug 21 01:25:03 2013
@@ -1,11 +1,79 @@
-// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o %t
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o - | FileCheck %s
-struct A {};
-struct B : virtual A {
- virtual ~B();
+struct VBase {
+ virtual void foo();
+ virtual void bar();
+ int field;
};
-struct C : B {
- C();
+
+struct B : virtual VBase {
+ virtual void foo();
+ virtual void bar();
};
-C::C() {}
+void B::foo() {
+// CHECK: define x86_thiscallcc void @"\01?foo at B@@UAEXXZ"(i8*
+//
+// B::foo gets 'this' cast to VBase* in ECX (i.e. this+8) so we
+// need to adjust 'this' before use.
+//
+// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.B*, align 4
+// CHECK: %[[THIS_i8:.*]] = getelementptr i8* %[[ECX:.*]], i64 -8
+// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B*
+// CHECK: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR]], align 4
+
+ field = 42;
+// CHECK: %[[THIS:.*]] = load %struct.B** %[[THIS_ADDR]]
+// CHECK: %[[THIS8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS8]], i32 0
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
+// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
+// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
+// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
+// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
+// CHECK: %[[THIS8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
+// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS8]], i32 %[[VBOFFSET]]
+// CHECK: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.VBase*
+// CHECK: %[[FIELD:.*]] = getelementptr inbounds %struct.VBase* %[[VBASE]], i32 0, i32 1
+// CHECK: store i32 42, i32* %[[FIELD]], align 4
+//
+// CHECK: ret void
+}
+
+void call_vbase_bar(B *obj) {
+// CHECK: define void @"\01?call_vbase_bar@@YAXPAUB@@@Z"(%struct.B* %obj)
+// CHECK: %[[OBJ:.*]] = load %struct.B
+
+ obj->bar();
+// When calling a vbase's virtual method, one needs to adjust 'this'
+// at the caller site.
+//
+// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
+// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
+// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
+// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
+// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
+// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
+// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
+// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (i8*)***
+// CHECK: %[[VFTABLE:.*]] = load void (i8*)*** %[[VFPTR]]
+// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)** %[[VFTABLE]], i64 1
+// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)** %[[VFUN]]
+//
+// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8*
+// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0
+// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8**
+// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]]
+// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4
+// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32*
+// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]]
+// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]]
+// CHECK: %[[VBASE:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]]
+//
+// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](i8* %[[VBASE]])
+//
+// CHECK: ret void
+}
Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp?rev=188870&r1=188869&r2=188870&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp Wed Aug 21 01:25:03 2013
@@ -17,12 +17,12 @@
// v*table info was required by a constructor or a method definition.
struct A {
- // CHECK-A: Vtable for 'A' (3 entries)
+ // CHECK-A: VFTable for 'A' (3 entries)
// CHECK-A-NEXT: 0 | void A::f()
// CHECK-A-NEXT: 1 | void A::g()
// CHECK-A-NEXT: 2 | void A::h()
- // CHECK-A: VFTable for 'A' (3 entries)
+ // CHECK-A: Vtable for 'A' (3 entries)
// CHECK-A-NEXT: 0 | void A::f()
// CHECK-A-NEXT: 1 | void A::g()
// CHECK-A-NEXT: 2 | void A::h()
More information about the cfe-commits
mailing list