Browse Source

Adding support for Microsoft's thiscall calling convention. Clang side of the patch.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151122 91177308-0d34-0410-b5e6-96231b3b80d8
Aaron Ballman 13 years ago
parent
commit
6c60c8d746
2 changed files with 64 additions and 9 deletions
  1. 23 9
      lib/CodeGen/TargetInfo.cpp
  2. 41 0
      test/CodeGenCXX/thiscall-struct-return.cpp

+ 23 - 9
lib/CodeGen/TargetInfo.cpp

@@ -424,7 +424,8 @@ class X86_32ABIInfo : public ABIInfo {
     return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
     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
   /// getIndirectResult - Give a source type \arg Ty, return a suitable result
   /// such that the argument will be passed in memory.
   /// such that the argument will be passed in memory.
@@ -435,11 +436,13 @@ class X86_32ABIInfo : public ABIInfo {
 
 
 public:
 public:
 
 
-  ABIArgInfo classifyReturnType(QualType RetTy) const;
+  ABIArgInfo classifyReturnType(QualType RetTy, 
+                                unsigned callingConvention) const;
   ABIArgInfo classifyArgumentType(QualType RetTy) const;
   ABIArgInfo classifyArgumentType(QualType RetTy) const;
 
 
   virtual void computeInfo(CGFunctionInfo &FI) 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();
     for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
          it != ie; ++it)
          it != ie; ++it)
       it->info = classifyArgumentType(it->type);
       it->info = classifyArgumentType(it->type);
@@ -485,7 +488,8 @@ public:
 /// shouldReturnTypeInRegister - Determine if the given type should be
 /// shouldReturnTypeInRegister - Determine if the given type should be
 /// passed in a register (for the Darwin ABI).
 /// passed in a register (for the Darwin ABI).
 bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
 bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
-                                               ASTContext &Context) {
+                                               ASTContext &Context,
+                                               unsigned callingConvention) {
   uint64_t Size = Context.getTypeSize(Ty);
   uint64_t Size = Context.getTypeSize(Ty);
 
 
   // Type must be register sized.
   // Type must be register sized.
@@ -510,7 +514,8 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
 
 
   // Arrays are treated like records.
   // Arrays are treated like records.
   if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
   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.
   // Otherwise, it must be a record type.
   const RecordType *RT = Ty->getAs<RecordType>();
   const RecordType *RT = Ty->getAs<RecordType>();
@@ -518,6 +523,13 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
 
 
   // FIXME: Traverse bases here too.
   // 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
   // Structure types are passed in register if all fields would be
   // passed in a register.
   // passed in a register.
   for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(),
   for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(),
@@ -529,14 +541,15 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
       continue;
       continue;
 
 
     // Check fields recursively.
     // Check fields recursively.
-    if (!shouldReturnTypeInRegister(FD->getType(), Context))
+    if (!shouldReturnTypeInRegister(FD->getType(), Context, 
+                                    callingConvention))
       return false;
       return false;
   }
   }
-
   return true;
   return true;
 }
 }
 
 
-ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const {
+ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, 
+                                            unsigned callingConvention) const {
   if (RetTy->isVoidType())
   if (RetTy->isVoidType())
     return ABIArgInfo::getIgnore();
     return ABIArgInfo::getIgnore();
 
 
@@ -583,7 +596,8 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const {
 
 
     // Small structures which are register sized are generally returned
     // Small structures which are register sized are generally returned
     // in a register.
     // in a register.
-    if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext())) {
+    if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext(), 
+                                                  callingConvention)) {
       uint64_t Size = getContext().getTypeSize(RetTy);
       uint64_t Size = getContext().getTypeSize(RetTy);
 
 
       // As a special-case, if the struct is a "single-element" struct, and
       // As a special-case, if the struct is a "single-element" struct, and

+ 41 - 0
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();
+}