Skip to content

Commit

Permalink
Binary conversion support (#125)
Browse files Browse the repository at this point in the history
* add new binary comp flag, update cmake matrix, add npf_bin_len

* clzll since we're in a uintmax_t world

* fix scope bug

* Select _BitScanReverse of _BitScanReverse64 based on magic windows tokens

* ULL

* try windows again

* _M_X64

* windows needs unsigned long for BSR

* update size report CI with new flags

* parenthesize subexpression

* bsr

* off by one

* win32 doesn't have _BSR64, use software fallback

* symbol for 32-bit tests, faster doctest

* correct size when using clzll

* bsr again

* require -> check for logs

* 32-bit windows

* need to add 1 to bsr result

* only works for large format specifiers, of course

* beginnings of binary printing

* more binary tests, fix subtle logic bug around when to skip cbuf_len prep

* more binary tests, uncomment paland binary tests

* paland submodule bump

* bump mpaland-conformance

* llb instead of lb in tests

* remove spurious ;

* fix binary tests that had bad define, whoops

* better size reporting

* fix typo

* add alternate form tests so I remember what I was doing

* comment out alternate form tests, try smaller clz when not using large specifiers

* 0b alternate form mostly working, special-case clzl vs clzll

* smarter BSR / CLZ logic, use the smallest version possible

* only check for c++11 if large format specifiers are requested

* Update README with binary printing functionality
  • Loading branch information
charlesnicholson authored Dec 28, 2021
1 parent 61f03ec commit a072377
Show file tree
Hide file tree
Showing 20 changed files with 562 additions and 218 deletions.
91 changes: 62 additions & 29 deletions .github/workflows/presubmit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ jobs:
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars${{ matrix.architecture }}.bat"
python.exe build.py --cfg ${{ matrix.configuration }} --paland -v
python.exe build.py --cfg ${{ matrix.configuration }} --paland -v --build-${{ matrix.architecture }}-bit
size-reports:
runs-on: ubuntu-latest
Expand All @@ -127,49 +127,82 @@ jobs:
shell: bash
run: |
. /work/venv/bin/activate
echo Minimal:
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -Os -x c -c -o cm0-min.o -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - <<< '#include "nanoprintf.h"'
arm-none-eabi-nm --print-size --size-sort cm0-min.o | python tests/size_report.py
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=0 -mcpu=cortex-m0 -Os -c -o cm0-0.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm0-0.o | python tests/size_report.py
echo Binary:
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=1 -mcpu=cortex-m0 -Os -c -o cm0-1.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm0-1.o | python tests/size_report.py
echo Field Width + Precision:
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=2 -mcpu=cortex-m0 -Os -c -o cm0-2.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm0-2.o | python tests/size_report.py
echo Medium:
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -Os -x c -c -o cm0-med.o -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - <<< '#include "nanoprintf.h"'
arm-none-eabi-nm --print-size --size-sort cm0-med.o | python tests/size_report.py
echo Field Width + Precision + Binary:
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=3 -mcpu=cortex-m0 -Os -c -o cm0-3.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm0-3.o | python tests/size_report.py
echo Maximal:
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -Os -x c -c -o cm0-max.o -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=1 - <<< '#include "nanoprintf.h"'
arm-none-eabi-nm --print-size --size-sort cm0-max.o | python tests/size_report.py
echo Float:
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=4 -mcpu=cortex-m0 -Os -c -o cm0-4.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm0-4.o | python tests/size_report.py
echo Everything:
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=5 -mcpu=cortex-m0 -Os -c -o cm0-5.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm0-5.o | python tests/size_report.py
- name: Cortex-M4
shell: bash
run: |
. /work/venv/bin/activate
echo Minimal:
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -Os -x c -c -o cm4-min.o -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - <<< '#include "nanoprintf.h"'
arm-none-eabi-nm --print-size --size-sort cm4-min.o | python tests/size_report.py
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=0 -mcpu=cortex-m4 -Os -c -o cm4-0.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm4-0.o | python tests/size_report.py
echo Binary:
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=1 -mcpu=cortex-m4 -Os -c -o cm4-1.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm4-1.o | python tests/size_report.py
echo Medium:
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -Os -x c -c -o cm4-med.o -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - <<< '#include "nanoprintf.h"'
arm-none-eabi-nm --print-size --size-sort cm4-med.o | python tests/size_report.py
echo Field Width + Precision:
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=2 -mcpu=cortex-m4 -Os -c -o cm4-2.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm4-2.o | python tests/size_report.py
echo Maximal:
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -Os -x c -c -o cm4-max.o -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=1 - <<< '#include "nanoprintf.h"'
arm-none-eabi-nm --print-size --size-sort cm4-max.o | python tests/size_report.py
echo Field Width + Precision + Binary:
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=3 -mcpu=cortex-m4 -Os -c -o cm4-3.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm4-3.o | python tests/size_report.py
- name: x64
echo Float:
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=4 -mcpu=cortex-m4 -Os -c -o cm4-4.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm4-4.o | python tests/size_report.py
echo Everything:
arm-none-eabi-gcc -DNANOPRINTF_SIZE_REPORT=5 -mcpu=cortex-m4 -Os -c -o cm4-5.o tests/size_report.c
arm-none-eabi-nm --print-size --size-sort cm4-5.o | python tests/size_report.py
- name: Linux x64
shell: bash
run: |
. /work/venv/bin/activate
echo Minimal:
gcc -Os -x c -c -o x64-min.o -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - <<< '#include "nanoprintf.h"'
nm --print-size --size-sort x64-min.o | python tests/size_report.py
gcc -DNANOPRINTF_SIZE_REPORT=0 -Os -c -o x64-0.o tests/size_report.c
nm --print-size --size-sort x64-0.o | python tests/size_report.py
echo Binary:
gcc -DNANOPRINTF_SIZE_REPORT=1 -Os -c -o x64-1.o tests/size_report.c
nm --print-size --size-sort x64-1.o | python tests/size_report.py
echo Field Width + Precision:
gcc -DNANOPRINTF_SIZE_REPORT=2 -Os -c -o x64-2.o tests/size_report.c
nm --print-size --size-sort x64-2.o | python tests/size_report.py
echo Field Width + Precision + Binary:
gcc -DNANOPRINTF_SIZE_REPORT=3 -Os -c -o x64-3.o tests/size_report.c
nm --print-size --size-sort x64-3.o | python tests/size_report.py
echo Medium:
gcc -Os -x c -c -o x64-med.o -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - <<< '#include "nanoprintf.h"'
nm --print-size --size-sort x64-med.o | python tests/size_report.py
echo Float:
gcc -DNANOPRINTF_SIZE_REPORT=4 -Os -c -o x64-4.o tests/size_report.c
nm --print-size --size-sort x64-4.o | python tests/size_report.py
echo Maximal:
gcc -Os -x c -c -o x64-max.o -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=1 - <<< '#include "nanoprintf.h"'
nm --print-size --size-sort x64-max.o | python tests/size_report.py
echo Everything:
gcc -DNANOPRINTF_SIZE_REPORT=5 -Os -c -o x64-5.o tests/size_report.c
nm --print-size --size-sort x64-5.o | python tests/size_report.py
123 changes: 72 additions & 51 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,64 +92,72 @@ foreach(fw 0 1)
foreach(precision 0 1)
foreach(large 0 1)
foreach(float 0 1)
foreach(wb 0 1)
if ((precision EQUAL 0) AND (float EQUAL 1))
continue()
endif()

set(test_name "")
if (fw EQUAL 1)
string(APPEND test_name "_fieldwidth")
endif()
if (precision EQUAL 1)
string(APPEND test_name "_precision")
endif()
if (large EQUAL 1)
string(APPEND test_name "_large")
endif()
if (float EQUAL 1)
string(APPEND test_name "_float")
endif()
if (wb EQUAL 1)
string(APPEND test_name "_writeback")
endif()

# Run a simple compilation test
set(compilation_test_name "npf_compile${test_name}_c")
npf_compilation_c_test(${compilation_test_name})
target_compile_definitions(
${compilation_test_name}
PRIVATE
NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=${fw}
NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=${precision}
NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=${large}
NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=${float}
NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=${wb})

# Run conformance tests (c++)
set(conformance_test_name "npf_conform${test_name}")
npf_test(${conformance_test_name} tests/conformance.cc)
target_compile_definitions(
${conformance_test_name}
PRIVATE
NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=${fw}
NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=${precision}
NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=${large}
NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=${float}
NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=${wb})

if (NPF_PALAND)
set(paland_test_name "npf_paland${test_name}")
npf_test(${paland_test_name} tests/mpaland-conformance/paland.cc)
foreach(binary 0 1)
foreach(wb 0 1)
if ((precision EQUAL 0) AND (float EQUAL 1))
continue()
endif()

set(test_name "")
if (fw EQUAL 1)
string(APPEND test_name "_fieldwidth")
endif()
if (precision EQUAL 1)
string(APPEND test_name "_precision")
endif()
if (large EQUAL 1)
string(APPEND test_name "_large")
endif()
if (float EQUAL 1)
string(APPEND test_name "_float")
endif()
if (binary EQUAL 1)
string(APPEND test_name "_binary")
endif()
if (wb EQUAL 1)
string(APPEND test_name "_writeback")
endif()

# Run a simple compilation test
set(compilation_test_name "npf_compile${test_name}_c")
npf_compilation_c_test(${compilation_test_name})
target_compile_definitions(
${paland_test_name}
${compilation_test_name}
PRIVATE
NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=${fw}
NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=${precision}
NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=${large}
NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=${float}
NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS=${binary}
NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=${wb})
endif()

# Run conformance tests (c++)
set(conformance_test_name "npf_conform${test_name}")
npf_test(${conformance_test_name} tests/conformance.cc)
target_compile_definitions(
${conformance_test_name}
PRIVATE
NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=${fw}
NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=${precision}
NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=${large}
NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=${float}
NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS=${binary}
NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=${wb})

if (NPF_PALAND)
set(paland_test_name "npf_paland${test_name}")
npf_test(${paland_test_name} tests/mpaland-conformance/paland.cc)
target_compile_definitions(
${paland_test_name}
PRIVATE
NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=${fw}
NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=${precision}
NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=${large}
NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=${float}
NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS=${binary}
NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=${wb})
endif()
endforeach()
endforeach()
endforeach()
endforeach()
Expand Down Expand Up @@ -181,6 +189,7 @@ add_executable(npf_include_multiple tests/include_multiple.c)
set(unit_test_files
nanoprintf.h
tests/unit_parse_format_spec.cc
tests/unit_binary.cc
tests/unit_bufputc.cc
tests/unit_ftoa_rev.cc
tests/unit_itoa_rev.cc
Expand All @@ -192,9 +201,21 @@ set(unit_test_files
npf_test(unit_tests_normal_sized_formatters "${unit_test_files}")
target_compile_definitions(unit_tests_normal_sized_formatters
PRIVATE
DOCTEST_CONFIG_SUPER_FAST_ASSERTS
NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0)
if (NPF_32BIT)
target_compile_definitions(unit_tests_normal_sized_formatters
PRIVATE
NANOPRINTF_32_BIT_TESTS)
endif()

npf_test(unit_tests_large_sized_formatters "${unit_test_files}")
target_compile_definitions(unit_tests_large_sized_formatters
PRIVATE
DOCTEST_CONFIG_SUPER_FAST_ASSERTS
NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=1)
if (NPF_32BIT)
target_compile_definitions(unit_tests_normal_sized_formatters
PRIVATE
NANOPRINTF_32_BIT_TESTS)
endif()
Loading

0 comments on commit a072377

Please sign in to comment.