Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multf3 has incorrect rounding of subnormals #91840

Closed
tgross35 opened this issue May 11, 2024 · 4 comments · Fixed by #97257
Closed

multf3 has incorrect rounding of subnormals #91840

tgross35 opened this issue May 11, 2024 · 4 comments · Fixed by #97257

Comments

@tgross35
Copy link

tgross35 commented May 11, 2024

Testing with the following program:

#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;
}

I am testing on aarch64. Using the built-in version of Clang that links against system libraries gets the multf3 symbol from either /usr/lib/gcc/aarch64-linux-gnu/11/libgcc.a or /usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.builtins-aarch64.a. This is the output, which is correct:

$ clang f128_demo.c -o f128_demo
$ ./f128_demo
0x00007fffffffffffffffffffffffffff 0.000000
0x40007fffffffffffffffffffffffffff 3.000000
0x00017ffffffffffffffffffffffffffc 0.000000

However, building with the current multf3.c produces an incorrect value (note the ending b):

$ clang f128_demo.c llvm-project/compiler-rt/lib/builtins/multf3.c -o f128_demo_current_rt
$ ./f128_demo_current_rt
0x00007fffffffffffffffffffffffffff 0.000000
0x40007fffffffffffffffffffffffffff 3.000000
0x00017ffffffffffffffffffffffffffb 0.000000

This was just tested in a ubuntu docker container which has Clang 14.0.0 and GCC 11.4.0.

I am not sure why this appears to be aarch64 only. reproduced on x86. See some more background at rust-lang/compiler-builtins#607.

@llvmbot
Copy link
Member

llvmbot commented May 11, 2024

@llvm/issue-subscribers-backend-aarch64

Author: Trevor Gross (tgross35)

Testing with the following program:
#define __STDC_WANT_IEC_60559_TYPES_EXT__

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;inttypes.h&gt;

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

typedef struct {
    uint64_t lower, upper;
} u128;


void f128_print(_Float128 val) {
    u128 ival = *((u128 *)(&amp;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 *)(&amp;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;
}

Using the builtin version of Clang that links against system libraries gets the multf3 symbol from either /usr/lib/gcc/aarch64-linux-gnu/11/libgcc.a or /usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.builtins-aarch64.a. This is the output, which is correct:

$ clang f128_demo.c -o f128_demo
$ ./f128_demo
0x00007fffffffffffffffffffffffffff 0.000000
0x40007fffffffffffffffffffffffffff 3.000000
0x00017ffffffffffffffffffffffffffc 0.000000

However, building with the current multf3.c produces an incorrect value (note the ending b):

$ clang f128_demo.c llvm-project/compiler-rt/lib/builtins/multf3.c -o f128_demo_current_rt
$ ./f128_demo_current_rt
0x00007fffffffffffffffffffffffffff 0.000000
0x40007fffffffffffffffffffffffffff 3.000000
0x00017ffffffffffffffffffffffffffb 0.000000

This was just tested in a ubuntu docker container which has clang 14.0.0 and gcc 11.4.0

@beetrees
Copy link
Contributor

beetrees commented Jul 1, 2024

I've reproduced this bug on x86_64-unknown-linux-gnu.

@tgross35 tgross35 changed the title multf3 has incorrect rounding on aarch64 linux multf3 has incorrect rounding Jul 1, 2024
@tgross35
Copy link
Author

tgross35 commented Jul 1, 2024

@EugeneZelenko since this is no longer aarch64-only, the labels could probably be updated

@beetrees
Copy link
Contributor

beetrees commented Jul 1, 2024

The bug is occurring within the wideMultiply (no rounding is involved). Specifically: 0x0001ffff_ffffffff_ffffffff_fffffffc * 0xbfffffff_ffffffff_ffffffff_ffff8000 should result in a productHi of 0x00017fff_ffffffff_ffffffff_fffffffc but instead results in a productHi of 0x00017fff_ffffffff_ffffffff_fffffffb. A quick search of the issue tracker suggests it might be related to #90009.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants