Operators.h 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  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/SIMDExtras.h>
  12. #include <AK/StringView.h>
  13. #include <AK/Types.h>
  14. #include <LibWasm/Types.h>
  15. #include <limits.h>
  16. #include <math.h>
  17. namespace Wasm::Operators {
  18. using namespace AK::SIMD;
  19. #define DEFINE_BINARY_OPERATOR(Name, operation) \
  20. struct Name { \
  21. template<typename Lhs, typename Rhs> \
  22. auto operator()(Lhs lhs, Rhs rhs) const \
  23. { \
  24. return lhs operation rhs; \
  25. } \
  26. \
  27. static StringView name() \
  28. { \
  29. return #operation##sv; \
  30. } \
  31. }
  32. DEFINE_BINARY_OPERATOR(Equals, ==);
  33. DEFINE_BINARY_OPERATOR(NotEquals, !=);
  34. DEFINE_BINARY_OPERATOR(GreaterThan, >);
  35. DEFINE_BINARY_OPERATOR(LessThan, <);
  36. DEFINE_BINARY_OPERATOR(LessThanOrEquals, <=);
  37. DEFINE_BINARY_OPERATOR(GreaterThanOrEquals, >=);
  38. DEFINE_BINARY_OPERATOR(Add, +);
  39. DEFINE_BINARY_OPERATOR(Subtract, -);
  40. DEFINE_BINARY_OPERATOR(Multiply, *);
  41. DEFINE_BINARY_OPERATOR(BitAnd, &);
  42. DEFINE_BINARY_OPERATOR(BitOr, |);
  43. DEFINE_BINARY_OPERATOR(BitXor, ^);
  44. #undef DEFINE_BINARY_OPERATOR
  45. struct Divide {
  46. template<typename Lhs, typename Rhs>
  47. auto operator()(Lhs lhs, Rhs rhs) const
  48. {
  49. if constexpr (IsFloatingPoint<Lhs>) {
  50. return lhs / rhs;
  51. } else {
  52. Checked value(lhs);
  53. value /= rhs;
  54. if (value.has_overflow())
  55. return AK::ErrorOr<Lhs, StringView>("Integer division overflow"sv);
  56. return AK::ErrorOr<Lhs, StringView>(value.value());
  57. }
  58. }
  59. static StringView name() { return "/"sv; }
  60. };
  61. struct Modulo {
  62. template<typename Lhs, typename Rhs>
  63. auto operator()(Lhs lhs, Rhs rhs) const
  64. {
  65. if (rhs == 0)
  66. return AK::ErrorOr<Lhs, StringView>("Integer division overflow"sv);
  67. if constexpr (IsSigned<Lhs>) {
  68. if (rhs == -1)
  69. return AK::ErrorOr<Lhs, StringView>(0); // Spec weirdness right here, signed division overflow is ignored.
  70. }
  71. return AK::ErrorOr<Lhs, StringView>(lhs % rhs);
  72. }
  73. static StringView name() { return "%"sv; }
  74. };
  75. struct Average {
  76. template<typename Lhs, typename Rhs>
  77. auto operator()(Lhs lhs, Rhs rhs) const
  78. {
  79. return static_cast<Lhs>((lhs + rhs + 1) / 2);
  80. }
  81. static StringView name() { return "avgr"sv; }
  82. };
  83. struct BitShiftLeft {
  84. template<typename Lhs, typename Rhs>
  85. auto operator()(Lhs lhs, Rhs rhs) const { return lhs << (rhs % (sizeof(lhs) * 8)); }
  86. static StringView name() { return "<<"sv; }
  87. };
  88. struct BitShiftRight {
  89. template<typename Lhs, typename Rhs>
  90. auto operator()(Lhs lhs, Rhs rhs) const { return lhs >> (rhs % (sizeof(lhs) * 8)); }
  91. static StringView name() { return ">>"sv; }
  92. };
  93. struct BitAndNot {
  94. template<typename Lhs, typename Rhs>
  95. auto operator()(Lhs lhs, Rhs rhs) const { return lhs & ~rhs; }
  96. static StringView name() { return "andnot"sv; }
  97. };
  98. struct BitNot {
  99. template<typename Lhs>
  100. auto operator()(Lhs lhs) const { return ~lhs; }
  101. static StringView name() { return "~"sv; }
  102. };
  103. struct BitRotateLeft {
  104. template<typename Lhs, typename Rhs>
  105. auto operator()(Lhs lhs, Rhs rhs) const
  106. {
  107. // generates a single 'rol' instruction if shift is positive
  108. // otherwise generate a `ror`
  109. auto const mask = CHAR_BIT * sizeof(Lhs) - 1;
  110. rhs &= mask;
  111. return (lhs << rhs) | (lhs >> ((-rhs) & mask));
  112. }
  113. static StringView name() { return "rotate_left"sv; }
  114. };
  115. struct BitRotateRight {
  116. template<typename Lhs, typename Rhs>
  117. auto operator()(Lhs lhs, Rhs rhs) const
  118. {
  119. // generates a single 'ror' instruction if shift is positive
  120. // otherwise generate a `rol`
  121. auto const mask = CHAR_BIT * sizeof(Lhs) - 1;
  122. rhs &= mask;
  123. return (lhs >> rhs) | (lhs << ((-rhs) & mask));
  124. }
  125. static StringView name() { return "rotate_right"sv; }
  126. };
  127. template<size_t VectorSize, template<typename> typename SetSign = MakeSigned>
  128. struct VectorAllTrue {
  129. auto operator()(u128 c) const
  130. {
  131. using ElementType = NativeIntegralType<128 / VectorSize>;
  132. auto any_false = bit_cast<Native128ByteVectorOf<ElementType, SetSign>>(c) == 0;
  133. return bit_cast<u128>(any_false) == 0;
  134. }
  135. static StringView name()
  136. {
  137. switch (VectorSize) {
  138. case 16:
  139. return "vec(8x16).all_true"sv;
  140. case 8:
  141. return "vec(16x8).all_true"sv;
  142. case 4:
  143. return "vec(32x4).all_true"sv;
  144. case 2:
  145. return "vec(64x2).all_true"sv;
  146. default:
  147. VERIFY_NOT_REACHED();
  148. }
  149. }
  150. };
  151. template<size_t VectorSize>
  152. struct VectorShiftLeft {
  153. auto operator()(u128 lhs, i32 rhs) const
  154. {
  155. auto shift_value = rhs % (sizeof(lhs) * 8 / VectorSize);
  156. return bit_cast<u128>(bit_cast<Native128ByteVectorOf<NativeIntegralType<128 / VectorSize>, MakeUnsigned>>(lhs) << shift_value);
  157. }
  158. static StringView name()
  159. {
  160. switch (VectorSize) {
  161. case 16:
  162. return "vec(8x16)<<"sv;
  163. case 8:
  164. return "vec(16x8)<<"sv;
  165. case 4:
  166. return "vec(32x4)<<"sv;
  167. case 2:
  168. return "vec(64x2)<<"sv;
  169. default:
  170. VERIFY_NOT_REACHED();
  171. }
  172. }
  173. };
  174. template<size_t VectorSize, template<typename> typename SetSign>
  175. struct VectorShiftRight {
  176. auto operator()(u128 lhs, i32 rhs) const
  177. {
  178. auto shift_value = rhs % (sizeof(lhs) * 8 / VectorSize);
  179. return bit_cast<u128>(bit_cast<Native128ByteVectorOf<NativeIntegralType<128 / VectorSize>, SetSign>>(lhs) >> shift_value);
  180. }
  181. static StringView name()
  182. {
  183. switch (VectorSize) {
  184. case 16:
  185. return "vec(8x16)>>"sv;
  186. case 8:
  187. return "vec(16x8)>>"sv;
  188. case 4:
  189. return "vec(32x4)>>"sv;
  190. case 2:
  191. return "vec(64x2)>>"sv;
  192. default:
  193. VERIFY_NOT_REACHED();
  194. }
  195. }
  196. };
  197. struct VectorSwizzle {
  198. auto operator()(u128 c1, u128 c2) const
  199. {
  200. // https://webassembly.github.io/spec/core/bikeshed/#-mathsfi8x16hrefsyntax-instr-vecmathsfswizzle%E2%91%A0
  201. auto i = bit_cast<Native128ByteVectorOf<i8, MakeSigned>>(c2);
  202. auto j = bit_cast<Native128ByteVectorOf<i8, MakeSigned>>(c1);
  203. auto result = shuffle_or_0(i, j);
  204. return bit_cast<u128>(result);
  205. }
  206. static StringView name() { return "vec(8x16).swizzle"sv; }
  207. };
  208. template<size_t VectorSize, template<typename> typename SetSign>
  209. struct VectorExtractLane {
  210. size_t lane;
  211. auto operator()(u128 c) const
  212. {
  213. auto result = bit_cast<Native128ByteVectorOf<NativeIntegralType<128 / VectorSize>, SetSign>>(c);
  214. return result[lane];
  215. }
  216. static StringView name()
  217. {
  218. switch (VectorSize) {
  219. case 16:
  220. return "vec(8x16).extract_lane"sv;
  221. case 8:
  222. return "vec(16x8).extract_lane"sv;
  223. case 4:
  224. return "vec(32x4).extract_lane"sv;
  225. case 2:
  226. return "vec(64x2).extract_lane"sv;
  227. default:
  228. VERIFY_NOT_REACHED();
  229. }
  230. }
  231. };
  232. template<size_t VectorSize>
  233. struct VectorExtractLaneFloat {
  234. size_t lane;
  235. auto operator()(u128 c) const
  236. {
  237. auto result = bit_cast<NativeFloatingVectorType<128 / VectorSize, VectorSize>>(c);
  238. return result[lane];
  239. }
  240. static StringView name()
  241. {
  242. switch (VectorSize) {
  243. case 16:
  244. return "vec(8x16).extract_lane"sv;
  245. case 8:
  246. return "vec(16x8).extract_lane"sv;
  247. case 4:
  248. return "vec(32x4).extract_lane"sv;
  249. case 2:
  250. return "vec(64x2).extract_lane"sv;
  251. default:
  252. VERIFY_NOT_REACHED();
  253. }
  254. }
  255. };
  256. template<size_t VectorSize, typename TrueValueType = NativeIntegralType<128 / VectorSize>>
  257. struct VectorReplaceLane {
  258. size_t lane;
  259. using ValueType = Conditional<IsFloatingPoint<TrueValueType>, NativeFloatingType<128 / VectorSize>, NativeIntegralType<128 / VectorSize>>;
  260. auto operator()(u128 c, TrueValueType value) const
  261. {
  262. auto result = bit_cast<Native128ByteVectorOf<ValueType, MakeUnsigned>>(c);
  263. result[lane] = static_cast<ValueType>(value);
  264. return bit_cast<u128>(result);
  265. }
  266. static StringView name()
  267. {
  268. switch (VectorSize) {
  269. case 16:
  270. return "vec(8x16).replace_lane"sv;
  271. case 8:
  272. return "vec(16x8).replace_lane"sv;
  273. case 4:
  274. return "vec(32x4).replace_lane"sv;
  275. case 2:
  276. return "vec(64x2).replace_lane"sv;
  277. default:
  278. VERIFY_NOT_REACHED();
  279. }
  280. }
  281. };
  282. template<size_t VectorSize, typename Op, template<typename> typename SetSign = MakeSigned>
  283. struct VectorCmpOp {
  284. auto operator()(u128 c1, u128 c2) const
  285. {
  286. using ElementType = NativeIntegralType<128 / VectorSize>;
  287. auto result = bit_cast<Native128ByteVectorOf<ElementType, SetSign>>(c1);
  288. auto other = bit_cast<Native128ByteVectorOf<ElementType, SetSign>>(c2);
  289. Op op;
  290. for (size_t i = 0; i < VectorSize; ++i) {
  291. SetSign<ElementType> lhs = result[i];
  292. SetSign<ElementType> rhs = other[i];
  293. result[i] = op(lhs, rhs) ? static_cast<MakeUnsigned<ElementType>>(-1) : 0;
  294. }
  295. return bit_cast<u128>(result);
  296. }
  297. static StringView name()
  298. {
  299. switch (VectorSize) {
  300. case 16:
  301. return "vec(8x16).cmp"sv;
  302. case 8:
  303. return "vec(16x8).cmp"sv;
  304. case 4:
  305. return "vec(32x4).cmp"sv;
  306. case 2:
  307. return "vec(64x2).cmp"sv;
  308. default:
  309. VERIFY_NOT_REACHED();
  310. }
  311. }
  312. };
  313. template<size_t VectorSize, typename Op>
  314. struct VectorFloatCmpOp {
  315. auto operator()(u128 c1, u128 c2) const
  316. {
  317. auto first = bit_cast<NativeFloatingVectorType<128, VectorSize, NativeFloatingType<128 / VectorSize>>>(c1);
  318. auto other = bit_cast<NativeFloatingVectorType<128, VectorSize, NativeFloatingType<128 / VectorSize>>>(c2);
  319. using ElementType = NativeIntegralType<128 / VectorSize>;
  320. Native128ByteVectorOf<ElementType, MakeUnsigned> result;
  321. Op op;
  322. for (size_t i = 0; i < VectorSize; ++i)
  323. result[i] = op(first[i], other[i]) ? static_cast<ElementType>(-1) : 0;
  324. return bit_cast<u128>(result);
  325. }
  326. static StringView name()
  327. {
  328. switch (VectorSize) {
  329. case 4:
  330. return "vecf(32x4).cmp"sv;
  331. case 2:
  332. return "vecf(64x2).cmp"sv;
  333. default:
  334. VERIFY_NOT_REACHED();
  335. }
  336. }
  337. };
  338. struct Minimum {
  339. template<typename Lhs, typename Rhs>
  340. auto operator()(Lhs lhs, Rhs rhs) const
  341. {
  342. if constexpr (IsFloatingPoint<Lhs> || IsFloatingPoint<Rhs>) {
  343. if (isnan(lhs) || isnan(rhs)) {
  344. return isnan(lhs) ? lhs : rhs;
  345. }
  346. if (lhs == 0 && rhs == 0) {
  347. return signbit(lhs) ? lhs : rhs;
  348. }
  349. }
  350. return min(lhs, rhs);
  351. }
  352. static StringView name() { return "minimum"sv; }
  353. };
  354. struct Maximum {
  355. template<typename Lhs, typename Rhs>
  356. auto operator()(Lhs lhs, Rhs rhs) const
  357. {
  358. if constexpr (IsFloatingPoint<Lhs> || IsFloatingPoint<Rhs>) {
  359. if (isnan(lhs) || isnan(rhs)) {
  360. return isnan(lhs) ? lhs : rhs;
  361. }
  362. if (lhs == 0 && rhs == 0) {
  363. return signbit(lhs) ? rhs : lhs;
  364. }
  365. }
  366. return max(lhs, rhs);
  367. }
  368. static StringView name() { return "maximum"sv; }
  369. };
  370. struct PseudoMinimum {
  371. template<typename Lhs, typename Rhs>
  372. auto operator()(Lhs lhs, Rhs rhs) const
  373. {
  374. return rhs < lhs ? rhs : lhs;
  375. }
  376. static StringView name() { return "pseudo_minimum"sv; }
  377. };
  378. struct PseudoMaximum {
  379. template<typename Lhs, typename Rhs>
  380. auto operator()(Lhs lhs, Rhs rhs) const
  381. {
  382. return lhs < rhs ? rhs : lhs;
  383. }
  384. static StringView name() { return "pseudo_maximum"sv; }
  385. };
  386. struct CopySign {
  387. template<typename Lhs, typename Rhs>
  388. auto operator()(Lhs lhs, Rhs rhs) const
  389. {
  390. if constexpr (IsSame<Lhs, float>)
  391. return copysignf(lhs, rhs);
  392. else if constexpr (IsSame<Lhs, double>)
  393. return copysign(lhs, rhs);
  394. else
  395. static_assert(DependentFalse<Lhs, Rhs>, "Invalid types to CopySign");
  396. }
  397. static StringView name() { return "copysign"sv; }
  398. };
  399. // Unary
  400. struct EqualsZero {
  401. template<typename Lhs>
  402. auto operator()(Lhs lhs) const { return lhs == 0; }
  403. static StringView name() { return "== 0"sv; }
  404. };
  405. struct CountLeadingZeros {
  406. template<typename Lhs>
  407. i32 operator()(Lhs lhs) const
  408. {
  409. if (lhs == 0)
  410. return sizeof(Lhs) * CHAR_BIT;
  411. if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
  412. return count_leading_zeroes(MakeUnsigned<Lhs>(lhs));
  413. else
  414. VERIFY_NOT_REACHED();
  415. }
  416. static StringView name() { return "clz"sv; }
  417. };
  418. struct CountTrailingZeros {
  419. template<typename Lhs>
  420. i32 operator()(Lhs lhs) const
  421. {
  422. if (lhs == 0)
  423. return sizeof(Lhs) * CHAR_BIT;
  424. if constexpr (sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
  425. return count_trailing_zeroes(MakeUnsigned<Lhs>(lhs));
  426. else
  427. VERIFY_NOT_REACHED();
  428. }
  429. static StringView name() { return "ctz"sv; }
  430. };
  431. struct PopCount {
  432. template<typename Lhs>
  433. auto operator()(Lhs lhs) const
  434. {
  435. if constexpr (sizeof(Lhs) == 1 || sizeof(Lhs) == 2 || sizeof(Lhs) == 4 || sizeof(Lhs) == 8)
  436. return popcount(MakeUnsigned<Lhs>(lhs));
  437. else
  438. VERIFY_NOT_REACHED();
  439. }
  440. static StringView name() { return "popcnt"sv; }
  441. };
  442. struct Absolute {
  443. template<typename Lhs>
  444. Lhs operator()(Lhs lhs) const
  445. {
  446. if constexpr (IsFloatingPoint<Lhs>)
  447. return AK::abs(lhs);
  448. if constexpr (IsSigned<Lhs>) {
  449. if (lhs == NumericLimits<Lhs>::min())
  450. return NumericLimits<Lhs>::min(); // Return the negation of _i_ modulo 2^N: https://www.w3.org/TR/wasm-core-2/#-hrefop-iabsmathrmiabs_n-i step 3
  451. }
  452. return AK::abs(lhs);
  453. }
  454. static StringView name() { return "abs"sv; }
  455. };
  456. struct Negate {
  457. template<typename Lhs>
  458. Lhs operator()(Lhs lhs) const
  459. {
  460. if constexpr (IsFloatingPoint<Lhs>)
  461. return -lhs;
  462. if constexpr (IsSigned<Lhs>) {
  463. if (lhs == NumericLimits<Lhs>::min())
  464. return NumericLimits<Lhs>::min(); // Return the negation of _i_ modulo 2^N: https://www.w3.org/TR/wasm-core-2/#-hrefop-iabsmathrmiabs_n-i step 3
  465. }
  466. return -lhs;
  467. }
  468. static StringView name() { return "== 0"sv; }
  469. };
  470. struct Ceil {
  471. template<typename Lhs>
  472. auto operator()(Lhs lhs) const
  473. {
  474. if constexpr (IsSame<Lhs, float>)
  475. return ceilf(lhs);
  476. else if constexpr (IsSame<Lhs, double>)
  477. return ceil(lhs);
  478. else
  479. VERIFY_NOT_REACHED();
  480. }
  481. static StringView name() { return "ceil"sv; }
  482. };
  483. template<size_t VectorSize, typename Op, template<typename> typename SetSign = MakeSigned>
  484. struct VectorIntegerExtOpPairwise {
  485. auto operator()(u128 c) const
  486. {
  487. using VectorResult = NativeVectorType<128 / VectorSize, VectorSize, SetSign>;
  488. using VectorInput = NativeVectorType<128 / (VectorSize * 2), VectorSize * 2, SetSign>;
  489. auto vector = bit_cast<VectorInput>(c);
  490. VectorResult result;
  491. Op op;
  492. // FIXME: Find a way to not loop here
  493. for (size_t i = 0; i < VectorSize; ++i) {
  494. result[i] = op(vector[i * 2], vector[(i * 2) + 1]);
  495. }
  496. return bit_cast<u128>(result);
  497. }
  498. static StringView name()
  499. {
  500. switch (VectorSize) {
  501. case 8:
  502. return "vec(16x8).ext_op_pairwise(8x16)"sv;
  503. case 4:
  504. return "vec(32x4).ext_op_pairwise(16x8)"sv;
  505. case 2:
  506. return "vec(64x2).ext_op_pairwise(32x4)"sv;
  507. default:
  508. VERIFY_NOT_REACHED();
  509. }
  510. }
  511. };
  512. enum class VectorExt {
  513. High,
  514. Low,
  515. };
  516. template<size_t VectorSize, VectorExt Mode, template<typename> typename SetSign = MakeSigned>
  517. struct VectorIntegerExt {
  518. auto operator()(u128 c) const
  519. {
  520. using VectorResult = NativeVectorType<128 / VectorSize, VectorSize, SetSign>;
  521. using VectorInput = NativeVectorType<128 / (VectorSize * 2), VectorSize * 2, SetSign>;
  522. auto vector = bit_cast<VectorInput>(c);
  523. VectorResult result;
  524. // FIXME: Find a way to not loop here
  525. for (size_t i = 0; i < VectorSize; ++i) {
  526. if constexpr (Mode == VectorExt::High)
  527. result[i] = vector[VectorSize + i];
  528. else if constexpr (Mode == VectorExt::Low)
  529. result[i] = vector[i];
  530. else
  531. VERIFY_NOT_REACHED();
  532. }
  533. return bit_cast<u128>(result);
  534. }
  535. static StringView name()
  536. {
  537. switch (VectorSize) {
  538. case 8:
  539. return "vec(16x8).ext(8x16)"sv;
  540. case 4:
  541. return "vec(32x4).ext(16x8)"sv;
  542. case 2:
  543. return "vec(64x2).ext(32x4)"sv;
  544. default:
  545. VERIFY_NOT_REACHED();
  546. }
  547. }
  548. };
  549. template<size_t VectorSize, typename Op, VectorExt Mode, template<typename> typename SetSign = MakeSigned>
  550. struct VectorIntegerExtOp {
  551. auto operator()(u128 lhs, u128 rhs) const
  552. {
  553. using VectorResult = NativeVectorType<128 / VectorSize, VectorSize, SetSign>;
  554. using VectorInput = NativeVectorType<128 / (VectorSize * 2), VectorSize * 2, SetSign>;
  555. auto first = bit_cast<VectorInput>(lhs);
  556. auto second = bit_cast<VectorInput>(rhs);
  557. VectorResult result;
  558. Op op;
  559. using ResultType = SetSign<NativeIntegralType<128 / VectorSize>>;
  560. // FIXME: Find a way to not loop here
  561. for (size_t i = 0; i < VectorSize; ++i) {
  562. if constexpr (Mode == VectorExt::High) {
  563. ResultType a = first[VectorSize + i];
  564. ResultType b = second[VectorSize + i];
  565. result[i] = op(a, b);
  566. } else if constexpr (Mode == VectorExt::Low) {
  567. ResultType a = first[i];
  568. ResultType b = second[i];
  569. result[i] = op(a, b);
  570. } else
  571. VERIFY_NOT_REACHED();
  572. }
  573. return bit_cast<u128>(result);
  574. }
  575. static StringView name()
  576. {
  577. switch (VectorSize) {
  578. case 8:
  579. return "vec(16x8).ext_op(8x16)"sv;
  580. case 4:
  581. return "vec(32x4).ext_op(16x8)"sv;
  582. case 2:
  583. return "vec(64x2).ext_op(32x4)"sv;
  584. default:
  585. VERIFY_NOT_REACHED();
  586. }
  587. }
  588. };
  589. template<size_t VectorSize, typename Op, template<typename> typename SetSign = MakeSigned>
  590. struct VectorIntegerBinaryOp {
  591. auto operator()(u128 lhs, u128 rhs) const
  592. {
  593. using VectorType = NativeVectorType<128 / VectorSize, VectorSize, SetSign>;
  594. auto first = bit_cast<VectorType>(lhs);
  595. auto second = bit_cast<VectorType>(rhs);
  596. VectorType result;
  597. Op op;
  598. // FIXME: Find a way to not loop here
  599. for (size_t i = 0; i < VectorSize; ++i) {
  600. result[i] = op(first[i], second[i]);
  601. }
  602. return bit_cast<u128>(result);
  603. }
  604. static StringView name()
  605. {
  606. switch (VectorSize) {
  607. case 16:
  608. return "vec(8x16).binary_op"sv;
  609. case 8:
  610. return "vec(16x8).binary_op"sv;
  611. case 4:
  612. return "vec(32x4).binary_op"sv;
  613. case 2:
  614. return "vec(64x2).binary_op"sv;
  615. default:
  616. VERIFY_NOT_REACHED();
  617. }
  618. }
  619. };
  620. template<size_t VectorSize, typename Op, template<typename> typename SetSign = MakeSigned>
  621. struct VectorIntegerUnaryOp {
  622. auto operator()(u128 lhs) const
  623. {
  624. using VectorType = NativeVectorType<128 / VectorSize, VectorSize, SetSign>;
  625. auto value = bit_cast<VectorType>(lhs);
  626. VectorType result;
  627. Op op;
  628. // FIXME: Find a way to not loop here
  629. for (size_t i = 0; i < VectorSize; ++i) {
  630. result[i] = op(value[i]);
  631. }
  632. return bit_cast<u128>(result);
  633. }
  634. static StringView name()
  635. {
  636. switch (VectorSize) {
  637. case 16:
  638. return "vec(8x16).unary_op"sv;
  639. case 8:
  640. return "vec(16x8).unary_op"sv;
  641. case 4:
  642. return "vec(32x4).unary_op"sv;
  643. case 2:
  644. return "vec(64x2).unary_op"sv;
  645. default:
  646. VERIFY_NOT_REACHED();
  647. }
  648. }
  649. };
  650. template<size_t VectorSize, typename Op>
  651. struct VectorFloatBinaryOp {
  652. auto operator()(u128 lhs, u128 rhs) const
  653. {
  654. using VectorType = NativeFloatingVectorType<128, VectorSize, NativeFloatingType<128 / VectorSize>>;
  655. auto first = bit_cast<VectorType>(lhs);
  656. auto second = bit_cast<VectorType>(rhs);
  657. VectorType result;
  658. Op op;
  659. for (size_t i = 0; i < VectorSize; ++i) {
  660. result[i] = op(first[i], second[i]);
  661. }
  662. return bit_cast<u128>(result);
  663. }
  664. static StringView name()
  665. {
  666. switch (VectorSize) {
  667. case 4:
  668. return "vecf(32x4).binary_op"sv;
  669. case 2:
  670. return "vecf(64x2).binary_op"sv;
  671. default:
  672. VERIFY_NOT_REACHED();
  673. }
  674. }
  675. };
  676. template<size_t VectorSize, typename Op>
  677. struct VectorFloatUnaryOp {
  678. auto operator()(u128 lhs) const
  679. {
  680. using VectorType = NativeFloatingVectorType<128, VectorSize, NativeFloatingType<128 / VectorSize>>;
  681. auto value = bit_cast<VectorType>(lhs);
  682. VectorType result;
  683. Op op;
  684. for (size_t i = 0; i < VectorSize; ++i) {
  685. result[i] = op(value[i]);
  686. }
  687. return bit_cast<u128>(result);
  688. }
  689. static StringView name()
  690. {
  691. switch (VectorSize) {
  692. case 4:
  693. return "vecf(32x4).unary_op"sv;
  694. case 2:
  695. return "vecf(64x2).unary_op"sv;
  696. default:
  697. VERIFY_NOT_REACHED();
  698. }
  699. }
  700. };
  701. struct Floor {
  702. template<typename Lhs>
  703. auto operator()(Lhs lhs) const
  704. {
  705. if constexpr (IsSame<Lhs, float>)
  706. return floorf(lhs);
  707. else if constexpr (IsSame<Lhs, double>)
  708. return floor(lhs);
  709. else
  710. VERIFY_NOT_REACHED();
  711. }
  712. static StringView name() { return "floor"sv; }
  713. };
  714. struct Truncate {
  715. template<typename Lhs>
  716. auto operator()(Lhs lhs) const
  717. {
  718. if constexpr (IsSame<Lhs, float>)
  719. return truncf(lhs);
  720. else if constexpr (IsSame<Lhs, double>)
  721. return trunc(lhs);
  722. else
  723. VERIFY_NOT_REACHED();
  724. }
  725. static StringView name() { return "truncate"sv; }
  726. };
  727. struct NearbyIntegral {
  728. template<typename Lhs>
  729. auto operator()(Lhs lhs) const
  730. {
  731. if constexpr (IsSame<Lhs, float>)
  732. return nearbyintf(lhs);
  733. else if constexpr (IsSame<Lhs, double>)
  734. return nearbyint(lhs);
  735. else
  736. VERIFY_NOT_REACHED();
  737. }
  738. static StringView name() { return "round"sv; }
  739. };
  740. struct SquareRoot {
  741. template<typename Lhs>
  742. auto operator()(Lhs lhs) const
  743. {
  744. if constexpr (IsSame<Lhs, float>)
  745. return sqrtf(lhs);
  746. else if constexpr (IsSame<Lhs, double>)
  747. return sqrt(lhs);
  748. else
  749. VERIFY_NOT_REACHED();
  750. }
  751. static StringView name() { return "sqrt"sv; }
  752. };
  753. template<typename Result>
  754. struct Wrap {
  755. template<typename Lhs>
  756. Result operator()(Lhs lhs) const
  757. {
  758. return static_cast<MakeUnsigned<Result>>(bit_cast<MakeUnsigned<Lhs>>(lhs));
  759. }
  760. static StringView name() { return "wrap"sv; }
  761. };
  762. template<typename ResultT>
  763. struct CheckedTruncate {
  764. template<typename Lhs>
  765. AK::ErrorOr<ResultT, StringView> operator()(Lhs lhs) const
  766. {
  767. if (isnan(lhs) || isinf(lhs)) // "undefined", let's just trap.
  768. return "Truncation undefined behavior"sv;
  769. Lhs truncated;
  770. if constexpr (IsSame<float, Lhs>)
  771. truncated = truncf(lhs);
  772. else if constexpr (IsSame<double, Lhs>)
  773. truncated = trunc(lhs);
  774. else
  775. VERIFY_NOT_REACHED();
  776. // FIXME: This function assumes that all values of ResultT are representable in Lhs
  777. // the assumption comes from the fact that this was used exclusively by LibJS,
  778. // which only considers values that are all representable in 'double'.
  779. if (!AK::is_within_range<ResultT>(truncated))
  780. return "Truncation out of range"sv;
  781. return static_cast<ResultT>(truncated);
  782. }
  783. static StringView name() { return "truncate.checked"sv; }
  784. };
  785. template<typename ResultT>
  786. struct Extend {
  787. template<typename Lhs>
  788. ResultT operator()(Lhs lhs) const
  789. {
  790. return lhs;
  791. }
  792. static StringView name() { return "extend"sv; }
  793. };
  794. template<typename ResultT>
  795. struct Convert {
  796. template<typename Lhs>
  797. ResultT operator()(Lhs lhs) const
  798. {
  799. auto interpretation = bit_cast<Lhs>(lhs);
  800. return static_cast<ResultT>(interpretation);
  801. }
  802. static StringView name() { return "convert"sv; }
  803. };
  804. template<typename ResultT>
  805. struct Reinterpret {
  806. template<typename Lhs>
  807. ResultT operator()(Lhs lhs) const
  808. {
  809. return bit_cast<ResultT>(lhs);
  810. }
  811. static StringView name() { return "reinterpret"sv; }
  812. };
  813. struct Promote {
  814. double operator()(float lhs) const
  815. {
  816. if (isnan(lhs))
  817. return nan(""); // FIXME: Ensure canonical NaN remains canonical
  818. return static_cast<double>(lhs);
  819. }
  820. static StringView name() { return "promote"sv; }
  821. };
  822. struct Demote {
  823. float operator()(double lhs) const
  824. {
  825. if (isnan(lhs))
  826. return nanf(""); // FIXME: Ensure canonical NaN remains canonical
  827. if (isinf(lhs))
  828. return copysignf(__builtin_huge_valf(), lhs);
  829. return static_cast<float>(lhs);
  830. }
  831. static StringView name() { return "demote"sv; }
  832. };
  833. template<typename InitialType>
  834. struct SignExtend {
  835. template<typename Lhs>
  836. Lhs operator()(Lhs lhs) const
  837. {
  838. auto unsigned_representation = bit_cast<MakeUnsigned<Lhs>>(lhs);
  839. auto truncated_unsigned_representation = static_cast<MakeUnsigned<InitialType>>(unsigned_representation);
  840. auto initial_value = bit_cast<InitialType>(truncated_unsigned_representation);
  841. return static_cast<Lhs>(initial_value);
  842. }
  843. static StringView name() { return "extend"sv; }
  844. };
  845. template<typename ResultT>
  846. struct SaturatingTruncate {
  847. template<typename Lhs>
  848. ResultT operator()(Lhs lhs) const
  849. {
  850. if (isnan(lhs))
  851. return 0;
  852. if (isinf(lhs)) {
  853. if (lhs < 0)
  854. return NumericLimits<ResultT>::min();
  855. return NumericLimits<ResultT>::max();
  856. }
  857. // FIXME: This assumes that all values in ResultT are representable in 'double'.
  858. // that assumption is not correct, which makes this function yield incorrect values
  859. // for 'edge' values of type i64.
  860. constexpr auto convert = []<typename ConvertT>(ConvertT truncated_value) {
  861. if (truncated_value < NumericLimits<ResultT>::min())
  862. return NumericLimits<ResultT>::min();
  863. if constexpr (IsSame<ConvertT, float>) {
  864. if (truncated_value >= static_cast<ConvertT>(NumericLimits<ResultT>::max()))
  865. return NumericLimits<ResultT>::max();
  866. } else {
  867. if (static_cast<double>(truncated_value) >= static_cast<double>(NumericLimits<ResultT>::max()))
  868. return NumericLimits<ResultT>::max();
  869. }
  870. return static_cast<ResultT>(truncated_value);
  871. };
  872. if constexpr (IsSame<Lhs, float>)
  873. return convert(truncf(lhs));
  874. else
  875. return convert(trunc(lhs));
  876. }
  877. static StringView name() { return "truncate.saturating"sv; }
  878. };
  879. template<typename ResultT, typename Op>
  880. struct SaturatingOp {
  881. template<typename Lhs, typename Rhs>
  882. ResultT operator()(Lhs lhs, Rhs rhs) const
  883. {
  884. Op op;
  885. double result = op(lhs, rhs);
  886. if (result <= static_cast<double>(NumericLimits<ResultT>::min())) {
  887. return NumericLimits<ResultT>::min();
  888. }
  889. if (result >= static_cast<double>(NumericLimits<ResultT>::max())) {
  890. return NumericLimits<ResultT>::max();
  891. }
  892. return static_cast<ResultT>(result);
  893. }
  894. static StringView name() { return "saturating_op"sv; }
  895. };
  896. }