casaroli opened a new pull request, #21505: URL: https://github.com/apache/nuttx/pull/21505
depends-on: apache/nuttx/pull/21493 This branch holds the 19 commits of #21474, the 10 commits of #21493 and 8 commits of its own, because these commits change the same code. **Review only the last 8 commits.** It stays a draft until #21493 merges. Part of #21467, step 3. ## Summary This PR fixes the output of correct calls that #21474 only made safe, and adds the missing conversions behind options: - **-0.0 prints its sign**, a fix in all profiles. It tests the sign bit in place of a compare: +0 on Cortex-M0, +8 on Cortex-M3, +24 on rv32 and -4 on arm64. A NaN with its sign bit set now prints `-nan`, as C23 requires. - **`%a` and `%A`**, behind `LIBC_PRINTF_HEXFLOAT`, off in Minimal and Default, on in Full. With the option off, `printf` reads the argument and prints `?`, as in #21474. The code works on the bits, with no floating point operation and no big numbers, so the option does not need `LIBC_FLOATINGPOINT` and pulls in no soft-float code. A `long double` has its own digits where it has more bits than a `double`. - **C23 `%b`, `%B`, `wN` and `wfN`**, behind `LIBC_PRINTF_C23`, same defaults. With the option off, they stay unknown conversions, as in #21474: the rest of the format prints as text. - **`%n` with a store**, behind `LIBC_PRINTF_PERCENT_N`, off in all profiles, also in Full. The prompt and the help say that it is dangerous. With the option off, `%n` reads its pointer, stores nothing and prints `?`, as in #21474. - **`scanf` with `%L`** stores a `long double`. `%Ld` stores a `long long`, as in GNU libc. It adds code only where `long double` differs from `double`, and only in an image that links `sscanf()` with floating point. Two commits only fix style, because the check reads all of a file that a commit changes. The one for `lib_libvscanf.c` indents the `case` labels: read it with `git show -w`. ## What is not fixed - More than 15 significant digits, and correct rounding of `%e`, `%f`, `%g`. That is step 4 of #21467, after a discussion there. - `%#g` drops trailing zeros: 917 tests of the suite. - The rest of `scanf`. ## Impact Default: the only output that changes is the sign of -0.0 and of a negative NaN. A config with `LIBC_FLOATINGPOINT` off has the same image text as #21493. No ABI change. Not a breaking change. No architecture code. Flat, protected and kernel builds. The Kconfig help has the text of the options. Step 5 of #21467 is the documentation page. Image text, each board's defaults; rv32 and arm64 have float on by default. Boards: `nucleo-f072rb:nsh`, `nucleo-f103rb:nsh`, `rv-virt:nsh`, `qemu-armv8a:nsh`: | | Cortex-M0 | Cortex-M3 | rv32 | arm64 | |---|---:|---:|---:|---:| | #21493 | 46,724 | 34,436 | 230,438 | 328,272 | | Minimal | 46,380 | 33,860 | 227,988 | 325,584 | | Default | 46,724 | 34,436 | 230,462 | 328,268 | | Full | 58,856 | 40,460 | 233,046 | 331,896 | | Default - #21493 | +0 | +0 | +24 | -4 | The cost of `-0.0`, image text, float on in both builds: | | Cortex-M0 | Cortex-M3 | rv32 | arm64 | |---|---:|---:|---:|---:| | #21493 | 56,856 | 38,596 | 230,438 | 328,272 | | With `-0.0` | 56,856 | 38,604 | 230,462 | 328,268 | | Delta | +0 | +8 | +24 | -4 | | All of this PR, Default | +0 | +8 | +24 | -4 | Image text with float off is the same as #21493 on all four boards in Default: | | Cortex-M0 | Cortex-M3 | rv32 | arm64 | |---|---:|---:|---:|---:| | #21493 | 46,724 | 34,436 | 228,362 | 326,044 | | This PR | 46,724 | 34,436 | 228,362 | 326,044 | One option added, image text: | | Cortex-M0 | Cortex-M3 | rv32 | arm64 | |---|---:|---:|---:|---:| | Default, float off, + `LIBC_PRINTF_HEXFLOAT` | +816 | +776 | +1112 | +1580 | | Minimal + `LIBC_PRINTF_HEXFLOAT` | +836 | +820 | +1048 | +1472 | | Default, float off, + `LIBC_PRINTF_C23` | +184 | +180 | +220 | +232 | | Minimal + `LIBC_PRINTF_C23` | +160 | +228 | +166 | +192 | | Default, float off, + `LIBC_PRINTF_PERCENT_N` | +28 | +48 | +48 | +36 | `vsprintf_internal` frame: | | Cortex-M0 | Cortex-M3 | rv32 | arm64 | |---|---:|---:|---:|---:| | #21493, Default | 88 | 72 | 144 | 160 | | Default | 88 | 72 | 144 | 160 | | Minimal | 80 | 72 | 96 | 160 | | Full | 184 | 176 | 208 | 256 | | Default, float off, + `%a` | 112 | 104 | 144 | 192 | | Default, float off, + C23 | 128 | 112 | 112 | 176 | | Minimal + `%a` | 112 | 104 | 128 | 192 | The growth with the options on comes from new code: `lib_hexfloat.c`, its output in `vsprintf_puthex()`, and the parser of `wN`. With `LIBC_PRINTF_C23` on, the conversion buffer holds all bits of an integer, so the frame of `vsprintf_internal` grows by up to 42 bytes. With `LIBC_PRINTF_HEXFLOAT` on, the frame holds the digits, and `lib_vsprintf()` with numbered arguments holds a `long double` for each argument where that is larger than a `double`. Image text of an image with `sscanf()` of `%lf`, the `%L` commit: rv32 +178, arm64 +176. A CPU where `long double` is `double` has no new code. ## Testing The suite at https://github.com/casaroli/printf-report on sim arm64, against #21493: | | C99 required | Correctly rounded | C23 | POSIX | XSI | Bit-exact | Crash + hang | |---|---:|---:|---:|---:|---:|---:|---:| | #21493 | 67.81% | 63.11% | 1.08% | 92.68% | 36.36% | 61.46% | 0 | | This PR, options off | 73.84% | 69.14% | 2.15% | 92.68% | 36.36% | 68.96% | 0 | | This PR, `%a` and C23 on | 94.85% | 90.08% | 92.47% | 95.12% | 36.36% | 90.08% | 0 | | The same, `%n` on | 94.89% | 90.12% | 96.77% | 100% | 36.36% | 90.14% | 0 | | Full profile | 94.85% | 90.08% | 92.47% | 95.12% | 36.36% | 90.08% | 0 | | Minimal | 5.50% | 5.50% | 1.08% | 27.91% | 33.33% | 5.52% | 0 | | Minimal, `%a` and C23 on | 24.17% | 24.17% | 75.27% | 27.91% | 33.33% | 24.32% | 0 | No test goes from pass to fail. 540 tests go from "allowed alternative" to "pass": a NaN with a sign bit prints its sign. The 3 `%wf16` tests that fail are not `printf`: `int_fast16_t` is `int`, and `INT_FAST16_MAX` in `include/stdint.h` is `INT16_MAX`. The `%n` tests fail by design with the option off. - `%a` against GNU libc 2.41: 3,123,276 conversions with precision none and 0 to 32, flags and widths, on boundary, tie, subnormal and random values of `double` and binary128: 0 differences. 471,276 of them also on big-endian s390x: 0 differences. macOS libc does not round ties to even and normalizes subnormal values, so it is not a reference. The 80-bit format of x86: 0 value differences without a precision, and with a precision not compared, because GNU libc has another first digit. - Host harness under ASan and UBSan, 49 builds, clang on macOS and gcc on Linux arm64: each profile, each option added or removed: clang on macOS, 49 builds: 49 builds correct usage: 0 reports, 0 timeouts, 0 bad returns, 0 sentinel errors, 49 builds wrong usage: 0 reports, 0 timeouts, 0 bad returns, 0 sentinel errors. gcc on Linux arm64, 49 builds: 49 builds correct usage: 0 reports, 0 timeouts, 0 bad returns, 0 sentinel errors, 49 builds wrong usage: 0 reports, 0 timeouts, 0 bad returns, 0 sentinel errors.. - Runtime: ostest with the new cases of the test in nuttx-apps, and a test program: `rv-virt:nsh` (flat) and `qemu-armv8a:knsh` (kernel), each with Default, Full, Minimal, Minimal with `%a` and C23, Default with `%a`, Default with C23, Full with `%n`: all exit 0 with 0 failures. - Builds with `EXTRAFLAGS="-Wno-cpp -Werror"`: Minimal, Default, Full on the four flat boards (12 of 12), each option added on them. `mps2-an500:knsh` (protected), `qemu-armv8a:knsh`, `rv-virt:knsh` (kernel), each profile and Minimal with all options: 12 of 12 on this head. Not run: - Cortex-M0 at run time. - A CMake build. - The suite on a 32-bit target: only the sim runs it here. `tools/checkpatch.sh -c -u -m -g` passes. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
