summaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm/flang-rt/flang-rt/lib/runtime/random.cpp
diff options
context:
space:
mode:
authorYDBot <[email protected]>2025-09-26 05:40:56 +0000
committerYDBot <[email protected]>2025-09-26 05:40:56 +0000
commita7e5af7043672a57f330696519f435f19fcd03d0 (patch)
treefa751accfbb8afcd928340c9078b00453c07dde1 /contrib/libs/llvm/flang-rt/flang-rt/lib/runtime/random.cpp
parentd7cd65635ff05f602b8eb7c6e2a42217057dd2c6 (diff)
parentee5ee24a4d661a146d6142a78050207193937281 (diff)
Merge pull request #25828 from ydb-platform/merge-rightlib-250926-0050
Diffstat (limited to 'contrib/libs/llvm/flang-rt/flang-rt/lib/runtime/random.cpp')
-rw-r--r--contrib/libs/llvm/flang-rt/flang-rt/lib/runtime/random.cpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/contrib/libs/llvm/flang-rt/flang-rt/lib/runtime/random.cpp b/contrib/libs/llvm/flang-rt/flang-rt/lib/runtime/random.cpp
new file mode 100644
index 00000000000..dc74f2725ed
--- /dev/null
+++ b/contrib/libs/llvm/flang-rt/flang-rt/lib/runtime/random.cpp
@@ -0,0 +1,228 @@
+//===-- lib/runtime/random.cpp ----------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+// Implements the intrinsic subroutines RANDOM_INIT, RANDOM_NUMBER, and
+// RANDOM_SEED.
+
+#include "flang/Runtime/random.h"
+#include "flang-rt/runtime/descriptor.h"
+#include "flang-rt/runtime/lock.h"
+#include "flang-rt/runtime/random-templates.h"
+#include "flang-rt/runtime/terminator.h"
+#include "flang/Common/float128.h"
+#include "flang/Common/leading-zero-bit-count.h"
+#include "flang/Common/uint128.h"
+#include "flang/Runtime/cpp-type.h"
+#include <cmath>
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <time.h>
+
+namespace Fortran::runtime::random {
+
+Lock lock;
+Generator generator;
+Fortran::common::optional<GeneratedWord> nextValue;
+
+extern "C" {
+
+void RTNAME(RandomInit)(bool repeatable, bool /*image_distinct*/) {
+ // TODO: multiple images and image_distinct: add image number
+ {
+ CriticalSection critical{lock};
+ if (repeatable) {
+ generator.seed(0);
+ } else {
+#ifdef CLOCK_REALTIME
+ timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ generator.seed(ts.tv_sec ^ ts.tv_nsec);
+#else
+ generator.seed(time(nullptr));
+#endif
+ }
+ }
+}
+
+void RTNAME(RandomNumber)(
+ const Descriptor &harvest, const char *source, int line) {
+ Terminator terminator{source, line};
+ auto typeCode{harvest.type().GetCategoryAndKind()};
+ RUNTIME_CHECK(terminator,
+ typeCode &&
+ (typeCode->first == TypeCategory::Real ||
+ typeCode->first == TypeCategory::Unsigned));
+ int kind{typeCode->second};
+ if (typeCode->first == TypeCategory::Real) {
+ switch (kind) {
+ // TODO: REAL (2 & 3)
+ case 4:
+ GenerateReal<CppTypeFor<TypeCategory::Real, 4>, 24>(harvest);
+ return;
+ case 8:
+ GenerateReal<CppTypeFor<TypeCategory::Real, 8>, 53>(harvest);
+ return;
+ case 10:
+ if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) {
+#if HAS_FLOAT80
+ GenerateReal<CppTypeFor<TypeCategory::Real, 10>, 64>(harvest);
+ return;
+#endif
+ }
+ break;
+ }
+ terminator.Crash(
+ "not yet implemented: intrinsic: REAL(KIND=%d) in RANDOM_NUMBER", kind);
+ } else if (typeCode->first == TypeCategory::Unsigned) {
+ switch (kind) {
+ case 1:
+ GenerateUnsigned<CppTypeFor<TypeCategory::Unsigned, 1>>(harvest);
+ return;
+ case 2:
+ GenerateUnsigned<CppTypeFor<TypeCategory::Unsigned, 2>>(harvest);
+ return;
+ case 4:
+ GenerateUnsigned<CppTypeFor<TypeCategory::Unsigned, 4>>(harvest);
+ return;
+ case 8:
+ GenerateUnsigned<CppTypeFor<TypeCategory::Unsigned, 8>>(harvest);
+ return;
+#ifdef __SIZEOF_INT128__
+ case 16:
+ if constexpr (HasCppTypeFor<TypeCategory::Unsigned, 16>) {
+ GenerateUnsigned<CppTypeFor<TypeCategory::Unsigned, 16>>(harvest);
+ return;
+ }
+ break;
+#endif
+ }
+ terminator.Crash(
+ "not yet implemented: intrinsic: UNSIGNED(KIND=%d) in RANDOM_NUMBER",
+ kind);
+ }
+}
+
+void RTNAME(RandomSeedSize)(
+ const Descriptor *size, const char *source, int line) {
+ if (!size || !size->raw().base_addr) {
+ RTNAME(RandomSeedDefaultPut)();
+ return;
+ }
+ Terminator terminator{source, line};
+ auto typeCode{size->type().GetCategoryAndKind()};
+ RUNTIME_CHECK(terminator,
+ size->rank() == 0 && typeCode &&
+ typeCode->first == TypeCategory::Integer);
+ int sizeArg{typeCode->second};
+ switch (sizeArg) {
+ case 4:
+ *size->OffsetElement<CppTypeFor<TypeCategory::Integer, 4>>() = 1;
+ break;
+ case 8:
+ *size->OffsetElement<CppTypeFor<TypeCategory::Integer, 8>>() = 1;
+ break;
+ default:
+ terminator.Crash(
+ "not yet implemented: intrinsic: RANDOM_SEED(SIZE=): size %d\n",
+ sizeArg);
+ }
+}
+
+void RTNAME(RandomSeedPut)(
+ const Descriptor *put, const char *source, int line) {
+ if (!put || !put->raw().base_addr) {
+ RTNAME(RandomSeedDefaultPut)();
+ return;
+ }
+ Terminator terminator{source, line};
+ auto typeCode{put->type().GetCategoryAndKind()};
+ RUNTIME_CHECK(terminator,
+ put->rank() == 1 && typeCode &&
+ typeCode->first == TypeCategory::Integer &&
+ put->GetDimension(0).Extent() >= 1);
+ int putArg{typeCode->second};
+ GeneratedWord seed;
+ switch (putArg) {
+ case 4:
+ seed = *put->OffsetElement<CppTypeFor<TypeCategory::Integer, 4>>();
+ break;
+ case 8:
+ seed = *put->OffsetElement<CppTypeFor<TypeCategory::Integer, 8>>();
+ break;
+ default:
+ terminator.Crash(
+ "not yet implemented: intrinsic: RANDOM_SEED(PUT=): put %d\n", putArg);
+ }
+ {
+ CriticalSection critical{lock};
+ generator.seed(seed);
+ nextValue = seed;
+ }
+}
+
+void RTNAME(RandomSeedDefaultPut)() {
+ // TODO: should this be time &/or image dependent?
+ {
+ CriticalSection critical{lock};
+ generator.seed(0);
+ }
+}
+
+void RTNAME(RandomSeedGet)(
+ const Descriptor *get, const char *source, int line) {
+ if (!get || !get->raw().base_addr) {
+ RTNAME(RandomSeedDefaultPut)();
+ return;
+ }
+ Terminator terminator{source, line};
+ auto typeCode{get->type().GetCategoryAndKind()};
+ RUNTIME_CHECK(terminator,
+ get->rank() == 1 && typeCode &&
+ typeCode->first == TypeCategory::Integer &&
+ get->GetDimension(0).Extent() >= 1);
+ int getArg{typeCode->second};
+ GeneratedWord seed;
+ {
+ CriticalSection critical{lock};
+ seed = GetNextValue();
+ nextValue = seed;
+ }
+ switch (getArg) {
+ case 4:
+ *get->OffsetElement<CppTypeFor<TypeCategory::Integer, 4>>() = seed;
+ break;
+ case 8:
+ *get->OffsetElement<CppTypeFor<TypeCategory::Integer, 8>>() = seed;
+ break;
+ default:
+ terminator.Crash(
+ "not yet implemented: intrinsic: RANDOM_SEED(GET=): get %d\n", getArg);
+ }
+}
+
+void RTNAME(RandomSeed)(const Descriptor *size, const Descriptor *put,
+ const Descriptor *get, const char *source, int line) {
+ bool sizePresent = size && size->raw().base_addr;
+ bool putPresent = put && put->raw().base_addr;
+ bool getPresent = get && get->raw().base_addr;
+ if (sizePresent + putPresent + getPresent > 1)
+ Terminator{source, line}.Crash(
+ "RANDOM_SEED must have either 1 or no arguments");
+ if (sizePresent)
+ RTNAME(RandomSeedSize)(size, source, line);
+ else if (putPresent)
+ RTNAME(RandomSeedPut)(put, source, line);
+ else if (getPresent)
+ RTNAME(RandomSeedGet)(get, source, line);
+ else
+ RTNAME(RandomSeedDefaultPut)();
+}
+
+} // extern "C"
+} // namespace Fortran::runtime::random