Summary
On s390x, f128 (IEEE 128-bit float) scalars are incorrectly passed indirectly (via pointer) instead of directly in FPR pairs. This causes ABI mismatch with C compilers.
Location
compiler/rustc_target/src/callconv/s390x.rs, lines 14-18 (classify_ret) and 58-61 (classify_arg)
Bug
f128 has size.bits() = 128, is_aggregate() = false, so the check !is_aggregate() && size.bits() <= 64 fails. It falls through to is_single_fp_element(cx), which returns false for F128 (only matches F32/F64 in rustc_abi::layout::ty.rs:156). Finally it hits _ => arg.make_indirect().
Per the s390x ELF ABI, f128 (i.e., long double on s390x) is:
- Arguments: passed in FPR pairs (f0+f2, f4+f6)
- Return values: returned in FPR pair f0+f2
Making it indirect forces a stack round-trip instead of FPR pair usage.
Impact
Any extern "C" function accepting or returning f128 on s390x has ABI mismatch with C code. s390x is a tier 2 target (Linux).
Fix
Add handling for f128 scalars before the <= 64 check: if the type is a scalar float of 128 bits, leave it as PassMode::Direct (or cast to an appropriate register pair). Also update is_single_fp_element to include Float::F128 for s390x.
Spec
s390x ELF ABI Supplement, Section "Parameter Passing"
Related
Also affects struct { f128 } (single-element f128 aggregate), which goes through the same is_single_fp_element path and is similarly mishandled.
Summary
On s390x,
f128(IEEE 128-bit float) scalars are incorrectly passed indirectly (via pointer) instead of directly in FPR pairs. This causes ABI mismatch with C compilers.Location
compiler/rustc_target/src/callconv/s390x.rs, lines 14-18 (classify_ret) and 58-61 (classify_arg)Bug
f128hassize.bits() = 128,is_aggregate() = false, so the check!is_aggregate() && size.bits() <= 64fails. It falls through tois_single_fp_element(cx), which returnsfalsefor F128 (only matches F32/F64 inrustc_abi::layout::ty.rs:156). Finally it hits_ => arg.make_indirect().Per the s390x ELF ABI,
f128(i.e.,long doubleon s390x) is:Making it indirect forces a stack round-trip instead of FPR pair usage.
Impact
Any
extern "C"function accepting or returningf128on s390x has ABI mismatch with C code. s390x is a tier 2 target (Linux).Fix
Add handling for
f128scalars before the<= 64check: if the type is a scalar float of 128 bits, leave it asPassMode::Direct(or cast to an appropriate register pair). Also updateis_single_fp_elementto includeFloat::F128for s390x.Spec
s390x ELF ABI Supplement, Section "Parameter Passing"
Related
Also affects
struct { f128 }(single-element f128 aggregate), which goes through the sameis_single_fp_elementpath and is similarly mishandled.