1e1114045Speter klausler //===-- runtime/random.cpp ------------------------------------------------===// 2e1114045Speter klausler // 3e1114045Speter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e1114045Speter klausler // See https://llvm.org/LICENSE.txt for license information. 5e1114045Speter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e1114045Speter klausler // 7e1114045Speter klausler //===----------------------------------------------------------------------===// 8e1114045Speter klausler 9e1114045Speter klausler // Implements the intrinsic subroutines RANDOM_INIT, RANDOM_NUMBER, and 10e1114045Speter klausler // RANDOM_SEED. 11e1114045Speter klausler 12830c0b90SPeter Klausler #include "flang/Runtime/random.h" 13e1114045Speter klausler #include "lock.h" 14e0738cc6SSlava Zakharin #include "random-templates.h" 15cc71e694SV Donaldson #include "terminator.h" 16478e0b58SPeter Steinfeld #include "flang/Common/float128.h" 17e1114045Speter klausler #include "flang/Common/leading-zero-bit-count.h" 18e1114045Speter klausler #include "flang/Common/uint128.h" 19830c0b90SPeter Klausler #include "flang/Runtime/cpp-type.h" 20830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h" 21e1114045Speter klausler #include <cmath> 22e1114045Speter klausler #include <cstdint> 23e1114045Speter klausler #include <limits> 24e1114045Speter klausler #include <memory> 25301a0dbaSPeter Klausler #include <time.h> 26e1114045Speter klausler 27e0738cc6SSlava Zakharin namespace Fortran::runtime::random { 28e1114045Speter klausler 29e0738cc6SSlava Zakharin Lock lock; 30e0738cc6SSlava Zakharin Generator generator; 3171e0261fSSlava Zakharin Fortran::common::optional<GeneratedWord> nextValue; 32e1114045Speter klausler 33e1114045Speter klausler extern "C" { 34e1114045Speter klausler 35e1114045Speter klausler void RTNAME(RandomInit)(bool repeatable, bool /*image_distinct*/) { 36e1114045Speter klausler // TODO: multiple images and image_distinct: add image number 37e1114045Speter klausler { 38e1114045Speter klausler CriticalSection critical{lock}; 39e1114045Speter klausler if (repeatable) { 40e1114045Speter klausler generator.seed(0); 41e1114045Speter klausler } else { 42301a0dbaSPeter Klausler #ifdef CLOCK_REALTIME 43301a0dbaSPeter Klausler timespec ts; 44301a0dbaSPeter Klausler clock_gettime(CLOCK_REALTIME, &ts); 456facf698SPeter Klausler generator.seed(ts.tv_sec ^ ts.tv_nsec); 46301a0dbaSPeter Klausler #else 47301a0dbaSPeter Klausler generator.seed(time(nullptr)); 48301a0dbaSPeter Klausler #endif 49e1114045Speter klausler } 50e1114045Speter klausler } 51e1114045Speter klausler } 52e1114045Speter klausler 53e1114045Speter klausler void RTNAME(RandomNumber)( 54e1114045Speter klausler const Descriptor &harvest, const char *source, int line) { 55e1114045Speter klausler Terminator terminator{source, line}; 56e1114045Speter klausler auto typeCode{harvest.type().GetCategoryAndKind()}; 57*fc97d2e6SPeter Klausler RUNTIME_CHECK(terminator, 58*fc97d2e6SPeter Klausler typeCode && 59*fc97d2e6SPeter Klausler (typeCode->first == TypeCategory::Real || 60*fc97d2e6SPeter Klausler typeCode->first == TypeCategory::Unsigned)); 61e1114045Speter klausler int kind{typeCode->second}; 62*fc97d2e6SPeter Klausler if (typeCode->first == TypeCategory::Real) { 63e1114045Speter klausler switch (kind) { 64e1114045Speter klausler // TODO: REAL (2 & 3) 65e1114045Speter klausler case 4: 66*fc97d2e6SPeter Klausler GenerateReal<CppTypeFor<TypeCategory::Real, 4>, 24>(harvest); 674daa33f6SPeter Klausler return; 68e1114045Speter klausler case 8: 69*fc97d2e6SPeter Klausler GenerateReal<CppTypeFor<TypeCategory::Real, 8>, 53>(harvest); 704daa33f6SPeter Klausler return; 71e1114045Speter klausler case 10: 724daa33f6SPeter Klausler if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) { 73104f3c18SSlava Zakharin #if HAS_FLOAT80 74*fc97d2e6SPeter Klausler GenerateReal<CppTypeFor<TypeCategory::Real, 10>, 64>(harvest); 754daa33f6SPeter Klausler return; 76e1114045Speter klausler #endif 77e1114045Speter klausler } 784daa33f6SPeter Klausler break; 794daa33f6SPeter Klausler } 8004b18530SPete Steinfeld terminator.Crash( 8104b18530SPete Steinfeld "not yet implemented: intrinsic: REAL(KIND=%d) in RANDOM_NUMBER", kind); 82*fc97d2e6SPeter Klausler } else if (typeCode->first == TypeCategory::Unsigned) { 83*fc97d2e6SPeter Klausler switch (kind) { 84*fc97d2e6SPeter Klausler case 1: 85*fc97d2e6SPeter Klausler GenerateUnsigned<CppTypeFor<TypeCategory::Unsigned, 1>>(harvest); 86*fc97d2e6SPeter Klausler return; 87*fc97d2e6SPeter Klausler case 2: 88*fc97d2e6SPeter Klausler GenerateUnsigned<CppTypeFor<TypeCategory::Unsigned, 2>>(harvest); 89*fc97d2e6SPeter Klausler return; 90*fc97d2e6SPeter Klausler case 4: 91*fc97d2e6SPeter Klausler GenerateUnsigned<CppTypeFor<TypeCategory::Unsigned, 4>>(harvest); 92*fc97d2e6SPeter Klausler return; 93*fc97d2e6SPeter Klausler case 8: 94*fc97d2e6SPeter Klausler GenerateUnsigned<CppTypeFor<TypeCategory::Unsigned, 8>>(harvest); 95*fc97d2e6SPeter Klausler return; 96*fc97d2e6SPeter Klausler #ifdef __SIZEOF_INT128__ 97*fc97d2e6SPeter Klausler case 16: 98*fc97d2e6SPeter Klausler if constexpr (HasCppTypeFor<TypeCategory::Unsigned, 16>) { 99*fc97d2e6SPeter Klausler GenerateUnsigned<CppTypeFor<TypeCategory::Unsigned, 16>>(harvest); 100*fc97d2e6SPeter Klausler return; 101*fc97d2e6SPeter Klausler } 102*fc97d2e6SPeter Klausler break; 103*fc97d2e6SPeter Klausler #endif 104*fc97d2e6SPeter Klausler } 105*fc97d2e6SPeter Klausler terminator.Crash( 106*fc97d2e6SPeter Klausler "not yet implemented: intrinsic: UNSIGNED(KIND=%d) in RANDOM_NUMBER", 107*fc97d2e6SPeter Klausler kind); 108*fc97d2e6SPeter Klausler } 109e1114045Speter klausler } 110e1114045Speter klausler 111e1114045Speter klausler void RTNAME(RandomSeedSize)( 112cc71e694SV Donaldson const Descriptor *size, const char *source, int line) { 113cc71e694SV Donaldson if (!size || !size->raw().base_addr) { 114cc71e694SV Donaldson RTNAME(RandomSeedDefaultPut)(); 115cc71e694SV Donaldson return; 116cc71e694SV Donaldson } 117e1114045Speter klausler Terminator terminator{source, line}; 118cc71e694SV Donaldson auto typeCode{size->type().GetCategoryAndKind()}; 119e1114045Speter klausler RUNTIME_CHECK(terminator, 120cc71e694SV Donaldson size->rank() == 0 && typeCode && 121cc71e694SV Donaldson typeCode->first == TypeCategory::Integer); 12204b18530SPete Steinfeld int sizeArg{typeCode->second}; 12304b18530SPete Steinfeld switch (sizeArg) { 124e1114045Speter klausler case 4: 125cc71e694SV Donaldson *size->OffsetElement<CppTypeFor<TypeCategory::Integer, 4>>() = 1; 126e1114045Speter klausler break; 127e1114045Speter klausler case 8: 128cc71e694SV Donaldson *size->OffsetElement<CppTypeFor<TypeCategory::Integer, 8>>() = 1; 129e1114045Speter klausler break; 130e1114045Speter klausler default: 131d4609ae4SPeter Steinfeld terminator.Crash( 13204b18530SPete Steinfeld "not yet implemented: intrinsic: RANDOM_SEED(SIZE=): size %d\n", 13304b18530SPete Steinfeld sizeArg); 134e1114045Speter klausler } 135e1114045Speter klausler } 136e1114045Speter klausler 137e1114045Speter klausler void RTNAME(RandomSeedPut)( 138cc71e694SV Donaldson const Descriptor *put, const char *source, int line) { 139cc71e694SV Donaldson if (!put || !put->raw().base_addr) { 140cc71e694SV Donaldson RTNAME(RandomSeedDefaultPut)(); 141cc71e694SV Donaldson return; 142cc71e694SV Donaldson } 143e1114045Speter klausler Terminator terminator{source, line}; 144cc71e694SV Donaldson auto typeCode{put->type().GetCategoryAndKind()}; 145e1114045Speter klausler RUNTIME_CHECK(terminator, 146cc71e694SV Donaldson put->rank() == 1 && typeCode && 147cc71e694SV Donaldson typeCode->first == TypeCategory::Integer && 148cc71e694SV Donaldson put->GetDimension(0).Extent() >= 1); 14904b18530SPete Steinfeld int putArg{typeCode->second}; 150e1114045Speter klausler GeneratedWord seed; 15104b18530SPete Steinfeld switch (putArg) { 152e1114045Speter klausler case 4: 153cc71e694SV Donaldson seed = *put->OffsetElement<CppTypeFor<TypeCategory::Integer, 4>>(); 154e1114045Speter klausler break; 155e1114045Speter klausler case 8: 156cc71e694SV Donaldson seed = *put->OffsetElement<CppTypeFor<TypeCategory::Integer, 8>>(); 157e1114045Speter klausler break; 158e1114045Speter klausler default: 15904b18530SPete Steinfeld terminator.Crash( 16004b18530SPete Steinfeld "not yet implemented: intrinsic: RANDOM_SEED(PUT=): put %d\n", putArg); 161e1114045Speter klausler } 162e1114045Speter klausler { 163e1114045Speter klausler CriticalSection critical{lock}; 164e1114045Speter klausler generator.seed(seed); 165ea1a69d6SPeter Klausler nextValue = seed; 166e1114045Speter klausler } 167e1114045Speter klausler } 168e1114045Speter klausler 169e1114045Speter klausler void RTNAME(RandomSeedDefaultPut)() { 170e1114045Speter klausler // TODO: should this be time &/or image dependent? 171e1114045Speter klausler { 172e1114045Speter klausler CriticalSection critical{lock}; 173e1114045Speter klausler generator.seed(0); 174e1114045Speter klausler } 175e1114045Speter klausler } 176e1114045Speter klausler 177e1114045Speter klausler void RTNAME(RandomSeedGet)( 178cc71e694SV Donaldson const Descriptor *get, const char *source, int line) { 179cc71e694SV Donaldson if (!get || !get->raw().base_addr) { 180cc71e694SV Donaldson RTNAME(RandomSeedDefaultPut)(); 181cc71e694SV Donaldson return; 182cc71e694SV Donaldson } 183e1114045Speter klausler Terminator terminator{source, line}; 184cc71e694SV Donaldson auto typeCode{get->type().GetCategoryAndKind()}; 185e1114045Speter klausler RUNTIME_CHECK(terminator, 186cc71e694SV Donaldson get->rank() == 1 && typeCode && 187cc71e694SV Donaldson typeCode->first == TypeCategory::Integer && 188cc71e694SV Donaldson get->GetDimension(0).Extent() >= 1); 18904b18530SPete Steinfeld int getArg{typeCode->second}; 190e1114045Speter klausler GeneratedWord seed; 191e1114045Speter klausler { 192e1114045Speter klausler CriticalSection critical{lock}; 193ea1a69d6SPeter Klausler seed = GetNextValue(); 194ea1a69d6SPeter Klausler nextValue = seed; 195e1114045Speter klausler } 19604b18530SPete Steinfeld switch (getArg) { 197e1114045Speter klausler case 4: 198cc71e694SV Donaldson *get->OffsetElement<CppTypeFor<TypeCategory::Integer, 4>>() = seed; 199e1114045Speter klausler break; 200e1114045Speter klausler case 8: 201cc71e694SV Donaldson *get->OffsetElement<CppTypeFor<TypeCategory::Integer, 8>>() = seed; 202e1114045Speter klausler break; 203e1114045Speter klausler default: 20404b18530SPete Steinfeld terminator.Crash( 20504b18530SPete Steinfeld "not yet implemented: intrinsic: RANDOM_SEED(GET=): get %d\n", getArg); 206e1114045Speter klausler } 207e1114045Speter klausler } 208cc71e694SV Donaldson 209cc71e694SV Donaldson void RTNAME(RandomSeed)(const Descriptor *size, const Descriptor *put, 210cc71e694SV Donaldson const Descriptor *get, const char *source, int line) { 211cc71e694SV Donaldson bool sizePresent = size && size->raw().base_addr; 212cc71e694SV Donaldson bool putPresent = put && put->raw().base_addr; 213cc71e694SV Donaldson bool getPresent = get && get->raw().base_addr; 214cc71e694SV Donaldson if (sizePresent + putPresent + getPresent > 1) 215cc71e694SV Donaldson Terminator{source, line}.Crash( 216cc71e694SV Donaldson "RANDOM_SEED must have either 1 or no arguments"); 217cc71e694SV Donaldson if (sizePresent) 218cc71e694SV Donaldson RTNAME(RandomSeedSize)(size, source, line); 219cc71e694SV Donaldson else if (putPresent) 220cc71e694SV Donaldson RTNAME(RandomSeedPut)(put, source, line); 221cc71e694SV Donaldson else if (getPresent) 222cc71e694SV Donaldson RTNAME(RandomSeedGet)(get, source, line); 223cc71e694SV Donaldson else 224cc71e694SV Donaldson RTNAME(RandomSeedDefaultPut)(); 225cc71e694SV Donaldson } 226cc71e694SV Donaldson 227e1114045Speter klausler } // extern "C" 228e0738cc6SSlava Zakharin } // namespace Fortran::runtime::random 229