I was implementing the classification algorithm specified in <a href="http://www.x86-64.org/documentation/abi.pdf">http://www.x86-64.org/documentation/abi.pdf</a> in my compiler, and I found a corner case where clang's calling convention appears to deviate from the letter of the specification. The spec says that if a chunk of an argument type is classified X87UP but the preceding chunk is not classified X87, the entire argument should be passed in memory. However, clang appears to pass the argument chunk as if it were classified SSE instead. For example, the following snippet:<div>
<br></div><div><font face="'courier new', monospace">union nutty_t {</font></div><div><font face="'courier new', monospace"> int x;</font></div><div><font face="'courier new', monospace"> long double y;<br>
};</font></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">union nutty_t foo(union nutty_t x) { return x; }</font></div><div><br></div><div>gets compiled to:</div>
<div><br></div><div><div><font face="'courier new', monospace">%0 = type { i64, double }</font></div><div><font face="'courier new', monospace">%union.nutty_t = type { x86_fp80 }</font></div><div><font face="'courier new', monospace"><br>
</font></div><div><font face="'courier new', monospace">define %0 @foo(i64 %x.coerce0, double %x.coerce1) nounwind uwtable ssp {</font></div><div><font face="'courier new', monospace"> %1 = alloca %union.nutty_t, align 16</font></div>
<div><font face="'courier new', monospace"> %x = alloca %union.nutty_t, align 16</font></div><div><font face="'courier new', monospace"> %2 = bitcast %union.nutty_t* %x to %0*</font></div><div><font face="'courier new', monospace"> %3 = getelementptr %0* %2, i32 0, i32 0</font></div>
<div><font face="'courier new', monospace"> store i64 %x.coerce0, i64* %3</font></div><div><font face="'courier new', monospace"> %4 = getelementptr %0* %2, i32 0, i32 1</font></div><div><font face="'courier new', monospace"> store double %x.coerce1, double* %4</font></div>
<div><font face="'courier new', monospace"> %5 = bitcast %union.nutty_t* %1 to i8*</font></div><div><font face="'courier new', monospace"> %6 = bitcast %union.nutty_t* %x to i8*</font></div><div><font face="'courier new', monospace"> call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* %6, i64 16, i32 16, i1 false)</font></div>
<div><font face="'courier new', monospace"> %7 = getelementptr %union.nutty_t* %1, i32 0, i32 0</font></div><div><font face="'courier new', monospace"> %8 = bitcast x86_fp80* %7 to %0*</font></div><div><font face="'courier new', monospace"> %9 = load %0* %8, align 1</font></div>
<div><font face="'courier new', monospace"> ret %0 %9</font></div><div><font face="'courier new', monospace">}</font></div></div><div><br></div><div>According to my understanding, the type should be passed byval and returned sret instead.</div>
<div><br></div><div>-Joe</div>