From ca1da36aec963c5504ae7ae2e834b37856c476db Mon Sep 17 00:00:00 2001 From: Schrodinger ZHU Yifan Date: Tue, 6 Feb 2024 09:35:56 -0500 Subject: [PATCH] [libc] add inttypes macros (#80726) Standard file: https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/ Notice that we are not quite the same as other implementations: 1. MUSL: https://github.com/bminor/musl/blob/master/include/inttypes.h 2. GLIBC: https://github.com/bminor/glibc/blob/bbd248ac0d75efdef8fe61ea69b1fb25fb95b6e7/stdlib/inttypes.h#L57 3. CheriBSD: https://github.com/CTSRD-CHERI/cheribsd/blob/698d1636dd1fe2322e5bc7029e415928c80b76b1/sys/arm64/include/_inttypes.h fixes #80186 --- libc/include/CMakeLists.txt | 1 + libc/include/inttypes.h.def | 1 + libc/include/llvm-libc-macros/CMakeLists.txt | 6 + .../llvm-libc-macros/inttypes-macros.h | 289 ++++++++++++++++++ libc/test/src/stdio/CMakeLists.txt | 1 + libc/test/src/stdio/sprintf_test.cpp | 20 ++ 6 files changed, 318 insertions(+) create mode 100644 libc/include/llvm-libc-macros/inttypes-macros.h diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 4f4d8434757d70..332410453b54d1 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -73,6 +73,7 @@ add_gen_header( DEPENDS .llvm_libc_common_h .llvm-libc-types.imaxdiv_t + .llvm-libc-macros.inttypes_macros ) add_gen_header( diff --git a/libc/include/inttypes.h.def b/libc/include/inttypes.h.def index 94cdc2f21eaf70..a99d4e931f5145 100644 --- a/libc/include/inttypes.h.def +++ b/libc/include/inttypes.h.def @@ -10,6 +10,7 @@ #define LLVM_LIBC_INTTYPES_H #include <__llvm-libc-common.h> +#include #include %%public_api() diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt index c5a7e742cadd13..562769a5e84cef 100644 --- a/libc/include/llvm-libc-macros/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/CMakeLists.txt @@ -221,3 +221,9 @@ add_macro_header( HDR wchar-macros.h ) + +add_macro_header( + inttypes_macros + HDR + inttypes-macros.h +) diff --git a/libc/include/llvm-libc-macros/inttypes-macros.h b/libc/include/llvm-libc-macros/inttypes-macros.h new file mode 100644 index 00000000000000..fc3e2517f19471 --- /dev/null +++ b/libc/include/llvm-libc-macros/inttypes-macros.h @@ -0,0 +1,289 @@ +//===-- Definition of macros from inttypes.h ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef __LLVM_LIBC_MACROS_INTTYPES_MACROS_H +#define __LLVM_LIBC_MACROS_INTTYPES_MACROS_H + +// fprintf/scanf format macros. +// POSIX.1-2008, Technical Corrigendum 1, XBD/TC1-2008/0050 [211] is applied. + +// clang provides these macros, so we don't need to define them. +// TODO: ISO C23 will provide binary notations. + +#ifndef __clang__ +#if __UINTPTR_MAX__ == __UINT64_MAX__ +#define __PRI64 "l" +#define __PRIPTR "l" +#elif __UINTPTR_MAX__ == __UINT32_MAX__ +#define __PRI64 "ll" +#define __PRIPTR "" +#else +// CHERI achitecture for example, has 128-bit pointers that use special "P" +// format. +#error "Unsupported pointer format" +#endif +#define __INT8_FMTd__ "hhd" +#define __INT16_FMTd__ "hd" +#define __INT32_FMTd__ "d" +#define __INT64_FMTd__ __PRI64 "d" +#define __INT_LEAST8_FMTd__ "hhd" +#define __INT_LEAST16_FMTd__ "hd" +#define __INT_LEAST32_FMTd__ "d" +#define __INT_LEAST64_FMTd__ __PRI64 "d" +#define __INT_FAST8_FMTd__ "hhd" +#define __INT_FAST16_FMTd__ "hd" +#define __INT_FAST32_FMTd__ "d" +#define __INT_FAST64_FMTd__ __PRI64 "d" +#define __INTMAX_FMTd__ __PRI64 "d" +#define __INTPTR_FMTd__ __PRIPTR "d" + +#define __INT8_FMTi__ "hhi" +#define __INT16_FMTi__ "hi" +#define __INT32_FMTi__ "i" +#define __INT64_FMTi__ __PRI64 "i" +#define __INT_LEAST8_FMTi__ "hhi" +#define __INT_LEAST16_FMTi__ "hi" +#define __INT_LEAST32_FMTi__ "i" +#define __INT_LEAST64_FMTi__ __PRI64 "i" +#define __INT_FAST8_FMTi__ "hhi" +#define __INT_FAST16_FMTi__ "hi" +#define __INT_FAST32_FMTi__ "i" +#define __INT_FAST64_FMTi__ __PRI64 "i" +#define __INTMAX_FMTi__ __PRI64 "i" +#define __INTPTR_FMTi__ __PRIPTR "i" + +#define __UINT8_FMTo__ "hho" +#define __UINT16_FMTo__ "ho" +#define __UINT32_FMTo__ "o" +#define __UINT64_FMTo__ __PRI64 "o" +#define __UINT_LEAST8_FMTo__ "hho" +#define __UINT_LEAST16_FMTo__ "ho" +#define __UINT_LEAST32_FMTo__ "o" +#define __UINT_LEAST64_FMTo__ __PRI64 "o" +#define __UINT_FAST8_FMTo__ "hho" +#define __UINT_FAST16_FMTo__ "ho" +#define __UINT_FAST32_FMTo__ "o" +#define __UINT_FAST64_FMTo__ __PRI64 "o" +#define __UINTMAX_FMTo__ __PRI64 "o" +#define __UINTPTR_FMTo__ __PRIPTR "o" + +#define __UINT8_FMTu__ "hhu" +#define __UINT16_FMTu__ "hu" +#define __UINT32_FMTu__ "u" +#define __UINT64_FMTu__ __PRI64 "u" +#define __UINT_LEAST8_FMTu__ "hhu" +#define __UINT_LEAST16_FMTu__ "hu" +#define __UINT_LEAST32_FMTu__ "u" +#define __UINT_LEAST64_FMTu__ __PRI64 "u" +#define __UINT_FAST8_FMTu__ "hhu" +#define __UINT_FAST16_FMTu__ "hu" +#define __UINT_FAST32_FMTu__ "u" +#define __UINT_FAST64_FMTu__ __PRI64 "u" +#define __UINTMAX_FMTu__ __PRI64 "u" +#define __UINTPTR_FMTu__ __PRIPTR "u" + +#define __UINT8_FMTx__ "hhx" +#define __UINT16_FMTx__ "hx" +#define __UINT32_FMTx__ "x" +#define __UINT64_FMTx__ __PRI64 "x" +#define __UINT_LEAST8_FMTx__ "hhx" +#define __UINT_LEAST16_FMTx__ "hx" +#define __UINT_LEAST32_FMTx__ "x" +#define __UINT_LEAST64_FMTx__ __PRI64 "x" +#define __UINT_FAST8_FMTx__ "hhx" +#define __UINT_FAST16_FMTx__ "hx" +#define __UINT_FAST32_FMTx__ "x" +#define __UINT_FAST64_FMTx__ __PRI64 "x" +#define __UINTMAX_FMTx__ __PRI64 "x" +#define __UINTPTR_FMTx__ __PRIPTR "x" + +#define __UINT8_FMTX__ "hhX" +#define __UINT16_FMTX__ "hX" +#define __UINT32_FMTX__ "X" +#define __UINT64_FMTX__ __PRI64 "X" +#define __UINT_LEAST8_FMTX__ "hhX" +#define __UINT_LEAST16_FMTX__ "hX" +#define __UINT_LEAST32_FMTX__ "X" +#define __UINT_LEAST64_FMTX__ __PRI64 "X" +#define __UINT_FAST8_FMTX__ "hhX" +#define __UINT_FAST16_FMTX__ "hX" +#define __UINT_FAST32_FMTX__ "X" +#define __UINT_FAST64_FMTX__ __PRI64 "X" +#define __UINTMAX_FMTX__ __PRI64 "X" +#define __UINTPTR_FMTX__ __PRIPTR "X" +#endif + +// The fprintf() macros for signed integers. +#define PRId8 __INT8_FMTd__ +#define PRId16 __INT16_FMTd__ +#define PRId32 __INT32_FMTd__ +#define PRId64 __INT64_FMTd__ +#define PRIdLEAST8 __INT_LEAST8_FMTd__ +#define PRIdLEAST16 __INT_LEAST16_FMTd__ +#define PRIdLEAST32 __INT_LEAST32_FMTd__ +#define PRIdLEAST64 __INT_LEAST64_FMTd__ +#define PRIdFAST8 __INT_FAST8_FMTd__ +#define PRIdFAST16 __INT_FAST16_FMTd__ +#define PRIdFAST32 __INT_FAST32_FMTd__ +#define PRIdFAST64 __INT_FAST64_FMTd__ +#define PRIdMAX __INTMAX_FMTd__ +#define PRIdPTR __INTPTR_FMTd__ + +#define PRIi8 __INT8_FMTi__ +#define PRIi16 __INT16_FMTi__ +#define PRIi32 __INT32_FMTi__ +#define PRIi64 __INT64_FMTi__ +#define PRIiLEAST8 __INT_LEAST8_FMTi__ +#define PRIiLEAST16 __INT_LEAST16_FMTi__ +#define PRIiLEAST32 __INT_LEAST32_FMTi__ +#define PRIiLEAST64 __INT_LEAST64_FMTi__ +#define PRIiFAST8 __INT_FAST8_FMTi__ +#define PRIiFAST16 __INT_FAST16_FMTi__ +#define PRIiFAST32 __INT_FAST32_FMTi__ +#define PRIiFAST64 __INT_FAST64_FMTi__ +#define PRIiMAX __INTMAX_FMTi__ +#define PRIiPTR __INTPTR_FMTi__ + +// The fprintf() macros for unsigned integers. +#define PRIo8 __UINT8_FMTo__ +#define PRIo16 __UINT16_FMTo__ +#define PRIo32 __UINT32_FMTo__ +#define PRIo64 __UINT64_FMTo__ +#define PRIoLEAST8 __UINT_LEAST8_FMTo__ +#define PRIoLEAST16 __UINT_LEAST16_FMTo__ +#define PRIoLEAST32 __UINT_LEAST32_FMTo__ +#define PRIoLEAST64 __UINT_LEAST64_FMTo__ +#define PRIoFAST8 __UINT_FAST8_FMTo__ +#define PRIoFAST16 __UINT_FAST16_FMTo__ +#define PRIoFAST32 __UINT_FAST32_FMTo__ +#define PRIoFAST64 __UINT_FAST64_FMTo__ +#define PRIoMAX __UINTMAX_FMTo__ +#define PRIoPTR __UINTPTR_FMTo__ + +#define PRIu8 __UINT8_FMTu__ +#define PRIu16 __UINT16_FMTu__ +#define PRIu32 __UINT32_FMTu__ +#define PRIu64 __UINT64_FMTu__ +#define PRIuLEAST8 __UINT_LEAST8_FMTu__ +#define PRIuLEAST16 __UINT_LEAST16_FMTu__ +#define PRIuLEAST32 __UINT_LEAST32_FMTu__ +#define PRIuLEAST64 __UINT_LEAST64_FMTu__ +#define PRIuFAST8 __UINT_FAST8_FMTu__ +#define PRIuFAST16 __UINT_FAST16_FMTu__ +#define PRIuFAST32 __UINT_FAST32_FMTu__ +#define PRIuFAST64 __UINT_FAST64_FMTu__ +#define PRIuMAX __UINTMAX_FMTu__ +#define PRIuPTR __UINTPTR_FMTu__ + +#define PRIx8 __UINT8_FMTx__ +#define PRIx16 __UINT16_FMTx__ +#define PRIx32 __UINT32_FMTx__ +#define PRIx64 __UINT64_FMTx__ +#define PRIxLEAST8 __UINT_LEAST8_FMTx__ +#define PRIxLEAST16 __UINT_LEAST16_FMTx__ +#define PRIxLEAST32 __UINT_LEAST32_FMTx__ +#define PRIxLEAST64 __UINT_LEAST64_FMTx__ +#define PRIxFAST8 __UINT_FAST8_FMTx__ +#define PRIxFAST16 __UINT_FAST16_FMTx__ +#define PRIxFAST32 __UINT_FAST32_FMTx__ +#define PRIxFAST64 __UINT_FAST64_FMTx__ +#define PRIxMAX __UINTMAX_FMTx__ +#define PRIxPTR __UINTPTR_FMTx__ + +#define PRIX8 __UINT8_FMTX__ +#define PRIX16 __UINT16_FMTX__ +#define PRIX32 __UINT32_FMTX__ +#define PRIX64 __UINT64_FMTX__ +#define PRIXLEAST8 __UINT_LEAST8_FMTX__ +#define PRIXLEAST16 __UINT_LEAST16_FMTX__ +#define PRIXLEAST32 __UINT_LEAST32_FMTX__ +#define PRIXLEAST64 __UINT_LEAST64_FMTX__ +#define PRIXFAST8 __UINT_FAST8_FMTX__ +#define PRIXFAST16 __UINT_FAST16_FMTX__ +#define PRIXFAST32 __UINT_FAST32_FMTX__ +#define PRIXFAST64 __UINT_FAST64_FMTX__ +#define PRIXMAX __UINTMAX_FMTX__ +#define PRIXPTR __UINTPTR_FMTX__ + +// The fscanf() macros for signed integers. +#define SCNd8 __INT8_FMTd__ +#define SCNd16 __INT16_FMTd__ +#define SCNd32 __INT32_FMTd__ +#define SCNd64 __INT64_FMTd__ +#define SCNdLEAST8 __INT_LEAST8_FMTd__ +#define SCNdLEAST16 __INT_LEAST16_FMTd__ +#define SCNdLEAST32 __INT_LEAST32_FMTd__ +#define SCNdLEAST64 __INT_LEAST64_FMTd__ +#define SCNdFAST8 __INT_FAST8_FMTd__ +#define SCNdFAST16 __INT_FAST16_FMTd__ +#define SCNdFAST32 __INT_FAST32_FMTd__ +#define SCNdFAST64 __INT_FAST64_FMTd__ +#define SCNdMAX __INTMAX_FMTd__ +#define SCNdPTR __INTPTR_FMTd__ + +#define SCNi8 __INT8_FMTi__ +#define SCNi16 __INT16_FMTi__ +#define SCNi32 __INT32_FMTi__ +#define SCNi64 __INT64_FMTi__ +#define SCNiLEAST8 __INT_LEAST8_FMTi__ +#define SCNiLEAST16 __INT_LEAST16_FMTi__ +#define SCNiLEAST32 __INT_LEAST32_FMTi__ +#define SCNiLEAST64 __INT_LEAST64_FMTi__ +#define SCNiFAST8 __INT_FAST8_FMTi__ +#define SCNiFAST16 __INT_FAST16_FMTi__ +#define SCNiFAST32 __INT_FAST32_FMTi__ +#define SCNiFAST64 __INT_FAST64_FMTi__ +#define SCNiMAX __INTMAX_FMTi__ +#define SCNiPTR __INTPTR_FMTi__ + +// The fscanf() macros for unsigned integers. +#define SCNo8 __UINT8_FMTo__ +#define SCNo16 __UINT16_FMTo__ +#define SCNo32 __UINT32_FMTo__ +#define SCNo64 __UINT64_FMTo__ +#define SCNoLEAST8 __UINT_LEAST8_FMTo__ +#define SCNoLEAST16 __UINT_LEAST16_FMTo__ +#define SCNoLEAST32 __UINT_LEAST32_FMTo__ +#define SCNoLEAST64 __UINT_LEAST64_FMTo__ +#define SCNoFAST8 __UINT_FAST8_FMTo__ +#define SCNoFAST16 __UINT_FAST16_FMTo__ +#define SCNoFAST32 __UINT_FAST32_FMTo__ +#define SCNoFAST64 __UINT_FAST64_FMTo__ +#define SCNoMAX __UINTMAX_FMTo__ +#define SCNoPTR __UINTPTR_FMTo__ + +#define SCNu8 __UINT8_FMTu__ +#define SCNu16 __UINT16_FMTu__ +#define SCNu32 __UINT32_FMTu__ +#define SCNu64 __UINT64_FMTu__ +#define SCNuLEAST8 __UINT_LEAST8_FMTu__ +#define SCNuLEAST16 __UINT_LEAST16_FMTu__ +#define SCNuLEAST32 __UINT_LEAST32_FMTu__ +#define SCNuLEAST64 __UINT_LEAST64_FMTu__ +#define SCNuFAST8 __UINT_FAST8_FMTu__ +#define SCNuFAST16 __UINT_FAST16_FMTu__ +#define SCNuFAST32 __UINT_FAST32_FMTu__ +#define SCNuFAST64 __UINT_FAST64_FMTu__ +#define SCNuMAX __UINTMAX_FMTu__ +#define SCNuPTR __UINTPTR_FMTu__ + +#define SCNx8 __UINT8_FMTx__ +#define SCNx16 __UINT16_FMTx__ +#define SCNx32 __UINT32_FMTx__ +#define SCNx64 __UINT64_FMTx__ +#define SCNxLEAST8 __UINT_LEAST8_FMTx__ +#define SCNxLEAST16 __UINT_LEAST16_FMTx__ +#define SCNxLEAST32 __UINT_LEAST32_FMTx__ +#define SCNxLEAST64 __UINT_LEAST64_FMTx__ +#define SCNxFAST8 __UINT_FAST8_FMTx__ +#define SCNxFAST16 __UINT_FAST16_FMTx__ +#define SCNxFAST32 __UINT_FAST32_FMTx__ +#define SCNxFAST64 __UINT_FAST64_FMTx__ +#define SCNxMAX __UINTMAX_FMTx__ +#define SCNxPTR __UINTPTR_FMTx__ + +#endif // __LLVM_LIBC_MACROS_INTTYPES_MACROS_H diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt index ffc238443863bf..8db2293ab74a97 100644 --- a/libc/test/src/stdio/CMakeLists.txt +++ b/libc/test/src/stdio/CMakeLists.txt @@ -132,6 +132,7 @@ add_fp_unittest( DEPENDS libc.src.stdio.sprintf libc.src.__support.FPUtil.fp_bits + libc.include.inttypes COMPILE_OPTIONS ${sprintf_test_copts} ) diff --git a/libc/test/src/stdio/sprintf_test.cpp b/libc/test/src/stdio/sprintf_test.cpp index 1468bffe2a031d..f3614b05a0c3e6 100644 --- a/libc/test/src/stdio/sprintf_test.cpp +++ b/libc/test/src/stdio/sprintf_test.cpp @@ -11,6 +11,7 @@ #include "src/__support/FPUtil/FPBits.h" #include "test/UnitTest/RoundingModeUtils.h" #include "test/UnitTest/Test.h" +#include // TODO: Add a comment here explaining the printf format string. @@ -33,6 +34,25 @@ using LIBC_NAMESPACE::fputil::testing::RoundingMode; EXPECT_EQ(actual_written, static_cast(sizeof(expected_str) - 1)); \ EXPECT_STREQ(actual_str, expected_str); +#define macro_test(FMT, X, expected) \ + do { \ + for (char &c : buff) { \ + c = 0; \ + } \ + LIBC_NAMESPACE::sprintf(buff, "%" FMT, X); \ + ASSERT_STREQ(buff, expected); \ + } while (0) + +TEST(LlvmLibcSPrintfTest, Macros) { + char buff[128]; + macro_test(PRIu8, 1, "1"); + macro_test(PRIX16, 0xAA, "AA"); + macro_test(PRId32, -123, "-123"); + macro_test(PRIX32, 0xFFFFFF85, "FFFFFF85"); + macro_test(PRIo8, 0xFF, "377"); + macro_test(PRIo64, 0123, "123"); +} + TEST(LlvmLibcSPrintfTest, SimpleNoConv) { char buff[64]; int written;