Operators.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. /*
  2. * Copyright (c) 2021-2023, Ali Mohammad Pur <mpfard@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/BitCast.h>
  8. #include <AK/BuiltinWrappers.h>
  9. #include <AK/Result.h>
  10. #include <AK/SIMD.h>
  11. #include <AK/StringView.h>
  12. #include <AK/Types.h>
  13. #include <limits.h>
  14. #include <math.h>
  15. namespace Wasm::Operators {
  16. using namespace AK::SIMD;
  17. #define DEFINE_BINARY_OPERATOR(Name, operation) \
  18. struct Name { \
  19. template<typename Lhs, typename Rhs> \
  20. auto operator()(Lhs lhs, Rhs rhs) const \
  21. { \
  22. return lhs operation rhs; \
  23. } \
  24. \
  25. static StringView name() \
  26. { \
  27. return #operation##sv; \
  28. } \
  29. }
  30. DEFINE_BINARY_OPERATOR(Equals, ==);
  31. DEFINE_BINARY_OPERATOR(NotEquals, !=);
  32. DEFINE_BINARY_OPERATOR(GreaterThan, >);
  33. DEFINE_BINARY_OPERATOR(LessThan, <);
  34. DEFINE_BINARY_OPERATOR(LessThanOrEquals, <=);
  35. DEFINE_BINARY_OPERATOR(GreaterThanOrEquals, >=);
  36. DEFINE_BINARY_OPERATOR(Add, +);
  37. DEFINE_BINARY_OPERATOR(Subtract, -);
  38. DEFINE_BINARY_OPERATOR(Multiply, *);
  39. DEFINE_BINARY_OPERATOR(BitAnd, &);
  40. DEFINE_BINARY_OPERATOR(BitOr, |);
  41. DEFINE_BINARY_OPERATOR(BitXor, ^);
  42. #undef DEFINE_BINARY_OPERATOR
  43. struct Divide {
  44. template<typename Lhs, typename Rhs>
  45. auto operator()(Lhs lhs, Rhs rhs) const
  46. {
  47. if constexpr (IsFloatingPoint<Lhs>) {
  48. return lhs / rhs;
  49. } else {
  50. Checked value(lhs);
  51. value /= rhs;
  52. if (value.has_overflow())
  53. return AK::Result<Lhs, StringView>("Integer division overflow"sv);
  54. return AK::Result<Lhs, StringView>(value.value());
  55. }
  56. }
  57. static StringView name() { return "/"sv; }
  58. };
  59. struct Modulo {
  60. template<typename Lhs, typename Rhs>
  61. auto operator()(Lhs lhs, Rhs rhs) const
  62. {
  63. if (rhs == 0)
  64. return AK::Result<Lhs, StringView>("Integer division overflow"sv);
  65. if constexpr (IsSigned<Lhs>) {
  66. if (rhs == -1)
  67. return AK::Result<Lhs, StringView>(0); // Spec weirdness right here, signed division overflow is ignored.
  68. }
  69. return AK::Result<Lhs, StringView>(lhs % rhs);
  70. }
  71. static StringView name() { return "%"sv; }
  72. };
  73. struct BitShiftLeft {
  74. template<typename Lhs, typename Rhs>
  75. auto operator()(Lhs lhs, Rhs rhs) const { return lhs << (rhs % (sizeof(lhs) * 8)); }
  76. static StringView name() { return "<<"sv; }
  77. };
  78. struct BitShiftRight {
  79. template<typename Lhs, typename Rhs>
  80. auto operator()(Lhs lhs, Rhs rhs) const { return lhs >> (rhs % (sizeof(lhs) * 8)); }
  81. static StringView name() { return ">>"sv; }
  82. };
  83. struct BitRotateLeft {
  84. template<typename Lhs, typename Rhs>
  85. auto operator()(Lhs lhs, Rhs rhs) const
  86. {
  87. // generates a single 'rol' instruction if shift is positive
  88. // otherwise generate a `ror`
  89. auto const mask = CHAR_BIT * sizeof(Lhs) - 1;
  90. rhs &= mask;
  91. return (lhs << rhs) | (lhs >> ((-rhs) & mask));
  92. }
  93. static StringView name() { return "rotate_left"sv; }
  94. };
  95. struct BitRotateRight {
  96. template<typename Lhs, typename Rhs>
  97. auto operator()(Lhs lhs, Rhs rhs) const
  98. {
  99. // generates a single 'ror' instruction if shift is positive
  100. // otherwise generate a `rol`
  101. auto const mask = CHAR_BIT * sizeof(Lhs) - 1;
  102. rhs &= mask;
  103. return (lhs >> rhs) | (lhs << ((-rhs) & mask));
  104. }
  105. static StringView name() { return "rotate_right"sv; }
  106. };
  107. template<size_t VectorSize>
  108. struct VectorShiftLeft {
  109. auto operator()(u128 lhs, i32 rhs) const
  110. {
  111. auto shift_value = rhs % (sizeof(lhs) * 8 / VectorSize);
  112. return bit_cast<u128>(bit_cast<Native128ByteVectorOf<NativeIntegralType<128 / VectorSize>, MakeUnsigned>>(lhs) << shift_value);
  113. }
  114. static StringView name()
  115. {
  116. switch (VectorSize) {
  117. case 16:
  118. return "vec(8x16)<<"sv;
  119. case 8:
  120. return "vec(16x8)<<"sv;
  121. case 4:
  122. return "vec(32x4)<<"sv;
  123. case 2:
  124. return "vec(64x2)<<"sv;
  125. default:
  126. VERIFY_NOT_REACHED();
  127. }
  128. }
  129. };
  130. template<size_t VectorSize, template<typename> typename SetSign>
  131. struct VectorShiftRight {
  132. auto operator()(u128 lhs, i32 rhs) const
  133. {
  134. auto shift_value = rhs % (sizeof(lhs) * 8 / VectorSize);
  135. return bit_cast<u128>(bit_cast<Native128ByteVectorOf<NativeIntegralType<128 / VectorSize>, SetSign>>(lhs) >> shift_value);
  136. }
  137. static StringView name()
  138. {
  139. switch (VectorSize) {
  140. case 16:
  141. return "vec(8x16)>>"sv;
  142. case 8:
  143. return "vec(16x8)>>"sv;
  144. case 4:
  145. return "vec(32x4)>>"sv;
  146. case 2:
  147. return "vec(64x2)>>"sv;
  148. default:
  149. VERIFY_NOT_REACHED();
  150. }
  151. }
  152. };
  153. struct Minimum {
  154. template<typename Lhs, typename Rhs>
  155. auto operator()(Lhs lhs, Rhs rhs) const
  156. {
  157. if constexpr (IsFloatingPoint<Lhs> || IsFloatingPoint<Rhs>) {
  158. if (isnan(lhs))
  159. return lhs;
  160. if (isnan(rhs))
  161. return rhs;
  162. if (isinf(lhs))
  163. return lhs > 0 ? rhs : lhs;
  164. if (isinf(rhs))
  165. return rhs > 0 ? lhs : rhs;
  166. }
  167. return min(lhs, rhs);
  168. }
  169. static StringView name() { return "minimum"sv; }
  170. };
  171. struct Maximum {
  172. template<typename Lhs, typename Rhs>
  173. auto operator()(Lhs lhs, Rhs rhs) const
  174. {
  175. if constexpr (IsFloatingPoint<Lhs> || IsFloatingPoint<Rhs>) {
  176. if (isnan(lhs))
  177. return lhs;
  178. if (isnan(rhs))
  179. return rhs;
  180. if (isinf(lhs))
  181. return lhs > 0 ? lhs : rhs;
  182. if (isinf(rhs))
  183. return rhs > 0 ? rhs : lhs;
  184. }
  185. return max(lhs, rhs);
  186. }
  187. static StringView name() { return "maximum"sv; }
  188. };
  189. struct CopySign {
  190. template<typename Lhs, typename Rhs>
  191. auto operator()(Lhs lhs, Rhs rhs) const
  192. {
  193. if constexpr (IsSame<Lhs, float>)
  194. return copysignf(lhs, rhs);
  195. else if constexpr (IsSame<Lhs, double>)
  196. return copysign(lhs, rhs);
  197. else
  198. static_assert(DependentFalse<Lhs, Rhs>, "Invalid types to CopySign");
  199. }
  200. static StringView name() { return "copysign"sv; }
  201. };
  202. // Unary
  203. struct EqualsZero {
  204. template<typename Lhs>
  205. auto operator()(Lhs lhs) const { return lhs == 0; }
  206. static StringView name() { return "== 0"sv; }
  207. };
  208. struct CountLeadingZeros {
  209. template<typename Lhs>
  210. i32 operator()(Lhs lhs) const
  211. {
  212. if (lhs == 0)
  213. return sizeof(Lhs) * CHAR_BIT;
  214. if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
  215. return count_leading_zeroes(MakeUnsigned<Lhs>(lhs));
  216. else
  217. VERIFY_NOT_REACHED();
  218. }
  219. static StringView name() { return "clz"sv; }
  220. };
  221. struct CountTrailingZeros {
  222. template<typename Lhs>
  223. i32 operator()(Lhs lhs) const
  224. {
  225. if (lhs == 0)
  226. return sizeof(Lhs) * CHAR_BIT;
  227. if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
  228. return count_trailing_zeroes(MakeUnsigned<Lhs>(lhs));
  229. else
  230. VERIFY_NOT_REACHED();
  231. }
  232. static StringView name() { return "ctz"sv; }
  233. };
  234. struct PopCount {
  235. template<typename Lhs>
  236. auto operator()(Lhs lhs) const
  237. {
  238. if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
  239. return popcount(MakeUnsigned<Lhs>(lhs));
  240. else
  241. VERIFY_NOT_REACHED();
  242. }
  243. static StringView name() { return "popcnt"sv; }
  244. };
  245. struct Absolute {
  246. template<typename Lhs>
  247. auto operator()(Lhs lhs) const { return AK::abs(lhs); }
  248. static StringView name() { return "abs"sv; }
  249. };
  250. struct Negate {
  251. template<typename Lhs>
  252. auto operator()(Lhs lhs) const { return -lhs; }
  253. static StringView name() { return "== 0"sv; }
  254. };
  255. struct Ceil {
  256. template<typename Lhs>
  257. auto operator()(Lhs lhs) const
  258. {
  259. if constexpr (IsSame<Lhs, float>)
  260. return ceilf(lhs);
  261. else if constexpr (IsSame<Lhs, double>)
  262. return ceil(lhs);
  263. else
  264. VERIFY_NOT_REACHED();
  265. }
  266. static StringView name() { return "ceil"sv; }
  267. };
  268. struct Floor {
  269. template<typename Lhs>
  270. auto operator()(Lhs lhs) const
  271. {
  272. if constexpr (IsSame<Lhs, float>)
  273. return floorf(lhs);
  274. else if constexpr (IsSame<Lhs, double>)
  275. return floor(lhs);
  276. else
  277. VERIFY_NOT_REACHED();
  278. }
  279. static StringView name() { return "floor"sv; }
  280. };
  281. struct Truncate {
  282. template<typename Lhs>
  283. AK::Result<Lhs, StringView> operator()(Lhs lhs) const
  284. {
  285. if constexpr (IsSame<Lhs, float>)
  286. return truncf(lhs);
  287. else if constexpr (IsSame<Lhs, double>)
  288. return trunc(lhs);
  289. else
  290. VERIFY_NOT_REACHED();
  291. }
  292. static StringView name() { return "truncate"sv; }
  293. };
  294. struct NearbyIntegral {
  295. template<typename Lhs>
  296. auto operator()(Lhs lhs) const
  297. {
  298. if constexpr (IsSame<Lhs, float>)
  299. return nearbyintf(lhs);
  300. else if constexpr (IsSame<Lhs, double>)
  301. return nearbyint(lhs);
  302. else
  303. VERIFY_NOT_REACHED();
  304. }
  305. static StringView name() { return "round"sv; }
  306. };
  307. struct SquareRoot {
  308. template<typename Lhs>
  309. auto operator()(Lhs lhs) const
  310. {
  311. if constexpr (IsSame<Lhs, float>)
  312. return sqrtf(lhs);
  313. else if constexpr (IsSame<Lhs, double>)
  314. return sqrt(lhs);
  315. else
  316. VERIFY_NOT_REACHED();
  317. }
  318. static StringView name() { return "sqrt"sv; }
  319. };
  320. template<typename Result>
  321. struct Wrap {
  322. template<typename Lhs>
  323. Result operator()(Lhs lhs) const
  324. {
  325. return static_cast<MakeUnsigned<Result>>(bit_cast<MakeUnsigned<Lhs>>(lhs));
  326. }
  327. static StringView name() { return "wrap"sv; }
  328. };
  329. template<typename ResultT>
  330. struct CheckedTruncate {
  331. template<typename Lhs>
  332. AK::Result<ResultT, StringView> operator()(Lhs lhs) const
  333. {
  334. if (isnan(lhs) || isinf(lhs)) // "undefined", let's just trap.
  335. return "Truncation undefined behavior"sv;
  336. Lhs truncated;
  337. if constexpr (IsSame<float, Lhs>)
  338. truncated = truncf(lhs);
  339. else if constexpr (IsSame<double, Lhs>)
  340. truncated = trunc(lhs);
  341. else
  342. VERIFY_NOT_REACHED();
  343. // FIXME: This function assumes that all values of ResultT are representable in Lhs
  344. // the assumption comes from the fact that this was used exclusively by LibJS,
  345. // which only considers values that are all representable in 'double'.
  346. if (!AK::is_within_range<ResultT>(truncated))
  347. return "Truncation out of range"sv;
  348. return static_cast<ResultT>(truncated);
  349. }
  350. static StringView name() { return "truncate.checked"sv; }
  351. };
  352. template<typename ResultT>
  353. struct Extend {
  354. template<typename Lhs>
  355. ResultT operator()(Lhs lhs) const
  356. {
  357. return lhs;
  358. }
  359. static StringView name() { return "extend"sv; }
  360. };
  361. template<typename ResultT>
  362. struct Convert {
  363. template<typename Lhs>
  364. ResultT operator()(Lhs lhs) const
  365. {
  366. auto signed_interpretation = bit_cast<MakeSigned<Lhs>>(lhs);
  367. return static_cast<ResultT>(signed_interpretation);
  368. }
  369. static StringView name() { return "convert"sv; }
  370. };
  371. template<typename ResultT>
  372. struct Reinterpret {
  373. template<typename Lhs>
  374. ResultT operator()(Lhs lhs) const
  375. {
  376. return bit_cast<ResultT>(lhs);
  377. }
  378. static StringView name() { return "reinterpret"sv; }
  379. };
  380. struct Promote {
  381. double operator()(float lhs) const
  382. {
  383. if (isnan(lhs))
  384. return nan(""); // FIXME: Ensure canonical NaN remains canonical
  385. return static_cast<double>(lhs);
  386. }
  387. static StringView name() { return "promote"sv; }
  388. };
  389. struct Demote {
  390. float operator()(double lhs) const
  391. {
  392. if (isnan(lhs))
  393. return nanf(""); // FIXME: Ensure canonical NaN remains canonical
  394. if (isinf(lhs))
  395. return __builtin_huge_valf();
  396. return static_cast<float>(lhs);
  397. }
  398. static StringView name() { return "demote"sv; }
  399. };
  400. template<typename InitialType>
  401. struct SignExtend {
  402. template<typename Lhs>
  403. Lhs operator()(Lhs lhs) const
  404. {
  405. auto unsigned_representation = bit_cast<MakeUnsigned<Lhs>>(lhs);
  406. auto truncated_unsigned_representation = static_cast<MakeUnsigned<InitialType>>(unsigned_representation);
  407. auto initial_value = bit_cast<InitialType>(truncated_unsigned_representation);
  408. return static_cast<Lhs>(initial_value);
  409. }
  410. static StringView name() { return "extend"sv; }
  411. };
  412. template<typename ResultT>
  413. struct SaturatingTruncate {
  414. template<typename Lhs>
  415. ResultT operator()(Lhs lhs) const
  416. {
  417. if (isnan(lhs))
  418. return 0;
  419. if (isinf(lhs)) {
  420. if (lhs < 0)
  421. return NumericLimits<ResultT>::min();
  422. return NumericLimits<ResultT>::max();
  423. }
  424. // FIXME: This assumes that all values in ResultT are representable in 'double'.
  425. // that assumption is not correct, which makes this function yield incorrect values
  426. // for 'edge' values of type i64.
  427. constexpr auto convert = []<typename ConvertT>(ConvertT truncated_value) {
  428. if (truncated_value < NumericLimits<ResultT>::min())
  429. return NumericLimits<ResultT>::min();
  430. if constexpr (IsSame<ConvertT, float>) {
  431. if (truncated_value >= static_cast<ConvertT>(NumericLimits<ResultT>::max()))
  432. return NumericLimits<ResultT>::max();
  433. } else {
  434. if (static_cast<double>(truncated_value) >= static_cast<double>(NumericLimits<ResultT>::max()))
  435. return NumericLimits<ResultT>::max();
  436. }
  437. return static_cast<ResultT>(truncated_value);
  438. };
  439. if constexpr (IsSame<Lhs, float>)
  440. return convert(truncf(lhs));
  441. else
  442. return convert(trunc(lhs));
  443. }
  444. static StringView name() { return "truncate.saturating"sv; }
  445. };
  446. }