| # How to add a new math function to LLVM-libc |
| |
| This document is to serve as a cookbook for adding a new math function |
| implementation to LLVM libc. To add a new function, apart from the actual |
| implementation, one has to follow a few other steps to setup proper registration |
| and shipping of the new function. Each of these steps will be described in |
| detail below. |
| |
| ## Registration |
| |
| To register the function's entry points for supported OSes and architectures, |
| together with its specifications: |
| |
| - Add entry points `libc.src.math.func` to the following files: |
| ``` |
| libc/config/linux/<arch>/entrypoints.txt |
| libc/config/windows/entrypoints.txt |
| ``` |
| - Add function specs to the file: |
| ``` |
| libc/include/math.yaml |
| ``` |
| |
| ## Implementation |
| |
| The function's actual implementation and its corresponding header should be |
| added to the following locations: |
| |
| - Add `add_math_entrypoint_object(<func>)` to: |
| ``` |
| libc/src/math/CMakeLists.txt |
| ``` |
| - Add function declaration (under `LIBC_NAMESPACE` namespace) to: |
| ``` |
| libc/src/math/<func>.h |
| ``` |
| - Add function definition to: |
| ``` |
| libc/src/math/generic/<func>.cpp |
| ``` |
| - Add the corresponding `add_entrypoint_object` to: |
| ``` |
| libc/src/math/generic/CMakeLists.txt |
| ``` |
| - Add architectural specific implementations to: |
| ``` |
| libc/src/math/<arch>/<func>.cpp |
| ``` |
| |
| ### Floating point utility |
| |
| - Floating point utilities and math functions that are also used internally are |
| located at: |
| ``` |
| libc/src/__support/FPUtils |
| ``` |
| - These are preferred to be included as header-only. |
| - To manipulate bits of floating point numbers, use the template class |
| `LIBC_NAMESPACE::fputil::FPBits<>` in the header file: |
| ``` |
| libc/src/__support/FPUtils/FPBits.h |
| ``` |
| |
| ## Testing |
| |
| ### MPFR utility |
| |
| In addition to the normal testing macros such as `EXPECT_EQ, ASSERT_THAT, ...` |
| there are two special macros `ASSERT_MPFR_MATCH` and `EXPECT_MPFR_MATCH` to |
| compare your outputs with the corresponding MPFR function. In |
| order for your new function to be supported by these two macros, |
| the following files will need to be updated: |
| |
| - Add the function enum to `LIBC_NAMESPACE::testing::mpfr::Operation` in the |
| header file: |
| ``` |
| libc/utils/MPFRWrapper/MPFRUtils.h |
| ``` |
| - Add support for `func` in the `MPFRNumber` class and the corresponding link |
| between the enum and its call to the file: |
| ``` |
| libc/utils/MPFRWrapper/MPFRUtils.cpp |
| ``` |
| |
| ### Unit tests |
| |
| Besides the usual testing macros like `EXPECT_EQ, ASSERT_TRUE, ...` there are |
| testing macros specifically used for floating point values, such as |
| `EXPECT_FP_EQ, ASSERT_FP_LE, ...` |
| |
| - Add smoke tests (simple cases and zeros / inf / nan inputs or outputs) to: |
| ``` |
| libc/test/src/math/smoke/<func>_test.cpp |
| ``` |
| - Add unit test that might require MPFR to: |
| ``` |
| libc/test/src/math/<func>_test.cpp |
| ``` |
| - Add the corresponding entry points to: |
| ``` |
| libc/test/src/math/smoke/CMakeLists.txt |
| libc/test/src/math/CMakeLists.txt |
| ``` |
| |
| ### Exhaustive tests |
| |
| Exhaustive tests are long-running tests that are not included when you run |
| `ninja check-libc`. These exhaustive tests are added and manually run in |
| order to find exceptional cases for your function's implementation. |
| |
| - Add an exhaustive test to: |
| ``` |
| libc/test/src/math/exhaustive/<func>_test.cpp |
| ``` |
| - Add the corresponding entry point to: |
| ``` |
| libc/test/src/math/exhaustive/CMakeLists.txt |
| ``` |
| - The template class `LlvmLibcExhaustiveMathTest` located at: |
| ``` |
| libc/test/src/math/exhaustive/exhaustive_test.h |
| ``` |
| can be used for conveniently parallelizing the exhaustive tests. |
| |
| ### Performance tests |
| |
| Performance tests compare your function's implementation with the system libc |
| implementation (which is very often glibc). |
| |
| - Add a performance test to: |
| ``` |
| libc/test/src/math/performance_testing/<func>_perf.cpp |
| ``` |
| - Add the corresponding entry point to: |
| ``` |
| libc/test/src/math/performance_testing/CMakeLists.txt |
| ``` |
| |
| ## Build and Run |
| |
| - Check out the LLVM source tree: |
| ``` |
| $ git clone https://github.com/llvm/llvm-project.git |
| ``` |
| |
| - Setup projects with CMake: |
| ``` |
| $ cd llvm-project |
| $ mkdir build |
| $ cd build |
| $ cmake ../llvm -G Ninja \ |
| -DLLVM_ENABLE_PROJECTS="llvm;libc" \ |
| -DCMAKE_BUILD_TYPE=Debug \ |
| -DCMAKE_C_COMPILER=clang \ |
| -DCMAKE_CXX_COMPILER=clang++ |
| ``` |
| |
| - Build the whole `libc`: |
| ``` |
| $ ninja libc |
| ``` |
| |
| - Run all unit tests: |
| ``` |
| $ ninja check-libc |
| ``` |
| |
| - Run math smoke tests only: |
| ``` |
| $ ninja libc-math-smoke-tests |
| ``` |
| |
| - Run math smoke and unit tests: |
| ``` |
| $ ninja libc-math-unittests |
| ``` |
| |
| - Build and Run a specific unit test: |
| ``` |
| $ ninja libc.test.src.math.<func>_test.__unit__ |
| $ projects/libc/test/src/math/libc.test.src.math.<func>_test |
| ``` |
| |
| - Build and Run exhaustive test (might take hours to run): |
| ``` |
| $ ninja libc.test.src.math.exhaustive.<func>_test |
| $ projects/libc/test/src/math/exhaustive/libc.test.src.math.exhaustive.<func>_test |
| ``` |
| |
| - Build and Run performance test: |
| ``` |
| $ ninja libc.test.src.math.performance_testing.<func>_perf |
| $ projects/libc/test/src/math/performance_testing/libc.test.src.math.performance_testing.<func>_perf |
| $ cat <func>_perf.log |
| ``` |
| |
| ## Code reviews |
| |
| We use GitHub's inbuilt pull request system for code review: |
| ``` |
| https://docs.github.com/articles/about-collaborative-development-models |
| https://docs.github.com/articles/about-pull-requests |
| ``` |