WasmMath.inl 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. using namespace Wasm;
  7. template<typename T>
  8. inline T WasmMath::Shl( T aLeft, T aRight )
  9. {
  10. return aLeft << (aRight & (sizeof(T)*8-1));
  11. }
  12. template<typename T>
  13. inline T WasmMath::Shr( T aLeft, T aRight )
  14. {
  15. return aLeft >> (aRight & (sizeof(T)*8-1));
  16. }
  17. template<typename T>
  18. inline T WasmMath::ShrU( T aLeft, T aRight )
  19. {
  20. return aLeft >> (aRight & (sizeof(T)*8-1));
  21. }
  22. template<>
  23. inline int WasmMath::Ctz(int value)
  24. {
  25. DWORD index;
  26. if (_BitScanForward(&index, value))
  27. {
  28. return index;
  29. }
  30. return 32;
  31. }
  32. template<>
  33. inline int64 WasmMath::Ctz(int64 value)
  34. {
  35. DWORD index;
  36. #if TARGET_64
  37. if (_BitScanForward64(&index, value))
  38. {
  39. return index;
  40. }
  41. #else
  42. if (_BitScanForward(&index, (int32)value))
  43. {
  44. return index;
  45. }
  46. if (_BitScanForward(&index, (int32)(value >> 32)))
  47. {
  48. return index + 32;
  49. }
  50. #endif
  51. return 64;
  52. }
  53. template<>
  54. inline int64 WasmMath::Clz(int64 value)
  55. {
  56. DWORD index;
  57. #if TARGET_64
  58. if (_BitScanReverse64(&index, value))
  59. {
  60. return 63 - index;
  61. }
  62. #else
  63. if (_BitScanReverse(&index, (int32)(value >> 32)))
  64. {
  65. return 31 - index;
  66. }
  67. if (_BitScanReverse(&index, (int32)value))
  68. {
  69. return 63 - index;
  70. }
  71. #endif
  72. return 64;
  73. }
  74. template<>
  75. inline int WasmMath::PopCnt(int value)
  76. {
  77. return ::Math::PopCnt32(value);
  78. }
  79. template<>
  80. inline int64 WasmMath::PopCnt(int64 value)
  81. {
  82. uint64 v = (uint64)value;
  83. // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
  84. v = v - ((v >> 1) & 0x5555555555555555LL);
  85. v = (v & 0x3333333333333333LL) + ((v >> 2) & 0x3333333333333333LL);
  86. v = (v + (v >> 4)) & 0x0f0f0f0f0f0f0f0f;
  87. v = (uint64)(v * 0x0101010101010101LL) >> (sizeof(uint64) - 1) * CHAR_BIT;
  88. return (int64)v;
  89. }
  90. template<typename T>
  91. inline int WasmMath::Eqz(T value)
  92. {
  93. return value == 0;
  94. }
  95. template<>
  96. inline double WasmMath::Copysign(double aLeft, double aRight)
  97. {
  98. uint64 aLeftI64 = *(uint64*)(&aLeft);
  99. uint64 aRightI64 = *(uint64*)(&aRight);
  100. uint64 res = ((aLeftI64 & 0x7fffffffffffffffull) | (aRightI64 & 0x8000000000000000ull));
  101. return *(double*)(&res);
  102. }
  103. template<>
  104. inline float WasmMath::Copysign(float aLeft, float aRight)
  105. {
  106. uint32 aLeftI32 = *(uint32*)(&aLeft);
  107. uint32 aRightI32 = *(uint32*)(&aRight);
  108. uint32 res = ((aLeftI32 & 0x7fffffffu) | (aRightI32 & 0x80000000u));
  109. return *(float*)(&res);
  110. }
  111. template <typename T> bool WasmMath::LessThan(T aLeft, T aRight)
  112. {
  113. return aLeft < aRight;
  114. }
  115. template <typename T> bool WasmMath::LessOrEqual(T aLeft, T aRight)
  116. {
  117. return aLeft <= aRight;
  118. }
  119. template <
  120. typename SrcType,
  121. typename DstType,
  122. typename ReinterpretType,
  123. ReinterpretType Max,
  124. ReinterpretType NegZero,
  125. ReinterpretType NegOne,
  126. WasmMath::CmpPtr<ReinterpretType> MaxCmp,
  127. WasmMath::CmpPtr<ReinterpretType> NegOneCmp,
  128. bool Saturate,
  129. DstType MinResult,
  130. DstType MaxResult>
  131. DstType WasmMath::ConvertFloatToInt(SrcType srcVal, _In_ Js::ScriptContext * scriptContext)
  132. {
  133. CompileAssert(sizeof(SrcType) == sizeof(ReinterpretType));
  134. if (IsNaN(srcVal))
  135. {
  136. if (!Saturate)
  137. {
  138. Js::JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, VBSERR_Overflow);
  139. }
  140. return 0;
  141. }
  142. // TODO NumberUtilities::ToSpecial
  143. ReinterpretType val = *reinterpret_cast<ReinterpretType*> (&srcVal);
  144. if (MaxCmp(val, Max) || (val >= NegZero && NegOneCmp(val, NegOne)))
  145. {
  146. return static_cast<DstType>(srcVal);
  147. }
  148. if (!Saturate)
  149. {
  150. Js::JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, VBSERR_Overflow);
  151. }
  152. return (srcVal < 0) ? MinResult : MaxResult;
  153. }
  154. template <typename STYPE> bool WasmMath::IsNaN(STYPE src)
  155. {
  156. return src != src;
  157. }
  158. template<typename T>
  159. inline T WasmMath::Trunc(T value)
  160. {
  161. if (value == 0.0)
  162. {
  163. return value;
  164. }
  165. else
  166. {
  167. T result;
  168. if (value < 0.0)
  169. {
  170. result = ceil(value);
  171. }
  172. else
  173. {
  174. result = floor(value);
  175. }
  176. // TODO: Propagating NaN sign for now awaiting consensus on semantics
  177. return result;
  178. }
  179. }
  180. template<typename T>
  181. inline T WasmMath::Nearest(T value)
  182. {
  183. if (value == 0.0)
  184. {
  185. return value;
  186. }
  187. else
  188. {
  189. T result;
  190. T u = ceil(value);
  191. T d = floor(value);
  192. T um = fabs(value - u);
  193. T dm = fabs(value - d);
  194. if (um < dm || (um == dm && floor(u / 2) == u / 2))
  195. {
  196. result = u;
  197. }
  198. else
  199. {
  200. result = d;
  201. }
  202. // TODO: Propagating NaN sign for now awaiting consensus on semantics
  203. return result;
  204. }
  205. }
  206. template<>
  207. inline int WasmMath::Rol(int aLeft, int aRight)
  208. {
  209. return _rotl(aLeft, aRight);
  210. }
  211. template<>
  212. inline int64 WasmMath::Rol(int64 aLeft, int64 aRight)
  213. {
  214. return _rotl64(aLeft, (int)aRight);
  215. }
  216. template<>
  217. inline int WasmMath::Ror(int aLeft, int aRight)
  218. {
  219. return _rotr(aLeft, aRight);
  220. }
  221. template<>
  222. inline int64 WasmMath::Ror(int64 aLeft, int64 aRight)
  223. {
  224. return _rotr64(aLeft, (int)aRight);
  225. }
  226. template<typename To, typename From>
  227. To WasmMath::SignExtend(To value)
  228. {
  229. return static_cast<To>(static_cast<From>(value));
  230. }
  231. template <bool Saturate>
  232. int32 WasmMath::F32ToI32(float src, _In_ Js::ScriptContext* scriptContext)
  233. {
  234. return WasmMath::ConvertFloatToInt<
  235. float, // SrcType
  236. int32, // DstType
  237. uint32, // ReinterpretType
  238. Js::NumberConstants::k_Float32TwoTo31,
  239. Js::NumberConstants::k_Float32NegZero,
  240. Js::NumberConstants::k_Float32NegTwoTo31,
  241. &WasmMath::LessThan<uint32>,
  242. &WasmMath::LessOrEqual<uint32>,
  243. Saturate,
  244. INT32_MIN,
  245. INT32_MAX>(
  246. src,
  247. scriptContext);
  248. }
  249. template <bool Saturate>
  250. uint32 WasmMath::F32ToU32(float src, _In_ Js::ScriptContext* scriptContext)
  251. {
  252. return WasmMath::ConvertFloatToInt<
  253. float, // SrcType
  254. uint32, // DstType
  255. uint32, // ReinterpretType
  256. Js::NumberConstants::k_Float32TwoTo32,
  257. Js::NumberConstants::k_Float32NegZero,
  258. Js::NumberConstants::k_Float32NegOne,
  259. &WasmMath::LessThan<uint32>,
  260. &WasmMath::LessThan<uint32>,
  261. Saturate,
  262. 0,
  263. UINT32_MAX>(
  264. src,
  265. scriptContext);
  266. }
  267. template <bool Saturate>
  268. int32 WasmMath::F64ToI32(double src, _In_ Js::ScriptContext* scriptContext)
  269. {
  270. return WasmMath::ConvertFloatToInt<
  271. double, // SrcType
  272. int32, // DstType
  273. uint64, // ReinterpretType
  274. Js::NumberConstants::k_TwoTo31,
  275. Js::NumberConstants::k_NegZero,
  276. Js::NumberConstants::k_NegTwoTo31,
  277. &WasmMath::LessOrEqual<uint64>,
  278. &WasmMath::LessOrEqual<uint64>,
  279. Saturate,
  280. INT32_MIN,
  281. INT32_MAX>(
  282. src,
  283. scriptContext);
  284. }
  285. template <bool Saturate>
  286. uint32 WasmMath::F64ToU32(double src, _In_ Js::ScriptContext* scriptContext)
  287. {
  288. return WasmMath::ConvertFloatToInt<
  289. double, // SrcType
  290. uint32, // DstType
  291. uint64, // ReinterpretType
  292. Js::NumberConstants::k_TwoTo32,
  293. Js::NumberConstants::k_NegZero,
  294. Js::NumberConstants::k_NegOne,
  295. &WasmMath::LessOrEqual<uint64>,
  296. &WasmMath::LessThan<uint64>,
  297. Saturate,
  298. 0,
  299. UINT32_MAX>(
  300. src,
  301. scriptContext);
  302. }
  303. template <bool Saturate>
  304. int64 WasmMath::F32ToI64(float src, _In_ Js::ScriptContext* scriptContext)
  305. {
  306. return WasmMath::ConvertFloatToInt<
  307. float, // SrcType
  308. int64, // DstType
  309. uint32, // ReinterpretType
  310. Js::NumberConstants::k_Float32TwoTo63,
  311. Js::NumberConstants::k_Float32NegZero,
  312. Js::NumberConstants::k_Float32NegTwoTo63,
  313. &WasmMath::LessThan<uint32>,
  314. &WasmMath::LessOrEqual<uint32>,
  315. Saturate,
  316. INT64_MIN,
  317. INT64_MAX>(
  318. src,
  319. scriptContext);
  320. }
  321. template <bool Saturate>
  322. uint64 WasmMath::F32ToU64(float src, _In_ Js::ScriptContext* scriptContext)
  323. {
  324. return WasmMath::ConvertFloatToInt<
  325. float, // SrcType
  326. uint64, // DstType
  327. uint32, // ReinterpretType
  328. Js::NumberConstants::k_Float32TwoTo64,
  329. Js::NumberConstants::k_Float32NegZero,
  330. Js::NumberConstants::k_Float32NegOne,
  331. &WasmMath::LessThan<uint32>,
  332. &WasmMath::LessThan<uint32>,
  333. Saturate,
  334. 0,
  335. UINT64_MAX>(
  336. src,
  337. scriptContext);
  338. }
  339. template <bool Saturate>
  340. int64 WasmMath::F64ToI64(double src, _In_ Js::ScriptContext* scriptContext)
  341. {
  342. return WasmMath::ConvertFloatToInt<
  343. double, // SrcType
  344. int64, // DstType
  345. uint64, // ReinterpretType
  346. Js::NumberConstants::k_TwoTo63,
  347. Js::NumberConstants::k_NegZero,
  348. Js::NumberConstants::k_NegTwoTo63,
  349. &WasmMath::LessThan<uint64>,
  350. &WasmMath::LessOrEqual<uint64>,
  351. Saturate,
  352. INT64_MIN,
  353. INT64_MAX>(
  354. src,
  355. scriptContext);
  356. }
  357. template <bool Saturate>
  358. uint64 WasmMath::F64ToU64(double src, _In_ Js::ScriptContext* scriptContext)
  359. {
  360. return WasmMath::ConvertFloatToInt<
  361. double, // SrcType
  362. uint64, // DstType
  363. uint64, // ReinterpretType
  364. Js::NumberConstants::k_TwoTo64,
  365. Js::NumberConstants::k_NegZero,
  366. Js::NumberConstants::k_NegOne,
  367. &WasmMath::LessThan<uint64>,
  368. &WasmMath::LessThan<uint64>,
  369. Saturate,
  370. 0,
  371. UINT64_MAX>(
  372. src,
  373. scriptContext);
  374. }