diff --git a/src/instructions_portable.cpp b/src/instructions_portable.cpp index d1253d8..d746727 100644 --- a/src/instructions_portable.cpp +++ b/src/instructions_portable.cpp @@ -157,6 +157,21 @@ void rx_set_rounding_mode(uint32_t mode) { } } +uint32_t rx_get_rounding_mode() { + switch (fegetround()) { + case FE_DOWNWARD: + return RoundDown; + case FE_UPWARD: + return RoundUp; + case FE_TOWARDZERO: + return RoundToZero; + case FE_TONEAREST: + return RoundToNearest; + default: + UNREACHABLE; + } +} + #endif #ifdef RANDOMX_USE_X87 diff --git a/src/intrin_portable.h b/src/intrin_portable.h index c9d4475..05f6cd3 100644 --- a/src/intrin_portable.h +++ b/src/intrin_portable.h @@ -173,6 +173,10 @@ FORCE_INLINE void rx_set_rounding_mode(uint32_t mode) { _mm_setcsr(rx_mxcsr_default | (mode << 13)); } +FORCE_INLINE uint32_t rx_get_rounding_mode() { + return (_mm_getcsr() >> 13) & 3; +} + #elif defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__) //sadly only POWER7 and newer will be able to use SIMD acceleration. Earlier processors cant use doubles or 64 bit integers with SIMD #include #include @@ -736,6 +740,8 @@ void rx_reset_float_state(); void rx_set_rounding_mode(uint32_t mode); +uint32_t rx_get_rounding_mode(); + #endif double loadDoublePortable(const void* addr); diff --git a/src/randomx.cpp b/src/randomx.cpp index 31289ff..75dfdfe 100644 --- a/src/randomx.cpp +++ b/src/randomx.cpp @@ -36,6 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "cpu.hpp" #include #include +#include extern "C" { @@ -349,6 +350,8 @@ extern "C" { assert(machine != nullptr); assert(inputSize == 0 || input != nullptr); assert(output != nullptr); + fenv_t fpstate; + fegetenv(&fpstate); alignas(16) uint64_t tempHash[8]; int blakeResult = blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0); assert(blakeResult == 0); @@ -361,6 +364,7 @@ extern "C" { } machine->run(&tempHash); machine->getFinalResult(output, RANDOMX_HASH_SIZE); + fesetenv(&fpstate); } void randomx_calculate_hash_first(randomx_vm* machine, const void* input, size_t inputSize) { diff --git a/src/randomx.h b/src/randomx.h index 48aaf8e..64d1806 100644 --- a/src/randomx.h +++ b/src/randomx.h @@ -246,6 +246,8 @@ RANDOMX_EXPORT void randomx_calculate_hash(randomx_vm *machine, const void *inpu * and begin the calculation of the next hash. * randomx_calculate_hash_last will output the hash value of the previous input. * + * WARNING: These functions may alter the floating point rounding mode of the calling thread. + * * @param machine is a pointer to a randomx_vm structure. Must not be NULL. * @param input is a pointer to memory to be hashed. Must not be NULL. * @param inputSize is the number of bytes to be hashed. diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp index b425f19..75daaba 100644 --- a/src/tests/tests.cpp +++ b/src/tests/tests.cpp @@ -1051,6 +1051,10 @@ int main() { assert(cacheMemory[33554431] == 0x1f47f056d05cd99b); }); + if (cache != nullptr) + randomx_release_cache(cache); + cache = randomx_alloc_cache(RANDOMX_FLAG_DEFAULT); + runTest("Hash batch test", RANDOMX_HAVE_COMPILER && stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), []() { char hash1[RANDOMX_HASH_SIZE]; char hash2[RANDOMX_HASH_SIZE]; @@ -1070,6 +1074,14 @@ int main() { assert(equalsHex(hash3, "c36d4ed4191e617309867ed66a443be4075014e2b061bcdaf9ce7b721d2b77a8")); }); + runTest("Preserve rounding mode", RANDOMX_FREQ_CFROUND > 0, []() { + rx_set_rounding_mode(RoundToNearest); + char hash[RANDOMX_HASH_SIZE]; + calcStringHash("test key 000", "Lorem ipsum dolor sit amet", &hash); + assert(equalsHex(hash, "300a0adb47603dedb42228ccb2b211104f4da45af709cd7547cd049e9489c969")); + assert(rx_get_rounding_mode() == RoundToNearest); + }); + randomx_destroy_vm(vm); vm = nullptr;