InstructionsPortable.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. //RandomX ALU + FPU test
  2. //https://github.com/tevador/RandomX
  3. //License: GPL v3
  4. #include "Instructions.h"
  5. #include <cfenv>
  6. #include <cmath>
  7. #if defined(__SIZEOF_INT128__)
  8. typedef unsigned __int128 uint128_t;
  9. typedef __int128 int128_t;
  10. static inline uint64_t __umulhi64(uint64_t a, uint64_t b) {
  11. return ((uint128_t)a * b) >> 64;
  12. }
  13. static inline uint64_t __imulhi64(int64_t a, int64_t b) {
  14. return ((int128_t)a * b) >> 64;
  15. }
  16. #define umulhi64 __umulhi64
  17. #define imulhi64 __imulhi64
  18. #endif
  19. #if defined(_MSC_VER)
  20. #include <intrin.h>
  21. #include <stdlib.h>
  22. #define ror64 _rotr64
  23. #define rol64 _rotl64
  24. #ifdef __MACHINEARM64_X64
  25. #define umulhi64 __umulh
  26. #endif
  27. #ifdef __MACHINEX64
  28. static inline uint64_t __imulhi64(int64_t a, int64_t b) {
  29. int64_t hi;
  30. _mul128(a, b, &hi);
  31. return hi;
  32. }
  33. #define imulhi64 __imulhi64
  34. #endif
  35. #ifdef __MACHINEX86_X64
  36. #define sar64 __ll_rshift
  37. #endif
  38. #endif
  39. #ifndef ror64
  40. static inline uint64_t __ror64(uint64_t a, int b) {
  41. return (a >> b) | (a << (64 - b));
  42. }
  43. #define ror64 __ror64
  44. #endif
  45. #ifndef rol64
  46. static inline uint64_t __rol64(uint64_t a, int b) {
  47. return (a << b) | (a >> (64 - b));
  48. }
  49. #define rol64 __rol64
  50. #endif
  51. #ifndef sar64
  52. #include <type_traits>
  53. constexpr int64_t builtintShr64(int64_t value, int shift) noexcept {
  54. return value >> shift;
  55. }
  56. struct usesArithmeticShift : std::integral_constant<bool, builtintShr64(-1LL, 1) == -1LL> {
  57. };
  58. static inline int64_t __sar64(int64_t a, int b) {
  59. return usesArithmeticShift::value ? builtintShr64(a, b) : (a < 0 ? ~(~a >> b) : a >> b);
  60. }
  61. #define sar64 __sar64
  62. #endif
  63. #ifndef umulhi64
  64. #define LO(x) ((x)&0xffffffff)
  65. #define HI(x) ((x)>>32)
  66. static inline uint64_t __umulhi64(uint64_t a, uint64_t b) {
  67. uint64_t ah = HI(a), al = LO(a);
  68. uint64_t bh = HI(b), bl = LO(b);
  69. uint64_t x00 = al * bl;
  70. uint64_t x01 = al * bh;
  71. uint64_t x10 = ah * bl;
  72. uint64_t x11 = ah * bh;
  73. uint64_t m1 = LO(x10) + LO(x01) + HI(x00);
  74. uint64_t m2 = HI(x10) + HI(x01) + LO(x11) + HI(m1);
  75. uint64_t m3 = HI(x11) + HI(m2);
  76. return (m3 << 32) + LO(m2);
  77. }
  78. #define umulhi64 __umulhi64
  79. #endif
  80. #ifndef imulhi64
  81. static inline int64_t __imulhi64(int64_t a, int64_t b) {
  82. int64_t hi = umulhi64(a, b);
  83. if (a < 0LL) hi -= b;
  84. if (b < 0LL) hi -= a;
  85. return hi;
  86. }
  87. #define imulhi64 __imulhi64
  88. #endif
  89. static double FlushDenormal(double x) {
  90. if (std::fpclassify(x) == FP_SUBNORMAL) {
  91. return 0;
  92. }
  93. return x;
  94. }
  95. #define FTZ(x) FlushDenormal(x)
  96. namespace RandomX {
  97. extern "C" {
  98. void ADD_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  99. c.u64 = a.u64 + b.u64;
  100. }
  101. void ADD_32(convertible_t& a, convertible_t& b, convertible_t& c) {
  102. c.u64 = a.u32 + b.u32;
  103. }
  104. void SUB_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  105. c.u64 = a.u64 - b.u64;
  106. }
  107. void SUB_32(convertible_t& a, convertible_t& b, convertible_t& c) {
  108. c.u64 = a.u32 - b.u32;
  109. }
  110. void MUL_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  111. c.u64 = a.u64 * b.u64;
  112. }
  113. void MULH_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  114. c.u64 = umulhi64(a.u64, b.u64);
  115. }
  116. void MUL_32(convertible_t& a, convertible_t& b, convertible_t& c) {
  117. c.u64 = (uint64_t)a.u32 * b.u32;
  118. }
  119. void IMUL_32(convertible_t& a, convertible_t& b, convertible_t& c) {
  120. c.i64 = (int64_t)a.i32 * b.i32;
  121. }
  122. void IMULH_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  123. c.i64 = imulhi64(a.i64, b.i64);
  124. }
  125. void DIV_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  126. c.u64 = a.u64 / (b.u32 != 0 ? b.u32 : 1U);
  127. }
  128. void IDIV_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  129. if (a.i64 == INT64_MIN && b.i64 == -1)
  130. c.i64 = INT64_MIN;
  131. else
  132. c.i64 = a.i64 / (b.i32 != 0 ? b.i32 : 1);
  133. }
  134. void AND_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  135. c.u64 = a.u64 & b.u64;
  136. }
  137. void AND_32(convertible_t& a, convertible_t& b, convertible_t& c) {
  138. c.u64 = a.u32 & b.u32;
  139. }
  140. void OR_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  141. c.u64 = a.u64 | b.u64;
  142. }
  143. void OR_32(convertible_t& a, convertible_t& b, convertible_t& c) {
  144. c.u64 = a.u32 | b.u32;
  145. }
  146. void XOR_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  147. c.u64 = a.u64 ^ b.u64;
  148. }
  149. void XOR_32(convertible_t& a, convertible_t& b, convertible_t& c) {
  150. c.u64 = a.u32 ^ b.u32;
  151. }
  152. void SHL_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  153. c.u64 = a.u64 << (b.u64 & 63);
  154. }
  155. void SHR_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  156. c.u64 = a.u64 >> (b.u64 & 63);
  157. }
  158. void SAR_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  159. c.u64 = sar64(a.i64, b.u64 & 63);
  160. }
  161. void ROL_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  162. c.u64 = rol64(a.u64, (b.u64 & 63));
  163. }
  164. void ROR_64(convertible_t& a, convertible_t& b, convertible_t& c) {
  165. c.u64 = ror64(a.u64, (b.u64 & 63));
  166. }
  167. void FPINIT() {
  168. fesetround(FE_TONEAREST);
  169. }
  170. void FADD_64(convertible_t& a, double b, convertible_t& c) {
  171. c.f64 = FTZ((double)a.i64 + b);
  172. }
  173. void FSUB_64(convertible_t& a, double b, convertible_t& c) {
  174. c.f64 = FTZ((double)a.i64 - b);
  175. }
  176. void FMUL_64(convertible_t& a, double b, convertible_t& c) {
  177. c.f64 = FTZ((double)a.i64 * b);
  178. }
  179. void FDIV_64(convertible_t& a, double b, convertible_t& c) {
  180. c.f64 = FTZ((double)a.i64 / b);
  181. }
  182. void FABSQRT(convertible_t& a, convertible_t& b, convertible_t& c) {
  183. double d = fabs((double)a.i64);
  184. c.f64 = FTZ(sqrt(d));
  185. }
  186. void FROUND(convertible_t& a, convertible_t& b, convertible_t& c) {
  187. c.f64 = (double)a.i64;
  188. switch (a.u64 & 3) {
  189. case RoundDown:
  190. fesetround(FE_DOWNWARD);
  191. break;
  192. case RoundUp:
  193. fesetround(FE_UPWARD);
  194. break;
  195. case RoundToZero:
  196. fesetround(FE_TOWARDZERO);
  197. break;
  198. default:
  199. fesetround(FE_TONEAREST);
  200. break;
  201. }
  202. }
  203. }
  204. }