From 3c42441b2c4d907e3236bbb416415510895afd4e Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Wed, 22 Feb 2012 03:04:13 +0000 Subject: [PATCH] Adding support for Microsoft's thiscall calling convention. Clang side of the patch. llvm-svn: 151122 --- clang/lib/CodeGen/TargetInfo.cpp | 32 +++++++++++---- .../CodeGenCXX/thiscall-struct-return.cpp | 41 +++++++++++++++++++ 2 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 clang/test/CodeGenCXX/thiscall-struct-return.cpp diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 2ee662c1e70b..0f00a6ebae2e 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -424,7 +424,8 @@ class X86_32ABIInfo : public ABIInfo { return (Size == 8 || Size == 16 || Size == 32 || Size == 64); } - static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context); + static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context, + unsigned callingConvention); /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be passed in memory. @@ -435,11 +436,13 @@ class X86_32ABIInfo : public ABIInfo { public: - ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyReturnType(QualType RetTy, + unsigned callingConvention) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; virtual void computeInfo(CGFunctionInfo &FI) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), + FI.getCallingConvention()); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) it->info = classifyArgumentType(it->type); @@ -485,7 +488,8 @@ public: /// shouldReturnTypeInRegister - Determine if the given type should be /// passed in a register (for the Darwin ABI). bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, - ASTContext &Context) { + ASTContext &Context, + unsigned callingConvention) { uint64_t Size = Context.getTypeSize(Ty); // Type must be register sized. @@ -510,7 +514,8 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, // Arrays are treated like records. if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) - return shouldReturnTypeInRegister(AT->getElementType(), Context); + return shouldReturnTypeInRegister(AT->getElementType(), Context, + callingConvention); // Otherwise, it must be a record type. const RecordType *RT = Ty->getAs(); @@ -518,6 +523,13 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, // FIXME: Traverse bases here too. + // For thiscall conventions, structures will never be returned in + // a register. This is for compatibility with the MSVC ABI + if (callingConvention == llvm::CallingConv::X86_ThisCall && + RT->isStructureType()) { + return false; + } + // Structure types are passed in register if all fields would be // passed in a register. for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(), @@ -529,14 +541,15 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, continue; // Check fields recursively. - if (!shouldReturnTypeInRegister(FD->getType(), Context)) + if (!shouldReturnTypeInRegister(FD->getType(), Context, + callingConvention)) return false; } - return true; } -ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const { +ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, + unsigned callingConvention) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); @@ -583,7 +596,8 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const { // Small structures which are register sized are generally returned // in a register. - if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext())) { + if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext(), + callingConvention)) { uint64_t Size = getContext().getTypeSize(RetTy); // As a special-case, if the struct is a "single-element" struct, and diff --git a/clang/test/CodeGenCXX/thiscall-struct-return.cpp b/clang/test/CodeGenCXX/thiscall-struct-return.cpp new file mode 100644 index 000000000000..c38fa4ac9976 --- /dev/null +++ b/clang/test/CodeGenCXX/thiscall-struct-return.cpp @@ -0,0 +1,41 @@ +// For MSVC ABI compatibility, all structures returned by value using the +// thiscall calling convention must use the hidden parameter. +// +// RUN: %clang_cc1 -triple i386-PC-Win32 %s -fms-compatibility -O0 -emit-llvm -o - | FileCheck %s + +// This structure would normally be returned via EAX +struct S { + int i; +}; + +// This structure would normally be returned via EAX/EDX +struct M { + int i; + int j; +}; + +class C { +public: + C() {} + + struct S __attribute__((thiscall)) Small() const { + struct S s = { 0 }; + return s; + } + + struct M __attribute__((thiscall)) Medium() const { + struct M m = { 0 }; + return m; + } +}; + +// CHECK: define void @_Z4testv() +void test( void ) { +// CHECK: call void @_ZN1CC1Ev(%class.C* %c) + C c; + +// CHECK: call x86_thiscallcc void @_ZNK1C5SmallEv(%struct.S* sret %tmp, %class.C* %c) + (void)c.Small(); +// CHECK: call x86_thiscallcc void @_ZNK1C6MediumEv(%struct.M* sret %tmp1, %class.C* %c) + (void)c.Medium(); +}