Skip to content

aarch64-linux multf3 symbol has incorrect rounding #607

@tgross35

Description

@tgross35

Still getting to the root of this, discussion started at https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/f128.20system.20libraries.20noncompliant.20platforms

Comparing this Rust code:

#![feature(f128)]

#[no_mangle]
fn mul_entry(a: f128, b: f128) -> f128 {
    a * b
}

fn main() {
    let a = f128::from_bits(0x00007fffffffffffffffffffffffffff);
    let b = f128::from_bits(0x40007fffffffffffffffffffffffffff);
    let c = mul_entry(a, b);
    dbg!(c);
}

Against this C version:

#define __STDC_WANT_IEC_60559_TYPES_EXT__

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

#if defined(__clang__) && (defined(__i386) || defined(__x86_64))
#define _Float128 __float128
#endif

typedef struct {
    uint64_t lower, upper;
} u128;


void f128_print(_Float128 val) {
    u128 ival = *((u128 *)(&val));

    #ifndef __clang__
    char buf[1024];
    strfromf128(buf, sizeof(buf), "%.32g", val);
    printf("%#018" PRIx64 "%016" PRIx64 " %s\n", ival.upper, ival.lower, buf);
    #else
    printf("%#018" PRIx64 "%016" PRIx64 " %lf\n", ival.upper, ival.lower, (double)val);
    #endif
}

_Float128 new_f128(uint64_t upper, uint64_t lower) {
    u128 val;
    val.lower = lower;
    val.upper = upper;
    return *((_Float128 *)(&val));
}

int main() {
    _Float128 a = new_f128(0x00007fffffffffff, 0xffffffffffffffff);
    _Float128 b = new_f128(0x40007fffffffffff, 0xffffffffffffffff);
    f128_print(a);
    f128_print(b);
    _Float128 c = a * b;
    f128_print(c);

    return 0;
}

With gcc:

0x00007fffffffffffffffffffffffffff 1.6810515715560467531313389086609e-4932
0x40007fffffffffffffffffffffffffff 3
0x00017ffffffffffffffffffffffffffc 5.0431547146681402593940167259826e-4932

Clang:

0x00007fffffffffffffffffffffffffff 0.000000
0x40007fffffffffffffffffffffffffff 3.000000
0x00017ffffffffffffffffffffffffffc 0.000000

Both of those are correct. However, the Rust version is not:

[f128_demo.rs:12:5] c = 0x00017ffffffffffffffffffffffffffb

Reproduction with C:

/usr/lib/llvm-14/bin/clang -cc1 -triple aarch64-unknown-linux-gnu -emit-obj \
-mrelax-all --mrelax-relocations -disable-free -clear-ast-before-backend \
-disable-llvm-verifier -discard-value-names \
-main-file-name f128_demo.c \
-mrelocation-model pic -pic-level 2 -pic-is-pie \
-mframe-pointer=non-leaf \
-fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 \
-target-cpu generic -target-feature +neon -target-feature +v8a -target-abi aapcs \
-fallow-half-arguments-and-returns -mllvm \
-treat-scalable-fixed-error-as-warning -debugger-tuning=gdb -v \
-fcoverage-compilation-dir=/root -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 \
-internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include \
-internal-isystem /usr/bin/../lib/gcc/aarch64-linux-gnu/11/../../../../aarch64-linux-gnu/include \
-internal-externc-isystem /usr/include/aarch64-linux-gnu -internal-externc-isystem /include \
-internal-externc-isystem /usr/include -fdebug-compilation-dir=/root \
-ferror-limit 19 -fno-signed-char -fgnuc-version=4.2.1 -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 \
-o f128_demo_clang.o -x c f128_demo.c

Linking:

/usr/bin/ld -pie -EL -z relro --hash-style=gnu --build-id --eh-frame-hdr -m aarch64linux \
-dynamic-linker /lib/ld-linux-aarch64.so.1 \
-o f128_demo_clang.out \
/lib/aarch64-linux-gnu/Scrt1.o /lib/aarch64-linux-gnu/crti.o /usr/bin/../lib/gcc/aarch64-linux-gnu/11/crtbeginS.o \
-L/usr/bin/../lib/gcc/aarch64-linux-gnu/11 -L/lib/aarch64-linux-gnu -L/usr/lib/aarch64-linux-gnu \
-L/usr/lib/llvm-14/bin/../lib -L/lib -L/usr/lib \
f128_demo_clang.o \
-lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed \
/usr/bin/../lib/gcc/aarch64-linux-gnu/11/crtendS.o /lib/aarch64-linux-gnu/crtn.o

This produces the same correct output as above (ending in c). However, changing the command to link the rust library

clang f128_demo.c \
.rustup/toolchains/nightly-aarch64-unknown-linux-gnu/lib/rustlib/aarch64-unknown-linux-gnu/lib/libcompiler_builtins-8750659c02157b46.rlib \
-o f128_demo_clang_with_rustlibs.out

Produces the same output as Rust, incorrect:

./f128_demo_clang_with_rustlibs.out
0x00007fffffffffffffffffffffffffff 0.000000
0x40007fffffffffffffffffffffffffff 3.000000
0x00017ffffffffffffffffffffffffffb 0.000000

rustc 1.80.0-nightly (6e1d94708 2024-05-10)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions