mirror of
https://github.com/wownero/RandomX.git
synced 2026-10-17 23:41:39 +02:00
Interpreter with bytecode
Fixed some undefined behavior with signed types Fixed different results on big endian systems Removed unused code files Restored FNEG_R instructions Updated documentation
This commit is contained in:
+49
-130
@@ -18,12 +18,14 @@ along with RandomX. If not, see<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//#define DEBUG
|
||||
#include "intrinPortable.h"
|
||||
#include "blake2/endian.h"
|
||||
#pragma STDC FENV_ACCESS on
|
||||
#include <cfenv>
|
||||
#include <cmath>
|
||||
#ifdef DEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
#include "common.hpp"
|
||||
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
typedef unsigned __int128 uint128_t;
|
||||
@@ -136,18 +138,18 @@ static inline int32_t safeSub(int32_t a, int32_t b) {
|
||||
|
||||
#if defined(__has_builtin)
|
||||
#if __has_builtin(__builtin_sub_overflow)
|
||||
static inline bool subOverflow__(int32_t a, int32_t b) {
|
||||
static inline bool subOverflow__(uint32_t a, uint32_t b) {
|
||||
int32_t temp;
|
||||
return __builtin_sub_overflow(a, b, &temp);
|
||||
return __builtin_sub_overflow(unsigned32ToSigned2sCompl(a), unsigned32ToSigned2sCompl(b), &temp);
|
||||
}
|
||||
#define HAVE_SUB_OVERFLOW
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SUB_OVERFLOW
|
||||
static inline bool subOverflow__(int32_t a, int32_t b) {
|
||||
auto c = safeSub(a, b);
|
||||
return (c < a) != (b > 0);
|
||||
static inline bool subOverflow__(uint32_t a, uint32_t b) {
|
||||
auto c = unsigned32ToSigned2sCompl(a - b);
|
||||
return (c < unsigned32ToSigned2sCompl(a)) != (unsigned32ToSigned2sCompl(b) > 0);
|
||||
}
|
||||
#define HAVE_SUB_OVERFLOW
|
||||
#endif
|
||||
@@ -166,40 +168,44 @@ static inline double FlushNaN(double x) {
|
||||
|
||||
void setRoundMode(uint32_t rcflag) {
|
||||
switch (rcflag & 3) {
|
||||
case RoundDown:
|
||||
setRoundMode__(FE_DOWNWARD);
|
||||
break;
|
||||
case RoundUp:
|
||||
setRoundMode__(FE_UPWARD);
|
||||
break;
|
||||
case RoundToZero:
|
||||
setRoundMode__(FE_TOWARDZERO);
|
||||
break;
|
||||
default:
|
||||
setRoundMode__(FE_TONEAREST);
|
||||
break;
|
||||
case RoundDown:
|
||||
setRoundMode__(FE_DOWNWARD);
|
||||
break;
|
||||
case RoundUp:
|
||||
setRoundMode__(FE_UPWARD);
|
||||
break;
|
||||
case RoundToZero:
|
||||
setRoundMode__(FE_TOWARDZERO);
|
||||
break;
|
||||
case RoundToNearest:
|
||||
setRoundMode__(FE_TONEAREST);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
bool condition(uint32_t type, int32_t value, int32_t imm32) {
|
||||
bool condition(uint32_t type, uint32_t value, uint32_t imm32) {
|
||||
switch (type & 7)
|
||||
{
|
||||
case 0:
|
||||
return (uint32_t)value <= (uint32_t)imm32;
|
||||
case 1:
|
||||
return (uint32_t)value > (uint32_t)imm32;
|
||||
case 2:
|
||||
return safeSub(value, imm32) < 0;
|
||||
case 3:
|
||||
return safeSub(value, imm32) >= 0;
|
||||
case 4:
|
||||
return subOverflow__(value, imm32);
|
||||
case 5:
|
||||
return !subOverflow__(value, imm32);
|
||||
case 6:
|
||||
return value < imm32;
|
||||
case 7:
|
||||
return value >= imm32;
|
||||
case 0:
|
||||
return value <= imm32;
|
||||
case 1:
|
||||
return value > imm32;
|
||||
case 2:
|
||||
return unsigned32ToSigned2sCompl(value - imm32) < 0;
|
||||
case 3:
|
||||
return unsigned32ToSigned2sCompl(value - imm32) >= 0;
|
||||
case 4:
|
||||
return subOverflow__(value, imm32);
|
||||
case 5:
|
||||
return !subOverflow__(value, imm32);
|
||||
case 6:
|
||||
return unsigned32ToSigned2sCompl(value) < unsigned32ToSigned2sCompl(imm32);
|
||||
case 7:
|
||||
return unsigned32ToSigned2sCompl(value) >= unsigned32ToSigned2sCompl(imm32);
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,100 +217,13 @@ void initFpu() {
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace RandomX {
|
||||
union double_ser_t {
|
||||
double f;
|
||||
uint64_t i;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
/*void DIV_64(convertible_t& a, convertible_t& b, convertible_t& c) {
|
||||
c.u64 = a.u64 / (b.u32 != 0 ? b.u32 : 1U);
|
||||
}
|
||||
|
||||
void IDIV_64(convertible_t& a, convertible_t& b, convertible_t& c) {
|
||||
if (a.i64 == INT64_MIN && b.i32 == -1)
|
||||
c.i64 = INT64_MIN;
|
||||
else
|
||||
c.i64 = a.i64 / (b.i32 != 0 ? b.i32 : 1);
|
||||
}
|
||||
|
||||
void FADD(convertible_t& a, fpu_reg_t& b, fpu_reg_t& c) {
|
||||
#ifdef __SSE2__
|
||||
__m128i ai = _mm_loadl_epi64((const __m128i*)&a);
|
||||
__m128d ad = _mm_cvtepi32_pd(ai);
|
||||
__m128d bd = _mm_load_pd(&b.lo.f64);
|
||||
__m128d cd = _mm_add_pd(ad, bd);
|
||||
_mm_store_pd(&c.lo.f64, cd);
|
||||
#else
|
||||
double alo = (double)a.i32lo;
|
||||
double ahi = (double)a.i32hi;
|
||||
c.lo.f64 = alo + b.lo.f64;
|
||||
c.hi.f64 = ahi + b.hi.f64;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FSUB(convertible_t& a, fpu_reg_t& b, fpu_reg_t& c) {
|
||||
#ifdef __SSE2__
|
||||
__m128i ai = _mm_loadl_epi64((const __m128i*)&a);
|
||||
__m128d ad = _mm_cvtepi32_pd(ai);
|
||||
__m128d bd = _mm_load_pd(&b.lo.f64);
|
||||
__m128d cd = _mm_sub_pd(ad, bd);
|
||||
_mm_store_pd(&c.lo.f64, cd);
|
||||
#else
|
||||
double alo = (double)a.i32lo;
|
||||
double ahi = (double)a.i32hi;
|
||||
c.lo.f64 = alo - b.lo.f64;
|
||||
c.hi.f64 = ahi - b.hi.f64;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FMUL(convertible_t& a, fpu_reg_t& b, fpu_reg_t& c) {
|
||||
#ifdef __SSE2__
|
||||
__m128i ai = _mm_loadl_epi64((const __m128i*)&a);
|
||||
__m128d ad = _mm_cvtepi32_pd(ai);
|
||||
__m128d bd = _mm_load_pd(&b.lo.f64);
|
||||
__m128d cd = _mm_mul_pd(ad, bd);
|
||||
__m128d mask = _mm_cmpeq_pd(cd, cd);
|
||||
cd = _mm_and_pd(cd, mask);
|
||||
_mm_store_pd(&c.lo.f64, cd);
|
||||
#else
|
||||
double alo = (double)a.i32lo;
|
||||
double ahi = (double)a.i32hi;
|
||||
c.lo.f64 = FlushNaN(alo * b.lo.f64);
|
||||
c.hi.f64 = FlushNaN(ahi * b.hi.f64);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FDIV(convertible_t& a, fpu_reg_t& b, fpu_reg_t& c) {
|
||||
#ifdef __SSE2__
|
||||
__m128i ai = _mm_loadl_epi64((const __m128i*)&a);
|
||||
__m128d ad = _mm_cvtepi32_pd(ai);
|
||||
__m128d bd = _mm_load_pd(&b.lo.f64);
|
||||
__m128d cd = _mm_div_pd(ad, bd);
|
||||
__m128d mask = _mm_cmpeq_pd(cd, cd);
|
||||
cd = _mm_and_pd(cd, mask);
|
||||
_mm_store_pd(&c.lo.f64, cd);
|
||||
#else
|
||||
double alo = (double)a.i32lo;
|
||||
double ahi = (double)a.i32hi;
|
||||
c.lo.f64 = FlushDenormalNaN(alo / b.lo.f64);
|
||||
c.hi.f64 = FlushDenormalNaN(ahi / b.hi.f64);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FSQRT(convertible_t& a, fpu_reg_t& b, fpu_reg_t& c) {
|
||||
#ifdef __SSE2__
|
||||
__m128i ai = _mm_loadl_epi64((const __m128i*)&a);
|
||||
__m128d ad = _mm_cvtepi32_pd(ai);
|
||||
const __m128d absmask = _mm_castsi128_pd(_mm_set1_epi64x(~(1LL << 63)));
|
||||
ad = _mm_and_pd(ad, absmask);
|
||||
__m128d cd = _mm_sqrt_pd(ad);
|
||||
_mm_store_pd(&c.lo.f64, cd);
|
||||
#else
|
||||
double alo = (double)a.i32lo;
|
||||
double ahi = (double)a.i32hi;
|
||||
c.lo.f64 = sqrt(std::abs(alo));
|
||||
c.hi.f64 = sqrt(std::abs(ahi));
|
||||
#endif
|
||||
}*/
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
double loadDoublePortable(const void* addr) {
|
||||
double_ser_t ds;
|
||||
ds.i = load64(addr);
|
||||
return ds.f;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user