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 @@ -82,6 +82,8 @@ libc.src.stdlib.llabs libc.src.stdlib.lldiv libc.src.stdlib.qsort + libc.src.stdlib.rand + libc.src.stdlib.srand libc.src.stdlib.strtod libc.src.stdlib.strtof libc.src.stdlib.strtol diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -157,6 +157,7 @@ GEN_HDR stdlib.h DEPENDS .llvm_libc_common_h + .llvm-libc-macros.stdlib_macros .llvm-libc-types.__bsearchcompare_t .llvm-libc-types.__qsortcompare_t .llvm-libc-types.div_t diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt --- a/libc/include/llvm-libc-macros/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/CMakeLists.txt @@ -22,6 +22,12 @@ .linux.signal_macros ) +add_header( + stdlib_macros + HDR + stdlib-macros.h +) + add_header( sys_stat_macros HDR diff --git a/libc/include/stdlib.h.def b/libc/include/llvm-libc-macros/stdlib-macros.h copy from libc/include/stdlib.h.def copy to libc/include/llvm-libc-macros/stdlib-macros.h --- a/libc/include/stdlib.h.def +++ b/libc/include/llvm-libc-macros/stdlib-macros.h @@ -1,4 +1,4 @@ -//===-- C standard library header stdlib.h --------------------------------===// +//===-- Definition of macros to be used with stdlib functions ----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,11 +6,9 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_STDLIB_H -#define LLVM_LIBC_STDLIB_H +#ifndef __LLVM_LIBC_MACROS_STDLIB_MACROS_H +#define __LLVM_LIBC_MACROS_STDLIB_MACROS_H -#include <__llvm-libc-common.h> +#define RAND_MAX 32767 -%%public_api() - -#endif // LLVM_LIBC_STDLIB_H +#endif // __LLVM_LIBC_MACROS_STDLIB_MACROS_H diff --git a/libc/include/stdlib.h.def b/libc/include/stdlib.h.def --- a/libc/include/stdlib.h.def +++ b/libc/include/stdlib.h.def @@ -10,6 +10,7 @@ #define LLVM_LIBC_STDLIB_H #include <__llvm-libc-common.h> +#include %%public_api() diff --git a/libc/spec/spec.td b/libc/spec/spec.td --- a/libc/spec/spec.td +++ b/libc/spec/spec.td @@ -39,6 +39,7 @@ def VarArgType : NamedType<"...">; def VoidType : NamedType<"void">; def IntType : NamedType<"int">; +def UnsignedIntType : NamedType<"unsigned int">; def LongType : NamedType<"long">; def UnsignedLongType : NamedType<"unsigned long">; def LongLongType : NamedType<"long long">; diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -648,6 +648,9 @@ FunctionSpec<"qsort", RetValSpec, [ArgSpec, ArgSpec, ArgSpec, ArgSpec]>, + FunctionSpec<"rand", RetValSpec, [ArgSpec]>, + FunctionSpec<"srand", RetValSpec, [ArgSpec]>, + FunctionSpec<"strtof", RetValSpec, [ArgSpec, ArgSpec]>, FunctionSpec<"strtod", RetValSpec, [ArgSpec, ArgSpec]>, FunctionSpec<"strtold", RetValSpec, [ArgSpec, ArgSpec]>, 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 @@ -201,6 +201,36 @@ libc.include.stdlib ) +add_object_library( + rand_util + SRCS + rand_util.cpp + HDRS + rand_util.h +) + +add_entrypoint_object( + rand + SRCS + rand.cpp + HDRS + rand.h + DEPENDS + .rand_util + libc.include.stdlib +) + +add_entrypoint_object( + srand + SRCS + srand.cpp + HDRS + srand.h + DEPENDS + .rand_util + libc.include.stdlib +) + if(LLVM_LIBC_INCLUDE_SCUDO) set(SCUDO_DEPS "") diff --git a/libc/include/stdlib.h.def b/libc/src/stdlib/rand.h copy from libc/include/stdlib.h.def copy to libc/src/stdlib/rand.h --- a/libc/include/stdlib.h.def +++ b/libc/src/stdlib/rand.h @@ -1,4 +1,4 @@ -//===-- C standard library header stdlib.h --------------------------------===// +//===-- Implementation header for rand --------------------------*- 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,11 +6,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_STDLIB_H -#define LLVM_LIBC_STDLIB_H +#include -#include <__llvm-libc-common.h> +#ifndef LLVM_LIBC_SRC_STDLIB_RAND_H +#define LLVM_LIBC_SRC_STDLIB_RAND_H -%%public_api() +namespace __llvm_libc { -#endif // LLVM_LIBC_STDLIB_H +int rand(void); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDLIB_RAND_H diff --git a/libc/src/stdlib/rand.cpp b/libc/src/stdlib/rand.cpp new file mode 100644 --- /dev/null +++ b/libc/src/stdlib/rand.cpp @@ -0,0 +1,22 @@ +//===-- Implementation of rand --------------------------------------------===// +// +// 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/rand.h" +#include "src/__support/common.h" +#include "src/stdlib/rand_util.h" + +namespace __llvm_libc { + +// This rand function is the example implementation from the C standard. It is +// not cryptographically secure. +LLVM_LIBC_FUNCTION(int, rand, (void)) { // RAND_MAX is assumed to be 32767 + rand_next = rand_next * 1103515245 + 12345; + return static_cast((rand_next / 65536) % 32768); +} + +} // namespace __llvm_libc diff --git a/libc/src/stdlib/rand_util.h b/libc/src/stdlib/rand_util.h new file mode 100644 --- /dev/null +++ b/libc/src/stdlib/rand_util.h @@ -0,0 +1,18 @@ +//===-- Implementation header for rand utilities ----------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDLIB_RAND_UTIL_H +#define LLVM_LIBC_SRC_STDLIB_RAND_UTIL_H + +namespace __llvm_libc { + +extern thread_local unsigned long rand_next; + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDLIB_RAND_UTIL_H diff --git a/libc/include/stdlib.h.def b/libc/src/stdlib/rand_util.cpp copy from libc/include/stdlib.h.def copy to libc/src/stdlib/rand_util.cpp --- a/libc/include/stdlib.h.def +++ b/libc/src/stdlib/rand_util.cpp @@ -1,4 +1,4 @@ -//===-- C standard library header stdlib.h --------------------------------===// +//===-- Shared utility for rand -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,11 +6,10 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_STDLIB_H -#define LLVM_LIBC_STDLIB_H +#include "src/stdlib/rand_util.h" -#include <__llvm-libc-common.h> +namespace __llvm_libc { -%%public_api() +thread_local unsigned long rand_next; -#endif // LLVM_LIBC_STDLIB_H +} // namespace __llvm_libc diff --git a/libc/src/stdlib/srand.h b/libc/src/stdlib/srand.h new file mode 100644 --- /dev/null +++ b/libc/src/stdlib/srand.h @@ -0,0 +1,20 @@ +//===-- Implementation header for srand -------------------------*- 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 + +#ifndef LLVM_LIBC_SRC_STDLIB_SRAND_H +#define LLVM_LIBC_SRC_STDLIB_SRAND_H + +namespace __llvm_libc { + +void srand(unsigned int seed); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STDLIB_SRAND_H diff --git a/libc/include/stdlib.h.def b/libc/src/stdlib/srand.cpp copy from libc/include/stdlib.h.def copy to libc/src/stdlib/srand.cpp --- a/libc/include/stdlib.h.def +++ b/libc/src/stdlib/srand.cpp @@ -1,4 +1,4 @@ -//===-- C standard library header stdlib.h --------------------------------===// +//===-- Implementation of srand -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,11 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_STDLIB_H -#define LLVM_LIBC_STDLIB_H +#include "src/stdlib/srand.h" +#include "src/__support/common.h" +#include "src/stdlib/rand_util.h" -#include <__llvm-libc-common.h> +namespace __llvm_libc { -%%public_api() +LLVM_LIBC_FUNCTION(void, srand, (unsigned int seed)) { rand_next = seed; } -#endif // LLVM_LIBC_STDLIB_H +} // namespace __llvm_libc 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 @@ -202,6 +202,18 @@ libc.src.stdlib.qsort ) +add_libc_unittest( + rand_test + SUITE + libc_stdlib_unittests + SRCS + rand_test.cpp + DEPENDS + libc.include.stdlib + libc.src.stdlib.rand + libc.src.stdlib.srand +) + if(LLVM_LIBC_FULL_BUILD) add_libc_unittest( diff --git a/libc/test/src/stdlib/rand_test.cpp b/libc/test/src/stdlib/rand_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/stdlib/rand_test.cpp @@ -0,0 +1,42 @@ +//===-- Unittests for rand ------------------------------------------------===// +// +// 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/rand.h" +#include "src/stdlib/srand.h" +#include "utils/UnitTest/Test.h" + +#include +#include + +TEST(LlvmLibcRandTest, UnsetSeed) { + for (size_t i = 0; i < 1000; ++i) { + int val = __llvm_libc::rand(); + ASSERT_GE(val, 0); + ASSERT_LE(val, RAND_MAX); + } +} + +TEST(LlvmLibcRandTest, SetSeed) { + const unsigned int SEED = 12344321; + __llvm_libc::srand(SEED); + const size_t NUM_RESULTS = 10; + int results[NUM_RESULTS]; + for (size_t i = 0; i < NUM_RESULTS; ++i) { + results[i] = __llvm_libc::rand(); + ASSERT_GE(results[i], 0); + ASSERT_LE(results[i], RAND_MAX); + } + + // If the seed is set to the same value, it should give the same sequence. + __llvm_libc::srand(SEED); + + for (size_t i = 0; i < NUM_RESULTS; ++i) { + int val = __llvm_libc::rand(); + EXPECT_EQ(results[i], val); + } +}