Operators.h 33 KB

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