Operators.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  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::ErrorOr<Lhs, StringView>("Integer division overflow"sv);
  54. return AK::ErrorOr<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::ErrorOr<Lhs, StringView>("Integer division overflow"sv);
  65. if constexpr (IsSigned<Lhs>) {
  66. if (rhs == -1)
  67. return AK::ErrorOr<Lhs, StringView>(0); // Spec weirdness right here, signed division overflow is ignored.
  68. }
  69. return AK::ErrorOr<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 BitAndNot {
  84. template<typename Lhs, typename Rhs>
  85. auto operator()(Lhs lhs, Rhs rhs) const { return lhs & ~rhs; }
  86. static StringView name() { return "andnot"sv; }
  87. };
  88. struct BitNot {
  89. template<typename Lhs>
  90. auto operator()(Lhs lhs) const { return ~lhs; }
  91. static StringView name() { return "~"sv; }
  92. };
  93. struct BitRotateLeft {
  94. template<typename Lhs, typename Rhs>
  95. auto operator()(Lhs lhs, Rhs rhs) const
  96. {
  97. // generates a single 'rol' instruction if shift is positive
  98. // otherwise generate a `ror`
  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_left"sv; }
  104. };
  105. struct BitRotateRight {
  106. template<typename Lhs, typename Rhs>
  107. auto operator()(Lhs lhs, Rhs rhs) const
  108. {
  109. // generates a single 'ror' instruction if shift is positive
  110. // otherwise generate a `rol`
  111. auto const mask = CHAR_BIT * sizeof(Lhs) - 1;
  112. rhs &= mask;
  113. return (lhs >> rhs) | (lhs << ((-rhs) & mask));
  114. }
  115. static StringView name() { return "rotate_right"sv; }
  116. };
  117. template<size_t VectorSize>
  118. struct VectorShiftLeft {
  119. auto operator()(u128 lhs, i32 rhs) const
  120. {
  121. auto shift_value = rhs % (sizeof(lhs) * 8 / VectorSize);
  122. return bit_cast<u128>(bit_cast<Native128ByteVectorOf<NativeIntegralType<128 / VectorSize>, MakeUnsigned>>(lhs) << shift_value);
  123. }
  124. static StringView name()
  125. {
  126. switch (VectorSize) {
  127. case 16:
  128. return "vec(8x16)<<"sv;
  129. case 8:
  130. return "vec(16x8)<<"sv;
  131. case 4:
  132. return "vec(32x4)<<"sv;
  133. case 2:
  134. return "vec(64x2)<<"sv;
  135. default:
  136. VERIFY_NOT_REACHED();
  137. }
  138. }
  139. };
  140. template<size_t VectorSize, template<typename> typename SetSign>
  141. struct VectorShiftRight {
  142. auto operator()(u128 lhs, i32 rhs) const
  143. {
  144. auto shift_value = rhs % (sizeof(lhs) * 8 / VectorSize);
  145. return bit_cast<u128>(bit_cast<Native128ByteVectorOf<NativeIntegralType<128 / VectorSize>, SetSign>>(lhs) >> shift_value);
  146. }
  147. static StringView name()
  148. {
  149. switch (VectorSize) {
  150. case 16:
  151. return "vec(8x16)>>"sv;
  152. case 8:
  153. return "vec(16x8)>>"sv;
  154. case 4:
  155. return "vec(32x4)>>"sv;
  156. case 2:
  157. return "vec(64x2)>>"sv;
  158. default:
  159. VERIFY_NOT_REACHED();
  160. }
  161. }
  162. };
  163. struct VectorSwizzle {
  164. auto operator()(u128 c1, u128 c2) const
  165. {
  166. // https://webassembly.github.io/spec/core/bikeshed/#-mathsfi8x16hrefsyntax-instr-vecmathsfswizzle%E2%91%A0
  167. auto i = bit_cast<Native128ByteVectorOf<i8, MakeSigned>>(c2);
  168. auto j = bit_cast<Native128ByteVectorOf<i8, MakeSigned>>(c1);
  169. auto result = AK::SIMD::shuffle(i, j);
  170. return bit_cast<u128>(result);
  171. }
  172. static StringView name() { return "vec(8x16).swizzle"sv; }
  173. };
  174. template<size_t VectorSize, template<typename> typename SetSign>
  175. struct VectorExtractLane {
  176. size_t lane;
  177. auto operator()(u128 c) const
  178. {
  179. auto result = bit_cast<Native128ByteVectorOf<NativeIntegralType<128 / VectorSize>, SetSign>>(c);
  180. return result[lane];
  181. }
  182. static StringView name()
  183. {
  184. switch (VectorSize) {
  185. case 16:
  186. return "vec(8x16).extract_lane"sv;
  187. case 8:
  188. return "vec(16x8).extract_lane"sv;
  189. case 4:
  190. return "vec(32x4).extract_lane"sv;
  191. case 2:
  192. return "vec(64x2).extract_lane"sv;
  193. default:
  194. VERIFY_NOT_REACHED();
  195. }
  196. }
  197. };
  198. template<size_t VectorSize>
  199. struct VectorExtractLaneFloat {
  200. size_t lane;
  201. auto operator()(u128 c) const
  202. {
  203. auto result = bit_cast<NativeFloatingVectorType<128 / VectorSize, VectorSize>>(c);
  204. return result[lane];
  205. }
  206. static StringView name()
  207. {
  208. switch (VectorSize) {
  209. case 16:
  210. return "vec(8x16).extract_lane"sv;
  211. case 8:
  212. return "vec(16x8).extract_lane"sv;
  213. case 4:
  214. return "vec(32x4).extract_lane"sv;
  215. case 2:
  216. return "vec(64x2).extract_lane"sv;
  217. default:
  218. VERIFY_NOT_REACHED();
  219. }
  220. }
  221. };
  222. template<size_t VectorSize, typename TrueValueType = NativeIntegralType<128 / VectorSize>>
  223. struct VectorReplaceLane {
  224. size_t lane;
  225. using ValueType = Conditional<IsFloatingPoint<TrueValueType>, NativeFloatingType<128 / VectorSize>, NativeIntegralType<128 / VectorSize>>;
  226. auto operator()(u128 c, TrueValueType value) const
  227. {
  228. auto result = bit_cast<Native128ByteVectorOf<ValueType, MakeUnsigned>>(c);
  229. result[lane] = static_cast<ValueType>(value);
  230. return bit_cast<u128>(result);
  231. }
  232. static StringView name()
  233. {
  234. switch (VectorSize) {
  235. case 16:
  236. return "vec(8x16).replace_lane"sv;
  237. case 8:
  238. return "vec(16x8).replace_lane"sv;
  239. case 4:
  240. return "vec(32x4).replace_lane"sv;
  241. case 2:
  242. return "vec(64x2).replace_lane"sv;
  243. default:
  244. VERIFY_NOT_REACHED();
  245. }
  246. }
  247. };
  248. template<size_t VectorSize, typename Op, template<typename> typename SetSign = MakeSigned>
  249. struct VectorCmpOp {
  250. auto operator()(u128 c1, u128 c2) const
  251. {
  252. using ElementType = NativeIntegralType<128 / VectorSize>;
  253. auto result = bit_cast<Native128ByteVectorOf<ElementType, SetSign>>(c1);
  254. auto other = bit_cast<Native128ByteVectorOf<ElementType, SetSign>>(c2);
  255. Op op;
  256. for (size_t i = 0; i < VectorSize; ++i)
  257. result[i] = op(result[i], other[i]) ? static_cast<MakeUnsigned<ElementType>>(-1) : 0;
  258. return bit_cast<u128>(result);
  259. }
  260. static StringView name()
  261. {
  262. switch (VectorSize) {
  263. case 16:
  264. return "vec(8x16).cmp"sv;
  265. case 8:
  266. return "vec(16x8).cmp"sv;
  267. case 4:
  268. return "vec(32x4).cmp"sv;
  269. case 2:
  270. return "vec(64x2).cmp"sv;
  271. default:
  272. VERIFY_NOT_REACHED();
  273. }
  274. }
  275. };
  276. template<size_t VectorSize, typename Op>
  277. struct VectorFloatCmpOp {
  278. auto operator()(u128 c1, u128 c2) const
  279. {
  280. auto first = bit_cast<NativeFloatingVectorType<128, VectorSize, NativeFloatingType<128 / VectorSize>>>(c1);
  281. auto other = bit_cast<NativeFloatingVectorType<128, VectorSize, NativeFloatingType<128 / VectorSize>>>(c2);
  282. using ElementType = NativeIntegralType<128 / VectorSize>;
  283. Native128ByteVectorOf<ElementType, MakeUnsigned> result;
  284. Op op;
  285. for (size_t i = 0; i < VectorSize; ++i)
  286. result[i] = op(first[i], other[i]) ? static_cast<ElementType>(-1) : 0;
  287. return bit_cast<u128>(result);
  288. }
  289. static StringView name()
  290. {
  291. switch (VectorSize) {
  292. case 4:
  293. return "vecf(32x4).cmp"sv;
  294. case 2:
  295. return "vecf(64x2).cmp"sv;
  296. default:
  297. VERIFY_NOT_REACHED();
  298. }
  299. }
  300. };
  301. struct Minimum {
  302. template<typename Lhs, typename Rhs>
  303. auto operator()(Lhs lhs, Rhs rhs) const
  304. {
  305. if constexpr (IsFloatingPoint<Lhs> || IsFloatingPoint<Rhs>) {
  306. if (isnan(lhs) || isnan(rhs)) {
  307. return isnan(lhs) ? lhs : rhs;
  308. }
  309. if (lhs == 0 && rhs == 0) {
  310. return signbit(lhs) ? lhs : rhs;
  311. }
  312. }
  313. return min(lhs, rhs);
  314. }
  315. static StringView name() { return "minimum"sv; }
  316. };
  317. struct Maximum {
  318. template<typename Lhs, typename Rhs>
  319. auto operator()(Lhs lhs, Rhs rhs) const
  320. {
  321. if constexpr (IsFloatingPoint<Lhs> || IsFloatingPoint<Rhs>) {
  322. if (isnan(lhs) || isnan(rhs)) {
  323. return isnan(lhs) ? lhs : rhs;
  324. }
  325. if (lhs == 0 && rhs == 0) {
  326. return signbit(lhs) ? rhs : lhs;
  327. }
  328. }
  329. return max(lhs, rhs);
  330. }
  331. static StringView name() { return "maximum"sv; }
  332. };
  333. struct PseudoMinimum {
  334. template<typename Lhs, typename Rhs>
  335. auto operator()(Lhs lhs, Rhs rhs) const
  336. {
  337. return rhs < lhs ? rhs : lhs;
  338. }
  339. static StringView name() { return "pseudo_minimum"sv; }
  340. };
  341. struct PseudoMaximum {
  342. template<typename Lhs, typename Rhs>
  343. auto operator()(Lhs lhs, Rhs rhs) const
  344. {
  345. return lhs < rhs ? rhs : lhs;
  346. }
  347. static StringView name() { return "pseudo_maximum"sv; }
  348. };
  349. struct CopySign {
  350. template<typename Lhs, typename Rhs>
  351. auto operator()(Lhs lhs, Rhs rhs) const
  352. {
  353. if constexpr (IsSame<Lhs, float>)
  354. return copysignf(lhs, rhs);
  355. else if constexpr (IsSame<Lhs, double>)
  356. return copysign(lhs, rhs);
  357. else
  358. static_assert(DependentFalse<Lhs, Rhs>, "Invalid types to CopySign");
  359. }
  360. static StringView name() { return "copysign"sv; }
  361. };
  362. // Unary
  363. struct EqualsZero {
  364. template<typename Lhs>
  365. auto operator()(Lhs lhs) const { return lhs == 0; }
  366. static StringView name() { return "== 0"sv; }
  367. };
  368. struct CountLeadingZeros {
  369. template<typename Lhs>
  370. i32 operator()(Lhs lhs) const
  371. {
  372. if (lhs == 0)
  373. return sizeof(Lhs) * CHAR_BIT;
  374. if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
  375. return count_leading_zeroes(MakeUnsigned<Lhs>(lhs));
  376. else
  377. VERIFY_NOT_REACHED();
  378. }
  379. static StringView name() { return "clz"sv; }
  380. };
  381. struct CountTrailingZeros {
  382. template<typename Lhs>
  383. i32 operator()(Lhs lhs) const
  384. {
  385. if (lhs == 0)
  386. return sizeof(Lhs) * CHAR_BIT;
  387. if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
  388. return count_trailing_zeroes(MakeUnsigned<Lhs>(lhs));
  389. else
  390. VERIFY_NOT_REACHED();
  391. }
  392. static StringView name() { return "ctz"sv; }
  393. };
  394. struct PopCount {
  395. template<typename Lhs>
  396. auto operator()(Lhs lhs) const
  397. {
  398. if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
  399. return popcount(MakeUnsigned<Lhs>(lhs));
  400. else
  401. VERIFY_NOT_REACHED();
  402. }
  403. static StringView name() { return "popcnt"sv; }
  404. };
  405. struct Absolute {
  406. template<typename Lhs>
  407. auto operator()(Lhs lhs) const { return AK::abs(lhs); }
  408. static StringView name() { return "abs"sv; }
  409. };
  410. struct Negate {
  411. template<typename Lhs>
  412. auto operator()(Lhs lhs) const { return -lhs; }
  413. static StringView name() { return "== 0"sv; }
  414. };
  415. struct Ceil {
  416. template<typename Lhs>
  417. auto operator()(Lhs lhs) const
  418. {
  419. if constexpr (IsSame<Lhs, float>)
  420. return ceilf(lhs);
  421. else if constexpr (IsSame<Lhs, double>)
  422. return ceil(lhs);
  423. else
  424. VERIFY_NOT_REACHED();
  425. }
  426. static StringView name() { return "ceil"sv; }
  427. };
  428. template<size_t VectorSize, typename Op>
  429. struct VectorFloatBinaryOp {
  430. auto operator()(u128 lhs, u128 rhs) const
  431. {
  432. using VectorType = NativeFloatingVectorType<128, VectorSize, NativeFloatingType<128 / VectorSize>>;
  433. auto first = bit_cast<VectorType>(lhs);
  434. auto second = bit_cast<VectorType>(rhs);
  435. VectorType result;
  436. Op op;
  437. for (size_t i = 0; i < VectorSize; ++i) {
  438. result[i] = op(first[i], second[i]);
  439. }
  440. return bit_cast<u128>(result);
  441. }
  442. static StringView name()
  443. {
  444. switch (VectorSize) {
  445. case 4:
  446. return "vecf(32x4).binary_op"sv;
  447. case 2:
  448. return "vecf(64x2).binary_op"sv;
  449. default:
  450. VERIFY_NOT_REACHED();
  451. }
  452. }
  453. };
  454. template<size_t VectorSize, typename Op>
  455. struct VectorFloatUnaryOp {
  456. auto operator()(u128 lhs) const
  457. {
  458. using VectorType = NativeFloatingVectorType<128, VectorSize, NativeFloatingType<128 / VectorSize>>;
  459. auto first = bit_cast<VectorType>(lhs);
  460. VectorType result;
  461. Op op;
  462. for (size_t i = 0; i < VectorSize; ++i) {
  463. result[i] = op(first[i]);
  464. }
  465. return bit_cast<u128>(result);
  466. }
  467. static StringView name()
  468. {
  469. switch (VectorSize) {
  470. case 4:
  471. return "vecf(32x4).unary_op"sv;
  472. case 2:
  473. return "vecf(64x2).unary_op"sv;
  474. default:
  475. VERIFY_NOT_REACHED();
  476. }
  477. }
  478. };
  479. struct Floor {
  480. template<typename Lhs>
  481. auto operator()(Lhs lhs) const
  482. {
  483. if constexpr (IsSame<Lhs, float>)
  484. return floorf(lhs);
  485. else if constexpr (IsSame<Lhs, double>)
  486. return floor(lhs);
  487. else
  488. VERIFY_NOT_REACHED();
  489. }
  490. static StringView name() { return "floor"sv; }
  491. };
  492. struct Truncate {
  493. template<typename Lhs>
  494. auto operator()(Lhs lhs) const
  495. {
  496. if constexpr (IsSame<Lhs, float>)
  497. return truncf(lhs);
  498. else if constexpr (IsSame<Lhs, double>)
  499. return trunc(lhs);
  500. else
  501. VERIFY_NOT_REACHED();
  502. }
  503. static StringView name() { return "truncate"sv; }
  504. };
  505. struct NearbyIntegral {
  506. template<typename Lhs>
  507. auto operator()(Lhs lhs) const
  508. {
  509. if constexpr (IsSame<Lhs, float>)
  510. return nearbyintf(lhs);
  511. else if constexpr (IsSame<Lhs, double>)
  512. return nearbyint(lhs);
  513. else
  514. VERIFY_NOT_REACHED();
  515. }
  516. static StringView name() { return "round"sv; }
  517. };
  518. struct SquareRoot {
  519. template<typename Lhs>
  520. auto operator()(Lhs lhs) const
  521. {
  522. if constexpr (IsSame<Lhs, float>)
  523. return sqrtf(lhs);
  524. else if constexpr (IsSame<Lhs, double>)
  525. return sqrt(lhs);
  526. else
  527. VERIFY_NOT_REACHED();
  528. }
  529. static StringView name() { return "sqrt"sv; }
  530. };
  531. template<typename Result>
  532. struct Wrap {
  533. template<typename Lhs>
  534. Result operator()(Lhs lhs) const
  535. {
  536. return static_cast<MakeUnsigned<Result>>(bit_cast<MakeUnsigned<Lhs>>(lhs));
  537. }
  538. static StringView name() { return "wrap"sv; }
  539. };
  540. template<typename ResultT>
  541. struct CheckedTruncate {
  542. template<typename Lhs>
  543. AK::ErrorOr<ResultT, StringView> operator()(Lhs lhs) const
  544. {
  545. if (isnan(lhs) || isinf(lhs)) // "undefined", let's just trap.
  546. return "Truncation undefined behavior"sv;
  547. Lhs truncated;
  548. if constexpr (IsSame<float, Lhs>)
  549. truncated = truncf(lhs);
  550. else if constexpr (IsSame<double, Lhs>)
  551. truncated = trunc(lhs);
  552. else
  553. VERIFY_NOT_REACHED();
  554. // FIXME: This function assumes that all values of ResultT are representable in Lhs
  555. // the assumption comes from the fact that this was used exclusively by LibJS,
  556. // which only considers values that are all representable in 'double'.
  557. if (!AK::is_within_range<ResultT>(truncated))
  558. return "Truncation out of range"sv;
  559. return static_cast<ResultT>(truncated);
  560. }
  561. static StringView name() { return "truncate.checked"sv; }
  562. };
  563. template<typename ResultT>
  564. struct Extend {
  565. template<typename Lhs>
  566. ResultT operator()(Lhs lhs) const
  567. {
  568. return lhs;
  569. }
  570. static StringView name() { return "extend"sv; }
  571. };
  572. template<typename ResultT>
  573. struct Convert {
  574. template<typename Lhs>
  575. ResultT operator()(Lhs lhs) const
  576. {
  577. auto interpretation = bit_cast<Lhs>(lhs);
  578. return static_cast<ResultT>(interpretation);
  579. }
  580. static StringView name() { return "convert"sv; }
  581. };
  582. template<typename ResultT>
  583. struct Reinterpret {
  584. template<typename Lhs>
  585. ResultT operator()(Lhs lhs) const
  586. {
  587. return bit_cast<ResultT>(lhs);
  588. }
  589. static StringView name() { return "reinterpret"sv; }
  590. };
  591. struct Promote {
  592. double operator()(float lhs) const
  593. {
  594. if (isnan(lhs))
  595. return nan(""); // FIXME: Ensure canonical NaN remains canonical
  596. return static_cast<double>(lhs);
  597. }
  598. static StringView name() { return "promote"sv; }
  599. };
  600. struct Demote {
  601. float operator()(double lhs) const
  602. {
  603. if (isnan(lhs))
  604. return nanf(""); // FIXME: Ensure canonical NaN remains canonical
  605. if (isinf(lhs))
  606. return copysignf(__builtin_huge_valf(), lhs);
  607. return static_cast<float>(lhs);
  608. }
  609. static StringView name() { return "demote"sv; }
  610. };
  611. template<typename InitialType>
  612. struct SignExtend {
  613. template<typename Lhs>
  614. Lhs operator()(Lhs lhs) const
  615. {
  616. auto unsigned_representation = bit_cast<MakeUnsigned<Lhs>>(lhs);
  617. auto truncated_unsigned_representation = static_cast<MakeUnsigned<InitialType>>(unsigned_representation);
  618. auto initial_value = bit_cast<InitialType>(truncated_unsigned_representation);
  619. return static_cast<Lhs>(initial_value);
  620. }
  621. static StringView name() { return "extend"sv; }
  622. };
  623. template<typename ResultT>
  624. struct SaturatingTruncate {
  625. template<typename Lhs>
  626. ResultT operator()(Lhs lhs) const
  627. {
  628. if (isnan(lhs))
  629. return 0;
  630. if (isinf(lhs)) {
  631. if (lhs < 0)
  632. return NumericLimits<ResultT>::min();
  633. return NumericLimits<ResultT>::max();
  634. }
  635. // FIXME: This assumes that all values in ResultT are representable in 'double'.
  636. // that assumption is not correct, which makes this function yield incorrect values
  637. // for 'edge' values of type i64.
  638. constexpr auto convert = []<typename ConvertT>(ConvertT truncated_value) {
  639. if (truncated_value < NumericLimits<ResultT>::min())
  640. return NumericLimits<ResultT>::min();
  641. if constexpr (IsSame<ConvertT, float>) {
  642. if (truncated_value >= static_cast<ConvertT>(NumericLimits<ResultT>::max()))
  643. return NumericLimits<ResultT>::max();
  644. } else {
  645. if (static_cast<double>(truncated_value) >= static_cast<double>(NumericLimits<ResultT>::max()))
  646. return NumericLimits<ResultT>::max();
  647. }
  648. return static_cast<ResultT>(truncated_value);
  649. };
  650. if constexpr (IsSame<Lhs, float>)
  651. return convert(truncf(lhs));
  652. else
  653. return convert(trunc(lhs));
  654. }
  655. static StringView name() { return "truncate.saturating"sv; }
  656. };
  657. }