[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
This commit is contained in:
Timur Iskhodzhanov 2012-07-12 09:50:54 +00:00
Родитель 9a50249cd3
Коммит 8f88a1dcc5
9 изменённых файлов: 130 добавлений и 26 удалений

Просмотреть файл

@ -1501,15 +1501,11 @@ public:
/// \brief Retrieves the default calling convention to use for /// \brief Retrieves the default calling convention to use for
/// C++ instance methods. /// C++ instance methods.
CallingConv getDefaultMethodCallConv(); CallingConv getDefaultCXXMethodCallConv(bool isVariadic);
/// \brief Retrieves the canonical representation of the given /// \brief Retrieves the canonical representation of the given
/// calling convention. /// calling convention.
CallingConv getCanonicalCallConv(CallingConv CC) const { CallingConv getCanonicalCallConv(CallingConv CC) const;
if (!LangOpts.MRTD && CC == CC_C)
return CC_Default;
return CC;
}
/// \brief Determines whether two calling conventions name the same /// \brief Determines whether two calling conventions name the same
/// calling convention. /// calling convention.

Просмотреть файл

@ -7098,9 +7098,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return true; return true;
} }
CallingConv ASTContext::getDefaultMethodCallConv() { CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
// Pass through to the C++ ABI object // 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 { bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {

Просмотреть файл

@ -32,7 +32,7 @@ public:
virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0; virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0;
/// Returns the default calling convention for C++ methods. /// 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 // Returns whether the given class is nearly empty, with just virtual pointers
// and no data except possibly virtual bases. // and no data except possibly virtual bases.

Просмотреть файл

@ -39,7 +39,7 @@ public:
return 1; return 1;
} }
CallingConv getDefaultMethodCallConv() const { CallingConv getDefaultMethodCallConv(bool isVariadic) const {
return CC_C; return CC_C;
} }

Просмотреть файл

@ -29,8 +29,8 @@ public:
unsigned getMemberPointerSize(const MemberPointerType *MPT) const; unsigned getMemberPointerSize(const MemberPointerType *MPT) const;
CallingConv getDefaultMethodCallConv() const { CallingConv getDefaultMethodCallConv(bool isVariadic) const {
if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) if (!isVariadic && Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
return CC_X86ThisCall; return CC_X86ThisCall;
else else
return CC_C; return CC_C;

Просмотреть файл

@ -1159,8 +1159,16 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
// that they could be in a DLL and somebody from another module could call // that they could be in a DLL and somebody from another module could call
// them.) // them.)
CallingConv CC = T->getCallConv(); CallingConv CC = T->getCallConv();
if (CC == CC_Default) if (CC == CC_Default) {
CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C; if (IsInstMethod) {
const FunctionProtoType *FPT =
T->getCanonicalTypeUnqualified().getAs<FunctionProtoType>();
bool isVariadic = FPT->isVariadic();
CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic);
} else {
CC = CC_C;
}
}
switch (CC) { switch (CC) {
default: default:
llvm_unreachable("Unsupported CC for mangling"); llvm_unreachable("Unsupported CC for mangling");

Просмотреть файл

@ -105,8 +105,12 @@ static const CGFunctionInfo &arrangeFreeFunctionType(CodeGenTypes &CGT,
/// Given the formal ext-info of a C++ instance method, adjust it /// Given the formal ext-info of a C++ instance method, adjust it
/// according to the C++ ABI in effect. /// according to the C++ ABI in effect.
static void adjustCXXMethodInfo(CodeGenTypes &CGT, static void adjustCXXMethodInfo(CodeGenTypes &CGT,
FunctionType::ExtInfo &extInfo) { FunctionType::ExtInfo &extInfo,
// FIXME: thiscall on Microsoft 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. /// 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, SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP) { CanQual<FunctionProtoType> FTP) {
FunctionType::ExtInfo extInfo = FTP->getExtInfo(); FunctionType::ExtInfo extInfo = FTP->getExtInfo();
adjustCXXMethodInfo(CGT, extInfo); adjustCXXMethodInfo(CGT, extInfo, FTP->isVariadic());
return arrangeLLVMFunctionInfo(CGT, prefix, FTP, extInfo); return arrangeLLVMFunctionInfo(CGT, prefix, FTP, extInfo);
} }
@ -202,7 +206,7 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
argTypes.push_back(FTP->getArgType(i)); argTypes.push_back(FTP->getArgType(i));
FunctionType::ExtInfo extInfo = FTP->getExtInfo(); FunctionType::ExtInfo extInfo = FTP->getExtInfo();
adjustCXXMethodInfo(*this, extInfo); adjustCXXMethodInfo(*this, extInfo, FTP->isVariadic());
return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, required); return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, required);
} }
@ -220,9 +224,10 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
CanQual<FunctionProtoType> FTP = GetFormalType(D); CanQual<FunctionProtoType> FTP = GetFormalType(D);
assert(FTP->getNumArgs() == 0 && "dtor with formal parameters"); assert(FTP->getNumArgs() == 0 && "dtor with formal parameters");
assert(FTP->isVariadic() == 0 && "dtor with formal parameters");
FunctionType::ExtInfo extInfo = FTP->getExtInfo(); FunctionType::ExtInfo extInfo = FTP->getExtInfo();
adjustCXXMethodInfo(*this, extInfo); adjustCXXMethodInfo(*this, extInfo, false);
return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo,
RequiredArgs::All); RequiredArgs::All);
} }
@ -354,7 +359,7 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
argTypes.push_back(Context.getCanonicalParamType(i->Ty)); argTypes.push_back(Context.getCanonicalParamType(i->Ty));
FunctionType::ExtInfo info = FPT->getExtInfo(); FunctionType::ExtInfo info = FPT->getExtInfo();
adjustCXXMethodInfo(*this, info); adjustCXXMethodInfo(*this, info, FPT->isVariadic());
return arrangeLLVMFunctionInfo(GetReturnType(FPT->getResultType()), return arrangeLLVMFunctionInfo(GetReturnType(FPT->getResultType()),
argTypes, info, required); argTypes, info, required);
} }

Просмотреть файл

@ -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"
}

Просмотреть файл

@ -6,12 +6,12 @@ struct S {
} s; } s;
// CHECK: define internal void [[INIT_s:@.*global_var.*]] nounwind // 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: call i32 @atexit(void ()* @"__dtor_\01?s@@3US@@A")
// CHECK: ret void // CHECK: ret void
// CHECK: define internal void @"__dtor_\01?s@@3US@@A"() nounwind { // 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 // CHECK: ret void
// Force WeakODRLinkage by using templates // Force WeakODRLinkage by using templates
@ -34,16 +34,16 @@ void force_usage() {
} }
// CHECK: define internal void [[INIT_foo:@.*global_var.*]] nounwind // 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: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]])
// CHECK: ret void // 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: 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: ret void
// CHECK: define internal void @_GLOBAL__I_a() nounwind { // CHECK: define internal void @_GLOBAL__I_a() nounwind {