Operators.h 12 KB

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