InstructionsPortable.cpp 5.8 KB

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