Skip to content

Commit 2789b51

Browse files
committed
add a hack to work around cranelift ABI oddities
1 parent d7b63a3 commit 2789b51

File tree

3 files changed

+20
-15
lines changed

3 files changed

+20
-15
lines changed

compiler/rustc_target/src/callconv/mod.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -776,17 +776,18 @@ impl<'a, Ty> FnAbi<'a, Ty> {
776776

777777
if arg_idx.is_none()
778778
&& arg.layout.size > Pointer(AddressSpace::DATA).size(cx) * 2
779-
&& arg.layout.is_aggregate()
779+
&& !matches!(arg.layout.backend_repr, BackendRepr::Vector { .. })
780780
{
781-
// Return aggregate values larger than 2 registers using a return area
781+
// Return values larger than 2 registers using a return area
782782
// pointer. LLVM and Cranelift disagree about how to return
783783
// values that don't fit in the registers designated for return
784784
// values. LLVM will force the entire return value to be passed
785785
// by return area pointer, while Cranelift will look at each IR level
786786
// return value independently and decide to pass it in a
787787
// register or not, which would result in the return value
788788
// being passed partially in registers and partially through a
789-
// return area pointer.
789+
// return area pointer. For large IR-level values such as `i128`,
790+
// cranelift will even split up the value into smaller chunks.
790791
//
791792
// While Cranelift may need to be fixed as the LLVM behavior is
792793
// generally more correct with respect to the surface language,
@@ -816,6 +817,8 @@ impl<'a, Ty> FnAbi<'a, Ty> {
816817
// rustc_target already ensure any return value which doesn't
817818
// fit in the available amount of return registers is passed in
818819
// the right way for the current target.
820+
// The adjustment is also not necessary nor desired for types with
821+
// a vector representation; those are handled below.
819822
arg.make_indirect();
820823
continue;
821824
}

compiler/rustc_target/src/callconv/x86.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -231,14 +231,17 @@ where
231231
BackendRepr::ScalarPair(s1, s2) => {
232232
matches!(s1.primitive(), Float(_)) || matches!(s2.primitive(), Float(_))
233233
}
234-
_ => false, // anyway not passed via registers on x86
234+
_ => false, // anyway not returned via registers on x86
235235
};
236236
if has_float {
237237
if cx.target_spec().rust_abi == Some(RustAbi::X86Sse2)
238238
&& fn_abi.ret.layout.backend_repr.is_scalar()
239-
&& fn_abi.ret.layout.size.bits() <= 128
239+
&& fn_abi.ret.layout.size.bits() <= 64
240240
{
241241
// This is a single scalar that fits into an SSE register.
242+
// FIXME: We cannot return 128-bit-floats this way since scalars larger than
243+
// 64bit must be returned indirectly to make cranelift happy. See the comment
244+
// in `adjust_for_rust_abi`.
242245
fn_abi.ret.cast_to(Reg { kind: RegKind::Vector, size: fn_abi.ret.layout.size });
243246
} else if fn_abi.ret.layout.size <= Pointer(AddressSpace::DATA).size(cx) {
244247
// Same size or smaller than pointer, return in an integer register.

tests/assembly/x86-return-float.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -323,16 +323,15 @@ pub fn return_f16(x: f16) -> f16 {
323323
#[no_mangle]
324324
pub fn return_f128(x: f128) -> f128 {
325325
// CHECK: pushl %ebp
326-
// sse: movaps [[#%d,OFFSET:]](%ebp), %xmm0
327-
// nosse: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
328-
// nosse-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
329-
// nosse-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
330-
// nosse-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL3:.*]]
331-
// nosse-NEXT: movl [[#%d,OFFSET+16]](%ebp), %[[VAL4:.*]]
332-
// nosse-NEXT: movl %[[VAL4:.*]] 12(%[[PTR]])
333-
// nosse-NEXT: movl %[[VAL3:.*]] 8(%[[PTR]])
334-
// nosse-NEXT: movl %[[VAL2:.*]] 4(%[[PTR]])
335-
// nosse-NEXT: movl %[[VAL1:.*]] (%[[PTR]])
326+
// CHECK: movl [[#%d,OFFSET:]](%ebp), %[[PTR:.*]]
327+
// CHECK-NEXT: movl [[#%d,OFFSET+4]](%ebp), %[[VAL1:.*]]
328+
// CHECK-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
329+
// CHECK-NEXT: movl [[#%d,OFFSET+12]](%ebp), %[[VAL3:.*]]
330+
// CHECK-NEXT: movl [[#%d,OFFSET+16]](%ebp), %[[VAL4:.*]]
331+
// CHECK-NEXT: movl %[[VAL4:.*]] 12(%[[PTR]])
332+
// CHECK-NEXT: movl %[[VAL3:.*]] 8(%[[PTR]])
333+
// CHECK-NEXT: movl %[[VAL2:.*]] 4(%[[PTR]])
334+
// CHECK-NEXT: movl %[[VAL1:.*]] (%[[PTR]])
336335
// CHECK: popl %ebp
337336
// CHECK: retl
338337
x

0 commit comments

Comments
 (0)