Operators.h 21 KB

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