Skip to content

s390x: f128 scalars incorrectly passed/returned indirectly instead of in FPR pairs #499

@SebTardif

Description

@SebTardif

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-abiABI and calling conventionsI-wrongWrong result or data corruptionP-mediumMedium impact: affects specific usage patternsbugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions