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

Use LLVM for printing compile-time reals to hex strings (and trim excessive zeros for decimal strings) #3410

Merged
merged 3 commits into from
May 6, 2020

Conversation

kinke
Copy link
Member

@kinke kinke commented Apr 25, 2020

Primary motivation are apparent printf issues for the hex format and quadruple C long double in Android's Bionic runtime for x86_64. This required an extra Termux patch until now:
https://github.com/termux/termux-packages/blob/3c0e8cd65e6abc2709462c0fe421de5a9f877362/packages/ldc/ldc-x64-sprintf.patch

(And using the %g format for mangling instead of %A is a horrible workaround.)

@kinke
Copy link
Member Author

kinke commented Apr 25, 2020

glibc reference on Linux x64:

import core.stdc.stdio;

void main()
{
    immutable real[] xs = [
                                real.nan,
                               -real.nan,
                           real.infinity,
                          -real.infinity,
                                    0.0L,
                                   -0.0L,
                                 0x1p-1L,
                                 0x3p-3L,
                                 0x1p+0L,
                                 0x3p-1L,
                                -0x3p-2L,
                                  100.0L,
                                 1e+300L,
                                 1e-300L,
         1.2345678901234567890123456789L,
        -12.345678901234567890123456789L,
         123456.78901234567890123456789L,
        -123456.78901234567890123456789L,
         1234567.8901234567890123456789L,
        -1234567.8901234567890123456789L,
         0.0001234567890123456789012345L,
        -0.0001234567890123456789012345L,
         0.0000123456789012345678901234L,
        -0.0000123456789012345678901234L,
    ];
    foreach (x; xs)
    {
        printf("%%g = %Lg", x);
        printf("\t%%a = %La", x);
        printf("\t%%A = %LA", x);
        printf("\t%%#g = %#Lg\n", x);
    }
}

=>

%g = nan	%a = nan	%A = NAN	%#g = nan
%g = -nan	%a = -nan	%A = -NAN	%#g = -nan
%g = inf	%a = inf	%A = INF	%#g = inf
%g = -inf	%a = -inf	%A = -INF	%#g = -inf
%g = 0	%a = 0x0p+0	%A = 0X0P+0	%#g = 0.00000
%g = -0	%a = -0x0p+0	%A = -0X0P+0	%#g = -0.00000
%g = 0.5	%a = 0x8p-4	%A = 0X8P-4	%#g = 0.500000
%g = 0.375	%a = 0xcp-5	%A = 0XCP-5	%#g = 0.375000
%g = 1	%a = 0x8p-3	%A = 0X8P-3	%#g = 1.00000
%g = 1.5	%a = 0xcp-3	%A = 0XCP-3	%#g = 1.50000
%g = -0.75	%a = -0xcp-4	%A = -0XCP-4	%#g = -0.750000
%g = 100	%a = 0xc.8p+3	%A = 0XC.8P+3	%#g = 100.000
%g = 1e+300	%a = 0xb.f21e44003acdd2dp+993	%A = 0XB.F21E44003ACDD2DP+993	%#g = 1.00000e+300
%g = 1e-300	%a = 0xa.b70fe17c79ac6cap-1000	%A = 0XA.B70FE17C79AC6CAP-1000	%#g = 1.00000e-300
%g = 1.23457	%a = 0x9.e06521462cfdb8dp-3	%A = 0X9.E06521462CFDB8DP-3	%#g = 1.23457
%g = -12.3457	%a = -0xc.587e6997b83d271p+0	%A = -0XC.587E6997B83D271P+0	%#g = -12.3457
%g = 123457	%a = 0xf.12064fe5b466a62p+13	%A = 0XF.12064FE5B466A62P+13	%#g = 123457.
%g = -123457	%a = -0xf.12064fe5b466a62p+13	%A = -0XF.12064FE5B466A62P+13	%#g = -123457.
%g = 1.23457e+06	%a = 0x9.6b43f1ef90c027dp+17	%A = 0X9.6B43F1EF90C027DP+17	%#g = 1.23457e+06
%g = -1.23457e+06	%a = -0x9.6b43f1ef90c027dp+17	%A = -0X9.6B43F1EF90C027DP+17	%#g = -1.23457e+06
%g = 0.000123457	%a = 0x8.1742df0c05ba23ep-16	%A = 0X8.1742DF0C05BA23EP-16	%#g = 0.000123457
%g = -0.000123457	%a = -0x8.1742df0c05ba23ep-16	%A = -0X8.1742DF0C05BA23EP-16	%#g = -0.000123457
%g = 1.23457e-05	%a = 0xc.f20498133c5d064p-20	%A = 0XC.F20498133C5D064P-20	%#g = 1.23457e-05
%g = -1.23457e-05	%a = -0xc.f20498133c5d064p-20	%A = -0XC.F20498133C5D064P-20	%#g = -1.23457e-05

(Previously, %#g (and not %g) was used in case the value could be losslessly represented as a 64-bit integer.)

@kinke kinke changed the title Don't use host C runtime for printing compile-time reals, use LLVM WIP: Don't use host C runtime for printing compile-time reals, use LLVM Apr 25, 2020
@kinke
Copy link
Member Author

kinke commented Apr 25, 2020

Some 2 dozen output-checking dmd-testsuite tests would need to be adapted, primarily because of 1.00000 => 1.0 shortening.

@kinke kinke force-pushed the real_t_sprint branch 4 times, most recently from 79b2f5f to 9cf4ff1 Compare April 29, 2020 22:58
@kinke kinke changed the title WIP: Don't use host C runtime for printing compile-time reals, use LLVM Use LLVM for printing compile-time reals to hex strings (and trim excessive zeros for decimal strings) Apr 29, 2020
@kinke
Copy link
Member Author

kinke commented May 4, 2020

It's a pity the decimal strings don't work yet with LLVM, but the hex strings are more important here anyway (used for mangling floating-point template params, as well as for .di header generation in case the short %g decimal format cannot be parsed to the identical value again). Using LLVM for this not just works for buggy host C runtimes, but also makes sure objects compiled on different hosts can be linked (well, as long as they use the same real_t precision). E.g., glibc apparently always chooses to start with the most significant mantissa bit being set, while MSVC and LLVM start with 1 (at least for non-subnormals), which I find much more readable (0x1p+0 vs. 0x8p-3).

@JohanEngelen
Copy link
Member

Consistent output across platforms is a big win!

@kinke kinke merged commit 920fe2c into ldc-developers:master May 6, 2020
@kinke kinke deleted the real_t_sprint branch May 6, 2020 19:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants