From: Timur Iskhodzhanov Date: Thu, 12 Jul 2012 09:50:54 +0000 (+0000) Subject: [Windows] Use thiscall as the default calling convention for class methods. PR12785 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8f88a1dcc57cfe8580eb1558a783ad8499bfe8e0;p=clang [Windows] Use thiscall as the default calling convention for class methods. PR12785 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160121 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 5283d6dadc..a8b00a7c7b 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 27e4de926d..2a1521e21e 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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 { diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 943c43e791..0d9c869d87 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -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. diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp index 0027dbf191..ce1244c542 100644 --- a/lib/AST/ItaniumCXXABI.cpp +++ b/lib/AST/ItaniumCXXABI.cpp @@ -39,7 +39,7 @@ public: return 1; } - CallingConv getDefaultMethodCallConv() const { + CallingConv getDefaultMethodCallConv(bool isVariadic) const { return CC_C; } diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index f33d6fe1f5..51308ea0c0 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -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; diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 37c654d666..d9fa057971 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -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(); + bool isVariadic = FPT->isVariadic(); + CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic); + } else { + CC = CC_C; + } + } switch (CC) { default: llvm_unreachable("Unsupported CC for mangling"); diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 0ecd97693f..37a9a5eaff 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -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 &prefix, CanQual 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 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 index 0000000000..6b7f00495d --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-methods.cpp @@ -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" +} diff --git a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp index 4ccd6bafec..d8b789943a 100644 --- a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp +++ b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp @@ -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 {