зеркало из https://github.com/microsoft/clang-1.git
[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:
Родитель
9a50249cd3
Коммит
8f88a1dcc5
|
@ -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 {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче