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