1 /*
2 * Copyright 2016 WebAssembly Community Group participants
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "literal.h"
18
19 #include <cassert>
20 #include <cmath>
21
22 #include "emscripten-optimizer/simple_ast.h"
23 #include "ir/bits.h"
24 #include "pretty_printing.h"
25 #include "support/bits.h"
26 #include "support/utilities.h"
27
28 namespace wasm {
29
30 template<int N> using LaneArray = std::array<Literal, N>;
31
Literal(Type type)32 Literal::Literal(Type type) : type(type) {
33 if (type == Type::i31ref) {
34 // i31ref is special in that it is non-nullable, so we construct with zero
35 i32 = 0;
36 } else {
37 assert(type != Type::unreachable && (!type.isRef() || type.isNullable()));
38 if (type.isException()) {
39 new (&exn) std::unique_ptr<ExceptionPackage>();
40 } else {
41 memset(&v128, 0, 16);
42 }
43 }
44 }
45
Literal(const uint8_t init[16])46 Literal::Literal(const uint8_t init[16]) : type(Type::v128) {
47 memcpy(&v128, init, 16);
48 }
49
Literal(const Literal & other)50 Literal::Literal(const Literal& other) : type(other.type) {
51 if (type.isException()) {
52 // Avoid calling the destructor on an uninitialized value
53 if (other.exn != nullptr) {
54 new (&exn) auto(std::make_unique<ExceptionPackage>(*other.exn));
55 } else {
56 new (&exn) std::unique_ptr<ExceptionPackage>();
57 }
58 } else if (type.isFunction()) {
59 func = other.func;
60 } else {
61 TODO_SINGLE_COMPOUND(type);
62 switch (type.getBasic()) {
63 case Type::i32:
64 case Type::f32:
65 case Type::i31ref:
66 i32 = other.i32;
67 break;
68 case Type::i64:
69 case Type::f64:
70 i64 = other.i64;
71 break;
72 case Type::v128:
73 memcpy(&v128, other.v128, 16);
74 break;
75 case Type::none:
76 break;
77 case Type::externref:
78 case Type::anyref:
79 case Type::eqref:
80 break; // null
81 case Type::funcref:
82 case Type::exnref:
83 case Type::unreachable:
84 WASM_UNREACHABLE("unexpected type");
85 }
86 }
87 }
88
operator =(const Literal & other)89 Literal& Literal::operator=(const Literal& other) {
90 if (this != &other) {
91 this->~Literal();
92 new (this) auto(other);
93 }
94 return *this;
95 }
96
97 template<typename LaneT, int Lanes>
extractBytes(uint8_t (& dest)[16],const LaneArray<Lanes> & lanes)98 static void extractBytes(uint8_t (&dest)[16], const LaneArray<Lanes>& lanes) {
99 std::array<uint8_t, 16> bytes;
100 const size_t lane_width = 16 / Lanes;
101 for (size_t lane_index = 0; lane_index < Lanes; ++lane_index) {
102 uint8_t bits[16];
103 lanes[lane_index].getBits(bits);
104 LaneT lane;
105 memcpy(&lane, bits, sizeof(lane));
106 for (size_t offset = 0; offset < lane_width; ++offset) {
107 bytes.at(lane_index * lane_width + offset) =
108 uint8_t(lane >> (8 * offset));
109 }
110 }
111 memcpy(&dest, bytes.data(), sizeof(bytes));
112 }
113
Literal(const LaneArray<16> & lanes)114 Literal::Literal(const LaneArray<16>& lanes) : type(Type::v128) {
115 extractBytes<uint8_t, 16>(v128, lanes);
116 }
117
Literal(const LaneArray<8> & lanes)118 Literal::Literal(const LaneArray<8>& lanes) : type(Type::v128) {
119 extractBytes<uint16_t, 8>(v128, lanes);
120 }
121
Literal(const LaneArray<4> & lanes)122 Literal::Literal(const LaneArray<4>& lanes) : type(Type::v128) {
123 extractBytes<uint32_t, 4>(v128, lanes);
124 }
125
Literal(const LaneArray<2> & lanes)126 Literal::Literal(const LaneArray<2>& lanes) : type(Type::v128) {
127 extractBytes<uint64_t, 2>(v128, lanes);
128 }
129
makeZeros(Type type)130 Literals Literal::makeZeros(Type type) {
131 assert(type.isConcrete());
132 Literals zeroes;
133 for (const auto& t : type) {
134 zeroes.push_back(makeZero(t));
135 }
136 return zeroes;
137 }
138
makeOnes(Type type)139 Literals Literal::makeOnes(Type type) {
140 assert(type.isConcrete());
141 Literals units;
142 for (const auto& t : type) {
143 units.push_back(makeOne(t));
144 }
145 return units;
146 }
147
makeNegOnes(Type type)148 Literals Literal::makeNegOnes(Type type) {
149 assert(type.isConcrete());
150 Literals units;
151 for (const auto& t : type) {
152 units.push_back(makeNegOne(t));
153 }
154 return units;
155 }
156
makeZero(Type type)157 Literal Literal::makeZero(Type type) {
158 assert(type.isSingle());
159 if (type.isRef()) {
160 if (type == Type::i31ref) {
161 return makeI31(0);
162 } else {
163 return makeNull(type);
164 }
165 } else {
166 return makeFromInt32(0, type);
167 }
168 }
169
makeOne(Type type)170 Literal Literal::makeOne(Type type) {
171 assert(type.isNumber());
172 return makeFromInt32(1, type);
173 }
174
makeNegOne(Type type)175 Literal Literal::makeNegOne(Type type) {
176 assert(type.isNumber());
177 return makeFromInt32(-1, type);
178 }
179
getv128() const180 std::array<uint8_t, 16> Literal::getv128() const {
181 assert(type == Type::v128);
182 std::array<uint8_t, 16> ret;
183 memcpy(ret.data(), v128, sizeof(ret));
184 return ret;
185 }
186
getExceptionPackage() const187 ExceptionPackage Literal::getExceptionPackage() const {
188 assert(type.isException() && exn != nullptr);
189 return *exn;
190 }
191
castToF32()192 Literal Literal::castToF32() {
193 assert(type == Type::i32);
194 Literal ret(Type::f32);
195 ret.i32 = i32;
196 return ret;
197 }
198
castToF64()199 Literal Literal::castToF64() {
200 assert(type == Type::i64);
201 Literal ret(Type::f64);
202 ret.i64 = i64;
203 return ret;
204 }
205
castToI32()206 Literal Literal::castToI32() {
207 assert(type == Type::f32);
208 Literal ret(Type::i32);
209 ret.i32 = i32;
210 return ret;
211 }
212
castToI64()213 Literal Literal::castToI64() {
214 assert(type == Type::f64);
215 Literal ret(Type::i64);
216 ret.i64 = i64;
217 return ret;
218 }
219
getInteger() const220 int64_t Literal::getInteger() const {
221 switch (type.getBasic()) {
222 case Type::i32:
223 return i32;
224 case Type::i64:
225 return i64;
226 default:
227 abort();
228 }
229 }
230
getUnsigned() const231 uint64_t Literal::getUnsigned() const {
232 switch (type.getBasic()) {
233 case Type::i32:
234 return static_cast<uint32_t>(i32);
235 case Type::i64:
236 return i64;
237 default:
238 abort();
239 }
240 }
241
getFloat() const242 double Literal::getFloat() const {
243 switch (type.getBasic()) {
244 case Type::f32:
245 return getf32();
246 case Type::f64:
247 return getf64();
248 default:
249 abort();
250 }
251 }
252
getBits(uint8_t (& buf)[16]) const253 void Literal::getBits(uint8_t (&buf)[16]) const {
254 memset(buf, 0, 16);
255 switch (type.getBasic()) {
256 case Type::i32:
257 case Type::f32:
258 memcpy(buf, &i32, sizeof(i32));
259 break;
260 case Type::i64:
261 case Type::f64:
262 memcpy(buf, &i64, sizeof(i64));
263 break;
264 case Type::v128:
265 memcpy(buf, &v128, sizeof(v128));
266 break;
267 case Type::none:
268 case Type::unreachable:
269 case Type::funcref:
270 case Type::externref:
271 case Type::exnref:
272 case Type::anyref:
273 case Type::eqref:
274 case Type::i31ref:
275 WASM_UNREACHABLE("invalid type");
276 }
277 }
278
operator ==(const Literal & other) const279 bool Literal::operator==(const Literal& other) const {
280 if (type != other.type) {
281 return false;
282 }
283 auto compareRef = [&]() {
284 assert(type.isRef());
285 if (isNull() || other.isNull()) {
286 return isNull() == other.isNull();
287 }
288 if (type.isFunction()) {
289 assert(func.is() && other.func.is());
290 return func == other.func;
291 }
292 if (type.isException()) {
293 assert(exn != nullptr && other.exn != nullptr);
294 return *exn == *other.exn;
295 }
296 // other non-null reference type literals cannot represent concrete values,
297 // i.e. there is no concrete externref, anyref or eqref other than null.
298 WASM_UNREACHABLE("unexpected type");
299 };
300 if (type.isBasic()) {
301 switch (type.getBasic()) {
302 case Type::none:
303 return true; // special voided literal
304 case Type::i32:
305 case Type::f32:
306 case Type::i31ref:
307 return i32 == other.i32;
308 case Type::i64:
309 case Type::f64:
310 return i64 == other.i64;
311 case Type::v128:
312 return memcmp(v128, other.v128, 16) == 0;
313 case Type::funcref:
314 case Type::externref:
315 case Type::exnref:
316 case Type::anyref:
317 case Type::eqref:
318 return compareRef();
319 case Type::unreachable:
320 break;
321 }
322 } else if (type.isRef()) {
323 return compareRef();
324 } else if (type.isRtt()) {
325 WASM_UNREACHABLE("TODO: rtt literals");
326 }
327 WASM_UNREACHABLE("unexpected type");
328 }
329
operator !=(const Literal & other) const330 bool Literal::operator!=(const Literal& other) const {
331 return !(*this == other);
332 }
333
isNaN()334 bool Literal::isNaN() {
335 if (type == Type::f32 && std::isnan(getf32())) {
336 return true;
337 }
338 if (type == Type::f64 && std::isnan(getf64())) {
339 return true;
340 }
341 // TODO: SIMD?
342 return false;
343 }
344
NaNPayload(float f)345 uint32_t Literal::NaNPayload(float f) {
346 assert(std::isnan(f) && "expected a NaN");
347 // SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF
348 // NaN has all-one exponent and non-zero fraction.
349 return ~0xff800000u & bit_cast<uint32_t>(f);
350 }
351
NaNPayload(double f)352 uint64_t Literal::NaNPayload(double f) {
353 assert(std::isnan(f) && "expected a NaN");
354 // SEEEEEEE EEEEFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
355 // NaN has all-one exponent and non-zero fraction.
356 return ~0xfff0000000000000ull & bit_cast<uint64_t>(f);
357 }
358
setQuietNaN(float f)359 float Literal::setQuietNaN(float f) {
360 assert(std::isnan(f) && "expected a NaN");
361 // An SNaN is a NaN with the most significant fraction bit clear.
362 return bit_cast<float>(0x00400000u | bit_cast<uint32_t>(f));
363 }
364
setQuietNaN(double f)365 double Literal::setQuietNaN(double f) {
366 assert(std::isnan(f) && "expected a NaN");
367 // An SNaN is a NaN with the most significant fraction bit clear.
368 return bit_cast<double>(0x0008000000000000ull | bit_cast<uint64_t>(f));
369 }
370
printFloat(std::ostream & o,float f)371 void Literal::printFloat(std::ostream& o, float f) {
372 if (std::isnan(f)) {
373 const char* sign = std::signbit(f) ? "-" : "";
374 o << sign << "nan";
375 if (uint32_t payload = NaNPayload(f)) {
376 o << ":0x" << std::hex << payload << std::dec;
377 }
378 return;
379 }
380 printDouble(o, f);
381 }
382
printDouble(std::ostream & o,double d)383 void Literal::printDouble(std::ostream& o, double d) {
384 if (d == 0 && std::signbit(d)) {
385 o << "-0";
386 return;
387 }
388 if (std::isnan(d)) {
389 const char* sign = std::signbit(d) ? "-" : "";
390 o << sign << "nan";
391 if (uint64_t payload = NaNPayload(d)) {
392 o << ":0x" << std::hex << payload << std::dec;
393 }
394 return;
395 }
396 if (!std::isfinite(d)) {
397 o << (std::signbit(d) ? "-inf" : "inf");
398 return;
399 }
400 const char* text = cashew::JSPrinter::numToString(d);
401 // spec interpreter hates floats starting with '.'
402 if (text[0] == '.') {
403 o << '0';
404 } else if (text[0] == '-' && text[1] == '.') {
405 o << "-0";
406 text++;
407 }
408 o << text;
409 }
410
printVec128(std::ostream & o,const std::array<uint8_t,16> & v)411 void Literal::printVec128(std::ostream& o, const std::array<uint8_t, 16>& v) {
412 o << std::hex;
413 for (auto i = 0; i < 16; i += 4) {
414 if (i) {
415 o << " ";
416 }
417 o << "0x" << std::setfill('0') << std::setw(8)
418 << uint32_t(v[i] | (v[i + 1] << 8) | (v[i + 2] << 16) | (v[i + 3] << 24));
419 }
420 o << std::dec;
421 }
422
operator <<(std::ostream & o,Literal literal)423 std::ostream& operator<<(std::ostream& o, Literal literal) {
424 prepareMinorColor(o);
425 TODO_SINGLE_COMPOUND(literal.type);
426 switch (literal.type.getBasic()) {
427 case Type::none:
428 o << "?";
429 break;
430 case Type::i32:
431 o << literal.geti32();
432 break;
433 case Type::i64:
434 o << literal.geti64();
435 break;
436 case Type::f32:
437 literal.printFloat(o, literal.getf32());
438 break;
439 case Type::f64:
440 literal.printDouble(o, literal.getf64());
441 break;
442 case Type::v128:
443 o << "i32x4 ";
444 literal.printVec128(o, literal.getv128());
445 break;
446 case Type::funcref:
447 if (literal.isNull()) {
448 o << "funcref(null)";
449 } else {
450 o << "funcref(" << literal.getFunc() << ")";
451 }
452 break;
453 case Type::externref:
454 assert(literal.isNull() && "unexpected non-null externref literal");
455 o << "externref(null)";
456 break;
457 case Type::exnref:
458 if (literal.isNull()) {
459 o << "exnref(null)";
460 } else {
461 o << "exnref(" << literal.getExceptionPackage() << ")";
462 }
463 break;
464 case Type::anyref:
465 assert(literal.isNull() && "unexpected non-null anyref literal");
466 o << "anyref(null)";
467 break;
468 case Type::eqref:
469 assert(literal.isNull() && "unexpected non-null eqref literal");
470 o << "eqref(null)";
471 break;
472 case Type::i31ref:
473 o << "i31ref(" << literal.geti31() << ")";
474 break;
475 case Type::unreachable:
476 WASM_UNREACHABLE("invalid type");
477 }
478 restoreNormalColor(o);
479 return o;
480 }
481
operator <<(std::ostream & o,wasm::Literals literals)482 std::ostream& operator<<(std::ostream& o, wasm::Literals literals) {
483 if (literals.size() == 1) {
484 return o << literals[0];
485 } else {
486 o << '(';
487 if (literals.size() > 0) {
488 o << literals[0];
489 }
490 for (size_t i = 1; i < literals.size(); ++i) {
491 o << ", " << literals[i];
492 }
493 return o << ')';
494 }
495 }
496
operator <<(std::ostream & o,const ExceptionPackage & exn)497 std::ostream& operator<<(std::ostream& o, const ExceptionPackage& exn) {
498 return o << exn.event << " " << exn.values;
499 }
500
countLeadingZeroes() const501 Literal Literal::countLeadingZeroes() const {
502 if (type == Type::i32) {
503 return Literal((int32_t)Bits::countLeadingZeroes(i32));
504 }
505 if (type == Type::i64) {
506 return Literal((int64_t)Bits::countLeadingZeroes(i64));
507 }
508 WASM_UNREACHABLE("invalid type");
509 }
510
countTrailingZeroes() const511 Literal Literal::countTrailingZeroes() const {
512 if (type == Type::i32) {
513 return Literal((int32_t)Bits::countTrailingZeroes(i32));
514 }
515 if (type == Type::i64) {
516 return Literal((int64_t)Bits::countTrailingZeroes(i64));
517 }
518 WASM_UNREACHABLE("invalid type");
519 }
520
popCount() const521 Literal Literal::popCount() const {
522 if (type == Type::i32) {
523 return Literal((int32_t)Bits::popCount(i32));
524 }
525 if (type == Type::i64) {
526 return Literal((int64_t)Bits::popCount(i64));
527 }
528 WASM_UNREACHABLE("invalid type");
529 }
530
extendToSI64() const531 Literal Literal::extendToSI64() const {
532 assert(type == Type::i32);
533 return Literal((int64_t)i32);
534 }
535
extendToUI64() const536 Literal Literal::extendToUI64() const {
537 assert(type == Type::i32);
538 return Literal((uint64_t)(uint32_t)i32);
539 }
540
extendToF64() const541 Literal Literal::extendToF64() const {
542 assert(type == Type::f32);
543 return Literal(double(getf32()));
544 }
545
extendS8() const546 Literal Literal::extendS8() const {
547 if (type == Type::i32) {
548 return Literal(int32_t(int8_t(geti32() & 0xFF)));
549 }
550 if (type == Type::i64) {
551 return Literal(int64_t(int8_t(geti64() & 0xFF)));
552 }
553 WASM_UNREACHABLE("invalid type");
554 }
555
extendS16() const556 Literal Literal::extendS16() const {
557 if (type == Type::i32) {
558 return Literal(int32_t(int16_t(geti32() & 0xFFFF)));
559 }
560 if (type == Type::i64) {
561 return Literal(int64_t(int16_t(geti64() & 0xFFFF)));
562 }
563 WASM_UNREACHABLE("invalid type");
564 }
565
extendS32() const566 Literal Literal::extendS32() const {
567 if (type == Type::i64) {
568 return Literal(int64_t(int32_t(geti64() & 0xFFFFFFFF)));
569 }
570 WASM_UNREACHABLE("invalid type");
571 }
572
wrapToI32() const573 Literal Literal::wrapToI32() const {
574 assert(type == Type::i64);
575 return Literal((int32_t)i64);
576 }
577
convertSIToF32() const578 Literal Literal::convertSIToF32() const {
579 if (type == Type::i32) {
580 return Literal(float(i32));
581 }
582 if (type == Type::i64) {
583 return Literal(float(i64));
584 }
585 WASM_UNREACHABLE("invalid type");
586 }
587
convertUIToF32() const588 Literal Literal::convertUIToF32() const {
589 if (type == Type::i32) {
590 return Literal(float(uint32_t(i32)));
591 }
592 if (type == Type::i64) {
593 return Literal(float(uint64_t(i64)));
594 }
595 WASM_UNREACHABLE("invalid type");
596 }
597
convertSIToF64() const598 Literal Literal::convertSIToF64() const {
599 if (type == Type::i32) {
600 return Literal(double(i32));
601 }
602 if (type == Type::i64) {
603 return Literal(double(i64));
604 }
605 WASM_UNREACHABLE("invalid type");
606 }
607
convertUIToF64() const608 Literal Literal::convertUIToF64() const {
609 if (type == Type::i32) {
610 return Literal(double(uint32_t(i32)));
611 }
612 if (type == Type::i64) {
613 return Literal(double(uint64_t(i64)));
614 }
615 WASM_UNREACHABLE("invalid type");
616 }
617
618 template<typename F> struct AsInt { using type = void; };
619 template<> struct AsInt<float> { using type = int32_t; };
620 template<> struct AsInt<double> { using type = int64_t; };
621
622 template<typename F, typename I, bool (*RangeCheck)(typename AsInt<F>::type)>
saturating_trunc(typename AsInt<F>::type val)623 static Literal saturating_trunc(typename AsInt<F>::type val) {
624 if (std::isnan(bit_cast<F>(val))) {
625 return Literal(I(0));
626 }
627 if (!RangeCheck(val)) {
628 if (std::signbit(bit_cast<F>(val))) {
629 return Literal(std::numeric_limits<I>::min());
630 } else {
631 return Literal(std::numeric_limits<I>::max());
632 }
633 }
634 return Literal(I(std::trunc(bit_cast<F>(val))));
635 }
636
truncSatToSI32() const637 Literal Literal::truncSatToSI32() const {
638 if (type == Type::f32) {
639 return saturating_trunc<float, int32_t, isInRangeI32TruncS>(
640 Literal(*this).castToI32().geti32());
641 }
642 if (type == Type::f64) {
643 return saturating_trunc<double, int32_t, isInRangeI32TruncS>(
644 Literal(*this).castToI64().geti64());
645 }
646 WASM_UNREACHABLE("invalid type");
647 }
648
truncSatToSI64() const649 Literal Literal::truncSatToSI64() const {
650 if (type == Type::f32) {
651 return saturating_trunc<float, int64_t, isInRangeI64TruncS>(
652 Literal(*this).castToI32().geti32());
653 }
654 if (type == Type::f64) {
655 return saturating_trunc<double, int64_t, isInRangeI64TruncS>(
656 Literal(*this).castToI64().geti64());
657 }
658 WASM_UNREACHABLE("invalid type");
659 }
660
truncSatToUI32() const661 Literal Literal::truncSatToUI32() const {
662 if (type == Type::f32) {
663 return saturating_trunc<float, uint32_t, isInRangeI32TruncU>(
664 Literal(*this).castToI32().geti32());
665 }
666 if (type == Type::f64) {
667 return saturating_trunc<double, uint32_t, isInRangeI32TruncU>(
668 Literal(*this).castToI64().geti64());
669 }
670 WASM_UNREACHABLE("invalid type");
671 }
672
truncSatToUI64() const673 Literal Literal::truncSatToUI64() const {
674 if (type == Type::f32) {
675 return saturating_trunc<float, uint64_t, isInRangeI64TruncU>(
676 Literal(*this).castToI32().geti32());
677 }
678 if (type == Type::f64) {
679 return saturating_trunc<double, uint64_t, isInRangeI64TruncU>(
680 Literal(*this).castToI64().geti64());
681 }
682 WASM_UNREACHABLE("invalid type");
683 }
684
eqz() const685 Literal Literal::eqz() const {
686 switch (type.getBasic()) {
687 case Type::i32:
688 return eq(Literal(int32_t(0)));
689 case Type::i64:
690 return eq(Literal(int64_t(0)));
691 case Type::f32:
692 return eq(Literal(float(0)));
693 case Type::f64:
694 return eq(Literal(double(0)));
695 case Type::v128:
696 case Type::funcref:
697 case Type::externref:
698 case Type::exnref:
699 case Type::anyref:
700 case Type::eqref:
701 case Type::i31ref:
702 case Type::none:
703 case Type::unreachable:
704 WASM_UNREACHABLE("unexpected type");
705 }
706 WASM_UNREACHABLE("invalid type");
707 }
708
neg() const709 Literal Literal::neg() const {
710 switch (type.getBasic()) {
711 case Type::i32:
712 return Literal(-uint32_t(i32));
713 case Type::i64:
714 return Literal(-uint64_t(i64));
715 case Type::f32:
716 return Literal(i32 ^ 0x80000000).castToF32();
717 case Type::f64:
718 return Literal(int64_t(i64 ^ 0x8000000000000000ULL)).castToF64();
719 case Type::v128:
720 case Type::funcref:
721 case Type::externref:
722 case Type::exnref:
723 case Type::anyref:
724 case Type::eqref:
725 case Type::i31ref:
726 case Type::none:
727 case Type::unreachable:
728 WASM_UNREACHABLE("unexpected type");
729 }
730 WASM_UNREACHABLE("invalid type");
731 }
732
abs() const733 Literal Literal::abs() const {
734 switch (type.getBasic()) {
735 case Type::i32:
736 return Literal(std::abs(i32));
737 case Type::i64:
738 return Literal(std::abs(i64));
739 case Type::f32:
740 return Literal(i32 & 0x7fffffff).castToF32();
741 case Type::f64:
742 return Literal(int64_t(i64 & 0x7fffffffffffffffULL)).castToF64();
743 case Type::v128:
744 case Type::funcref:
745 case Type::externref:
746 case Type::exnref:
747 case Type::anyref:
748 case Type::eqref:
749 case Type::i31ref:
750 case Type::none:
751 case Type::unreachable:
752 WASM_UNREACHABLE("unexpected type");
753 }
754 WASM_UNREACHABLE("unexpected type");
755 }
756
ceil() const757 Literal Literal::ceil() const {
758 switch (type.getBasic()) {
759 case Type::f32:
760 return Literal(std::ceil(getf32()));
761 case Type::f64:
762 return Literal(std::ceil(getf64()));
763 default:
764 WASM_UNREACHABLE("unexpected type");
765 }
766 }
767
floor() const768 Literal Literal::floor() const {
769 switch (type.getBasic()) {
770 case Type::f32:
771 return Literal(std::floor(getf32()));
772 case Type::f64:
773 return Literal(std::floor(getf64()));
774 default:
775 WASM_UNREACHABLE("unexpected type");
776 }
777 }
778
trunc() const779 Literal Literal::trunc() const {
780 switch (type.getBasic()) {
781 case Type::f32:
782 return Literal(std::trunc(getf32()));
783 case Type::f64:
784 return Literal(std::trunc(getf64()));
785 default:
786 WASM_UNREACHABLE("unexpected type");
787 }
788 }
789
nearbyint() const790 Literal Literal::nearbyint() const {
791 switch (type.getBasic()) {
792 case Type::f32:
793 return Literal(std::nearbyint(getf32()));
794 case Type::f64:
795 return Literal(std::nearbyint(getf64()));
796 default:
797 WASM_UNREACHABLE("unexpected type");
798 }
799 }
800
sqrt() const801 Literal Literal::sqrt() const {
802 switch (type.getBasic()) {
803 case Type::f32:
804 return Literal(std::sqrt(getf32()));
805 case Type::f64:
806 return Literal(std::sqrt(getf64()));
807 default:
808 WASM_UNREACHABLE("unexpected type");
809 }
810 }
811
demote() const812 Literal Literal::demote() const {
813 auto f64 = getf64();
814 if (std::isnan(f64)) {
815 return Literal(float(f64));
816 }
817 if (std::isinf(f64)) {
818 return Literal(float(f64));
819 }
820 // when close to the limit, but still truncatable to a valid value, do that
821 // see
822 // https://github.com/WebAssembly/sexpr-wasm-prototype/blob/2d375e8d502327e814d62a08f22da9d9b6b675dc/src/wasm-interpreter.c#L247
823 uint64_t bits = reinterpreti64();
824 if (bits > 0x47efffffe0000000ULL && bits < 0x47effffff0000000ULL) {
825 return Literal(std::numeric_limits<float>::max());
826 }
827 if (bits > 0xc7efffffe0000000ULL && bits < 0xc7effffff0000000ULL) {
828 return Literal(-std::numeric_limits<float>::max());
829 }
830 // when we must convert to infinity, do that
831 if (f64 < -std::numeric_limits<float>::max()) {
832 return Literal(-std::numeric_limits<float>::infinity());
833 }
834 if (f64 > std::numeric_limits<float>::max()) {
835 return Literal(std::numeric_limits<float>::infinity());
836 }
837 return Literal(float(getf64()));
838 }
839
add(const Literal & other) const840 Literal Literal::add(const Literal& other) const {
841 switch (type.getBasic()) {
842 case Type::i32:
843 return Literal(uint32_t(i32) + uint32_t(other.i32));
844 case Type::i64:
845 return Literal(uint64_t(i64) + uint64_t(other.i64));
846 case Type::f32:
847 return Literal(getf32() + other.getf32());
848 case Type::f64:
849 return Literal(getf64() + other.getf64());
850 case Type::v128:
851 case Type::funcref:
852 case Type::externref:
853 case Type::exnref:
854 case Type::anyref:
855 case Type::eqref:
856 case Type::i31ref:
857 case Type::none:
858 case Type::unreachable:
859 WASM_UNREACHABLE("unexpected type");
860 }
861 WASM_UNREACHABLE("unexpected type");
862 }
863
sub(const Literal & other) const864 Literal Literal::sub(const Literal& other) const {
865 switch (type.getBasic()) {
866 case Type::i32:
867 return Literal(uint32_t(i32) - uint32_t(other.i32));
868 case Type::i64:
869 return Literal(uint64_t(i64) - uint64_t(other.i64));
870 case Type::f32:
871 return Literal(getf32() - other.getf32());
872 case Type::f64:
873 return Literal(getf64() - other.getf64());
874 case Type::v128:
875 case Type::funcref:
876 case Type::externref:
877 case Type::exnref:
878 case Type::anyref:
879 case Type::eqref:
880 case Type::i31ref:
881 case Type::none:
882 case Type::unreachable:
883 WASM_UNREACHABLE("unexpected type");
884 }
885 WASM_UNREACHABLE("unexpected type");
886 }
887
add_sat_s(T a,T b)888 template<typename T> static T add_sat_s(T a, T b) {
889 static_assert(std::is_signed<T>::value,
890 "Trying to instantiate add_sat_s with unsigned type");
891 using UT = typename std::make_unsigned<T>::type;
892 UT ua = static_cast<UT>(a);
893 UT ub = static_cast<UT>(b);
894 UT ures = ua + ub;
895 // overflow if sign of result is different from sign of a and b
896 if (static_cast<T>((ures ^ ua) & (ures ^ ub)) < 0) {
897 return (a < 0) ? std::numeric_limits<T>::min()
898 : std::numeric_limits<T>::max();
899 }
900 return static_cast<T>(ures);
901 }
902
sub_sat_s(T a,T b)903 template<typename T> static T sub_sat_s(T a, T b) {
904 static_assert(std::is_signed<T>::value,
905 "Trying to instantiate sub_sat_s with unsigned type");
906 using UT = typename std::make_unsigned<T>::type;
907 UT ua = static_cast<UT>(a);
908 UT ub = static_cast<UT>(b);
909 UT ures = ua - ub;
910 // overflow if a and b have different signs and result and a differ in sign
911 if (static_cast<T>((ua ^ ub) & (ures ^ ua)) < 0) {
912 return (a < 0) ? std::numeric_limits<T>::min()
913 : std::numeric_limits<T>::max();
914 }
915 return static_cast<T>(ures);
916 }
917
add_sat_u(T a,T b)918 template<typename T> static T add_sat_u(T a, T b) {
919 static_assert(std::is_unsigned<T>::value,
920 "Trying to instantiate add_sat_u with signed type");
921 T res = a + b;
922 // overflow if result is less than arguments
923 return (res < a) ? std::numeric_limits<T>::max() : res;
924 }
925
sub_sat_u(T a,T b)926 template<typename T> static T sub_sat_u(T a, T b) {
927 static_assert(std::is_unsigned<T>::value,
928 "Trying to instantiate sub_sat_u with signed type");
929 T res = a - b;
930 // overflow if result is greater than a
931 return (res > a) ? 0 : res;
932 }
933
addSatSI8(const Literal & other) const934 Literal Literal::addSatSI8(const Literal& other) const {
935 return Literal(add_sat_s<int8_t>(geti32(), other.geti32()));
936 }
addSatUI8(const Literal & other) const937 Literal Literal::addSatUI8(const Literal& other) const {
938 return Literal(add_sat_u<uint8_t>(geti32(), other.geti32()));
939 }
addSatSI16(const Literal & other) const940 Literal Literal::addSatSI16(const Literal& other) const {
941 return Literal(add_sat_s<int16_t>(geti32(), other.geti32()));
942 }
addSatUI16(const Literal & other) const943 Literal Literal::addSatUI16(const Literal& other) const {
944 return Literal(add_sat_u<uint16_t>(geti32(), other.geti32()));
945 }
subSatSI8(const Literal & other) const946 Literal Literal::subSatSI8(const Literal& other) const {
947 return Literal(sub_sat_s<int8_t>(geti32(), other.geti32()));
948 }
subSatUI8(const Literal & other) const949 Literal Literal::subSatUI8(const Literal& other) const {
950 return Literal(sub_sat_u<uint8_t>(geti32(), other.geti32()));
951 }
subSatSI16(const Literal & other) const952 Literal Literal::subSatSI16(const Literal& other) const {
953 return Literal(sub_sat_s<int16_t>(geti32(), other.geti32()));
954 }
subSatUI16(const Literal & other) const955 Literal Literal::subSatUI16(const Literal& other) const {
956 return Literal(sub_sat_u<uint16_t>(geti32(), other.geti32()));
957 }
958
mul(const Literal & other) const959 Literal Literal::mul(const Literal& other) const {
960 switch (type.getBasic()) {
961 case Type::i32:
962 return Literal(uint32_t(i32) * uint32_t(other.i32));
963 case Type::i64:
964 return Literal(uint64_t(i64) * uint64_t(other.i64));
965 case Type::f32:
966 return Literal(getf32() * other.getf32());
967 case Type::f64:
968 return Literal(getf64() * other.getf64());
969 case Type::v128:
970 case Type::funcref:
971 case Type::externref:
972 case Type::exnref:
973 case Type::anyref:
974 case Type::eqref:
975 case Type::i31ref:
976 case Type::none:
977 case Type::unreachable:
978 WASM_UNREACHABLE("unexpected type");
979 }
980 WASM_UNREACHABLE("unexpected type");
981 }
982
div(const Literal & other) const983 Literal Literal::div(const Literal& other) const {
984 switch (type.getBasic()) {
985 case Type::f32: {
986 float lhs = getf32(), rhs = other.getf32();
987 float sign = std::signbit(lhs) == std::signbit(rhs) ? 0.f : -0.f;
988 switch (std::fpclassify(rhs)) {
989 case FP_ZERO:
990 switch (std::fpclassify(lhs)) {
991 case FP_NAN:
992 return Literal(setQuietNaN(lhs));
993 case FP_ZERO:
994 return Literal(
995 std::copysign(std::numeric_limits<float>::quiet_NaN(), sign));
996 case FP_NORMAL: // fallthrough
997 case FP_SUBNORMAL: // fallthrough
998 case FP_INFINITE:
999 return Literal(
1000 std::copysign(std::numeric_limits<float>::infinity(), sign));
1001 default:
1002 WASM_UNREACHABLE("invalid fp classification");
1003 }
1004 case FP_NAN: // fallthrough
1005 case FP_INFINITE: // fallthrough
1006 case FP_NORMAL: // fallthrough
1007 case FP_SUBNORMAL:
1008 return Literal(lhs / rhs);
1009 default:
1010 WASM_UNREACHABLE("invalid fp classification");
1011 }
1012 }
1013 case Type::f64: {
1014 double lhs = getf64(), rhs = other.getf64();
1015 double sign = std::signbit(lhs) == std::signbit(rhs) ? 0. : -0.;
1016 switch (std::fpclassify(rhs)) {
1017 case FP_ZERO:
1018 switch (std::fpclassify(lhs)) {
1019 case FP_NAN:
1020 return Literal(setQuietNaN(lhs));
1021 case FP_ZERO:
1022 return Literal(
1023 std::copysign(std::numeric_limits<double>::quiet_NaN(), sign));
1024 case FP_NORMAL: // fallthrough
1025 case FP_SUBNORMAL: // fallthrough
1026 case FP_INFINITE:
1027 return Literal(
1028 std::copysign(std::numeric_limits<double>::infinity(), sign));
1029 default:
1030 WASM_UNREACHABLE("invalid fp classification");
1031 }
1032 case FP_NAN: // fallthrough
1033 case FP_INFINITE: // fallthrough
1034 case FP_NORMAL: // fallthrough
1035 case FP_SUBNORMAL:
1036 return Literal(lhs / rhs);
1037 default:
1038 WASM_UNREACHABLE("invalid fp classification");
1039 }
1040 }
1041 default:
1042 WASM_UNREACHABLE("unexpected type");
1043 }
1044 }
1045
divS(const Literal & other) const1046 Literal Literal::divS(const Literal& other) const {
1047 switch (type.getBasic()) {
1048 case Type::i32:
1049 return Literal(i32 / other.i32);
1050 case Type::i64:
1051 return Literal(i64 / other.i64);
1052 default:
1053 WASM_UNREACHABLE("unexpected type");
1054 }
1055 }
1056
divU(const Literal & other) const1057 Literal Literal::divU(const Literal& other) const {
1058 switch (type.getBasic()) {
1059 case Type::i32:
1060 return Literal(uint32_t(i32) / uint32_t(other.i32));
1061 case Type::i64:
1062 return Literal(uint64_t(i64) / uint64_t(other.i64));
1063 default:
1064 WASM_UNREACHABLE("unexpected type");
1065 }
1066 }
1067
remS(const Literal & other) const1068 Literal Literal::remS(const Literal& other) const {
1069 switch (type.getBasic()) {
1070 case Type::i32:
1071 return Literal(i32 % other.i32);
1072 case Type::i64:
1073 return Literal(i64 % other.i64);
1074 default:
1075 WASM_UNREACHABLE("unexpected type");
1076 }
1077 }
1078
remU(const Literal & other) const1079 Literal Literal::remU(const Literal& other) const {
1080 switch (type.getBasic()) {
1081 case Type::i32:
1082 return Literal(uint32_t(i32) % uint32_t(other.i32));
1083 case Type::i64:
1084 return Literal(uint64_t(i64) % uint64_t(other.i64));
1085 default:
1086 WASM_UNREACHABLE("unexpected type");
1087 }
1088 }
1089
minInt(const Literal & other) const1090 Literal Literal::minInt(const Literal& other) const {
1091 return geti32() < other.geti32() ? *this : other;
1092 }
maxInt(const Literal & other) const1093 Literal Literal::maxInt(const Literal& other) const {
1094 return geti32() > other.geti32() ? *this : other;
1095 }
minUInt(const Literal & other) const1096 Literal Literal::minUInt(const Literal& other) const {
1097 return uint32_t(geti32()) < uint32_t(other.geti32()) ? *this : other;
1098 }
maxUInt(const Literal & other) const1099 Literal Literal::maxUInt(const Literal& other) const {
1100 return uint32_t(geti32()) > uint32_t(other.geti32()) ? *this : other;
1101 }
1102
avgrUInt(const Literal & other) const1103 Literal Literal::avgrUInt(const Literal& other) const {
1104 return Literal((geti32() + other.geti32() + 1) / 2);
1105 }
1106
and_(const Literal & other) const1107 Literal Literal::and_(const Literal& other) const {
1108 switch (type.getBasic()) {
1109 case Type::i32:
1110 return Literal(i32 & other.i32);
1111 case Type::i64:
1112 return Literal(i64 & other.i64);
1113 default:
1114 WASM_UNREACHABLE("unexpected type");
1115 }
1116 }
1117
or_(const Literal & other) const1118 Literal Literal::or_(const Literal& other) const {
1119 switch (type.getBasic()) {
1120 case Type::i32:
1121 return Literal(i32 | other.i32);
1122 case Type::i64:
1123 return Literal(i64 | other.i64);
1124 default:
1125 WASM_UNREACHABLE("unexpected type");
1126 }
1127 }
1128
xor_(const Literal & other) const1129 Literal Literal::xor_(const Literal& other) const {
1130 switch (type.getBasic()) {
1131 case Type::i32:
1132 return Literal(i32 ^ other.i32);
1133 case Type::i64:
1134 return Literal(i64 ^ other.i64);
1135 default:
1136 WASM_UNREACHABLE("unexpected type");
1137 }
1138 }
1139
shl(const Literal & other) const1140 Literal Literal::shl(const Literal& other) const {
1141 switch (type.getBasic()) {
1142 case Type::i32:
1143 return Literal(uint32_t(i32)
1144 << Bits::getEffectiveShifts(other.i32, Type::i32));
1145 case Type::i64:
1146 return Literal(uint64_t(i64)
1147 << Bits::getEffectiveShifts(other.i64, Type::i64));
1148 default:
1149 WASM_UNREACHABLE("unexpected type");
1150 }
1151 }
1152
shrS(const Literal & other) const1153 Literal Literal::shrS(const Literal& other) const {
1154 switch (type.getBasic()) {
1155 case Type::i32:
1156 return Literal(i32 >> Bits::getEffectiveShifts(other.i32, Type::i32));
1157 case Type::i64:
1158 return Literal(i64 >> Bits::getEffectiveShifts(other.i64, Type::i64));
1159 default:
1160 WASM_UNREACHABLE("unexpected type");
1161 }
1162 }
1163
shrU(const Literal & other) const1164 Literal Literal::shrU(const Literal& other) const {
1165 switch (type.getBasic()) {
1166 case Type::i32:
1167 return Literal(uint32_t(i32) >>
1168 Bits::getEffectiveShifts(other.i32, Type::i32));
1169 case Type::i64:
1170 return Literal(uint64_t(i64) >>
1171 Bits::getEffectiveShifts(other.i64, Type::i64));
1172 default:
1173 WASM_UNREACHABLE("unexpected type");
1174 }
1175 }
1176
rotL(const Literal & other) const1177 Literal Literal::rotL(const Literal& other) const {
1178 switch (type.getBasic()) {
1179 case Type::i32:
1180 return Literal(Bits::rotateLeft(uint32_t(i32), uint32_t(other.i32)));
1181 case Type::i64:
1182 return Literal(Bits::rotateLeft(uint64_t(i64), uint64_t(other.i64)));
1183 default:
1184 WASM_UNREACHABLE("unexpected type");
1185 }
1186 }
1187
rotR(const Literal & other) const1188 Literal Literal::rotR(const Literal& other) const {
1189 switch (type.getBasic()) {
1190 case Type::i32:
1191 return Literal(Bits::rotateRight(uint32_t(i32), uint32_t(other.i32)));
1192 case Type::i64:
1193 return Literal(Bits::rotateRight(uint64_t(i64), uint64_t(other.i64)));
1194 default:
1195 WASM_UNREACHABLE("unexpected type");
1196 }
1197 }
1198
eq(const Literal & other) const1199 Literal Literal::eq(const Literal& other) const {
1200 switch (type.getBasic()) {
1201 case Type::i32:
1202 return Literal(i32 == other.i32);
1203 case Type::i64:
1204 return Literal(i64 == other.i64);
1205 case Type::f32:
1206 return Literal(getf32() == other.getf32());
1207 case Type::f64:
1208 return Literal(getf64() == other.getf64());
1209 case Type::v128:
1210 case Type::funcref:
1211 case Type::externref:
1212 case Type::exnref:
1213 case Type::anyref:
1214 case Type::eqref:
1215 case Type::i31ref:
1216 case Type::none:
1217 case Type::unreachable:
1218 WASM_UNREACHABLE("unexpected type");
1219 }
1220 WASM_UNREACHABLE("unexpected type");
1221 }
1222
ne(const Literal & other) const1223 Literal Literal::ne(const Literal& other) const {
1224 switch (type.getBasic()) {
1225 case Type::i32:
1226 return Literal(i32 != other.i32);
1227 case Type::i64:
1228 return Literal(i64 != other.i64);
1229 case Type::f32:
1230 return Literal(getf32() != other.getf32());
1231 case Type::f64:
1232 return Literal(getf64() != other.getf64());
1233 case Type::v128:
1234 case Type::funcref:
1235 case Type::externref:
1236 case Type::exnref:
1237 case Type::anyref:
1238 case Type::eqref:
1239 case Type::i31ref:
1240 case Type::none:
1241 case Type::unreachable:
1242 WASM_UNREACHABLE("unexpected type");
1243 }
1244 WASM_UNREACHABLE("unexpected type");
1245 }
1246
ltS(const Literal & other) const1247 Literal Literal::ltS(const Literal& other) const {
1248 switch (type.getBasic()) {
1249 case Type::i32:
1250 return Literal(i32 < other.i32);
1251 case Type::i64:
1252 return Literal(i64 < other.i64);
1253 default:
1254 WASM_UNREACHABLE("unexpected type");
1255 }
1256 }
1257
ltU(const Literal & other) const1258 Literal Literal::ltU(const Literal& other) const {
1259 switch (type.getBasic()) {
1260 case Type::i32:
1261 return Literal(uint32_t(i32) < uint32_t(other.i32));
1262 case Type::i64:
1263 return Literal(uint64_t(i64) < uint64_t(other.i64));
1264 default:
1265 WASM_UNREACHABLE("unexpected type");
1266 }
1267 }
1268
lt(const Literal & other) const1269 Literal Literal::lt(const Literal& other) const {
1270 switch (type.getBasic()) {
1271 case Type::f32:
1272 return Literal(getf32() < other.getf32());
1273 case Type::f64:
1274 return Literal(getf64() < other.getf64());
1275 default:
1276 WASM_UNREACHABLE("unexpected type");
1277 }
1278 }
1279
leS(const Literal & other) const1280 Literal Literal::leS(const Literal& other) const {
1281 switch (type.getBasic()) {
1282 case Type::i32:
1283 return Literal(i32 <= other.i32);
1284 case Type::i64:
1285 return Literal(i64 <= other.i64);
1286 default:
1287 WASM_UNREACHABLE("unexpected type");
1288 }
1289 }
1290
leU(const Literal & other) const1291 Literal Literal::leU(const Literal& other) const {
1292 switch (type.getBasic()) {
1293 case Type::i32:
1294 return Literal(uint32_t(i32) <= uint32_t(other.i32));
1295 case Type::i64:
1296 return Literal(uint64_t(i64) <= uint64_t(other.i64));
1297 default:
1298 WASM_UNREACHABLE("unexpected type");
1299 }
1300 }
1301
le(const Literal & other) const1302 Literal Literal::le(const Literal& other) const {
1303 switch (type.getBasic()) {
1304 case Type::f32:
1305 return Literal(getf32() <= other.getf32());
1306 case Type::f64:
1307 return Literal(getf64() <= other.getf64());
1308 default:
1309 WASM_UNREACHABLE("unexpected type");
1310 }
1311 }
1312
gtS(const Literal & other) const1313 Literal Literal::gtS(const Literal& other) const {
1314 switch (type.getBasic()) {
1315 case Type::i32:
1316 return Literal(i32 > other.i32);
1317 case Type::i64:
1318 return Literal(i64 > other.i64);
1319 default:
1320 WASM_UNREACHABLE("unexpected type");
1321 }
1322 }
1323
gtU(const Literal & other) const1324 Literal Literal::gtU(const Literal& other) const {
1325 switch (type.getBasic()) {
1326 case Type::i32:
1327 return Literal(uint32_t(i32) > uint32_t(other.i32));
1328 case Type::i64:
1329 return Literal(uint64_t(i64) > uint64_t(other.i64));
1330 default:
1331 WASM_UNREACHABLE("unexpected type");
1332 }
1333 }
1334
gt(const Literal & other) const1335 Literal Literal::gt(const Literal& other) const {
1336 switch (type.getBasic()) {
1337 case Type::f32:
1338 return Literal(getf32() > other.getf32());
1339 case Type::f64:
1340 return Literal(getf64() > other.getf64());
1341 default:
1342 WASM_UNREACHABLE("unexpected type");
1343 }
1344 }
1345
geS(const Literal & other) const1346 Literal Literal::geS(const Literal& other) const {
1347 switch (type.getBasic()) {
1348 case Type::i32:
1349 return Literal(i32 >= other.i32);
1350 case Type::i64:
1351 return Literal(i64 >= other.i64);
1352 default:
1353 WASM_UNREACHABLE("unexpected type");
1354 }
1355 }
1356
geU(const Literal & other) const1357 Literal Literal::geU(const Literal& other) const {
1358 switch (type.getBasic()) {
1359 case Type::i32:
1360 return Literal(uint32_t(i32) >= uint32_t(other.i32));
1361 case Type::i64:
1362 return Literal(uint64_t(i64) >= uint64_t(other.i64));
1363 default:
1364 WASM_UNREACHABLE("unexpected type");
1365 }
1366 }
1367
ge(const Literal & other) const1368 Literal Literal::ge(const Literal& other) const {
1369 switch (type.getBasic()) {
1370 case Type::f32:
1371 return Literal(getf32() >= other.getf32());
1372 case Type::f64:
1373 return Literal(getf64() >= other.getf64());
1374 default:
1375 WASM_UNREACHABLE("unexpected type");
1376 }
1377 }
1378
min(const Literal & other) const1379 Literal Literal::min(const Literal& other) const {
1380 switch (type.getBasic()) {
1381 case Type::f32: {
1382 auto l = getf32(), r = other.getf32();
1383 if (l == r && l == 0) {
1384 return Literal(std::signbit(l) ? l : r);
1385 }
1386 auto result = std::min(l, r);
1387 bool lnan = std::isnan(l), rnan = std::isnan(r);
1388 if (!std::isnan(result) && !lnan && !rnan) {
1389 return Literal(result);
1390 }
1391 if (!lnan && !rnan) {
1392 return Literal((int32_t)0x7fc00000).castToF32();
1393 }
1394 return Literal(lnan ? l : r)
1395 .castToI32()
1396 .or_(Literal(0xc00000))
1397 .castToF32();
1398 }
1399 case Type::f64: {
1400 auto l = getf64(), r = other.getf64();
1401 if (l == r && l == 0) {
1402 return Literal(std::signbit(l) ? l : r);
1403 }
1404 auto result = std::min(l, r);
1405 bool lnan = std::isnan(l), rnan = std::isnan(r);
1406 if (!std::isnan(result) && !lnan && !rnan) {
1407 return Literal(result);
1408 }
1409 if (!lnan && !rnan) {
1410 return Literal((int64_t)0x7ff8000000000000LL).castToF64();
1411 }
1412 return Literal(lnan ? l : r)
1413 .castToI64()
1414 .or_(Literal(int64_t(0x8000000000000LL)))
1415 .castToF64();
1416 }
1417 default:
1418 WASM_UNREACHABLE("unexpected type");
1419 }
1420 }
1421
max(const Literal & other) const1422 Literal Literal::max(const Literal& other) const {
1423 switch (type.getBasic()) {
1424 case Type::f32: {
1425 auto l = getf32(), r = other.getf32();
1426 if (l == r && l == 0) {
1427 return Literal(std::signbit(l) ? r : l);
1428 }
1429 auto result = std::max(l, r);
1430 bool lnan = std::isnan(l), rnan = std::isnan(r);
1431 if (!std::isnan(result) && !lnan && !rnan) {
1432 return Literal(result);
1433 }
1434 if (!lnan && !rnan) {
1435 return Literal((int32_t)0x7fc00000).castToF32();
1436 }
1437 return Literal(lnan ? l : r)
1438 .castToI32()
1439 .or_(Literal(0xc00000))
1440 .castToF32();
1441 }
1442 case Type::f64: {
1443 auto l = getf64(), r = other.getf64();
1444 if (l == r && l == 0) {
1445 return Literal(std::signbit(l) ? r : l);
1446 }
1447 auto result = std::max(l, r);
1448 bool lnan = std::isnan(l), rnan = std::isnan(r);
1449 if (!std::isnan(result) && !lnan && !rnan) {
1450 return Literal(result);
1451 }
1452 if (!lnan && !rnan) {
1453 return Literal((int64_t)0x7ff8000000000000LL).castToF64();
1454 }
1455 return Literal(lnan ? l : r)
1456 .castToI64()
1457 .or_(Literal(int64_t(0x8000000000000LL)))
1458 .castToF64();
1459 }
1460 default:
1461 WASM_UNREACHABLE("unexpected type");
1462 }
1463 }
1464
pmin(const Literal & other) const1465 Literal Literal::pmin(const Literal& other) const {
1466 switch (type.getBasic()) {
1467 case Type::f32:
1468 case Type::f64:
1469 return other.lt(*this).geti32() ? other : *this;
1470 default:
1471 WASM_UNREACHABLE("unexpected type");
1472 }
1473 }
1474
pmax(const Literal & other) const1475 Literal Literal::pmax(const Literal& other) const {
1476 switch (type.getBasic()) {
1477 case Type::f32:
1478 case Type::f64:
1479 return this->lt(other).geti32() ? other : *this;
1480 default:
1481 WASM_UNREACHABLE("unexpected type");
1482 }
1483 }
1484
copysign(const Literal & other) const1485 Literal Literal::copysign(const Literal& other) const {
1486 // operate on bits directly, to avoid signalling bit being set on a float
1487 switch (type.getBasic()) {
1488 case Type::f32:
1489 return Literal((i32 & 0x7fffffff) | (other.i32 & 0x80000000)).castToF32();
1490 break;
1491 case Type::f64:
1492 return Literal((i64 & 0x7fffffffffffffffUL) |
1493 (other.i64 & 0x8000000000000000UL))
1494 .castToF64();
1495 break;
1496 default:
1497 WASM_UNREACHABLE("unexpected type");
1498 }
1499 }
1500
1501 template<typename LaneT, int Lanes>
getLanes(const Literal & val)1502 static LaneArray<Lanes> getLanes(const Literal& val) {
1503 assert(val.type == Type::v128);
1504 const size_t lane_width = 16 / Lanes;
1505 std::array<uint8_t, 16> bytes = val.getv128();
1506 LaneArray<Lanes> lanes;
1507 for (size_t lane_index = 0; lane_index < Lanes; ++lane_index) {
1508 LaneT lane(0);
1509 for (size_t offset = 0; offset < lane_width; ++offset) {
1510 lane |= LaneT(bytes.at(lane_index * lane_width + offset))
1511 << LaneT(8 * offset);
1512 }
1513 lanes.at(lane_index) = Literal(lane);
1514 }
1515 return lanes;
1516 }
1517
getLanesSI8x16() const1518 LaneArray<16> Literal::getLanesSI8x16() const {
1519 return getLanes<int8_t, 16>(*this);
1520 }
getLanesUI8x16() const1521 LaneArray<16> Literal::getLanesUI8x16() const {
1522 return getLanes<uint8_t, 16>(*this);
1523 }
getLanesSI16x8() const1524 LaneArray<8> Literal::getLanesSI16x8() const {
1525 return getLanes<int16_t, 8>(*this);
1526 }
getLanesUI16x8() const1527 LaneArray<8> Literal::getLanesUI16x8() const {
1528 return getLanes<uint16_t, 8>(*this);
1529 }
getLanesI32x4() const1530 LaneArray<4> Literal::getLanesI32x4() const {
1531 return getLanes<int32_t, 4>(*this);
1532 }
getLanesI64x2() const1533 LaneArray<2> Literal::getLanesI64x2() const {
1534 return getLanes<int64_t, 2>(*this);
1535 }
getLanesF32x4() const1536 LaneArray<4> Literal::getLanesF32x4() const {
1537 auto lanes = getLanesI32x4();
1538 for (size_t i = 0; i < lanes.size(); ++i) {
1539 lanes[i] = lanes[i].castToF32();
1540 }
1541 return lanes;
1542 }
getLanesF64x2() const1543 LaneArray<2> Literal::getLanesF64x2() const {
1544 auto lanes = getLanesI64x2();
1545 for (size_t i = 0; i < lanes.size(); ++i) {
1546 lanes[i] = lanes[i].castToF64();
1547 }
1548 return lanes;
1549 }
1550
shuffleV8x16(const Literal & other,const std::array<uint8_t,16> & mask) const1551 Literal Literal::shuffleV8x16(const Literal& other,
1552 const std::array<uint8_t, 16>& mask) const {
1553 assert(type == Type::v128);
1554 uint8_t bytes[16];
1555 for (size_t i = 0; i < mask.size(); ++i) {
1556 bytes[i] = (mask[i] < 16) ? v128[mask[i]] : other.v128[mask[i] - 16];
1557 }
1558 return Literal(bytes);
1559 }
1560
splat(const Literal & val)1561 template<Type::BasicID Ty, int Lanes> static Literal splat(const Literal& val) {
1562 assert(val.type == Ty);
1563 LaneArray<Lanes> lanes;
1564 lanes.fill(val);
1565 return Literal(lanes);
1566 }
1567
splatI8x16() const1568 Literal Literal::splatI8x16() const { return splat<Type::i32, 16>(*this); }
splatI16x8() const1569 Literal Literal::splatI16x8() const { return splat<Type::i32, 8>(*this); }
splatI32x4() const1570 Literal Literal::splatI32x4() const { return splat<Type::i32, 4>(*this); }
splatI64x2() const1571 Literal Literal::splatI64x2() const { return splat<Type::i64, 2>(*this); }
splatF32x4() const1572 Literal Literal::splatF32x4() const { return splat<Type::f32, 4>(*this); }
splatF64x2() const1573 Literal Literal::splatF64x2() const { return splat<Type::f64, 2>(*this); }
1574
extractLaneSI8x16(uint8_t index) const1575 Literal Literal::extractLaneSI8x16(uint8_t index) const {
1576 return getLanesSI8x16().at(index);
1577 }
extractLaneUI8x16(uint8_t index) const1578 Literal Literal::extractLaneUI8x16(uint8_t index) const {
1579 return getLanesUI8x16().at(index);
1580 }
extractLaneSI16x8(uint8_t index) const1581 Literal Literal::extractLaneSI16x8(uint8_t index) const {
1582 return getLanesSI16x8().at(index);
1583 }
extractLaneUI16x8(uint8_t index) const1584 Literal Literal::extractLaneUI16x8(uint8_t index) const {
1585 return getLanesUI16x8().at(index);
1586 }
extractLaneI32x4(uint8_t index) const1587 Literal Literal::extractLaneI32x4(uint8_t index) const {
1588 return getLanesI32x4().at(index);
1589 }
extractLaneI64x2(uint8_t index) const1590 Literal Literal::extractLaneI64x2(uint8_t index) const {
1591 return getLanesI64x2().at(index);
1592 }
extractLaneF32x4(uint8_t index) const1593 Literal Literal::extractLaneF32x4(uint8_t index) const {
1594 return getLanesF32x4().at(index);
1595 }
extractLaneF64x2(uint8_t index) const1596 Literal Literal::extractLaneF64x2(uint8_t index) const {
1597 return getLanesF64x2().at(index);
1598 }
1599
1600 template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
1601 static Literal
replace(const Literal & val,const Literal & other,uint8_t index)1602 replace(const Literal& val, const Literal& other, uint8_t index) {
1603 LaneArray<Lanes> lanes = (val.*IntoLanes)();
1604 lanes.at(index) = other;
1605 auto ret = Literal(lanes);
1606 return ret;
1607 }
1608
replaceLaneI8x16(const Literal & other,uint8_t index) const1609 Literal Literal::replaceLaneI8x16(const Literal& other, uint8_t index) const {
1610 return replace<16, &Literal::getLanesUI8x16>(*this, other, index);
1611 }
replaceLaneI16x8(const Literal & other,uint8_t index) const1612 Literal Literal::replaceLaneI16x8(const Literal& other, uint8_t index) const {
1613 return replace<8, &Literal::getLanesUI16x8>(*this, other, index);
1614 }
replaceLaneI32x4(const Literal & other,uint8_t index) const1615 Literal Literal::replaceLaneI32x4(const Literal& other, uint8_t index) const {
1616 return replace<4, &Literal::getLanesI32x4>(*this, other, index);
1617 }
replaceLaneI64x2(const Literal & other,uint8_t index) const1618 Literal Literal::replaceLaneI64x2(const Literal& other, uint8_t index) const {
1619 return replace<2, &Literal::getLanesI64x2>(*this, other, index);
1620 }
replaceLaneF32x4(const Literal & other,uint8_t index) const1621 Literal Literal::replaceLaneF32x4(const Literal& other, uint8_t index) const {
1622 return replace<4, &Literal::getLanesF32x4>(*this, other, index);
1623 }
replaceLaneF64x2(const Literal & other,uint8_t index) const1624 Literal Literal::replaceLaneF64x2(const Literal& other, uint8_t index) const {
1625 return replace<2, &Literal::getLanesF64x2>(*this, other, index);
1626 }
1627
1628 template<int Lanes,
1629 LaneArray<Lanes> (Literal::*IntoLanes)() const,
1630 Literal (Literal::*UnaryOp)(void) const>
unary(const Literal & val)1631 static Literal unary(const Literal& val) {
1632 LaneArray<Lanes> lanes = (val.*IntoLanes)();
1633 for (size_t i = 0; i < Lanes; ++i) {
1634 lanes[i] = (lanes[i].*UnaryOp)();
1635 }
1636 return Literal(lanes);
1637 }
1638
notV128() const1639 Literal Literal::notV128() const {
1640 std::array<uint8_t, 16> ones;
1641 ones.fill(0xff);
1642 return xorV128(Literal(ones.data()));
1643 }
absI8x16() const1644 Literal Literal::absI8x16() const {
1645 return unary<16, &Literal::getLanesSI8x16, &Literal::abs>(*this);
1646 }
absI16x8() const1647 Literal Literal::absI16x8() const {
1648 return unary<8, &Literal::getLanesSI16x8, &Literal::abs>(*this);
1649 }
absI32x4() const1650 Literal Literal::absI32x4() const {
1651 return unary<4, &Literal::getLanesI32x4, &Literal::abs>(*this);
1652 }
negI8x16() const1653 Literal Literal::negI8x16() const {
1654 return unary<16, &Literal::getLanesUI8x16, &Literal::neg>(*this);
1655 }
negI16x8() const1656 Literal Literal::negI16x8() const {
1657 return unary<8, &Literal::getLanesUI16x8, &Literal::neg>(*this);
1658 }
negI32x4() const1659 Literal Literal::negI32x4() const {
1660 return unary<4, &Literal::getLanesI32x4, &Literal::neg>(*this);
1661 }
negI64x2() const1662 Literal Literal::negI64x2() const {
1663 return unary<2, &Literal::getLanesI64x2, &Literal::neg>(*this);
1664 }
absF32x4() const1665 Literal Literal::absF32x4() const {
1666 return unary<4, &Literal::getLanesF32x4, &Literal::abs>(*this);
1667 }
negF32x4() const1668 Literal Literal::negF32x4() const {
1669 return unary<4, &Literal::getLanesF32x4, &Literal::neg>(*this);
1670 }
sqrtF32x4() const1671 Literal Literal::sqrtF32x4() const {
1672 return unary<4, &Literal::getLanesF32x4, &Literal::sqrt>(*this);
1673 }
ceilF32x4() const1674 Literal Literal::ceilF32x4() const {
1675 return unary<4, &Literal::getLanesF32x4, &Literal::ceil>(*this);
1676 }
floorF32x4() const1677 Literal Literal::floorF32x4() const {
1678 return unary<4, &Literal::getLanesF32x4, &Literal::floor>(*this);
1679 }
truncF32x4() const1680 Literal Literal::truncF32x4() const {
1681 return unary<4, &Literal::getLanesF32x4, &Literal::trunc>(*this);
1682 }
nearestF32x4() const1683 Literal Literal::nearestF32x4() const {
1684 return unary<4, &Literal::getLanesF32x4, &Literal::nearbyint>(*this);
1685 }
absF64x2() const1686 Literal Literal::absF64x2() const {
1687 return unary<2, &Literal::getLanesF64x2, &Literal::abs>(*this);
1688 }
negF64x2() const1689 Literal Literal::negF64x2() const {
1690 return unary<2, &Literal::getLanesF64x2, &Literal::neg>(*this);
1691 }
sqrtF64x2() const1692 Literal Literal::sqrtF64x2() const {
1693 return unary<2, &Literal::getLanesF64x2, &Literal::sqrt>(*this);
1694 }
ceilF64x2() const1695 Literal Literal::ceilF64x2() const {
1696 return unary<2, &Literal::getLanesF64x2, &Literal::ceil>(*this);
1697 }
floorF64x2() const1698 Literal Literal::floorF64x2() const {
1699 return unary<2, &Literal::getLanesF64x2, &Literal::floor>(*this);
1700 }
truncF64x2() const1701 Literal Literal::truncF64x2() const {
1702 return unary<2, &Literal::getLanesF64x2, &Literal::trunc>(*this);
1703 }
nearestF64x2() const1704 Literal Literal::nearestF64x2() const {
1705 return unary<2, &Literal::getLanesF64x2, &Literal::nearbyint>(*this);
1706 }
truncSatToSI32x4() const1707 Literal Literal::truncSatToSI32x4() const {
1708 return unary<4, &Literal::getLanesF32x4, &Literal::truncSatToSI32>(*this);
1709 }
truncSatToUI32x4() const1710 Literal Literal::truncSatToUI32x4() const {
1711 return unary<4, &Literal::getLanesF32x4, &Literal::truncSatToUI32>(*this);
1712 }
truncSatToSI64x2() const1713 Literal Literal::truncSatToSI64x2() const {
1714 return unary<2, &Literal::getLanesF64x2, &Literal::truncSatToSI64>(*this);
1715 }
truncSatToUI64x2() const1716 Literal Literal::truncSatToUI64x2() const {
1717 return unary<2, &Literal::getLanesF64x2, &Literal::truncSatToUI64>(*this);
1718 }
convertSToF32x4() const1719 Literal Literal::convertSToF32x4() const {
1720 return unary<4, &Literal::getLanesI32x4, &Literal::convertSIToF32>(*this);
1721 }
convertUToF32x4() const1722 Literal Literal::convertUToF32x4() const {
1723 return unary<4, &Literal::getLanesI32x4, &Literal::convertUIToF32>(*this);
1724 }
convertSToF64x2() const1725 Literal Literal::convertSToF64x2() const {
1726 return unary<2, &Literal::getLanesI64x2, &Literal::convertSIToF64>(*this);
1727 }
convertUToF64x2() const1728 Literal Literal::convertUToF64x2() const {
1729 return unary<2, &Literal::getLanesI64x2, &Literal::convertUIToF64>(*this);
1730 }
1731
1732 template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
any_true(const Literal & val)1733 static Literal any_true(const Literal& val) {
1734 LaneArray<Lanes> lanes = (val.*IntoLanes)();
1735 for (size_t i = 0; i < Lanes; ++i) {
1736 if (lanes[i] != Literal::makeZero(lanes[i].type)) {
1737 return Literal(int32_t(1));
1738 }
1739 }
1740 return Literal(int32_t(0));
1741 }
1742
1743 template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
all_true(const Literal & val)1744 static Literal all_true(const Literal& val) {
1745 LaneArray<Lanes> lanes = (val.*IntoLanes)();
1746 for (size_t i = 0; i < Lanes; ++i) {
1747 if (lanes[i] == Literal::makeZero(lanes[i].type)) {
1748 return Literal(int32_t(0));
1749 }
1750 }
1751 return Literal(int32_t(1));
1752 }
1753
1754 template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
bitmask(const Literal & val)1755 static Literal bitmask(const Literal& val) {
1756 uint32_t result = 0;
1757 LaneArray<Lanes> lanes = (val.*IntoLanes)();
1758 for (size_t i = 0; i < Lanes; ++i) {
1759 if (lanes[i].geti32() & (1 << 31)) {
1760 result = result | (1 << i);
1761 }
1762 }
1763 return Literal(result);
1764 }
1765
anyTrueI8x16() const1766 Literal Literal::anyTrueI8x16() const {
1767 return any_true<16, &Literal::getLanesUI8x16>(*this);
1768 }
allTrueI8x16() const1769 Literal Literal::allTrueI8x16() const {
1770 return all_true<16, &Literal::getLanesUI8x16>(*this);
1771 }
bitmaskI8x16() const1772 Literal Literal::bitmaskI8x16() const {
1773 return bitmask<16, &Literal::getLanesSI8x16>(*this);
1774 }
anyTrueI16x8() const1775 Literal Literal::anyTrueI16x8() const {
1776 return any_true<8, &Literal::getLanesUI16x8>(*this);
1777 }
allTrueI16x8() const1778 Literal Literal::allTrueI16x8() const {
1779 return all_true<8, &Literal::getLanesUI16x8>(*this);
1780 }
bitmaskI16x8() const1781 Literal Literal::bitmaskI16x8() const {
1782 return bitmask<8, &Literal::getLanesSI16x8>(*this);
1783 }
anyTrueI32x4() const1784 Literal Literal::anyTrueI32x4() const {
1785 return any_true<4, &Literal::getLanesI32x4>(*this);
1786 }
allTrueI32x4() const1787 Literal Literal::allTrueI32x4() const {
1788 return all_true<4, &Literal::getLanesI32x4>(*this);
1789 }
bitmaskI32x4() const1790 Literal Literal::bitmaskI32x4() const {
1791 return bitmask<4, &Literal::getLanesI32x4>(*this);
1792 }
anyTrueI64x2() const1793 Literal Literal::anyTrueI64x2() const {
1794 return any_true<2, &Literal::getLanesI64x2>(*this);
1795 }
allTrueI64x2() const1796 Literal Literal::allTrueI64x2() const {
1797 return all_true<2, &Literal::getLanesI64x2>(*this);
1798 }
1799
1800 template<int Lanes,
1801 LaneArray<Lanes> (Literal::*IntoLanes)() const,
1802 Literal (Literal::*ShiftOp)(const Literal&) const>
shift(const Literal & vec,const Literal & shift)1803 static Literal shift(const Literal& vec, const Literal& shift) {
1804 assert(shift.type == Type::i32);
1805 size_t lane_bits = 128 / Lanes;
1806 LaneArray<Lanes> lanes = (vec.*IntoLanes)();
1807 for (size_t i = 0; i < Lanes; ++i) {
1808 lanes[i] =
1809 (lanes[i].*ShiftOp)(Literal(int32_t(shift.geti32() % lane_bits)));
1810 }
1811 return Literal(lanes);
1812 }
1813
shlI8x16(const Literal & other) const1814 Literal Literal::shlI8x16(const Literal& other) const {
1815 return shift<16, &Literal::getLanesUI8x16, &Literal::shl>(*this, other);
1816 }
shrSI8x16(const Literal & other) const1817 Literal Literal::shrSI8x16(const Literal& other) const {
1818 return shift<16, &Literal::getLanesSI8x16, &Literal::shrS>(*this, other);
1819 }
shrUI8x16(const Literal & other) const1820 Literal Literal::shrUI8x16(const Literal& other) const {
1821 return shift<16, &Literal::getLanesUI8x16, &Literal::shrU>(*this, other);
1822 }
shlI16x8(const Literal & other) const1823 Literal Literal::shlI16x8(const Literal& other) const {
1824 return shift<8, &Literal::getLanesUI16x8, &Literal::shl>(*this, other);
1825 }
shrSI16x8(const Literal & other) const1826 Literal Literal::shrSI16x8(const Literal& other) const {
1827 return shift<8, &Literal::getLanesSI16x8, &Literal::shrS>(*this, other);
1828 }
shrUI16x8(const Literal & other) const1829 Literal Literal::shrUI16x8(const Literal& other) const {
1830 return shift<8, &Literal::getLanesUI16x8, &Literal::shrU>(*this, other);
1831 }
shlI32x4(const Literal & other) const1832 Literal Literal::shlI32x4(const Literal& other) const {
1833 return shift<4, &Literal::getLanesI32x4, &Literal::shl>(*this, other);
1834 }
shrSI32x4(const Literal & other) const1835 Literal Literal::shrSI32x4(const Literal& other) const {
1836 return shift<4, &Literal::getLanesI32x4, &Literal::shrS>(*this, other);
1837 }
shrUI32x4(const Literal & other) const1838 Literal Literal::shrUI32x4(const Literal& other) const {
1839 return shift<4, &Literal::getLanesI32x4, &Literal::shrU>(*this, other);
1840 }
shlI64x2(const Literal & other) const1841 Literal Literal::shlI64x2(const Literal& other) const {
1842 return shift<2, &Literal::getLanesI64x2, &Literal::shl>(*this, other);
1843 }
shrSI64x2(const Literal & other) const1844 Literal Literal::shrSI64x2(const Literal& other) const {
1845 return shift<2, &Literal::getLanesI64x2, &Literal::shrS>(*this, other);
1846 }
shrUI64x2(const Literal & other) const1847 Literal Literal::shrUI64x2(const Literal& other) const {
1848 return shift<2, &Literal::getLanesI64x2, &Literal::shrU>(*this, other);
1849 }
1850
1851 template<int Lanes,
1852 LaneArray<Lanes> (Literal::*IntoLanes)() const,
1853 Literal (Literal::*CompareOp)(const Literal&) const,
1854 typename LaneT = int32_t>
compare(const Literal & val,const Literal & other)1855 static Literal compare(const Literal& val, const Literal& other) {
1856 LaneArray<Lanes> lanes = (val.*IntoLanes)();
1857 LaneArray<Lanes> other_lanes = (other.*IntoLanes)();
1858 for (size_t i = 0; i < Lanes; ++i) {
1859 lanes[i] = (lanes[i].*CompareOp)(other_lanes[i]) == Literal(int32_t(1))
1860 ? Literal(LaneT(-1))
1861 : Literal(LaneT(0));
1862 }
1863 return Literal(lanes);
1864 }
1865
eqI8x16(const Literal & other) const1866 Literal Literal::eqI8x16(const Literal& other) const {
1867 return compare<16, &Literal::getLanesUI8x16, &Literal::eq>(*this, other);
1868 }
neI8x16(const Literal & other) const1869 Literal Literal::neI8x16(const Literal& other) const {
1870 return compare<16, &Literal::getLanesUI8x16, &Literal::ne>(*this, other);
1871 }
ltSI8x16(const Literal & other) const1872 Literal Literal::ltSI8x16(const Literal& other) const {
1873 return compare<16, &Literal::getLanesSI8x16, &Literal::ltS>(*this, other);
1874 }
ltUI8x16(const Literal & other) const1875 Literal Literal::ltUI8x16(const Literal& other) const {
1876 return compare<16, &Literal::getLanesUI8x16, &Literal::ltU>(*this, other);
1877 }
gtSI8x16(const Literal & other) const1878 Literal Literal::gtSI8x16(const Literal& other) const {
1879 return compare<16, &Literal::getLanesSI8x16, &Literal::gtS>(*this, other);
1880 }
gtUI8x16(const Literal & other) const1881 Literal Literal::gtUI8x16(const Literal& other) const {
1882 return compare<16, &Literal::getLanesUI8x16, &Literal::gtU>(*this, other);
1883 }
leSI8x16(const Literal & other) const1884 Literal Literal::leSI8x16(const Literal& other) const {
1885 return compare<16, &Literal::getLanesSI8x16, &Literal::leS>(*this, other);
1886 }
leUI8x16(const Literal & other) const1887 Literal Literal::leUI8x16(const Literal& other) const {
1888 return compare<16, &Literal::getLanesUI8x16, &Literal::leU>(*this, other);
1889 }
geSI8x16(const Literal & other) const1890 Literal Literal::geSI8x16(const Literal& other) const {
1891 return compare<16, &Literal::getLanesSI8x16, &Literal::geS>(*this, other);
1892 }
geUI8x16(const Literal & other) const1893 Literal Literal::geUI8x16(const Literal& other) const {
1894 return compare<16, &Literal::getLanesUI8x16, &Literal::geU>(*this, other);
1895 }
eqI16x8(const Literal & other) const1896 Literal Literal::eqI16x8(const Literal& other) const {
1897 return compare<8, &Literal::getLanesUI16x8, &Literal::eq>(*this, other);
1898 }
neI16x8(const Literal & other) const1899 Literal Literal::neI16x8(const Literal& other) const {
1900 return compare<8, &Literal::getLanesUI16x8, &Literal::ne>(*this, other);
1901 }
ltSI16x8(const Literal & other) const1902 Literal Literal::ltSI16x8(const Literal& other) const {
1903 return compare<8, &Literal::getLanesSI16x8, &Literal::ltS>(*this, other);
1904 }
ltUI16x8(const Literal & other) const1905 Literal Literal::ltUI16x8(const Literal& other) const {
1906 return compare<8, &Literal::getLanesUI16x8, &Literal::ltU>(*this, other);
1907 }
gtSI16x8(const Literal & other) const1908 Literal Literal::gtSI16x8(const Literal& other) const {
1909 return compare<8, &Literal::getLanesSI16x8, &Literal::gtS>(*this, other);
1910 }
gtUI16x8(const Literal & other) const1911 Literal Literal::gtUI16x8(const Literal& other) const {
1912 return compare<8, &Literal::getLanesUI16x8, &Literal::gtU>(*this, other);
1913 }
leSI16x8(const Literal & other) const1914 Literal Literal::leSI16x8(const Literal& other) const {
1915 return compare<8, &Literal::getLanesSI16x8, &Literal::leS>(*this, other);
1916 }
leUI16x8(const Literal & other) const1917 Literal Literal::leUI16x8(const Literal& other) const {
1918 return compare<8, &Literal::getLanesUI16x8, &Literal::leU>(*this, other);
1919 }
geSI16x8(const Literal & other) const1920 Literal Literal::geSI16x8(const Literal& other) const {
1921 return compare<8, &Literal::getLanesSI16x8, &Literal::geS>(*this, other);
1922 }
geUI16x8(const Literal & other) const1923 Literal Literal::geUI16x8(const Literal& other) const {
1924 return compare<8, &Literal::getLanesUI16x8, &Literal::geU>(*this, other);
1925 }
eqI32x4(const Literal & other) const1926 Literal Literal::eqI32x4(const Literal& other) const {
1927 return compare<4, &Literal::getLanesI32x4, &Literal::eq>(*this, other);
1928 }
neI32x4(const Literal & other) const1929 Literal Literal::neI32x4(const Literal& other) const {
1930 return compare<4, &Literal::getLanesI32x4, &Literal::ne>(*this, other);
1931 }
ltSI32x4(const Literal & other) const1932 Literal Literal::ltSI32x4(const Literal& other) const {
1933 return compare<4, &Literal::getLanesI32x4, &Literal::ltS>(*this, other);
1934 }
ltUI32x4(const Literal & other) const1935 Literal Literal::ltUI32x4(const Literal& other) const {
1936 return compare<4, &Literal::getLanesI32x4, &Literal::ltU>(*this, other);
1937 }
gtSI32x4(const Literal & other) const1938 Literal Literal::gtSI32x4(const Literal& other) const {
1939 return compare<4, &Literal::getLanesI32x4, &Literal::gtS>(*this, other);
1940 }
gtUI32x4(const Literal & other) const1941 Literal Literal::gtUI32x4(const Literal& other) const {
1942 return compare<4, &Literal::getLanesI32x4, &Literal::gtU>(*this, other);
1943 }
leSI32x4(const Literal & other) const1944 Literal Literal::leSI32x4(const Literal& other) const {
1945 return compare<4, &Literal::getLanesI32x4, &Literal::leS>(*this, other);
1946 }
leUI32x4(const Literal & other) const1947 Literal Literal::leUI32x4(const Literal& other) const {
1948 return compare<4, &Literal::getLanesI32x4, &Literal::leU>(*this, other);
1949 }
geSI32x4(const Literal & other) const1950 Literal Literal::geSI32x4(const Literal& other) const {
1951 return compare<4, &Literal::getLanesI32x4, &Literal::geS>(*this, other);
1952 }
geUI32x4(const Literal & other) const1953 Literal Literal::geUI32x4(const Literal& other) const {
1954 return compare<4, &Literal::getLanesI32x4, &Literal::geU>(*this, other);
1955 }
eqF32x4(const Literal & other) const1956 Literal Literal::eqF32x4(const Literal& other) const {
1957 return compare<4, &Literal::getLanesF32x4, &Literal::eq>(*this, other);
1958 }
neF32x4(const Literal & other) const1959 Literal Literal::neF32x4(const Literal& other) const {
1960 return compare<4, &Literal::getLanesF32x4, &Literal::ne>(*this, other);
1961 }
ltF32x4(const Literal & other) const1962 Literal Literal::ltF32x4(const Literal& other) const {
1963 return compare<4, &Literal::getLanesF32x4, &Literal::lt>(*this, other);
1964 }
gtF32x4(const Literal & other) const1965 Literal Literal::gtF32x4(const Literal& other) const {
1966 return compare<4, &Literal::getLanesF32x4, &Literal::gt>(*this, other);
1967 }
leF32x4(const Literal & other) const1968 Literal Literal::leF32x4(const Literal& other) const {
1969 return compare<4, &Literal::getLanesF32x4, &Literal::le>(*this, other);
1970 }
geF32x4(const Literal & other) const1971 Literal Literal::geF32x4(const Literal& other) const {
1972 return compare<4, &Literal::getLanesF32x4, &Literal::ge>(*this, other);
1973 }
eqF64x2(const Literal & other) const1974 Literal Literal::eqF64x2(const Literal& other) const {
1975 return compare<2, &Literal::getLanesF64x2, &Literal::eq, int64_t>(*this,
1976 other);
1977 }
neF64x2(const Literal & other) const1978 Literal Literal::neF64x2(const Literal& other) const {
1979 return compare<2, &Literal::getLanesF64x2, &Literal::ne, int64_t>(*this,
1980 other);
1981 }
ltF64x2(const Literal & other) const1982 Literal Literal::ltF64x2(const Literal& other) const {
1983 return compare<2, &Literal::getLanesF64x2, &Literal::lt, int64_t>(*this,
1984 other);
1985 }
gtF64x2(const Literal & other) const1986 Literal Literal::gtF64x2(const Literal& other) const {
1987 return compare<2, &Literal::getLanesF64x2, &Literal::gt, int64_t>(*this,
1988 other);
1989 }
leF64x2(const Literal & other) const1990 Literal Literal::leF64x2(const Literal& other) const {
1991 return compare<2, &Literal::getLanesF64x2, &Literal::le, int64_t>(*this,
1992 other);
1993 }
geF64x2(const Literal & other) const1994 Literal Literal::geF64x2(const Literal& other) const {
1995 return compare<2, &Literal::getLanesF64x2, &Literal::ge, int64_t>(*this,
1996 other);
1997 }
1998
1999 template<int Lanes,
2000 LaneArray<Lanes> (Literal::*IntoLanes)() const,
2001 Literal (Literal::*BinaryOp)(const Literal&) const>
binary(const Literal & val,const Literal & other)2002 static Literal binary(const Literal& val, const Literal& other) {
2003 LaneArray<Lanes> lanes = (val.*IntoLanes)();
2004 LaneArray<Lanes> other_lanes = (other.*IntoLanes)();
2005 for (size_t i = 0; i < Lanes; ++i) {
2006 lanes[i] = (lanes[i].*BinaryOp)(other_lanes[i]);
2007 }
2008 return Literal(lanes);
2009 }
2010
andV128(const Literal & other) const2011 Literal Literal::andV128(const Literal& other) const {
2012 return binary<4, &Literal::getLanesI32x4, &Literal::and_>(*this, other);
2013 }
orV128(const Literal & other) const2014 Literal Literal::orV128(const Literal& other) const {
2015 return binary<4, &Literal::getLanesI32x4, &Literal::or_>(*this, other);
2016 }
xorV128(const Literal & other) const2017 Literal Literal::xorV128(const Literal& other) const {
2018 return binary<4, &Literal::getLanesI32x4, &Literal::xor_>(*this, other);
2019 }
addI8x16(const Literal & other) const2020 Literal Literal::addI8x16(const Literal& other) const {
2021 return binary<16, &Literal::getLanesUI8x16, &Literal::add>(*this, other);
2022 }
addSaturateSI8x16(const Literal & other) const2023 Literal Literal::addSaturateSI8x16(const Literal& other) const {
2024 return binary<16, &Literal::getLanesUI8x16, &Literal::addSatSI8>(*this,
2025 other);
2026 }
addSaturateUI8x16(const Literal & other) const2027 Literal Literal::addSaturateUI8x16(const Literal& other) const {
2028 return binary<16, &Literal::getLanesSI8x16, &Literal::addSatUI8>(*this,
2029 other);
2030 }
subI8x16(const Literal & other) const2031 Literal Literal::subI8x16(const Literal& other) const {
2032 return binary<16, &Literal::getLanesUI8x16, &Literal::sub>(*this, other);
2033 }
subSaturateSI8x16(const Literal & other) const2034 Literal Literal::subSaturateSI8x16(const Literal& other) const {
2035 return binary<16, &Literal::getLanesUI8x16, &Literal::subSatSI8>(*this,
2036 other);
2037 }
subSaturateUI8x16(const Literal & other) const2038 Literal Literal::subSaturateUI8x16(const Literal& other) const {
2039 return binary<16, &Literal::getLanesSI8x16, &Literal::subSatUI8>(*this,
2040 other);
2041 }
mulI8x16(const Literal & other) const2042 Literal Literal::mulI8x16(const Literal& other) const {
2043 return binary<16, &Literal::getLanesUI8x16, &Literal::mul>(*this, other);
2044 }
minSI8x16(const Literal & other) const2045 Literal Literal::minSI8x16(const Literal& other) const {
2046 return binary<16, &Literal::getLanesSI8x16, &Literal::minInt>(*this, other);
2047 }
minUI8x16(const Literal & other) const2048 Literal Literal::minUI8x16(const Literal& other) const {
2049 return binary<16, &Literal::getLanesUI8x16, &Literal::minInt>(*this, other);
2050 }
maxSI8x16(const Literal & other) const2051 Literal Literal::maxSI8x16(const Literal& other) const {
2052 return binary<16, &Literal::getLanesSI8x16, &Literal::maxInt>(*this, other);
2053 }
maxUI8x16(const Literal & other) const2054 Literal Literal::maxUI8x16(const Literal& other) const {
2055 return binary<16, &Literal::getLanesUI8x16, &Literal::maxInt>(*this, other);
2056 }
avgrUI8x16(const Literal & other) const2057 Literal Literal::avgrUI8x16(const Literal& other) const {
2058 return binary<16, &Literal::getLanesUI8x16, &Literal::avgrUInt>(*this, other);
2059 }
addI16x8(const Literal & other) const2060 Literal Literal::addI16x8(const Literal& other) const {
2061 return binary<8, &Literal::getLanesUI16x8, &Literal::add>(*this, other);
2062 }
addSaturateSI16x8(const Literal & other) const2063 Literal Literal::addSaturateSI16x8(const Literal& other) const {
2064 return binary<8, &Literal::getLanesUI16x8, &Literal::addSatSI16>(*this,
2065 other);
2066 }
addSaturateUI16x8(const Literal & other) const2067 Literal Literal::addSaturateUI16x8(const Literal& other) const {
2068 return binary<8, &Literal::getLanesSI16x8, &Literal::addSatUI16>(*this,
2069 other);
2070 }
subI16x8(const Literal & other) const2071 Literal Literal::subI16x8(const Literal& other) const {
2072 return binary<8, &Literal::getLanesUI16x8, &Literal::sub>(*this, other);
2073 }
subSaturateSI16x8(const Literal & other) const2074 Literal Literal::subSaturateSI16x8(const Literal& other) const {
2075 return binary<8, &Literal::getLanesUI16x8, &Literal::subSatSI16>(*this,
2076 other);
2077 }
subSaturateUI16x8(const Literal & other) const2078 Literal Literal::subSaturateUI16x8(const Literal& other) const {
2079 return binary<8, &Literal::getLanesSI16x8, &Literal::subSatUI16>(*this,
2080 other);
2081 }
mulI16x8(const Literal & other) const2082 Literal Literal::mulI16x8(const Literal& other) const {
2083 return binary<8, &Literal::getLanesUI16x8, &Literal::mul>(*this, other);
2084 }
minSI16x8(const Literal & other) const2085 Literal Literal::minSI16x8(const Literal& other) const {
2086 return binary<8, &Literal::getLanesSI16x8, &Literal::minInt>(*this, other);
2087 }
minUI16x8(const Literal & other) const2088 Literal Literal::minUI16x8(const Literal& other) const {
2089 return binary<8, &Literal::getLanesUI16x8, &Literal::minInt>(*this, other);
2090 }
maxSI16x8(const Literal & other) const2091 Literal Literal::maxSI16x8(const Literal& other) const {
2092 return binary<8, &Literal::getLanesSI16x8, &Literal::maxInt>(*this, other);
2093 }
maxUI16x8(const Literal & other) const2094 Literal Literal::maxUI16x8(const Literal& other) const {
2095 return binary<8, &Literal::getLanesUI16x8, &Literal::maxInt>(*this, other);
2096 }
avgrUI16x8(const Literal & other) const2097 Literal Literal::avgrUI16x8(const Literal& other) const {
2098 return binary<8, &Literal::getLanesUI16x8, &Literal::avgrUInt>(*this, other);
2099 }
addI32x4(const Literal & other) const2100 Literal Literal::addI32x4(const Literal& other) const {
2101 return binary<4, &Literal::getLanesI32x4, &Literal::add>(*this, other);
2102 }
subI32x4(const Literal & other) const2103 Literal Literal::subI32x4(const Literal& other) const {
2104 return binary<4, &Literal::getLanesI32x4, &Literal::sub>(*this, other);
2105 }
mulI32x4(const Literal & other) const2106 Literal Literal::mulI32x4(const Literal& other) const {
2107 return binary<4, &Literal::getLanesI32x4, &Literal::mul>(*this, other);
2108 }
minSI32x4(const Literal & other) const2109 Literal Literal::minSI32x4(const Literal& other) const {
2110 return binary<4, &Literal::getLanesI32x4, &Literal::minInt>(*this, other);
2111 }
minUI32x4(const Literal & other) const2112 Literal Literal::minUI32x4(const Literal& other) const {
2113 return binary<4, &Literal::getLanesI32x4, &Literal::minUInt>(*this, other);
2114 }
maxSI32x4(const Literal & other) const2115 Literal Literal::maxSI32x4(const Literal& other) const {
2116 return binary<4, &Literal::getLanesI32x4, &Literal::maxInt>(*this, other);
2117 }
maxUI32x4(const Literal & other) const2118 Literal Literal::maxUI32x4(const Literal& other) const {
2119 return binary<4, &Literal::getLanesI32x4, &Literal::maxUInt>(*this, other);
2120 }
addI64x2(const Literal & other) const2121 Literal Literal::addI64x2(const Literal& other) const {
2122 return binary<2, &Literal::getLanesI64x2, &Literal::add>(*this, other);
2123 }
subI64x2(const Literal & other) const2124 Literal Literal::subI64x2(const Literal& other) const {
2125 return binary<2, &Literal::getLanesI64x2, &Literal::sub>(*this, other);
2126 }
mulI64x2(const Literal & other) const2127 Literal Literal::mulI64x2(const Literal& other) const {
2128 return binary<2, &Literal::getLanesI64x2, &Literal::mul>(*this, other);
2129 }
addF32x4(const Literal & other) const2130 Literal Literal::addF32x4(const Literal& other) const {
2131 return binary<4, &Literal::getLanesF32x4, &Literal::add>(*this, other);
2132 }
subF32x4(const Literal & other) const2133 Literal Literal::subF32x4(const Literal& other) const {
2134 return binary<4, &Literal::getLanesF32x4, &Literal::sub>(*this, other);
2135 }
mulF32x4(const Literal & other) const2136 Literal Literal::mulF32x4(const Literal& other) const {
2137 return binary<4, &Literal::getLanesF32x4, &Literal::mul>(*this, other);
2138 }
divF32x4(const Literal & other) const2139 Literal Literal::divF32x4(const Literal& other) const {
2140 return binary<4, &Literal::getLanesF32x4, &Literal::div>(*this, other);
2141 }
minF32x4(const Literal & other) const2142 Literal Literal::minF32x4(const Literal& other) const {
2143 return binary<4, &Literal::getLanesF32x4, &Literal::min>(*this, other);
2144 }
maxF32x4(const Literal & other) const2145 Literal Literal::maxF32x4(const Literal& other) const {
2146 return binary<4, &Literal::getLanesF32x4, &Literal::max>(*this, other);
2147 }
pminF32x4(const Literal & other) const2148 Literal Literal::pminF32x4(const Literal& other) const {
2149 return binary<4, &Literal::getLanesF32x4, &Literal::pmin>(*this, other);
2150 }
pmaxF32x4(const Literal & other) const2151 Literal Literal::pmaxF32x4(const Literal& other) const {
2152 return binary<4, &Literal::getLanesF32x4, &Literal::pmax>(*this, other);
2153 }
addF64x2(const Literal & other) const2154 Literal Literal::addF64x2(const Literal& other) const {
2155 return binary<2, &Literal::getLanesF64x2, &Literal::add>(*this, other);
2156 }
subF64x2(const Literal & other) const2157 Literal Literal::subF64x2(const Literal& other) const {
2158 return binary<2, &Literal::getLanesF64x2, &Literal::sub>(*this, other);
2159 }
mulF64x2(const Literal & other) const2160 Literal Literal::mulF64x2(const Literal& other) const {
2161 return binary<2, &Literal::getLanesF64x2, &Literal::mul>(*this, other);
2162 }
divF64x2(const Literal & other) const2163 Literal Literal::divF64x2(const Literal& other) const {
2164 return binary<2, &Literal::getLanesF64x2, &Literal::div>(*this, other);
2165 }
minF64x2(const Literal & other) const2166 Literal Literal::minF64x2(const Literal& other) const {
2167 return binary<2, &Literal::getLanesF64x2, &Literal::min>(*this, other);
2168 }
maxF64x2(const Literal & other) const2169 Literal Literal::maxF64x2(const Literal& other) const {
2170 return binary<2, &Literal::getLanesF64x2, &Literal::max>(*this, other);
2171 }
pminF64x2(const Literal & other) const2172 Literal Literal::pminF64x2(const Literal& other) const {
2173 return binary<2, &Literal::getLanesF64x2, &Literal::pmin>(*this, other);
2174 }
pmaxF64x2(const Literal & other) const2175 Literal Literal::pmaxF64x2(const Literal& other) const {
2176 return binary<2, &Literal::getLanesF64x2, &Literal::pmax>(*this, other);
2177 }
2178
dotSI16x8toI32x4(const Literal & other) const2179 Literal Literal::dotSI16x8toI32x4(const Literal& other) const {
2180 LaneArray<8> lhs = getLanesSI16x8();
2181 LaneArray<8> rhs = other.getLanesSI16x8();
2182 LaneArray<4> result;
2183 for (size_t i = 0; i < 4; ++i) {
2184 result[i] = Literal(lhs[i * 2].geti32() * rhs[i * 2].geti32() +
2185 lhs[i * 2 + 1].geti32() * rhs[i * 2 + 1].geti32());
2186 }
2187 return Literal(result);
2188 }
2189
bitselectV128(const Literal & left,const Literal & right) const2190 Literal Literal::bitselectV128(const Literal& left,
2191 const Literal& right) const {
2192 return andV128(left).orV128(notV128().andV128(right));
2193 }
2194
2195 template<typename T> struct TwiceWidth {};
2196 template<> struct TwiceWidth<int8_t> { using type = int16_t; };
2197 template<> struct TwiceWidth<int16_t> { using type = int32_t; };
2198
2199 template<typename T>
saturating_narrow(typename TwiceWidth<typename std::make_signed<T>::type>::type val)2200 Literal saturating_narrow(
2201 typename TwiceWidth<typename std::make_signed<T>::type>::type val) {
2202 using WideT = typename TwiceWidth<typename std::make_signed<T>::type>::type;
2203 if (val > WideT(std::numeric_limits<T>::max())) {
2204 val = std::numeric_limits<T>::max();
2205 } else if (val < WideT(std::numeric_limits<T>::min())) {
2206 val = std::numeric_limits<T>::min();
2207 }
2208 return Literal(int32_t(val));
2209 }
2210
2211 template<size_t Lanes,
2212 typename T,
2213 LaneArray<Lanes / 2> (Literal::*IntoLanes)() const>
2214 Literal narrow(const Literal& low, const Literal& high) {
2215 LaneArray<Lanes / 2> lowLanes = (low.*IntoLanes)();
2216 LaneArray<Lanes / 2> highLanes = (high.*IntoLanes)();
2217 LaneArray<Lanes> result;
2218 for (size_t i = 0; i < Lanes / 2; ++i) {
2219 result[i] = saturating_narrow<T>(lowLanes[i].geti32());
2220 result[Lanes / 2 + i] = saturating_narrow<T>(highLanes[i].geti32());
2221 }
2222 return Literal(result);
2223 }
2224
narrowSToVecI8x16(const Literal & other) const2225 Literal Literal::narrowSToVecI8x16(const Literal& other) const {
2226 return narrow<16, int8_t, &Literal::getLanesSI16x8>(*this, other);
2227 }
narrowUToVecI8x16(const Literal & other) const2228 Literal Literal::narrowUToVecI8x16(const Literal& other) const {
2229 return narrow<16, uint8_t, &Literal::getLanesSI16x8>(*this, other);
2230 }
narrowSToVecI16x8(const Literal & other) const2231 Literal Literal::narrowSToVecI16x8(const Literal& other) const {
2232 return narrow<8, int16_t, &Literal::getLanesI32x4>(*this, other);
2233 }
narrowUToVecI16x8(const Literal & other) const2234 Literal Literal::narrowUToVecI16x8(const Literal& other) const {
2235 return narrow<8, uint16_t, &Literal::getLanesI32x4>(*this, other);
2236 }
2237
2238 enum class LaneOrder { Low, High };
2239
2240 template<size_t Lanes,
2241 LaneArray<Lanes * 2> (Literal::*IntoLanes)() const,
2242 LaneOrder Side>
2243 Literal widen(const Literal& vec) {
2244 LaneArray<Lanes* 2> lanes = (vec.*IntoLanes)();
2245 LaneArray<Lanes> result;
2246 for (size_t i = 0; i < Lanes; ++i) {
2247 result[i] = lanes[(Side == LaneOrder::Low) ? i : i + Lanes];
2248 }
2249 return Literal(result);
2250 }
2251
widenLowSToVecI16x8() const2252 Literal Literal::widenLowSToVecI16x8() const {
2253 return widen<8, &Literal::getLanesSI8x16, LaneOrder::Low>(*this);
2254 }
widenHighSToVecI16x8() const2255 Literal Literal::widenHighSToVecI16x8() const {
2256 return widen<8, &Literal::getLanesSI8x16, LaneOrder::High>(*this);
2257 }
widenLowUToVecI16x8() const2258 Literal Literal::widenLowUToVecI16x8() const {
2259 return widen<8, &Literal::getLanesUI8x16, LaneOrder::Low>(*this);
2260 }
widenHighUToVecI16x8() const2261 Literal Literal::widenHighUToVecI16x8() const {
2262 return widen<8, &Literal::getLanesUI8x16, LaneOrder::High>(*this);
2263 }
widenLowSToVecI32x4() const2264 Literal Literal::widenLowSToVecI32x4() const {
2265 return widen<4, &Literal::getLanesSI16x8, LaneOrder::Low>(*this);
2266 }
widenHighSToVecI32x4() const2267 Literal Literal::widenHighSToVecI32x4() const {
2268 return widen<4, &Literal::getLanesSI16x8, LaneOrder::High>(*this);
2269 }
widenLowUToVecI32x4() const2270 Literal Literal::widenLowUToVecI32x4() const {
2271 return widen<4, &Literal::getLanesUI16x8, LaneOrder::Low>(*this);
2272 }
widenHighUToVecI32x4() const2273 Literal Literal::widenHighUToVecI32x4() const {
2274 return widen<4, &Literal::getLanesUI16x8, LaneOrder::High>(*this);
2275 }
2276
swizzleVec8x16(const Literal & other) const2277 Literal Literal::swizzleVec8x16(const Literal& other) const {
2278 auto lanes = getLanesUI8x16();
2279 auto indices = other.getLanesUI8x16();
2280 LaneArray<16> result;
2281 for (size_t i = 0; i < 16; ++i) {
2282 size_t index = indices[i].geti32();
2283 result[i] = index >= 16 ? Literal(int32_t(0)) : lanes[index];
2284 }
2285 return Literal(result);
2286 }
2287
2288 } // namespace wasm
2289