]> granicus.if.org Git - clang/commitdiff
[Windows] Use thiscall as the default calling convention for class methods. PR12785
authorTimur Iskhodzhanov <timurrrr@google.com>
Thu, 12 Jul 2012 09:50:54 +0000 (09:50 +0000)
committerTimur Iskhodzhanov <timurrrr@google.com>
Thu, 12 Jul 2012 09:50:54 +0000 (09:50 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160121 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/AST/CXXABI.h
lib/AST/ItaniumCXXABI.cpp
lib/AST/MicrosoftCXXABI.cpp
lib/AST/MicrosoftMangle.cpp
lib/CodeGen/CGCall.cpp
test/CodeGenCXX/microsoft-abi-methods.cpp [new file with mode: 0644]
test/CodeGenCXX/microsoft-abi-static-initializers.cpp

index 5283d6dadccf5e87d50b8a3ba8e9d98d452ea4cf..a8b00a7c7bb6590d049832e0c1120e93186d7943 100644 (file)
@@ -1501,15 +1501,11 @@ public:
 
   /// \brief Retrieves the default calling convention to use for
   /// C++ instance methods.
-  CallingConv getDefaultMethodCallConv();
+  CallingConv getDefaultCXXMethodCallConv(bool isVariadic);
 
   /// \brief Retrieves the canonical representation of the given
   /// calling convention.
-  CallingConv getCanonicalCallConv(CallingConv CC) const {
-    if (!LangOpts.MRTD && CC == CC_C)
-      return CC_Default;
-    return CC;
-  }
+  CallingConv getCanonicalCallConv(CallingConv CC) const;
 
   /// \brief Determines whether two calling conventions name the same
   /// calling convention.
index 27e4de926d3d001b77854a8774eea9fb52d75662..2a1521e21e8a15fb411ea9f0b54982a7f6939cba 100644 (file)
@@ -7098,9 +7098,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
   return true;
 }
 
-CallingConv ASTContext::getDefaultMethodCallConv() {
+CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
   // Pass through to the C++ ABI object
-  return ABI->getDefaultMethodCallConv();
+  return ABI->getDefaultMethodCallConv(isVariadic);
+}
+
+CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const {
+  if (CC == CC_C && !LangOpts.MRTD && getTargetInfo().getCXXABI() != CXXABI_Microsoft)
+    return CC_Default;
+  return CC;
 }
 
 bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
index 943c43e791987329fd104afe0dc41d35a1d7793a..0d9c869d87ca415a66047919c406a6de00168ac3 100644 (file)
@@ -32,7 +32,7 @@ public:
   virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0;
 
   /// Returns the default calling convention for C++ methods.
-  virtual CallingConv getDefaultMethodCallConv() const = 0;
+  virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0;
 
   // Returns whether the given class is nearly empty, with just virtual pointers
   // and no data except possibly virtual bases.
index 0027dbf1915bbbdea240493d1eef82c0e092cbbb..ce1244c542726488a831c3d70588733104c40e87 100644 (file)
@@ -39,7 +39,7 @@ public:
     return 1;
   }
 
-  CallingConv getDefaultMethodCallConv() const {
+  CallingConv getDefaultMethodCallConv(bool isVariadic) const {
     return CC_C;
   }
 
index f33d6fe1f5632eef6be67acd5ae1cd321378393e..51308ea0c0f550fe694ecb77b99ee132a97443c2 100644 (file)
@@ -29,8 +29,8 @@ public:
 
   unsigned getMemberPointerSize(const MemberPointerType *MPT) const;
 
-  CallingConv getDefaultMethodCallConv() const {
-    if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
+  CallingConv getDefaultMethodCallConv(bool isVariadic) const {
+    if (!isVariadic && Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
       return CC_X86ThisCall;
     else
       return CC_C;
index 37c654d66695fe0e0ec22a3ad00b06f972d5a126..d9fa057971399992f0f9c969232796e8fb4c08c7 100644 (file)
@@ -1159,8 +1159,16 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
   // that they could be in a DLL and somebody from another module could call
   // them.)
   CallingConv CC = T->getCallConv();
-  if (CC == CC_Default)
-    CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C;
+  if (CC == CC_Default) {
+    if (IsInstMethod) {
+      const FunctionProtoType *FPT =
+        T->getCanonicalTypeUnqualified().getAs<FunctionProtoType>();
+      bool isVariadic = FPT->isVariadic();
+      CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic);
+    } else {
+      CC = CC_C;
+    }
+  }
   switch (CC) {
     default:
       llvm_unreachable("Unsupported CC for mangling");
index 0ecd97693fe0e43d23a426ba65ac5d950a3a9018..37a9a5eaff03319e31d54460699c964630505b63 100644 (file)
@@ -105,8 +105,12 @@ static const CGFunctionInfo &arrangeFreeFunctionType(CodeGenTypes &CGT,
 /// Given the formal ext-info of a C++ instance method, adjust it
 /// according to the C++ ABI in effect.
 static void adjustCXXMethodInfo(CodeGenTypes &CGT,
-                                FunctionType::ExtInfo &extInfo) {
-  // FIXME: thiscall on Microsoft
+                                FunctionType::ExtInfo &extInfo,
+                                bool isVariadic) {
+  if (extInfo.getCC() == CC_Default) {
+    CallingConv CC = CGT.getContext().getDefaultCXXMethodCallConv(isVariadic);
+    extInfo = extInfo.withCallingConv(CC);
+  }
 }
 
 /// Arrange the argument and result information for a free function (i.e.
@@ -115,7 +119,7 @@ static const CGFunctionInfo &arrangeCXXMethodType(CodeGenTypes &CGT,
                                       SmallVectorImpl<CanQualType> &prefix,
                                             CanQual<FunctionProtoType> FTP) {
   FunctionType::ExtInfo extInfo = FTP->getExtInfo();
-  adjustCXXMethodInfo(CGT, extInfo);
+  adjustCXXMethodInfo(CGT, extInfo, FTP->isVariadic());
   return arrangeLLVMFunctionInfo(CGT, prefix, FTP, extInfo);
 }
 
@@ -202,7 +206,7 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
     argTypes.push_back(FTP->getArgType(i));
 
   FunctionType::ExtInfo extInfo = FTP->getExtInfo();
-  adjustCXXMethodInfo(*this, extInfo);
+  adjustCXXMethodInfo(*this, extInfo, FTP->isVariadic());
   return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, required);
 }
 
@@ -220,9 +224,10 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
 
   CanQual<FunctionProtoType> FTP = GetFormalType(D);
   assert(FTP->getNumArgs() == 0 && "dtor with formal parameters");
+  assert(FTP->isVariadic() == 0 && "dtor with formal parameters");
 
   FunctionType::ExtInfo extInfo = FTP->getExtInfo();
-  adjustCXXMethodInfo(*this, extInfo);
+  adjustCXXMethodInfo(*this, extInfo, false);
   return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo,
                                  RequiredArgs::All);
 }
@@ -354,7 +359,7 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
     argTypes.push_back(Context.getCanonicalParamType(i->Ty));
 
   FunctionType::ExtInfo info = FPT->getExtInfo();
-  adjustCXXMethodInfo(*this, info);
+  adjustCXXMethodInfo(*this, info, FPT->isVariadic());
   return arrangeLLVMFunctionInfo(GetReturnType(FPT->getResultType()),
                                  argTypes, info, required);
 }
diff --git a/test/CodeGenCXX/microsoft-abi-methods.cpp b/test/CodeGenCXX/microsoft-abi-methods.cpp
new file mode 100644 (file)
index 0000000..6b7f004
--- /dev/null
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+class C {
+ public:
+  void simple_method() {}
+
+  void __cdecl cdecl_method() {}
+
+  void vararg_method(const char *fmt, ...) {}
+
+  static void static_method() {}
+
+  int a;
+};
+
+void call_simple_method() {
+  C instance;
+
+  instance.simple_method();
+// Make sure that the call uses the right calling convention:
+// CHECK: call x86_thiscallcc void @"\01?simple_method@C@@QAEXXZ"
+// CHECK: ret
+
+// Make sure that the definition uses the right calling convention:
+// CHECK: define linkonce_odr x86_thiscallcc void @"\01?simple_method@C@@QAEXXZ"
+// CHECK: ret
+}
+
+void call_cdecl_method() {
+  C instance;
+  instance.cdecl_method();
+// Make sure that the call uses the right calling convention:
+// CHECK: call void @"\01?cdecl_method@C@@QAAXXZ"
+// CHECK: ret
+
+// Make sure that the definition uses the right calling convention:
+// CHECK: define linkonce_odr void @"\01?cdecl_method@C@@QAAXXZ"
+// CHECK: ret
+}
+
+void call_vararg_method() {
+  C instance;
+  instance.vararg_method("Hello");
+// Make sure that the call uses the right calling convention:
+// CHECK: call void (%class.C*, i8*, ...)* @"\01?vararg_method@C@@QAAXPBDZZ"
+// CHECK: ret
+
+// Make sure that the definition uses the right calling convention:
+// CHECK: define linkonce_odr void @"\01?vararg_method@C@@QAAXPBDZZ"
+}
+
+void call_static_method() {
+  C::static_method();
+// Make sure that the call uses the right calling convention:
+// CHECK: call void @"\01?static_method@C@@SAXXZ"
+// CHECK: ret
+
+// Make sure that the definition uses the right calling convention:
+// CHECK: define linkonce_odr void @"\01?static_method@C@@SAXXZ"
+}
+
+class Base {
+ public:
+  Base() {}
+  ~Base() {}
+};
+
+class Child: public Base { };
+
+void constructors() {
+  Child c;
+// Make sure that the Base constructor call in the Child constructor uses
+// the right calling convention:
+// CHECK: define linkonce_odr x86_thiscallcc void @"\01??0Child@@QAE@XZ"
+// CHECK: call x86_thiscallcc void @"\01??0Base@@QAE@XZ"
+// CHECK: ret
+
+// Make sure that the Base destructor call in the Child denstructor uses
+// the right calling convention:
+// CHECK: define linkonce_odr x86_thiscallcc void @"\01??1Child@@QAE@XZ"
+// CHECK: call x86_thiscallcc void @"\01??1Base@@QAE@XZ"
+// CHECK: ret
+
+// Make sure that the Base destructor definition uses the right CC:
+// CHECK: define linkonce_odr x86_thiscallcc void @"\01??1Base@@QAE@XZ"
+
+// Make sure that the Base constructor definition uses the right CC:
+// CHECK: define linkonce_odr x86_thiscallcc void @"\01??0Base@@QAE@XZ"
+}
index 4ccd6bafecf179543a76e942d0634918a1a3d70b..d8b789943a430942efc6869ac58f195dada10d47 100644 (file)
@@ -6,12 +6,12 @@ struct S {
 } s;
 
 // CHECK: define internal void [[INIT_s:@.*global_var.*]] nounwind
-// CHECK: call void @"\01??0S@@QAE@XZ"
+// CHECK: call x86_thiscallcc void @"\01??0S@@QAE@XZ"
 // CHECK: call i32 @atexit(void ()* @"__dtor_\01?s@@3US@@A")
 // CHECK: ret void
 
 // CHECK: define internal void @"__dtor_\01?s@@3US@@A"() nounwind {
-// CHECK: call void @"\01??1S@@QAE@XZ"
+// CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ"
 // CHECK: ret void
 
 // Force WeakODRLinkage by using templates
@@ -34,16 +34,16 @@ void force_usage() {
 }
 
 // CHECK: define internal void [[INIT_foo:@.*global_var.*]] nounwind
-// CHECK: call void @"\01??0A@@QAE@XZ"
+// CHECK: call x86_thiscallcc void @"\01??0A@@QAE@XZ"
 // CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]])
 // CHECK: ret void
 
-// CHECK: define linkonce_odr void @"\01??0A@@QAE@XZ"
+// CHECK: define linkonce_odr x86_thiscallcc void @"\01??0A@@QAE@XZ"
 
-// CHECK: define linkonce_odr void @"\01??1A@@QAE@XZ"
+// CHECK: define linkonce_odr x86_thiscallcc void @"\01??1A@@QAE@XZ"
 
 // CHECK: define internal void [[FOO_DTOR]]
-// CHECK: call void @"\01??1A@@QAE@XZ"{{.*}}foo
+// CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"{{.*}}foo
 // CHECK: ret void
 
 // CHECK: define internal void @_GLOBAL__I_a() nounwind {