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

Add support for C99 %a and %A printf format support. #1198

Conversation

joncampbell123
Copy link
Contributor

This adds support for printing point constants in hexadecimal format using %a and %A. The code is written to mimic how GNU glibc does it.

Feel free to clean it up as needed.

…ting point constants in hexadecimal format. The code is written to mimic how GNU glibc does it
@joncampbell123
Copy link
Contributor Author

This is to help resolve issue #1066

@joncampbell123
Copy link
Contributor Author

Please see this to confirm what I am doing with the 64-bit double floating point type: https://en.wikipedia.org/wiki/Double-precision_floating-point_format

@jmalak
Copy link
Member

jmalak commented Jan 2, 2024

It requires extend to scanf and for 80-bit long double.
now it is only for printf double and float.

There is attribute SF_LONG_DOUBLE which handle 80-bit long double format.

NOTE: it must be part of math library to not load FP until floating data are used.
it should be moved to EFG_printf in math library and be extended for %a, %la, %A and %LA formats.
For scanf it is another story. it looks like the long double stuff is completely missing. It will require review and add long double stuff first.

I looked into math library and it looks like there is already implemented read of hexadecimal FP format in strtod.c to support C99. Anyway it will need review at all.

@joncampbell123
Copy link
Contributor Author

joncampbell123 commented Jan 2, 2024

It requires extend to scanf and for 80-bit long double.
now it is only for printf double and float.

There is attribute SF_LONG_DOUBLE which handle 80-bit long double format.

NOTE: it must be part of math library to not load FP until floating data are used.
it should be moved to EFG_printf in math library and be extended for %a, %la, %A and %LA formats.
For scanf it is another story. it looks like the long double stuff is completely missing. It will require review and add long double stuff first.

I looked into math library and it looks like there is already implemented read of hexadecimal FP format in strtod.c to support C99. Anyway it will need review at all.

The issue does not mention %la, it mentions only %a, that is what this pull is meant to resolve. Also my version does not need the math library :) I figured other variations could be added later, this is just the first step.

Handle this code however you think is best.

@joncampbell123
Copy link
Contributor Author

joncampbell123 commented Jan 2, 2024

@jmalak Should I revise my pull request here with additional code changes or are you going to handle it?

I think the best way to full the request is to add %a support in whatever manner you think best and then worry about %la later. Since %a prints out the various fields of the float without needing to try to convert to decimal it really is possible to implement without needing the full floating point or math library and %la can do the same given the Intel 80-bit long double format as well. Or perhaps it might be appropriate to put into the math library anyway?

@jmalak
Copy link
Member

jmalak commented Jan 2, 2024

The request is general without implementation knowledge, that it is not important what was exactly requested. There are still a few important C99 features missing which are more important then %a/%A format specifier. I am working on C99 compound literals and designated initializers which are most important, but it is going slowly, it is mainly about study of compiler code. C compiler is hand-crafted parser that there are many specific construct etc.
To ensure correct C99 %a feature in OW C run-time library means to implement %a/%A and %La/%LA
Sorry %la/%lA is wrong, it is not valid format specifiers.
Implementation of support in scanf is not urgent, it can be done later with implementing long double in scanf. I think strtod has support for C99 hexadecimal FP constant that can be used if needed as workaround.
If you have some time then it helps if you prepare processing of 80-bit long double with existing 64-bit version you created.
I will integrated it to math library later and do some change necessary for integration with C run-time library there is internal CRTL flag for 80-bit or 64-bit FP support.

@joncampbell123
Copy link
Contributor Author

joncampbell123 commented Jan 3, 2024

@jmalak I can't even get printf() to accept any long double parameters. They always seem to come in as type double!

See DOSLIB test program: https://github.com/joncampbell123/doslib/blob/master/hw/dos/testprna.c

GCC 9.3 output, x86_64, GNU GLIBC printf():

0x3ff0000000000000     f=1.000000 a=0x1p+0 A=0X1P+0
0x3fff8000000000000000 Lf=1.000000 La=0x8p-3 LA=0X8P-3
0x3ff8000000000000     f=1.500000 a=0x1.8p+0 A=0X1.8P+0
0x3fffc000000000000000 Lf=1.500000 La=0xcp-3 LA=0XCP-3
0x3ffc000000000000     f=1.750000 a=0x1.cp+0 A=0X1.CP+0
0x3fffe000000000000000 Lf=1.750000 La=0xep-3 LA=0XEP-3
0x4000000000000000     f=2.000000 a=0x1p+1 A=0X1P+1
0x40008000000000000000 Lf=2.000000 La=0x8p-2 LA=0X8P-2
0x4008000000000000     f=3.000000 a=0x1.8p+1 A=0X1.8P+1
0x4000c000000000000000 Lf=3.000000 La=0xcp-2 LA=0XCP-2
0x4010000000000000     f=4.000000 a=0x1p+2 A=0X1P+2
0x40018000000000000000 Lf=4.000000 La=0x8p-1 LA=0X8P-1
0x0000000000000000     f=0.000000 a=0x0p+0 A=0X0P+0
0x00000000000000000000 Lf=0.000000 La=0x0p+0 LA=0X0P+0
0xbff0000000000000     f=-1.000000 a=-0x1p+0 A=-0X1P+0
0xbfff8000000000000000 Lf=-1.000000 La=-0x8p-3 LA=-0X8P-3
0xbff8000000000000     f=-1.500000 a=-0x1.8p+0 A=-0X1.8P+0
0xbfffc000000000000000 Lf=-1.500000 La=-0xcp-3 LA=-0XCP-3
0xbffc000000000000     f=-1.750000 a=-0x1.cp+0 A=-0X1.CP+0
0xbfffe000000000000000 Lf=-1.750000 La=-0xep-3 LA=-0XEP-3
0xc000000000000000     f=-2.000000 a=-0x1p+1 A=-0X1P+1
0xc0008000000000000000 Lf=-2.000000 La=-0x8p-2 LA=-0X8P-2
0xc008000000000000     f=-3.000000 a=-0x1.8p+1 A=-0X1.8P+1
0xc000c000000000000000 Lf=-3.000000 La=-0xcp-2 LA=-0XCP-2
0xc010000000000000     f=-4.000000 a=-0x1p+2 A=-0X1P+2
0xc0018000000000000000 Lf=-4.000000 La=-0x8p-1 LA=-0X8P-1

Open Watcom compiled DOS program with this %a implementation (result is the same regardless of 16-bit, 32-bit):

0x070c3ff0000000000000 f=1.000000 a=0x1p+0 A=0X1P+0
0x3ff0000000000000     Lf=1.000000 La=0x1p+0 LA=0X1P+0
0x070c3ff8000000000000 f=1.500000 a=0x1.8p+0 A=0X1.8P+0
0x3ff8000000000000     Lf=1.500000 La=0x1.8p+0 LA=0X1.8P+0
0x070c3ffc000000000000 f=1.750000 a=0x1.cp+0 A=0X1.CP+0
0x3ffc000000000000     Lf=1.750000 La=0x1.cp+0 LA=0X1.CP+0
0x070c4000000000000000 f=2.000000 a=0x1p+1 A=0X1P+1
0x4000000000000000     Lf=2.000000 La=0x1p+1 LA=0X1P+1
0x070c4008000000000000 f=3.000000 a=0x1.8p+1 A=0X1.8P+1
0x4008000000000000     Lf=3.000000 La=0x1.8p+1 LA=0X1.8P+1
0x070c4010000000000000 f=4.000000 a=0x1p+2 A=0X1P+2
0x4010000000000000     Lf=4.000000 La=0x1p+2 LA=0X1P+2
0x070c0000000000000000 f=0.000000 a=0x0p+0 A=0X0P+0
0x0000000000000000     Lf=0.000000 La=0x0p+0 LA=0X0P+0
0x070cbff0000000000000 f=-1.000000 a=-0x1p+0 A=-0X1P+0
0xbff0000000000000     Lf=-1.000000 La=-0x1p+0 LA=-0X1P+0
0x070cbff8000000000000 f=-1.500000 a=-0x1.8p+0 A=-0X1.8P+0
0xbff8000000000000     Lf=-1.500000 La=-0x1.8p+0 LA=-0X1.8P+0
0x070cbffc000000000000 f=-1.750000 a=-0x1.cp+0 A=-0X1.CP+0
0xbffc000000000000     Lf=-1.750000 La=-0x1.cp+0 LA=-0X1.CP+0
0x070cc000000000000000 f=-2.000000 a=-0x1p+1 A=-0X1P+1
0xc000000000000000     Lf=-2.000000 La=-0x1p+1 LA=-0X1P+1
0x070cc008000000000000 f=-3.000000 a=-0x1.8p+1 A=-0X1.8P+1
0xc008000000000000     Lf=-3.000000 La=-0x1.8p+1 LA=-0X1.8P+1
0x070cc010000000000000 f=-4.000000 a=-0x1p+2 A=-0X1P+2
0xc010000000000000     Lf=-4.000000 La=-0x1p+2 LA=-0X1P+2

If the call really were passing a long double to printf() in OW, the second result given the current %a implementation would produce some erronous bogus output as a result of interpreting an 80-bit long double as 64-bit double.

So as it stands, it seems there's no point at this time in worrying about %La vs %a because at least as the test program shows, they're the same datatype.

Note the GCC GLIBC output makes sense in that the 80-bit format has the explicit leading bit that the 32/64-bit floats omit as the "implied bit". So it's showing the not-implied bit as 0x8 with an exponent.

@jmalak
Copy link
Member

jmalak commented Jan 3, 2024

It is default setup that it uses 64-bit double as long double.
Try to use -fld compiler option.

@joncampbell123
Copy link
Contributor Author

joncampbell123 commented Jan 3, 2024

It is default setup that it uses 64-bit double as long double. Try to use -fld compiler option.

First, why doesn't that appear when I run the compiler and it prints out all the options?

Second... "Error! E1119: Internal compiler error 136"? 🤨

%write tmp.cmd -fr=nul -fo=dos86c/.obj -i.. -i"../.." -e=2 -zu -zq -mc -d0 -s -bt=dos -oilrb -os -wx -0 -dTARGET_MSDOS=16 -dMSDOS=1 -dTARGET86=86 -DMMODE=c -q -x -i"/usr/src/open-watcom-v2-upstream/rel/h" -fld testprna.c
testprna.c(35): Error! E1119: Internal compiler error 136
Segmentation fault
Error(E42): Last command making (dos86c/testprna.obj) returned a bad status
Error(E02): Make execution terminated

@joncampbell123
Copy link
Contributor Author

joncampbell123 commented Jan 3, 2024

That "Zoiks" (heh, someone likes Scooby Doo) is in ./cg/intel/i86/c/i86splt2.c line 357. It's the default case for N_CONSTANT because there isn't one for long double. It needs a case statement for "FL" (long double) below "FD" (double).

@joncampbell123
Copy link
Contributor Author

The segfault according to "WD" is in insutil.c line 134 in function FindNameConf(). Parameter "name" is NULL.

@joncampbell123
Copy link
Contributor Author

joncampbell123 commented Jan 3, 2024

The 32-bit compiler wcc386 doesn't throw any obvious errors but then any function call that passes a long double as a parameter causes the program to crash after that point, whether or not that function does anything with it. At least when compiled as a 32-bit DOS program.

@joncampbell123
Copy link
Contributor Author

joncampbell123 commented Jan 3, 2024

So to answer my own question, -fld isn't documented because 80-bit "long double" support within the compiler is totally broken. Right? :)

@joncampbell123
Copy link
Contributor Author

joncampbell123 commented Jan 3, 2024

Even if I just pass the long double constant to printf() directly it still triggers that error (16-bit wcc) or causes the program to crash (32-bit wcc386). In the compiler's current state it is impossible to pass a long double to printf() and therefore it is pointless to try to implement %La or %LA any differently from %a and %A at this time.

@jmalak
Copy link
Member

jmalak commented Jan 8, 2024

No, it must be ready to use 80-bit LD in CRTL. The CRTL support 80-bit LD even if compiler not yet.
The same with location of code to math library. If it is in C library then it do standard part bigger even if double or long double is not used in application. It is critical on 16-bit to ensure library code be as small as possible without float support. It is reason to move it in the math library. As soon as you use FP number then you will be using math library to process such variable somehow etc. that it will load this stuff.
Anyway 80-bit support is not broken it is not finished yet. -fld option is for use with 80-bit LD when CG will be ready.
I will review your code and put it into math library to save space in CRTL (mainly for 16-bit).
I will add code for 80-bit LD %La and %LA even if it will not used in application but can be used for CRTL 80-bit LD testing and it will be complete C99 compliant support %LA and %La for long double type even if long double can be 64-bit or 80-bit.

jmalak added a commit that referenced this pull request Feb 6, 2024
reimplemented pull request "Add support for C99 %a and %A printf format support." #1198
this is final change to add new specifier processing into math library
it supports also 'L' prefix for long double type and is ready when C compiler will fully support 80-bit long double type
@jmalak
Copy link
Member

jmalak commented Feb 6, 2024

I reimplemented it to math library including long double

@jmalak jmalak closed this Feb 6, 2024
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.

None yet

2 participants