diff options
author | Daniel Dunbar <daniel@zuster.org> | 2009-03-06 17:50:25 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2009-03-06 17:50:25 +0000 |
commit | 100f402451da96f74ea58b1f49fc53b4fa149a57 (patch) | |
tree | 2519a7f207f287e0500e31120f7f7ddb7f148299 | |
parent | 63a9e0ff79f01a542afaf9b912e3dee3d395ebc5 (diff) |
x86_64 ABI: Handle long double in union when upper eightbyte results
in a lone X87 class.
- PR3735.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66277 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 24 | ||||
-rw-r--r-- | test/CodeGen/x86_64-arguments.c | 13 |
2 files changed, 28 insertions, 9 deletions
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 28152f2de1..1ae4a87606 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -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; diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c index 69d3a81dcb..eed4eb696f 100644 --- a/test/CodeGen/x86_64-arguments.c +++ b/test/CodeGen/x86_64-arguments.c @@ -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) {} |