rust-lang/compiler-builtins

`aarch64-linux` `multf3` symbol has incorrect rounding

tgross35 opened this issue · 1 comments

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)

I think it is a LLVM problem llvm/llvm-project#91840