[libc] implement basic rand and srand

This provides the reference implementation of rand and srand. In future
this will likely be upgraded to something that supports full ints.

Reviewed By: sivachandra

Differential Revision: https://reviews.llvm.org/D135187
This commit is contained in:
Michael Jones 2022-10-04 11:59:55 -07:00
parent 42fead6834
commit 38b6f58e33
16 changed files with 224 additions and 0 deletions

View File

@ -82,6 +82,8 @@ set(TARGET_LIBC_ENTRYPOINTS
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

View File

@ -157,6 +157,7 @@ add_gen_header(
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

View File

@ -22,6 +22,12 @@ add_header(
.linux.signal_macros
)
add_header(
stdlib_macros
HDR
stdlib-macros.h
)
add_header(
sys_stat_macros
HDR

View File

@ -0,0 +1,14 @@
//===-- 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.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef __LLVM_LIBC_MACROS_STDLIB_MACROS_H
#define __LLVM_LIBC_MACROS_STDLIB_MACROS_H
#define RAND_MAX 32767
#endif // __LLVM_LIBC_MACROS_STDLIB_MACROS_H

View File

@ -10,6 +10,7 @@
#define LLVM_LIBC_STDLIB_H
#include <__llvm-libc-common.h>
#include <llvm-libc-macros/stdlib-macros.h>
%%public_api()

View File

@ -39,6 +39,7 @@ class RestrictedPtrType<Type type> : Type {
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">;

View File

@ -648,6 +648,9 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"qsort", RetValSpec<VoidType>, [ArgSpec<VoidPtr>, ArgSpec<SizeTType>, ArgSpec<SizeTType>, ArgSpec<QSortCompareT>]>,
FunctionSpec<"rand", RetValSpec<IntType>, [ArgSpec<VoidType>]>,
FunctionSpec<"srand", RetValSpec<VoidType>, [ArgSpec<UnsignedIntType>]>,
FunctionSpec<"strtof", RetValSpec<FloatType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>]>,
FunctionSpec<"strtod", RetValSpec<DoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>]>,
FunctionSpec<"strtold", RetValSpec<LongDoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>]>,

View File

@ -201,6 +201,36 @@ add_entrypoint_object(
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 "")

22
libc/src/stdlib/rand.cpp Normal file
View File

@ -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<unsigned int>((rand_next / 65536) % 32768);
}
} // namespace __llvm_libc

20
libc/src/stdlib/rand.h Normal file
View File

@ -0,0 +1,20 @@
//===-- 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.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <stdlib.h>
#ifndef LLVM_LIBC_SRC_STDLIB_RAND_H
#define LLVM_LIBC_SRC_STDLIB_RAND_H
namespace __llvm_libc {
int rand(void);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_STDLIB_RAND_H

View File

@ -0,0 +1,15 @@
//===-- 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.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "src/stdlib/rand_util.h"
namespace __llvm_libc {
thread_local unsigned long rand_next;
} // namespace __llvm_libc

View File

@ -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

17
libc/src/stdlib/srand.cpp Normal file
View File

@ -0,0 +1,17 @@
//===-- 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.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "src/stdlib/srand.h"
#include "src/__support/common.h"
#include "src/stdlib/rand_util.h"
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(void, srand, (unsigned int seed)) { rand_next = seed; }
} // namespace __llvm_libc

20
libc/src/stdlib/srand.h Normal file
View File

@ -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 <stdlib.h>
#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

View File

@ -202,6 +202,18 @@ add_libc_unittest(
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(

View File

@ -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 <stddef.h>
#include <stdlib.h>
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);
}
}