[cfe-commits] r68197 - in /cfe/trunk: lib/CodeGen/CGCall.cpp test/CodeGen/x86_32-arguments.c

Daniel Dunbar daniel at zuster.org
Wed Apr 1 00:45:01 PDT 2009


Author: ddunbar
Date: Wed Apr  1 02:45:00 2009
New Revision: 68197

URL: http://llvm.org/viewvc/llvm-project?rev=68197&view=rev
Log:
x86-32 Darwin ABI: Handle small structures correctly.
 - Small structures are returned in a register if: 
    1. They fit nicely in a  register.
    2. All fields fit nicely in a register.
   (more or less)

 - We now pass the first 5000 ABITests if unions are disabled.

 - <rdar://problem/6497882> [irgen] x86-32 ABI compatibility with
   small structs

Modified:
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/test/CodeGen/x86_32-arguments.c

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=68197&r1=68196&r2=68197&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Wed Apr  1 02:45:00 2009
@@ -262,6 +262,8 @@
     return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
   }
 
+  static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context);
+
 public:
   ABIArgInfo classifyReturnType(QualType RetTy, 
                                 ASTContext &Context) const;
@@ -283,6 +285,60 @@
 };
 }
 
+
+/// shouldReturnTypeInRegister - Determine if the given type should be
+/// passed in a register (for the Darwin ABI).
+bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
+                                               ASTContext &Context) {
+  uint64_t Size = Context.getTypeSize(Ty);
+
+  // Type must be register sized.
+  if (!isRegisterSize(Size))
+    return false;
+
+  if (Ty->isVectorType()) {
+    // 64- and 128- bit vectors inside structures are not returned in
+    // registers.
+    if (Size == 64 || Size == 128)
+      return false;
+
+    return true;
+  }
+
+  // If this is a builtin, pointer, or complex type, it is ok.
+  if (Ty->getAsBuiltinType() || Ty->isPointerType() || Ty->isAnyComplexType())
+    return true;
+
+  // Arrays are treated like records.
+  if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
+    return shouldReturnTypeInRegister(AT->getElementType(), Context);
+
+  // Otherwise, it must be a record type.
+  const RecordType *RT = Ty->getAsRecordType();
+  if (!RT) 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(), 
+         e = RT->getDecl()->field_end(); i != e; ++i) {
+    const FieldDecl *FD = *i;
+    
+    // FIXME: Reject bitfields wholesale for now; this is incorrect.
+    if (FD->isBitField())
+      return false;
+
+    // Empty structures are ignored.
+    if (isEmptyRecord(FD->getType()))
+      continue;
+
+    // Check fields recursively.
+    if (!shouldReturnTypeInRegister(FD->getType(), Context))
+      return false;
+  }
+
+  return true;
+}
+
 ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
                                             ASTContext &Context) const {
   if (RetTy->isVoidType()) {
@@ -345,8 +401,18 @@
     }
 
     uint64_t Size = Context.getTypeSize(RetTy);
-    if (isRegisterSize(Size))
-      return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size));
+    if (isRegisterSize(Size)) {
+      // Always return in register for unions for now.
+      // FIXME: This is wrong, but better than treating as a
+      // structure.
+      if (RetTy->isUnionType())
+        return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size));
+
+      // Small structures which are register sized are generally returned
+      // in a register.
+      if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context))
+        return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size));
+    }
 
     return ABIArgInfo::getIndirect(0);
   } else {

Modified: cfe/trunk/test/CodeGen/x86_32-arguments.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/x86_32-arguments.c?rev=68197&r1=68196&r2=68197&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/x86_32-arguments.c (original)
+++ cfe/trunk/test/CodeGen/x86_32-arguments.c Wed Apr  1 02:45:00 2009
@@ -9,11 +9,6 @@
 // RUN: grep 'define void @f7(i32 %a0)' %t &&
 // RUN: grep 'define i64 @f8_1()' %t && 
 // RUN: grep 'define void @f8_2(i32 %a0.0, i32 %a0.1)' %t &&
-// RUN: grep 'define i64 @f9_1()' %t &&
-
-// FIXME: This is wrong, but we want the coverage of the other
-// tests. This should be the same as @f8_2.
-// RUN: grep 'define void @f9_2(%.truct.s9\* byval %a0)' %t &&
 
 char f0(void) {
 }
@@ -52,8 +47,13 @@
 
 // This should be passed just as s8.
 
-// FIXME: This is currently broken, but the test case is accepting it
-// so we get coverage of the other cases.
+// FIXME: This is wrong, but we want the coverage of the other
+// tests. This should be the same as @f8_1.
+// RUN: grep 'define void @f9_1(%.truct.s9\* noalias sret %agg.result)' %t &&
+
+// FIXME: This is wrong, but we want the coverage of the other
+// tests. This should be the same as @f8_2.
+// RUN: grep 'define void @f9_2(%.truct.s9\* byval %a0)' %t &&
 struct s9 {
   int a : 17;
   int b;
@@ -96,11 +96,11 @@
 // 128-bits).
 
 // RUN: grep 'i32 @f17()' %t &&
-// RUN: grep -F 'void @f18(%0* noalias sret %agg.result)' %t &&
-// RUN: grep -F 'void @f19(%1* noalias sret %agg.result)' %t &&
-// RUN: grep -F 'void @f20(%2* noalias sret %agg.result)' %t &&
-// RUN: grep -F 'void @f21(%3* noalias sret %agg.result)' %t &&
-// RUN: grep -F 'void @f22(%4* noalias sret %agg.result)' %t &&
+// RUN: grep -F 'void @f18(%3* noalias sret %agg.result)' %t &&
+// RUN: grep -F 'void @f19(%4* noalias sret %agg.result)' %t &&
+// RUN: grep -F 'void @f20(%5* noalias sret %agg.result)' %t &&
+// RUN: grep -F 'void @f21(%6* noalias sret %agg.result)' %t &&
+// RUN: grep -F 'void @f22(%7* noalias sret %agg.result)' %t &&
 struct { T11 a; } f17(void) {}
 struct { T12 a; } f18(void) {}
 struct { T13 a; } f19(void) {}
@@ -117,4 +117,10 @@
 struct { float a[1]; } f24(void) {}
 struct { struct {} a; struct { float a[1]; } b; } f25(void) {}
 
+// Small structures are handled recursively
+// RUN: grep -F 'i32 @f26()' %t &&
+// RUN: grep 'void @f27(%.truct.s27\* noalias sret %agg.result)' %t &&
+struct s26 { struct { char a, b; } a; struct { char a, b } b; } f26(void) {}
+struct s27 { struct { char a, b, c; } a; struct { char a } b; } f27(void) {}
+
 // RUN: true





More information about the cfe-commits mailing list