Operators.h 13 KB

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