New patch addressing Timur's comments.
Hi rnk, timurrrr,
http://llvm-reviews.chandlerc.com/D2104
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D2104?vs=5358&id=5420#toc
Files:
include/clang/AST/Mangle.h
lib/AST/MicrosoftMangle.cpp
lib/CodeGen/CGVTables.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/MicrosoftCXXABI.cpp
test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
Index: include/clang/AST/Mangle.h
===================================================================
--- include/clang/AST/Mangle.h
+++ include/clang/AST/Mangle.h
@@ -193,6 +193,9 @@
ArrayRef<const CXXRecordDecl *> BasePath,
raw_ostream &Out) = 0;
+ virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ int OffsetInVFTable, raw_ostream &) = 0;
+
static bool classof(const MangleContext *C) {
return C->getKind() == MK_Microsoft;
}
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -181,6 +181,8 @@
: MicrosoftMangleContext(Context, Diags) {}
virtual bool shouldMangleCXXName(const NamedDecl *D);
virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out);
+ virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ int OffsetInVFTable, raw_ostream &);
virtual void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &);
@@ -1921,6 +1923,19 @@
}
}
+void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(
+ const CXXMethodDecl *MD, int OffsetInVFTable, raw_ostream &Out) {
+ bool Is64Bit = getASTContext().getTargetInfo().getPointerWidth(0) == 64;
+
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_9";
+ Mangler.mangleName(MD->getParent());
+ Mangler.getStream() << "$B";
+ Mangler.mangleNumber(OffsetInVFTable);
+ Mangler.getStream() << "A";
+ Mangler.getStream() << (Is64Bit ? "A" : "E");
+}
+
void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &Out) {
Index: lib/CodeGen/CGVTables.cpp
===================================================================
--- lib/CodeGen/CGVTables.cpp
+++ lib/CodeGen/CGVTables.cpp
@@ -253,6 +253,7 @@
// CodeGenFunction::GenerateCode.
// Create the implicit 'this' parameter declaration.
+ assert(!CurGD.getDecl() && "CurGD was already set!");
CurGD = GD;
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResultType, FunctionArgs);
@@ -339,6 +340,81 @@
setThunkVisibility(CGM, MD, Thunk, Fn);
}
+llvm::Function *
+CodeGenFunction::GenerateVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ StringRef ThunkName) {
+ // If the thunk has been generated previously, just return it.
+ if (llvm::GlobalValue *GV = CGM.getModule().getNamedValue(ThunkName))
+ return cast<llvm::Function>(GV);
+
+ // Create the llvm::Function.
+ const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(MD);
+ llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
+ llvm::Function *ThunkFn =
+ llvm::Function::Create(ThunkTy, llvm::Function::ExternalLinkage,
+ ThunkName.str(), &CGM.getModule());
+ assert(ThunkFn->getName() == ThunkName && "name was uniqued!");
+ ThunkFn->setLinkage(llvm::GlobalValue::LinkOnceODRLinkage);
+ CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn);
+ CGM.SetLLVMFunctionAttributesForDefinition(MD, ThunkFn);
+
+ CurGD = MD;
+
+ // Build FunctionArgs.
+ FunctionArgList FunctionArgs;
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ QualType ResultType = FPT->getResultType();
+ CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResultType, FunctionArgs);
+ for (FunctionDecl::param_const_iterator I = MD->param_begin(),
+ E = MD->param_end();
+ I != E; ++I)
+ FunctionArgs.push_back(*I);
+
+ // Start defining the function.
+ StartFunction(GlobalDecl(), ResultType, ThunkFn, FnInfo, FunctionArgs,
+ SourceLocation());
+ CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
+
+ // Get the 'this' pointer.
+ CXXThisValue = CXXABIThisValue;
+ llvm::Value *This = LoadCXXThis();
+
+ // Get to the Callee in the ABI-specific way.
+ llvm::Value *Callee =
+ CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, ThunkTy);
+
+ // Build call arguments.
+ CallArgList CallArgs;
+ QualType ThisType = MD->getThisType(getContext());
+ CallArgs.add(RValue::get(This), ThisType);
+ for (FunctionDecl::param_const_iterator I = MD->param_begin(),
+ E = MD->param_end();
+ I != E; ++I)
+ EmitDelegateCallArg(CallArgs, *I, (*I)->getLocStart());
+
+ // Determine whether we have a return value slot to use.
+ ReturnValueSlot Slot;
+ if (!ResultType->isVoidType() &&
+ FnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
+ !hasScalarEvaluationKind(CurFnInfo->getReturnType()))
+ Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
+
+ // Emit the call.
+ RValue RV = EmitCall(FnInfo, Callee, Slot, CallArgs, MD);
+
+ // Note: we don't do any return adjustment. The callee should be doing that if
+ // necessary.
+
+ // Emit return.
+ if (!ResultType->isVoidType() && Slot.isNull())
+ CGM.getCXXABI().EmitReturnFromThunk(*this, RV, ResultType);
+
+ FinishFunction();
+ CGM.setFunctionLinkage(MD, ThunkFn); // XXX: Do we need this?
+
+ return ThunkFn;
+}
+
void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
bool ForVTable) {
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeGlobalDeclaration(GD);
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1157,6 +1157,11 @@
void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk);
+ /// \brief Generate a thunk for calling virtual member function MD, which
+ /// is at position VTableIndex in the vtable.
+ llvm::Function *GenerateVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ StringRef ThunkName);
+
void GenerateVarArgsThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk);
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1370,11 +1370,34 @@
CodeGenTypes &Types = CGM.getTypes();
llvm::Constant *FirstField;
- if (MD->isVirtual()) {
- // FIXME: We have to instantiate a thunk that loads the vftable and jumps to
- // the right offset.
- CGM.ErrorUnsupported(MD, "pointer to virtual member function");
+ if (MD->isVirtual() && MD->isVariadic()) {
+ CGM.ErrorUnsupported(MD, "pointer to variadic virtual member function");
FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
+ } else if (MD->isVirtual() && !CGM.getTypes().isFuncTypeConvertible(
+ MD->getType()->castAs<FunctionType>())) {
+ CGM.ErrorUnsupported(MD, "pointer to virtual member function with "
+ "incomplete return or parameter type");
+ FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
+ } else if (MD->isVirtual() && CGM.getMicrosoftVTableContext()
+ .getMethodVFTableLocation(MD)
+ .VBase) {
+ CGM.ErrorUnsupported(MD, "pointer to virtual member function overriding "
+ "member function in virtual base class");
+ FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
+ } else if (MD->isVirtual()) {
+ MicrosoftVTableContext::MethodVFTableLocation ML =
+ CGM.getMicrosoftVTableContext().getMethodVFTableLocation(MD);
+
+ SmallString<256> ThunkName;
+ bool Is64Bit = getContext().getTargetInfo().getPointerWidth(0) == 64;
+ int OffsetInVFTable = ML.Index * (Is64Bit ? 8 : 4);
+ llvm::raw_svector_ostream Out(ThunkName);
+ getMangleContext().mangleVirtualMemPtrThunk(MD, OffsetInVFTable, Out);
+ Out.flush();
+
+ CodeGenFunction CGF(CGM);
+ llvm::Function *Thunk = CGF.GenerateVirtualMemPtrThunk(MD, ThunkName.str());
+ FirstField = llvm::ConstantExpr::getBitCast(Thunk, CGM.VoidPtrTy);
} else {
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
llvm::Type *Ty;
@@ -1875,4 +1898,3 @@
CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
return new MicrosoftCXXABI(CGM);
}
-
Index: test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/microsoft-abi-virtual-member-pointers.cpp
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=i386-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK32
+// RUN: %clang_cc1 -fno-rtti -emit-llvm -cxx-abi microsoft -triple=x86_64-pc-win32 %s -o - | FileCheck %s --check-prefix=CHECK64
+
+struct S {
+ int x, y, z;
+};
+
+struct C {
+ virtual void foo();
+ virtual int bar(int, double);
+ virtual S baz(int);
+};
+
+void f() {
+ void (C::*ptr)();
+ ptr = &C::foo;
+ ptr = &C::foo; // Don't crash trying to define the thunk twice :)
+
+ int (C::*ptr2)(int, double);
+ ptr2 = &C::bar;
+
+ S (C::*ptr3)(int);
+ ptr3 = &C::baz;
+
+// CHECK32-LABEL: define void @"\01?f@@YAXXZ"()
+// CHECK32: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AE" to i8*), i8** %ptr
+// CHECK32: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B3AE" to i8*), i8** %ptr2
+// CHECK32: store i8* bitcast (void (%struct.S*, %struct.C*, i32)* @"\01??_9C@@$B7AE" to i8*), i8** %ptr3
+// CHECK32: }
+//
+// CHECK64-LABEL: define void @"\01?f@@YAXXZ"()
+// CHECK64: store i8* bitcast (void (%struct.C*)* @"\01??_9C@@$BA@AA" to i8*), i8** %ptr
+// CHECK64: store i8* bitcast (i32 (%struct.C*, i32, double)* @"\01??_9C@@$B7AA" to i8*), i8** %ptr2
+// CHECK64: store i8* bitcast (void (%struct.S*, %struct.C*, i32)* @"\01??_9C@@$BBA@AA" to i8*), i8** %ptr3
+// CHECK64: }
+}
+
+// Thunk for calling the 1st virtual function in C with no parameters.
+// CHECK32-LABEL: define x86_thiscallcc void @"\01??_9C@@$BA@AE"(%struct.C* %this) unnamed_addr
+// CHECK32: %vfn = getelementptr inbounds void (%struct.C*)** %vtable, i64 0
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.C*)** %vfn
+// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.C* %this{{.*}})
+// CHECK32: ret void
+// CHECK32: }
+//
+// CHECK64-LABEL: define void @"\01??_9C@@$BA@AA"(%struct.C* %this) unnamed_addr
+// CHECK64: %vfn = getelementptr inbounds void (%struct.C*)** %vtable, i64 0
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.C*)** %vfn
+// CHECK64: call void [[CALLEE]](%struct.C* %this{{.*}})
+// CHECK64: ret void
+// CHECK64: }
+
+// Thunk for calling the 2nd virtual function in C, taking int and double as parameters, returning int.
+// CHECK32-LABEL: define x86_thiscallcc i32 @"\01??_9C@@$B3AE"(%struct.C* %this, i32, double) unnamed_addr
+// CHECK32: %vfn = getelementptr inbounds i32 (%struct.C*, i32, double)** %vtable, i64 1
+// CHECK32: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** %vfn
+// CHECK32: %call = call x86_thiscallcc i32 [[CALLEE]](%struct.C* %this{{.*}}, i32 %{{.*}}, double %{{.*}})
+// CHECK32: ret i32 %call
+// CHECK32: }
+//
+// CHECK64-LABEL: define i32 @"\01??_9C@@$B7AA"(%struct.C* %this, i32, double) unnamed_addr
+// CHECK64: %vfn = getelementptr inbounds i32 (%struct.C*, i32, double)** %vtable, i64 1
+// CHECK64: [[CALLEE:%.*]] = load i32 (%struct.C*, i32, double)** %vfn
+// CHECK64: %call = call i32 [[CALLEE]](%struct.C* %this{{.*}}, i32 %{{.*}}, double %{{.*}})
+// CHECK64: ret i32 %call
+// CHECK64: }
+
+// Thunk for calling the 3rd virtual function in C, taking an int parameter, returning a struct.
+// CHECK32-LABEL: define x86_thiscallcc void @"\01??_9C@@$B7AE"(%struct.S* noalias sret %agg.result, %struct.C* %this, i32) unnamed_addr
+// CHECK32: %vfn = getelementptr inbounds void (%struct.S*, %struct.C*, i32)** %vtable, i64 2
+// CHECK32: [[CALLEE:%.*]] = load void (%struct.S*, %struct.C*, i32)** %vfn
+// CHECK32: call x86_thiscallcc void [[CALLEE]](%struct.S* sret %agg.result, %struct.C* %this{{.*}}, i32 %{{.*}})
+// CHECK32: ret void
+// CHECK32: }
+//
+// CHECK64-LABEL: define void @"\01??_9C@@$BBA@AA"(%struct.S* noalias sret %agg.result, %struct.C* %this, i32) unnamed_addr
+// CHECK64: %vfn = getelementptr inbounds void (%struct.S*, %struct.C*, i32)** %vtable, i64 2
+// CHECK64: [[CALLEE:%.*]] = load void (%struct.S*, %struct.C*, i32)** %vfn
+// CHECK64: call void [[CALLEE]](%struct.S* sret %agg.result, %struct.C* %this{{.*}}, i32 %{{.*}})
+// CHECK64: ret void
+// CHECK64: }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits