Skip to content

ABI mismatch on powerpc64 (elfv1) for union containing floats #162011

Description

@folkertdev

with

https://godbolt.org/z/EYxKxTs4f

// --target=powerpc64-unknown-linux-gnu -Copt-level=3
#[repr(C)] pub union TwoFloats { a: f32, b: f32 }

#[unsafe(no_mangle)]
extern "C" fn foo(x: TwoFloats) -> f32 {
    unsafe { x.a }
}

rustc emits

foo:
        .quad   .Lfunc_begin0
        .quad   .TOC.@tocbase
        .quad   0
.Lfunc_begin0:
        blr

I.e. the argument is already in a float register, and it stays there for the return. But with GCC and Clang the equivalent

https://godbolt.org/z/Mx8GEzdvn

typedef union { float a; float b; } TwoFloats;

float foo(TwoFloats x) {
    return x.a;
}

Has an explicit move from GPR to memory to FPR

foo:
        .quad   .Lfunc_begin0
        .quad   .TOC.@tocbase
        .quad   0
.Lfunc_begin0:
        stw 3, -4(1)
        lfs 1, -4(1)
        blr

You can see this difference in the LLVM IR emitted by rustc and clang too:

; rust 
define noundef float @foo(float returned %0) unnamed_addr {
start:
  ret float %0
}

; clang
define dso_local float @foo(i32 %x.coerce) local_unnamed_addr {
entry:
  %0 = bitcast i32 %x.coerce to float
  ret float %0
}

This came up in relation to #161987.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ABIArea: Concerning the application binary interface (ABI)C-bugCategory: This is a bug.I-miscompileIssue: Correct Rust code lowers to incorrect machine codeO-PowerPCTarget: PowerPC processorsP-highHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions