diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -46,13 +46,20 @@ libc.src.string.strtok_r # inttypes.h entrypoints + libc.src.inttypes.imaxdiv libc.src.inttypes.strtoimax libc.src.inttypes.strtoumax # stdlib.h entrypoints + libc.src.stdlib.abs libc.src.stdlib.atoi libc.src.stdlib.atol libc.src.stdlib.atoll + libc.src.stdlib.div + libc.src.stdlib.labs + libc.src.stdlib.ldiv + libc.src.stdlib.llabs + libc.src.stdlib.lldiv libc.src.stdlib.strtol libc.src.stdlib.strtoll libc.src.stdlib.strtoul @@ -161,15 +168,6 @@ libc.src.math.truncl ) -if(LLVM_LIBC_FULL_BUILD) - list(APPEND TARGET_LIBC_ENTRYPOINTS - # stdlib.h entrypoints - libc.src.stdlib.abs - libc.src.stdlib.labs - libc.src.stdlib.llabs - ) -endif() - set(TARGET_LLVMLIBC_ENTRYPOINTS ${TARGET_LIBC_ENTRYPOINTS} ${TARGET_LIBM_ENTRYPOINTS} diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -111,6 +111,21 @@ def CTypeAPI : PublicAPI<"ctype.h"> { } +def IMaxDivT : TypeDecl<"imaxdiv_t"> { + let Decl = [{ + typedef struct { + intmax_t quot; + intmax_t rem; + } imaxdiv_t; + }]; +} + +def IntTypesAPI : PublicAPI<"inttypes.h"> { + let TypeDeclarations = [ + IMaxDivT, + ]; +} + def MathErrHandlingMacro : MacroDef<"math_errhandling"> { let Defn = [{ #ifndef math_errhandling @@ -239,7 +254,39 @@ ]; } +def DivT : TypeDecl<"div_t"> { + let Decl = [{ + typedef struct { + int quot; + int rem; + } div_t; + }]; +} + +def LDivT : TypeDecl<"ldiv_t"> { + let Decl = [{ + typedef struct { + long quot; + long rem; + } ldiv_t; + }]; +} + +def LLDivT : TypeDecl<"lldiv_t"> { + let Decl = [{ + typedef struct { + long long quot; + long long rem; + } lldiv_t; + }]; +} + def StdlibAPI : PublicAPI<"stdlib.h"> { + let TypeDeclarations = [ + DivT, + LDivT, + LLDivT, + ]; } def TimeAPI : PublicAPI<"time.h"> { diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -46,13 +46,20 @@ libc.src.string.strtok_r # inttypes.h entrypoints + libc.src.inttypes.imaxdiv libc.src.inttypes.strtoimax libc.src.inttypes.strtoumax # stdlib.h entrypoints + libc.src.stdlib.abs libc.src.stdlib.atoi libc.src.stdlib.atol libc.src.stdlib.atoll + libc.src.stdlib.div + libc.src.stdlib.labs + libc.src.stdlib.ldiv + libc.src.stdlib.llabs + libc.src.stdlib.lldiv libc.src.stdlib.strtol libc.src.stdlib.strtoll libc.src.stdlib.strtoul @@ -172,9 +179,6 @@ # stdlib.h entrypoints libc.src.stdlib._Exit libc.src.stdlib.abort - libc.src.stdlib.abs - libc.src.stdlib.labs - libc.src.stdlib.llabs # signal.h entrypoints libc.src.signal.raise diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -7,6 +7,10 @@ PtrType StructTmPtr = PtrType; PtrType TimeTTypePtr = PtrType; + NamedType DivTType = NamedType<"div_t">; + NamedType LDivTType = NamedType<"ldiv_t">; + NamedType LLDivTType = NamedType<"lldiv_t">; + HeaderSpec Assert = HeaderSpec< "assert.h", [ @@ -471,32 +475,48 @@ HeaderSpec StdLib = HeaderSpec< "stdlib.h", [], // Macros - [], // Types + [ + DivTType, + LDivTType, + LLDivTType, + ], // Types [], // Enumerations [ FunctionSpec<"abort", RetValSpec, [ArgSpec]>, + FunctionSpec<"abs", RetValSpec, [ArgSpec]>, + FunctionSpec<"labs", RetValSpec, [ArgSpec]>, + FunctionSpec<"llabs", RetValSpec, [ArgSpec]>, + FunctionSpec<"atoi", RetValSpec, [ArgSpec]>, FunctionSpec<"atol", RetValSpec, [ArgSpec]>, FunctionSpec<"atoll", RetValSpec, [ArgSpec]>, - FunctionSpec<"labs", RetValSpec, [ArgSpec]>, - FunctionSpec<"llabs", RetValSpec, [ArgSpec]>, + + FunctionSpec<"div", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"ldiv", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"lldiv", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"strtol", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, FunctionSpec<"strtoll", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, FunctionSpec<"strtoul", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, FunctionSpec<"strtoull", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, + FunctionSpec<"_Exit", RetValSpec, [ArgSpec]>, ] >; + NamedType IMaxDivTType = NamedType<"imaxdiv_t">; + HeaderSpec IntTypes = HeaderSpec< "inttypes.h", [], // Macros - [], // Types + [ + IMaxDivTType, + ], // Types [], // Enumerations [ FunctionSpec<"imaxabs", RetValSpec, [ArgSpec]>, - FunctionSpec<"imaxdiv", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"imaxdiv", RetValSpec, [ArgSpec, ArgSpec]>, FunctionSpec<"strtoimax", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, FunctionSpec<"strtoumax", RetValSpec, [ArgSpec, ArgSpec, ArgSpec]>, ] diff --git a/libc/src/__support/integer_operations.h b/libc/src/__support/integer_operations.h --- a/libc/src/__support/integer_operations.h +++ b/libc/src/__support/integer_operations.h @@ -19,6 +19,13 @@ return (n < 0) ? -n : n; } +template +static constexpr cpp::EnableIfType::Value, void> +integerRemQuo(T x, T y, T ", T &rem) { + quot = x / y; + rem = x % y; +} + } // namespace __llvm_libc #endif // LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H diff --git a/libc/src/inttypes/CMakeLists.txt b/libc/src/inttypes/CMakeLists.txt --- a/libc/src/inttypes/CMakeLists.txt +++ b/libc/src/inttypes/CMakeLists.txt @@ -17,3 +17,13 @@ DEPENDS libc.src.__support.str_conv_utils ) + +add_entrypoint_object( + imaxdiv + SRCS + imaxdiv.cpp + HDRS + imaxdiv.h + DEPENDS + libc.src.__support.integer_operations +) diff --git a/libc/src/__support/integer_operations.h b/libc/src/inttypes/imaxdiv.h copy from libc/src/__support/integer_operations.h copy to libc/src/inttypes/imaxdiv.h --- a/libc/src/__support/integer_operations.h +++ b/libc/src/inttypes/imaxdiv.h @@ -1,4 +1,4 @@ -//===-- Utils for abs and friends -------------------------------*- C++ -*-===// +//===-- Implementation header for imaxdiv -----------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,19 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H -#define LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H +#ifndef LLVM_LIBC_SRC_INTTYPES_IMAXDIV_H +#define LLVM_LIBC_SRC_INTTYPES_IMAXDIV_H -#include "utils/CPP/TypeTraits.h" +#include namespace __llvm_libc { -template -static constexpr cpp::EnableIfType::Value, T> -integerAbs(T n) { - return (n < 0) ? -n : n; -} +imaxdiv_t imaxdiv(intmax_t x, intmax_t y); } // namespace __llvm_libc -#endif // LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H +#endif // LLVM_LIBC_SRC_INTTYPES_IMAXDIV_H diff --git a/libc/src/inttypes/imaxdiv.cpp b/libc/src/inttypes/imaxdiv.cpp new file mode 100644 --- /dev/null +++ b/libc/src/inttypes/imaxdiv.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of imaxdiv -----------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/inttypes/imaxdiv.h" +#include "src/__support/common.h" +#include "src/__support/integer_operations.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(imaxdiv_t, imaxdiv, (intmax_t x, intmax_t y)) { + imaxdiv_t res; + integerRemQuo(x, y, res.quot, res.rem); + return res; +} + +} // namespace __llvm_libc diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt --- a/libc/src/stdlib/CMakeLists.txt +++ b/libc/src/stdlib/CMakeLists.txt @@ -124,3 +124,33 @@ DEPENDS libc.src.__support.integer_operations ) + +add_entrypoint_object( + div + SRCS + div.cpp + HDRS + div.h + DEPENDS + libc.src.__support.integer_operations +) + +add_entrypoint_object( + ldiv + SRCS + ldiv.cpp + HDRS + ldiv.h + DEPENDS + libc.src.__support.integer_operations +) + +add_entrypoint_object( + lldiv + SRCS + lldiv.cpp + HDRS + lldiv.h + DEPENDS + libc.src.__support.integer_operations +) diff --git a/libc/src/__support/integer_operations.h b/libc/src/stdlib/div.h copy from libc/src/__support/integer_operations.h copy to libc/src/stdlib/div.h --- a/libc/src/__support/integer_operations.h +++ b/libc/src/stdlib/div.h @@ -1,4 +1,4 @@ -//===-- Utils for abs and friends -------------------------------*- C++ -*-===// +//===-- Implementation header for div ---------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,19 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H -#define LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H +#include -#include "utils/CPP/TypeTraits.h" +#ifndef LLVM_LIBC_SRC_STDLIB_DIV_H +#define LLVM_LIBC_SRC_STDLIB_DIV_H namespace __llvm_libc { -template -static constexpr cpp::EnableIfType::Value, T> -integerAbs(T n) { - return (n < 0) ? -n : n; -} +div_t div(int x, int y); } // namespace __llvm_libc -#endif // LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H +#endif // LLVM_LIBC_SRC_STDLIB_DIV_H diff --git a/libc/src/stdlib/div.cpp b/libc/src/stdlib/div.cpp new file mode 100644 --- /dev/null +++ b/libc/src/stdlib/div.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of div ---------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdlib/div.h" +#include "src/__support/common.h" +#include "src/__support/integer_operations.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(div_t, div, (int x, int y)) { + div_t res; + integerRemQuo(x, y, res.quot, res.rem); + return res; +} + +} // namespace __llvm_libc diff --git a/libc/src/__support/integer_operations.h b/libc/src/stdlib/ldiv.h copy from libc/src/__support/integer_operations.h copy to libc/src/stdlib/ldiv.h --- a/libc/src/__support/integer_operations.h +++ b/libc/src/stdlib/ldiv.h @@ -1,4 +1,4 @@ -//===-- Utils for abs and friends -------------------------------*- C++ -*-===// +//===-- Implementation header for ldiv --------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,19 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H -#define LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H +#include -#include "utils/CPP/TypeTraits.h" +#ifndef LLVM_LIBC_SRC_STDLIB_LDIV_H +#define LLVM_LIBC_SRC_STDLIB_LDIV_H namespace __llvm_libc { -template -static constexpr cpp::EnableIfType::Value, T> -integerAbs(T n) { - return (n < 0) ? -n : n; -} +ldiv_t ldiv(long x, long y); } // namespace __llvm_libc -#endif // LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H +#endif // LLVM_LIBC_SRC_STDLIB_LDIV_H diff --git a/libc/src/stdlib/ldiv.cpp b/libc/src/stdlib/ldiv.cpp new file mode 100644 --- /dev/null +++ b/libc/src/stdlib/ldiv.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of ldiv --------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdlib/ldiv.h" +#include "src/__support/common.h" +#include "src/__support/integer_operations.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(ldiv_t, ldiv, (long x, long y)) { + ldiv_t res; + integerRemQuo(x, y, res.quot, res.rem); + return res; +} + +} // namespace __llvm_libc diff --git a/libc/src/__support/integer_operations.h b/libc/src/stdlib/lldiv.h copy from libc/src/__support/integer_operations.h copy to libc/src/stdlib/lldiv.h --- a/libc/src/__support/integer_operations.h +++ b/libc/src/stdlib/lldiv.h @@ -1,4 +1,4 @@ -//===-- Utils for abs and friends -------------------------------*- C++ -*-===// +//===-- Implementation header for lldiv -------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,19 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H -#define LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H +#include -#include "utils/CPP/TypeTraits.h" +#ifndef LLVM_LIBC_SRC_STDLIB_LLDIV_H +#define LLVM_LIBC_SRC_STDLIB_LLDIV_H namespace __llvm_libc { -template -static constexpr cpp::EnableIfType::Value, T> -integerAbs(T n) { - return (n < 0) ? -n : n; -} +lldiv_t lldiv(long long x, long long y); } // namespace __llvm_libc -#endif // LLVM_LIBC_SRC_STDLIB_ABS_UTILS_H +#endif // LLVM_LIBC_SRC_STDLIB_LDIV_H diff --git a/libc/src/stdlib/lldiv.cpp b/libc/src/stdlib/lldiv.cpp new file mode 100644 --- /dev/null +++ b/libc/src/stdlib/lldiv.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of lldiv -------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "src/stdlib/lldiv.h" +#include "src/__support/common.h" +#include "src/__support/integer_operations.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(lldiv_t, lldiv, (long long x, long long y)) { + lldiv_t res; + integerRemQuo(x, y, res.quot, res.rem); + return res; +} + +} // namespace __llvm_libc diff --git a/libc/test/src/inttypes/CMakeLists.txt b/libc/test/src/inttypes/CMakeLists.txt --- a/libc/test/src/inttypes/CMakeLists.txt +++ b/libc/test/src/inttypes/CMakeLists.txt @@ -19,3 +19,16 @@ DEPENDS libc.src.inttypes.strtoumax ) + +add_libc_unittest( + imaxdiv_test + SUITE + libc_inttypes_unittests + SRCS + imaxdiv_test.cpp + HDRS + ../stdlib/DivTest.h + DEPENDS + libc.include.stdlib + libc.src.inttypes.imaxdiv +) diff --git a/libc/test/src/inttypes/imaxdiv_test.cpp b/libc/test/src/inttypes/imaxdiv_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/inttypes/imaxdiv_test.cpp @@ -0,0 +1,15 @@ +//===-- Unittests for imaxdiv ---------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "../stdlib/DivTest.h" + +#include "src/inttypes/imaxdiv.h" + +#include + +LIST_DIV_TESTS(intmax_t, imaxdiv_t, __llvm_libc::imaxdiv) diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt --- a/libc/test/src/stdlib/CMakeLists.txt +++ b/libc/test/src/stdlib/CMakeLists.txt @@ -128,3 +128,42 @@ DEPENDS libc.src.stdlib.llabs ) + +add_libc_unittest( + div_test + SUITE + libc_stdlib_unittests + SRCS + div_test.cpp + HDRS + DivTest.h + DEPENDS + libc.include.stdlib + libc.src.stdlib.div +) + +add_libc_unittest( + ldiv_test + SUITE + libc_stdlib_unittests + SRCS + ldiv_test.cpp + HDRS + DivTest.h + DEPENDS + libc.include.stdlib + libc.src.stdlib.ldiv +) + +add_libc_unittest( + lldiv_test + SUITE + libc_stdlib_unittests + SRCS + lldiv_test.cpp + HDRS + DivTest.h + DEPENDS + libc.include.stdlib + libc.src.stdlib.lldiv +) diff --git a/libc/test/src/stdlib/DivTest.h b/libc/test/src/stdlib/DivTest.h new file mode 100644 --- /dev/null +++ b/libc/test/src/stdlib/DivTest.h @@ -0,0 +1,37 @@ +//===-- A template class for testing div functions --------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "utils/UnitTest/Test.h" + +template +class DivTest : public __llvm_libc::testing::Test { +public: + using DivFunc = ReturnType(IntType, IntType); + + void simpleTest(DivFunc func) { + auto result = func(10, 3); + EXPECT_EQ(result.quot, IntType(3)); + EXPECT_EQ(result.rem, IntType(1)); + + result = func(-10, 3); + EXPECT_EQ(result.quot, IntType(-3)); + EXPECT_EQ(result.rem, IntType(-1)); + + result = func(-10, -3); + EXPECT_EQ(result.quot, IntType(3)); + EXPECT_EQ(result.rem, IntType(-1)); + + result = func(10, -3); + EXPECT_EQ(result.quot, IntType(-3)); + EXPECT_EQ(result.rem, IntType(1)); + } +}; + +#define LIST_DIV_TESTS(IntType, ReturnType, func) \ + using LlvmLibcDivTest = DivTest; \ + TEST_F(LlvmLibcDivTest, SimpleTest) { simpleTest(func); } diff --git a/libc/test/src/stdlib/div_test.cpp b/libc/test/src/stdlib/div_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/stdlib/div_test.cpp @@ -0,0 +1,15 @@ +//===-- Unittests for div -------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "DivTest.h" + +#include "src/stdlib/div.h" + +#include + +LIST_DIV_TESTS(int, div_t, __llvm_libc::div) diff --git a/libc/test/src/stdlib/ldiv_test.cpp b/libc/test/src/stdlib/ldiv_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/stdlib/ldiv_test.cpp @@ -0,0 +1,15 @@ +//===-- Unittests for ldiv ------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "DivTest.h" + +#include "src/stdlib/ldiv.h" + +#include + +LIST_DIV_TESTS(long, ldiv_t, __llvm_libc::ldiv) diff --git a/libc/test/src/stdlib/lldiv_test.cpp b/libc/test/src/stdlib/lldiv_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/stdlib/lldiv_test.cpp @@ -0,0 +1,15 @@ +//===-- Unittests for lldiv -----------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "DivTest.h" + +#include "src/stdlib/lldiv.h" + +#include + +LIST_DIV_TESTS(long long, lldiv_t, __llvm_libc::lldiv)