# 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//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()` to: ``` libc/src/math/CMakeLists.txt ``` - Add function declaration (under `LIBC_NAMESPACE` namespace) to: ``` libc/src/math/.h ``` - Add function definition to: ``` libc/src/math/generic/.cpp ``` - Add the corresponding `add_entrypoint_object` to: ``` libc/src/math/generic/CMakeLists.txt ``` - Add architectural specific implementations to: ``` libc/src/math//.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/_test.cpp ``` - Add unit test that might require MPFR to: ``` libc/test/src/math/_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/_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/_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._test.__unit__ $ projects/libc/test/src/math/libc.test.src.math._test ``` - Build and Run exhaustive test (might take hours to run): ``` $ ninja libc.test.src.math.exhaustive._test.__unit__ $ projects/libc/test/src/math/exhaustive/libc.test.src.math.exhaustive._test.__unit__ ``` - Build and Run performance test: ``` $ ninja libc.test.src.math.performance_testing._perf $ projects/libc/test/src/math/performance_testing/libc.test.src.math.performance_testing._perf $ cat _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 ```