Operators.h 12 KB

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