1 /*
2  * Copyright 2017 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 #ifndef wasm_literal_h
18 #define wasm_literal_h
19 
20 #include <array>
21 #include <iostream>
22 
23 #include "compiler-support.h"
24 #include "support/hash.h"
25 #include "support/name.h"
26 #include "support/small_vector.h"
27 #include "support/utilities.h"
28 #include "wasm-type.h"
29 
30 namespace wasm {
31 
32 class Literals;
33 struct ExceptionPackage;
34 
35 class Literal {
36   // store only integers, whose bits are deterministic. floats
37   // can have their signalling bit set, for example.
38   union {
39     int32_t i32;
40     int64_t i64;
41     uint8_t v128[16];
42     // funcref function name. `isNull()` indicates a `null` value.
43     Name func;
44     // exnref package. `nullptr` indicates a `null` value.
45     std::unique_ptr<ExceptionPackage> exn;
46     // TODO: Literals of type `externref` can only be `null` currently but we
47     // will need to represent extern values eventually, to
48     // 1) run the spec tests and fuzzer with reference types enabled and
49     // 2) avoid bailing out when seeing a reference typed value in precompute
50   };
51 
52 public:
53   // Type of the literal. Immutable because the literal's payload depends on it.
54   const Type type;
55 
Literal()56   Literal() : v128(), type(Type::none) {}
57   explicit Literal(Type type);
Literal(Type::BasicID typeId)58   explicit Literal(Type::BasicID typeId) : Literal(Type(typeId)) {}
Literal(int32_t init)59   explicit Literal(int32_t init) : i32(init), type(Type::i32) {}
Literal(uint32_t init)60   explicit Literal(uint32_t init) : i32(init), type(Type::i32) {}
Literal(int64_t init)61   explicit Literal(int64_t init) : i64(init), type(Type::i64) {}
Literal(uint64_t init)62   explicit Literal(uint64_t init) : i64(init), type(Type::i64) {}
Literal(float init)63   explicit Literal(float init)
64     : i32(bit_cast<int32_t>(init)), type(Type::f32) {}
Literal(double init)65   explicit Literal(double init)
66     : i64(bit_cast<int64_t>(init)), type(Type::f64) {}
67   // v128 literal from bytes
68   explicit Literal(const uint8_t init[16]);
69   // v128 literal from lane value literals
70   explicit Literal(const std::array<Literal, 16>&);
71   explicit Literal(const std::array<Literal, 8>&);
72   explicit Literal(const std::array<Literal, 4>&);
73   explicit Literal(const std::array<Literal, 2>&);
Literal(Name func)74   explicit Literal(Name func) : func(func), type(Type::funcref) {}
Literal(std::unique_ptr<ExceptionPackage> && exn)75   explicit Literal(std::unique_ptr<ExceptionPackage>&& exn)
76     : exn(std::move(exn)), type(Type::exnref) {}
77   Literal(const Literal& other);
78   Literal& operator=(const Literal& other);
~Literal()79   ~Literal() {
80     if (type.isException()) {
81       exn.~unique_ptr();
82     }
83   }
84 
isConcrete()85   bool isConcrete() const { return type != Type::none; }
isNone()86   bool isNone() const { return type == Type::none; }
isNull()87   bool isNull() const {
88     if (type.isNullable()) {
89       if (type.isFunction()) {
90         return func.isNull();
91       }
92       if (type.isException()) {
93         return !exn;
94       }
95       return true;
96     }
97     return false;
98   }
isZero()99   bool isZero() const {
100     switch (type.getBasic()) {
101       case Type::i32:
102         return i32 == 0;
103       case Type::i64:
104         return i64 == 0LL;
105       case Type::f32:
106         return bit_cast<float>(i32) == 0.0f;
107       case Type::f64:
108         return bit_cast<double>(i64) == 0.0;
109       case Type::v128: {
110         uint8_t zeros[16] = {0};
111         return memcmp(&v128, zeros, 16) == 0;
112       }
113       default:
114         WASM_UNREACHABLE("unexpected type");
115     }
116   }
isSignedMin()117   bool isSignedMin() const {
118     switch (type.getBasic()) {
119       case Type::i32:
120         return i32 == std::numeric_limits<int32_t>::min();
121       case Type::i64:
122         return i64 == std::numeric_limits<int64_t>::min();
123       default:
124         WASM_UNREACHABLE("unexpected type");
125     }
126   }
isSignedMax()127   bool isSignedMax() const {
128     switch (type.getBasic()) {
129       case Type::i32:
130         return i32 == std::numeric_limits<int32_t>::max();
131       case Type::i64:
132         return i64 == std::numeric_limits<int64_t>::max();
133       default:
134         WASM_UNREACHABLE("unexpected type");
135     }
136   }
isUnsignedMax()137   bool isUnsignedMax() const {
138     switch (type.getBasic()) {
139       case Type::i32:
140         return uint32_t(i32) == std::numeric_limits<uint32_t>::max();
141       case Type::i64:
142         return uint64_t(i64) == std::numeric_limits<uint64_t>::max();
143       default:
144         WASM_UNREACHABLE("unexpected type");
145     }
146   }
147 
148   static Literals makeZeros(Type type);
149   static Literals makeOnes(Type type);
150   static Literals makeNegOnes(Type type);
151   static Literal makeZero(Type type);
152   static Literal makeOne(Type type);
153   static Literal makeNegOne(Type type);
makeFromInt32(int32_t x,Type type)154   static Literal makeFromInt32(int32_t x, Type type) {
155     switch (type.getBasic()) {
156       case Type::i32:
157         return Literal(int32_t(x));
158       case Type::i64:
159         return Literal(int64_t(x));
160       case Type::f32:
161         return Literal(float(x));
162       case Type::f64:
163         return Literal(double(x));
164       case Type::v128:
165         return Literal(std::array<Literal, 4>{{Literal(x),
166                                                Literal(int32_t(0)),
167                                                Literal(int32_t(0)),
168                                                Literal(int32_t(0))}});
169       default:
170         WASM_UNREACHABLE("unexpected type");
171     }
172   }
makeFromInt64(int64_t x,Type type)173   static Literal makeFromInt64(int64_t x, Type type) {
174     switch (type.getBasic()) {
175       case Type::i32:
176         return Literal(int32_t(x));
177       case Type::i64:
178         return Literal(int64_t(x));
179       case Type::f32:
180         return Literal(float(x));
181       case Type::f64:
182         return Literal(double(x));
183       case Type::v128:
184         return Literal(
185           std::array<Literal, 2>{{Literal(x), Literal(int64_t(0))}});
186       default:
187         WASM_UNREACHABLE("unexpected type");
188     }
189   }
makeSignedMin(Type type)190   static Literal makeSignedMin(Type type) {
191     switch (type.getBasic()) {
192       case Type::i32:
193         return Literal(std::numeric_limits<int32_t>::min());
194       case Type::i64:
195         return Literal(std::numeric_limits<int64_t>::min());
196       default:
197         WASM_UNREACHABLE("unexpected type");
198     }
199   }
makeSignedMax(Type type)200   static Literal makeSignedMax(Type type) {
201     switch (type.getBasic()) {
202       case Type::i32:
203         return Literal(std::numeric_limits<int32_t>::max());
204       case Type::i64:
205         return Literal(std::numeric_limits<int64_t>::max());
206       default:
207         WASM_UNREACHABLE("unexpected type");
208     }
209   }
makeUnsignedMax(Type type)210   static Literal makeUnsignedMax(Type type) {
211     switch (type.getBasic()) {
212       case Type::i32:
213         return Literal(std::numeric_limits<uint32_t>::max());
214       case Type::i64:
215         return Literal(std::numeric_limits<uint64_t>::max());
216       default:
217         WASM_UNREACHABLE("unexpected type");
218     }
219   }
makeNull(Type type)220   static Literal makeNull(Type type) {
221     assert(type.isNullable());
222     return Literal(type);
223   }
makeFunc(Name func)224   static Literal makeFunc(Name func) { return Literal(func.c_str()); }
makeExn(std::unique_ptr<ExceptionPackage> && exn)225   static Literal makeExn(std::unique_ptr<ExceptionPackage>&& exn) {
226     return Literal(std::move(exn));
227   }
makeI31(int32_t value)228   static Literal makeI31(int32_t value) {
229     auto lit = Literal(Type::i31ref);
230     lit.i32 = value & 0x7fffffff;
231     return lit;
232   }
233 
234   Literal castToF32();
235   Literal castToF64();
236   Literal castToI32();
237   Literal castToI64();
238 
geti32()239   int32_t geti32() const {
240     assert(type == Type::i32);
241     return i32;
242   }
243   int32_t geti31(bool signed_ = true) const {
244     assert(type == Type::i31ref);
245     return signed_ ? (i32 << 1) >> 1 : i32;
246   }
geti64()247   int64_t geti64() const {
248     assert(type == Type::i64);
249     return i64;
250   }
getf32()251   float getf32() const {
252     assert(type == Type::f32);
253     return bit_cast<float>(i32);
254   }
getf64()255   double getf64() const {
256     assert(type == Type::f64);
257     return bit_cast<double>(i64);
258   }
259   std::array<uint8_t, 16> getv128() const;
getFunc()260   Name getFunc() const {
261     assert(type.isFunction() && !func.isNull());
262     return func;
263   }
264   ExceptionPackage getExceptionPackage() const;
265 
266   // careful!
geti32Ptr()267   int32_t* geti32Ptr() {
268     assert(type == Type::i32);
269     return &i32;
270   }
getv128Ptr()271   uint8_t* getv128Ptr() {
272     assert(type == Type::v128);
273     return v128;
274   }
getv128Ptr()275   const uint8_t* getv128Ptr() const {
276     assert(type == Type::v128);
277     return v128;
278   }
279 
reinterpreti32()280   int32_t reinterpreti32() const {
281     assert(type == Type::f32);
282     return i32;
283   }
reinterpreti64()284   int64_t reinterpreti64() const {
285     assert(type == Type::f64);
286     return i64;
287   }
reinterpretf32()288   float reinterpretf32() const {
289     assert(type == Type::i32);
290     return bit_cast<float>(i32);
291   }
reinterpretf64()292   double reinterpretf64() const {
293     assert(type == Type::i64);
294     return bit_cast<double>(i64);
295   }
296 
297   int64_t getInteger() const;
298   uint64_t getUnsigned() const;
299   double getFloat() const;
300   // Obtains the bits of a basic value typed literal.
301   void getBits(uint8_t (&buf)[16]) const;
302   // Equality checks for the type and the bits, so a nan float would
303   // be compared bitwise (which means that a Literal containing a nan
304   // would be equal to itself, if the bits are equal).
305   bool operator==(const Literal& other) const;
306   bool operator!=(const Literal& other) const;
307 
308   bool isNaN();
309 
310   static uint32_t NaNPayload(float f);
311   static uint64_t NaNPayload(double f);
312   static float setQuietNaN(float f);
313   static double setQuietNaN(double f);
314 
315   static void printFloat(std::ostream& o, float f);
316   static void printDouble(std::ostream& o, double d);
317   static void printVec128(std::ostream& o, const std::array<uint8_t, 16>& v);
318 
319   Literal countLeadingZeroes() const;
320   Literal countTrailingZeroes() const;
321   Literal popCount() const;
322 
323   Literal extendToSI64() const;
324   Literal extendToUI64() const;
325   Literal extendToF64() const;
326   Literal extendS8() const;
327   Literal extendS16() const;
328   Literal extendS32() const;
329   Literal wrapToI32() const;
330 
331   Literal convertSIToF32() const;
332   Literal convertUIToF32() const;
333   Literal convertSIToF64() const;
334   Literal convertUIToF64() const;
335 
336   Literal truncSatToSI32() const;
337   Literal truncSatToSI64() const;
338   Literal truncSatToUI32() const;
339   Literal truncSatToUI64() const;
340 
341   Literal eqz() const;
342   Literal neg() const;
343   Literal abs() const;
344   Literal ceil() const;
345   Literal floor() const;
346   Literal trunc() const;
347   Literal nearbyint() const;
348   Literal sqrt() const;
349   Literal demote() const;
350 
351   Literal add(const Literal& other) const;
352   Literal sub(const Literal& other) const;
353   Literal mul(const Literal& other) const;
354   Literal div(const Literal& other) const;
355   Literal divS(const Literal& other) const;
356   Literal divU(const Literal& other) const;
357   Literal remS(const Literal& other) const;
358   Literal remU(const Literal& other) const;
359   Literal and_(const Literal& other) const;
360   Literal or_(const Literal& other) const;
361   Literal xor_(const Literal& other) const;
362   Literal shl(const Literal& other) const;
363   Literal shrS(const Literal& other) const;
364   Literal shrU(const Literal& other) const;
365   Literal rotL(const Literal& other) const;
366   Literal rotR(const Literal& other) const;
367 
368   // Note that these functions perform equality checks based
369   // on the type of the literal, so that (unlike the == operator)
370   // a float nan would not be identical to itself.
371   Literal eq(const Literal& other) const;
372   Literal ne(const Literal& other) const;
373   Literal ltS(const Literal& other) const;
374   Literal ltU(const Literal& other) const;
375   Literal lt(const Literal& other) const;
376   Literal leS(const Literal& other) const;
377   Literal leU(const Literal& other) const;
378   Literal le(const Literal& other) const;
379 
380   Literal gtS(const Literal& other) const;
381   Literal gtU(const Literal& other) const;
382   Literal gt(const Literal& other) const;
383   Literal geS(const Literal& other) const;
384   Literal geU(const Literal& other) const;
385   Literal ge(const Literal& other) const;
386 
387   Literal min(const Literal& other) const;
388   Literal max(const Literal& other) const;
389   Literal pmin(const Literal& other) const;
390   Literal pmax(const Literal& other) const;
391   Literal copysign(const Literal& other) const;
392 
393   std::array<Literal, 16> getLanesSI8x16() const;
394   std::array<Literal, 16> getLanesUI8x16() const;
395   std::array<Literal, 8> getLanesSI16x8() const;
396   std::array<Literal, 8> getLanesUI16x8() const;
397   std::array<Literal, 4> getLanesI32x4() const;
398   std::array<Literal, 2> getLanesI64x2() const;
399   std::array<Literal, 4> getLanesF32x4() const;
400   std::array<Literal, 2> getLanesF64x2() const;
401 
402   Literal shuffleV8x16(const Literal& other,
403                        const std::array<uint8_t, 16>& mask) const;
404   Literal splatI8x16() const;
405   Literal extractLaneSI8x16(uint8_t index) const;
406   Literal extractLaneUI8x16(uint8_t index) const;
407   Literal replaceLaneI8x16(const Literal& other, uint8_t index) const;
408   Literal splatI16x8() const;
409   Literal extractLaneSI16x8(uint8_t index) const;
410   Literal extractLaneUI16x8(uint8_t index) const;
411   Literal replaceLaneI16x8(const Literal& other, uint8_t index) const;
412   Literal splatI32x4() const;
413   Literal extractLaneI32x4(uint8_t index) const;
414   Literal replaceLaneI32x4(const Literal& other, uint8_t index) const;
415   Literal splatI64x2() const;
416   Literal extractLaneI64x2(uint8_t index) const;
417   Literal replaceLaneI64x2(const Literal& other, uint8_t index) const;
418   Literal splatF32x4() const;
419   Literal extractLaneF32x4(uint8_t index) const;
420   Literal replaceLaneF32x4(const Literal& other, uint8_t index) const;
421   Literal splatF64x2() const;
422   Literal extractLaneF64x2(uint8_t index) const;
423   Literal replaceLaneF64x2(const Literal& other, uint8_t index) const;
424   Literal eqI8x16(const Literal& other) const;
425   Literal neI8x16(const Literal& other) const;
426   Literal ltSI8x16(const Literal& other) const;
427   Literal ltUI8x16(const Literal& other) const;
428   Literal gtSI8x16(const Literal& other) const;
429   Literal gtUI8x16(const Literal& other) const;
430   Literal leSI8x16(const Literal& other) const;
431   Literal leUI8x16(const Literal& other) const;
432   Literal geSI8x16(const Literal& other) const;
433   Literal geUI8x16(const Literal& other) const;
434   Literal eqI16x8(const Literal& other) const;
435   Literal neI16x8(const Literal& other) const;
436   Literal ltSI16x8(const Literal& other) const;
437   Literal ltUI16x8(const Literal& other) const;
438   Literal gtSI16x8(const Literal& other) const;
439   Literal gtUI16x8(const Literal& other) const;
440   Literal leSI16x8(const Literal& other) const;
441   Literal leUI16x8(const Literal& other) const;
442   Literal geSI16x8(const Literal& other) const;
443   Literal geUI16x8(const Literal& other) const;
444   Literal eqI32x4(const Literal& other) const;
445   Literal neI32x4(const Literal& other) const;
446   Literal ltSI32x4(const Literal& other) const;
447   Literal ltUI32x4(const Literal& other) const;
448   Literal gtSI32x4(const Literal& other) const;
449   Literal gtUI32x4(const Literal& other) const;
450   Literal leSI32x4(const Literal& other) const;
451   Literal leUI32x4(const Literal& other) const;
452   Literal geSI32x4(const Literal& other) const;
453   Literal geUI32x4(const Literal& other) const;
454   Literal eqF32x4(const Literal& other) const;
455   Literal neF32x4(const Literal& other) const;
456   Literal ltF32x4(const Literal& other) const;
457   Literal gtF32x4(const Literal& other) const;
458   Literal leF32x4(const Literal& other) const;
459   Literal geF32x4(const Literal& other) const;
460   Literal eqF64x2(const Literal& other) const;
461   Literal neF64x2(const Literal& other) const;
462   Literal ltF64x2(const Literal& other) const;
463   Literal gtF64x2(const Literal& other) const;
464   Literal leF64x2(const Literal& other) const;
465   Literal geF64x2(const Literal& other) const;
466   Literal notV128() const;
467   Literal andV128(const Literal& other) const;
468   Literal orV128(const Literal& other) const;
469   Literal xorV128(const Literal& other) const;
470   Literal bitselectV128(const Literal& left, const Literal& right) const;
471   Literal absI8x16() const;
472   Literal negI8x16() const;
473   Literal anyTrueI8x16() const;
474   Literal allTrueI8x16() const;
475   Literal bitmaskI8x16() const;
476   Literal shlI8x16(const Literal& other) const;
477   Literal shrSI8x16(const Literal& other) const;
478   Literal shrUI8x16(const Literal& other) const;
479   Literal addI8x16(const Literal& other) const;
480   Literal addSaturateSI8x16(const Literal& other) const;
481   Literal addSaturateUI8x16(const Literal& other) const;
482   Literal subI8x16(const Literal& other) const;
483   Literal subSaturateSI8x16(const Literal& other) const;
484   Literal subSaturateUI8x16(const Literal& other) const;
485   Literal mulI8x16(const Literal& other) const;
486   Literal minSI8x16(const Literal& other) const;
487   Literal minUI8x16(const Literal& other) const;
488   Literal maxSI8x16(const Literal& other) const;
489   Literal maxUI8x16(const Literal& other) const;
490   Literal avgrUI8x16(const Literal& other) const;
491   Literal absI16x8() const;
492   Literal negI16x8() const;
493   Literal anyTrueI16x8() const;
494   Literal allTrueI16x8() const;
495   Literal bitmaskI16x8() const;
496   Literal shlI16x8(const Literal& other) const;
497   Literal shrSI16x8(const Literal& other) const;
498   Literal shrUI16x8(const Literal& other) const;
499   Literal addI16x8(const Literal& other) const;
500   Literal addSaturateSI16x8(const Literal& other) const;
501   Literal addSaturateUI16x8(const Literal& other) const;
502   Literal subI16x8(const Literal& other) const;
503   Literal subSaturateSI16x8(const Literal& other) const;
504   Literal subSaturateUI16x8(const Literal& other) const;
505   Literal mulI16x8(const Literal& other) const;
506   Literal minSI16x8(const Literal& other) const;
507   Literal minUI16x8(const Literal& other) const;
508   Literal maxSI16x8(const Literal& other) const;
509   Literal maxUI16x8(const Literal& other) const;
510   Literal avgrUI16x8(const Literal& other) const;
511   Literal absI32x4() const;
512   Literal negI32x4() const;
513   Literal anyTrueI32x4() const;
514   Literal allTrueI32x4() const;
515   Literal bitmaskI32x4() const;
516   Literal shlI32x4(const Literal& other) const;
517   Literal shrSI32x4(const Literal& other) const;
518   Literal shrUI32x4(const Literal& other) const;
519   Literal addI32x4(const Literal& other) const;
520   Literal subI32x4(const Literal& other) const;
521   Literal mulI32x4(const Literal& other) const;
522   Literal minSI32x4(const Literal& other) const;
523   Literal minUI32x4(const Literal& other) const;
524   Literal maxSI32x4(const Literal& other) const;
525   Literal maxUI32x4(const Literal& other) const;
526   Literal dotSI16x8toI32x4(const Literal& other) const;
527   Literal negI64x2() const;
528   Literal anyTrueI64x2() const;
529   Literal allTrueI64x2() const;
530   Literal shlI64x2(const Literal& other) const;
531   Literal shrSI64x2(const Literal& other) const;
532   Literal shrUI64x2(const Literal& other) const;
533   Literal addI64x2(const Literal& other) const;
534   Literal subI64x2(const Literal& other) const;
535   Literal mulI64x2(const Literal& other) const;
536   Literal absF32x4() const;
537   Literal negF32x4() const;
538   Literal sqrtF32x4() const;
539   Literal addF32x4(const Literal& other) const;
540   Literal subF32x4(const Literal& other) const;
541   Literal mulF32x4(const Literal& other) const;
542   Literal divF32x4(const Literal& other) const;
543   Literal minF32x4(const Literal& other) const;
544   Literal maxF32x4(const Literal& other) const;
545   Literal pminF32x4(const Literal& other) const;
546   Literal pmaxF32x4(const Literal& other) const;
547   Literal ceilF32x4() const;
548   Literal floorF32x4() const;
549   Literal truncF32x4() const;
550   Literal nearestF32x4() const;
551   Literal absF64x2() const;
552   Literal negF64x2() const;
553   Literal sqrtF64x2() const;
554   Literal addF64x2(const Literal& other) const;
555   Literal subF64x2(const Literal& other) const;
556   Literal mulF64x2(const Literal& other) const;
557   Literal divF64x2(const Literal& other) const;
558   Literal minF64x2(const Literal& other) const;
559   Literal maxF64x2(const Literal& other) const;
560   Literal pminF64x2(const Literal& other) const;
561   Literal pmaxF64x2(const Literal& other) const;
562   Literal ceilF64x2() const;
563   Literal floorF64x2() const;
564   Literal truncF64x2() const;
565   Literal nearestF64x2() const;
566   Literal truncSatToSI32x4() const;
567   Literal truncSatToUI32x4() const;
568   Literal truncSatToSI64x2() const;
569   Literal truncSatToUI64x2() const;
570   Literal convertSToF32x4() const;
571   Literal convertUToF32x4() const;
572   Literal convertSToF64x2() const;
573   Literal convertUToF64x2() const;
574   Literal narrowSToVecI8x16(const Literal& other) const;
575   Literal narrowUToVecI8x16(const Literal& other) const;
576   Literal narrowSToVecI16x8(const Literal& other) const;
577   Literal narrowUToVecI16x8(const Literal& other) const;
578   Literal widenLowSToVecI16x8() const;
579   Literal widenHighSToVecI16x8() const;
580   Literal widenLowUToVecI16x8() const;
581   Literal widenHighUToVecI16x8() const;
582   Literal widenLowSToVecI32x4() const;
583   Literal widenHighSToVecI32x4() const;
584   Literal widenLowUToVecI32x4() const;
585   Literal widenHighUToVecI32x4() const;
586   Literal swizzleVec8x16(const Literal& other) const;
587 
588 private:
589   Literal addSatSI8(const Literal& other) const;
590   Literal addSatUI8(const Literal& other) const;
591   Literal addSatSI16(const Literal& other) const;
592   Literal addSatUI16(const Literal& other) const;
593   Literal subSatSI8(const Literal& other) const;
594   Literal subSatUI8(const Literal& other) const;
595   Literal subSatSI16(const Literal& other) const;
596   Literal subSatUI16(const Literal& other) const;
597   Literal minInt(const Literal& other) const;
598   Literal maxInt(const Literal& other) const;
599   Literal minUInt(const Literal& other) const;
600   Literal maxUInt(const Literal& other) const;
601   Literal avgrUInt(const Literal& other) const;
602 };
603 
604 class Literals : public SmallVector<Literal, 1> {
605 public:
606   Literals() = default;
Literals(std::initializer_list<Literal> init)607   Literals(std::initializer_list<Literal> init)
608     : SmallVector<Literal, 1>(init) {
609 #ifndef NDEBUG
610     for (auto& lit : init) {
611       assert(lit.isConcrete());
612     }
613 #endif
614   };
getType()615   Type getType() {
616     std::vector<Type> types;
617     for (auto& val : *this) {
618       types.push_back(val.type);
619     }
620     return Type(types);
621   }
isNone()622   bool isNone() { return size() == 0; }
isConcrete()623   bool isConcrete() { return size() != 0; }
624 };
625 
626 // A struct for a thrown exception, which includes a tag (event) and thrown
627 // values
628 struct ExceptionPackage {
629   Name event;
630   Literals values;
631   bool operator==(const ExceptionPackage& other) const {
632     return event == other.event && values == other.values;
633   }
634   bool operator!=(const ExceptionPackage& other) const {
635     return !(*this == other);
636   }
637 };
638 
639 std::ostream& operator<<(std::ostream& o, wasm::Literal literal);
640 std::ostream& operator<<(std::ostream& o, wasm::Literals literals);
641 std::ostream& operator<<(std::ostream& o, const ExceptionPackage& exn);
642 
643 } // namespace wasm
644 
645 namespace std {
646 template<> struct hash<wasm::Literal> {
647   size_t operator()(const wasm::Literal& a) const {
648     auto digest = wasm::hash(a.type.getID());
649     auto hashRef = [&]() {
650       assert(a.type.isRef());
651       if (a.isNull()) {
652         return digest;
653       }
654       if (a.type.isFunction()) {
655         wasm::rehash(digest, a.getFunc());
656         return digest;
657       }
658       if (a.type.isException()) {
659         auto exn = a.getExceptionPackage();
660         wasm::rehash(digest, exn.event);
661         wasm::rehash(digest, exn.values);
662         return digest;
663       }
664       // other non-null reference type literals cannot represent concrete
665       // values, i.e. there is no concrete externref, anyref or eqref other than
666       // null.
667       WASM_UNREACHABLE("unexpected type");
668     };
669     if (a.type.isBasic()) {
670       switch (a.type.getBasic()) {
671         case wasm::Type::i32:
672           wasm::rehash(digest, a.geti32());
673           return digest;
674         case wasm::Type::f32:
675           wasm::rehash(digest, a.reinterpreti32());
676           return digest;
677         case wasm::Type::i64:
678           wasm::rehash(digest, a.geti64());
679           return digest;
680         case wasm::Type::f64:
681           wasm::rehash(digest, a.reinterpreti64());
682           return digest;
683         case wasm::Type::v128:
684           uint64_t chunks[2];
685           memcpy(&chunks, a.getv128Ptr(), 16);
686           wasm::rehash(digest, chunks[0]);
687           wasm::rehash(digest, chunks[1]);
688           return digest;
689         case wasm::Type::funcref:
690         case wasm::Type::externref:
691         case wasm::Type::exnref:
692         case wasm::Type::anyref:
693         case wasm::Type::eqref:
694           return hashRef();
695         case wasm::Type::i31ref:
696           wasm::rehash(digest, a.geti31(true));
697           return digest;
698         case wasm::Type::none:
699         case wasm::Type::unreachable:
700           break;
701       }
702     } else if (a.type.isRef()) {
703       return hashRef();
704     } else if (a.type.isRtt()) {
705       WASM_UNREACHABLE("TODO: rtt literals");
706     }
707     WASM_UNREACHABLE("unexpected type");
708   }
709 };
710 template<> struct hash<wasm::Literals> {
711   size_t operator()(const wasm::Literals& a) const {
712     auto digest = wasm::hash(a.size());
713     for (const auto& lit : a) {
714       wasm::rehash(digest, lit);
715     }
716     return digest;
717   }
718 };
719 template<> struct less<wasm::Literal> {
720   bool operator()(const wasm::Literal& a, const wasm::Literal& b) const {
721     if (a.type < b.type) {
722       return true;
723     }
724     if (b.type < a.type) {
725       return false;
726     }
727     TODO_SINGLE_COMPOUND(a.type);
728     switch (a.type.getBasic()) {
729       case wasm::Type::i32:
730         return a.geti32() < b.geti32();
731       case wasm::Type::f32:
732         return a.reinterpreti32() < b.reinterpreti32();
733       case wasm::Type::i64:
734         return a.geti64() < b.geti64();
735       case wasm::Type::f64:
736         return a.reinterpreti64() < b.reinterpreti64();
737       case wasm::Type::v128:
738         return memcmp(a.getv128Ptr(), b.getv128Ptr(), 16) < 0;
739       case wasm::Type::funcref:
740       case wasm::Type::externref:
741       case wasm::Type::exnref:
742       case wasm::Type::anyref:
743       case wasm::Type::eqref:
744       case wasm::Type::i31ref:
745       case wasm::Type::none:
746       case wasm::Type::unreachable:
747         return false;
748     }
749     WASM_UNREACHABLE("unexpected type");
750   }
751 };
752 } // namespace std
753 
754 #endif // wasm_literal_h
755