WasmMath.inl 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  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. ReinterpretType val = *reinterpret_cast<ReinterpretType*> (&srcVal);
  143. if (MaxCmp(val, Max) || (val >= NegZero && NegOneCmp(val, NegOne)))
  144. {
  145. return static_cast<DstType>(srcVal);
  146. }
  147. if (!Saturate)
  148. {
  149. Js::JavascriptError::ThrowWebAssemblyRuntimeError(scriptContext, VBSERR_Overflow);
  150. }
  151. return (srcVal < 0) ? MinResult : MaxResult;
  152. }
  153. template <typename STYPE> bool WasmMath::IsNaN(STYPE src)
  154. {
  155. return src != src;
  156. }
  157. template<typename T>
  158. inline T WasmMath::Trunc(T value)
  159. {
  160. if (value == 0.0)
  161. {
  162. return value;
  163. }
  164. else
  165. {
  166. T result;
  167. if (value < 0.0)
  168. {
  169. result = ceil(value);
  170. }
  171. else
  172. {
  173. result = floor(value);
  174. }
  175. // TODO: Propagating NaN sign for now awaiting consensus on semantics
  176. return result;
  177. }
  178. }
  179. template<typename T>
  180. inline T WasmMath::Nearest(T value)
  181. {
  182. if (value == 0.0)
  183. {
  184. return value;
  185. }
  186. else
  187. {
  188. T result;
  189. T u = ceil(value);
  190. T d = floor(value);
  191. T um = fabs(value - u);
  192. T dm = fabs(value - d);
  193. if (um < dm || (um == dm && floor(u / 2) == u / 2))
  194. {
  195. result = u;
  196. }
  197. else
  198. {
  199. result = d;
  200. }
  201. // TODO: Propagating NaN sign for now awaiting consensus on semantics
  202. return result;
  203. }
  204. }
  205. template<>
  206. inline int WasmMath::Rol(int aLeft, int aRight)
  207. {
  208. return _rotl(aLeft, aRight);
  209. }
  210. template<>
  211. inline int64 WasmMath::Rol(int64 aLeft, int64 aRight)
  212. {
  213. return _rotl64(aLeft, (int)aRight);
  214. }
  215. template<>
  216. inline int WasmMath::Ror(int aLeft, int aRight)
  217. {
  218. return _rotr(aLeft, aRight);
  219. }
  220. template<>
  221. inline int64 WasmMath::Ror(int64 aLeft, int64 aRight)
  222. {
  223. return _rotr64(aLeft, (int)aRight);
  224. }
  225. template<typename To, typename From>
  226. To WasmMath::SignExtend(To value)
  227. {
  228. return static_cast<To>(static_cast<From>(value));
  229. }
  230. template <bool Saturate>
  231. int32 WasmMath::F32ToI32(float src, _In_ Js::ScriptContext* scriptContext)
  232. {
  233. return WasmMath::ConvertFloatToInt<
  234. float, // SrcType
  235. int32, // DstType
  236. uint32, // ReinterpretType
  237. Js::NumberConstants::k_Float32TwoTo31,
  238. Js::NumberConstants::k_Float32NegZero,
  239. Js::NumberConstants::k_Float32NegTwoTo31,
  240. &WasmMath::LessThan<uint32>,
  241. &WasmMath::LessOrEqual<uint32>,
  242. Saturate,
  243. INT32_MIN,
  244. INT32_MAX>(
  245. src,
  246. scriptContext);
  247. }
  248. template <bool Saturate>
  249. uint32 WasmMath::F32ToU32(float src, _In_ Js::ScriptContext* scriptContext)
  250. {
  251. return WasmMath::ConvertFloatToInt<
  252. float, // SrcType
  253. uint32, // DstType
  254. uint32, // ReinterpretType
  255. Js::NumberConstants::k_Float32TwoTo32,
  256. Js::NumberConstants::k_Float32NegZero,
  257. Js::NumberConstants::k_Float32NegOne,
  258. &WasmMath::LessThan<uint32>,
  259. &WasmMath::LessThan<uint32>,
  260. Saturate,
  261. 0,
  262. UINT32_MAX>(
  263. src,
  264. scriptContext);
  265. }
  266. template <bool Saturate>
  267. int32 WasmMath::F64ToI32(double src, _In_ Js::ScriptContext* scriptContext)
  268. {
  269. return WasmMath::ConvertFloatToInt<
  270. double, // SrcType
  271. int32, // DstType
  272. uint64, // ReinterpretType
  273. Js::NumberConstants::k_TwoTo31,
  274. Js::NumberConstants::k_NegZero,
  275. Js::NumberConstants::k_NegTwoTo31,
  276. &WasmMath::LessOrEqual<uint64>,
  277. &WasmMath::LessOrEqual<uint64>,
  278. Saturate,
  279. INT32_MIN,
  280. INT32_MAX>(
  281. src,
  282. scriptContext);
  283. }
  284. template <bool Saturate>
  285. uint32 WasmMath::F64ToU32(double src, _In_ Js::ScriptContext* scriptContext)
  286. {
  287. return WasmMath::ConvertFloatToInt<
  288. double, // SrcType
  289. uint32, // DstType
  290. uint64, // ReinterpretType
  291. Js::NumberConstants::k_TwoTo32,
  292. Js::NumberConstants::k_NegZero,
  293. Js::NumberConstants::k_NegOne,
  294. &WasmMath::LessOrEqual<uint64>,
  295. &WasmMath::LessThan<uint64>,
  296. Saturate,
  297. 0,
  298. UINT32_MAX>(
  299. src,
  300. scriptContext);
  301. }
  302. template <bool Saturate>
  303. int64 WasmMath::F32ToI64(float src, _In_ Js::ScriptContext* scriptContext)
  304. {
  305. return WasmMath::ConvertFloatToInt<
  306. float, // SrcType
  307. int64, // DstType
  308. uint32, // ReinterpretType
  309. Js::NumberConstants::k_Float32TwoTo63,
  310. Js::NumberConstants::k_Float32NegZero,
  311. Js::NumberConstants::k_Float32NegTwoTo63,
  312. &WasmMath::LessThan<uint32>,
  313. &WasmMath::LessOrEqual<uint32>,
  314. Saturate,
  315. INT64_MIN,
  316. INT64_MAX>(
  317. src,
  318. scriptContext);
  319. }
  320. template <bool Saturate>
  321. uint64 WasmMath::F32ToU64(float src, _In_ Js::ScriptContext* scriptContext)
  322. {
  323. return WasmMath::ConvertFloatToInt<
  324. float, // SrcType
  325. uint64, // DstType
  326. uint32, // ReinterpretType
  327. Js::NumberConstants::k_Float32TwoTo64,
  328. Js::NumberConstants::k_Float32NegZero,
  329. Js::NumberConstants::k_Float32NegOne,
  330. &WasmMath::LessThan<uint32>,
  331. &WasmMath::LessThan<uint32>,
  332. Saturate,
  333. 0,
  334. UINT64_MAX>(
  335. src,
  336. scriptContext);
  337. }
  338. template <bool Saturate>
  339. int64 WasmMath::F64ToI64(double src, _In_ Js::ScriptContext* scriptContext)
  340. {
  341. return WasmMath::ConvertFloatToInt<
  342. double, // SrcType
  343. int64, // DstType
  344. uint64, // ReinterpretType
  345. Js::NumberConstants::k_TwoTo63,
  346. Js::NumberConstants::k_NegZero,
  347. Js::NumberConstants::k_NegTwoTo63,
  348. &WasmMath::LessThan<uint64>,
  349. &WasmMath::LessOrEqual<uint64>,
  350. Saturate,
  351. INT64_MIN,
  352. INT64_MAX>(
  353. src,
  354. scriptContext);
  355. }
  356. template <bool Saturate>
  357. uint64 WasmMath::F64ToU64(double src, _In_ Js::ScriptContext* scriptContext)
  358. {
  359. return WasmMath::ConvertFloatToInt<
  360. double, // SrcType
  361. uint64, // DstType
  362. uint64, // ReinterpretType
  363. Js::NumberConstants::k_TwoTo64,
  364. Js::NumberConstants::k_NegZero,
  365. Js::NumberConstants::k_NegOne,
  366. &WasmMath::LessThan<uint64>,
  367. &WasmMath::LessThan<uint64>,
  368. Saturate,
  369. 0,
  370. UINT64_MAX>(
  371. src,
  372. scriptContext);
  373. }