]> granicus.if.org Git - clang/commitdiff
x86_64 ABI: Handle long double in union when upper eightbyte results
authorDaniel Dunbar <daniel@zuster.org>
Fri, 6 Mar 2009 17:50:25 +0000 (17:50 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Fri, 6 Mar 2009 17:50:25 +0000 (17:50 +0000)
in a lone X87 class.
 - PR3735.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66277 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCall.cpp
test/CodeGen/x86_64-arguments.c

index 28152f2de16a166f13f2ae344a5e3fc2a42343fd..1ae4a87606c0011d183058fef28d2d63f404ef97 100644 (file)
@@ -473,8 +473,10 @@ X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum,
   // MEMORY is used as class.
   //
   // (f) Otherwise class SSE is used.
-  assert((Accum == NoClass || Accum == Integer || 
-          Accum == SSE || Accum == SSEUp) &&
+
+  // Accum should never be memory (we should have returned) or
+  // ComplexX87 (because this cannot be passed in a structure).
+  assert((Accum != Memory && Accum != ComplexX87) &&
          "Invalid accumulated classification during merge.");
   if (Accum == Field || Field == NoClass)
     return Accum;
@@ -807,11 +809,13 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
 
     // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is
     // returned together with the previous X87 value in %st0.
-    //
-    // X87UP should always be preceeded by X87, so we don't need to do
-    // anything here.
   case X87Up:
-    assert(Lo == X87 && "Unexpected X87Up classification.");
+    // If X87Up is preceeded by X87, we don't need to do
+    // anything. However, in some cases with unions it may not be
+    // preceeded by X87. In such situations we follow gcc and pass the
+    // extra bits in an SSE reg.
+    if (Lo != X87) 
+      ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL);
     break;
   }
 
@@ -874,16 +878,20 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
     // which is passed in memory.
   case Memory:
   case X87:
-  case X87Up:
   case ComplexX87:
     assert(0 && "Invalid classification for hi word.");
+    break;
 
   case NoClass: break;
   case Integer:
     ResType = llvm::StructType::get(ResType, llvm::Type::Int64Ty, NULL);
     ++neededInt;
     break;
-  case SSE:    
+
+    // X87Up generally doesn't occur here (long double is passed in
+    // memory), except in situations involving unions.
+  case X87Up:
+  case SSE:
     ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL);
     ++neededSSE;
     break;
index 69d3a81dcb415a9b71b57c3c8912e681ab748c0a..eed4eb696f35b269433a783537a68afad7330311 100644 (file)
@@ -6,7 +6,10 @@
 // RUN: grep 'define double @f4()' %t &&
 // RUN: grep 'define x86_fp80 @f5()' %t &&
 // RUN: grep 'define void @f6(i8 signext %a0, i16 signext %a1, i32 %a2, i64 %a3, i8\* %a4)' %t &&
-// RUN: grep 'define void @f7(i32 %a0)' %t
+// RUN: grep 'define void @f7(i32 %a0)' %t &&
+// RUN: grep 'type { i64, double }.*type .0' %t &&
+// RUN: grep 'define .0 @f8_1()' %t &&
+// RUN: grep 'define void @f8_2(.0)' %t
 
 char f0(void) {
 }
@@ -33,3 +36,11 @@ typedef enum { A, B, C } E;
 
 void f7(E a0) {
 }
+
+// Test merging/passing of upper eightbyte with X87 class.
+union u8 {
+  long double a;
+  int b;
+};
+union u8 f8_1() {}
+void f8_2(union u8 a0) {}