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

Reply via email to