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 | #include <variant> |
23 | |
24 | #include "compiler-support.h" |
25 | #include "support/hash.h" |
26 | #include "support/name.h" |
27 | #include "support/small_vector.h" |
28 | #include "support/utilities.h" |
29 | #include "wasm-type.h" |
30 | |
31 | namespace wasm { |
32 | |
33 | class Literals; |
34 | struct GCData; |
35 | |
36 | class Literal { |
37 | // store only integers, whose bits are deterministic. floats |
38 | // can have their signalling bit set, for example. |
39 | union { |
40 | // Note: i31 is stored in the |i32| field, with the lower 31 bits containing |
41 | // the value if there is one, and the highest bit containing whether there |
42 | // is a value. Thus, a null is |i32 === 0|. |
43 | int32_t i32; |
44 | int64_t i64; |
45 | uint8_t v128[16]; |
46 | // funcref function name. `isNull()` indicates a `null` value. |
47 | Name func; |
48 | // A reference to GC data, either a Struct or an Array. For both of those we |
49 | // store the referred data as a Literals object (which is natural for an |
50 | // Array, and for a Struct, is just the fields in order). The type is used |
51 | // to indicate whether this is a Struct or an Array, and of what type. We |
52 | // also use this to store String data, as it is similarly stored on the |
53 | // heap. For externrefs, the gcData is the same as for the corresponding |
54 | // internal references and the values are only differentiated by the type. |
55 | // Externalized i31 references have a gcData containing the internal i31 |
56 | // reference as its sole value even though internal i31 references do not |
57 | // have a gcData. |
58 | std::shared_ptr<GCData> gcData; |
59 | }; |
60 | |
61 | public: |
62 | // Type of the literal. Immutable because the literal's payload depends on it. |
63 | const Type type; |
64 | |
65 | Literal() : v128(), type(Type::none) {} |
66 | explicit Literal(Type type); |
67 | explicit Literal(Type::BasicType type) : Literal(Type(type)) {} |
68 | explicit Literal(int32_t init) : i32(init), type(Type::i32) {} |
69 | explicit Literal(uint32_t init) : i32(init), type(Type::i32) {} |
70 | explicit Literal(int64_t init) : i64(init), type(Type::i64) {} |
71 | explicit Literal(uint64_t init) : i64(init), type(Type::i64) {} |
72 | explicit Literal(float init) |
73 | : i32(bit_cast<int32_t>(init)), type(Type::f32) {} |
74 | explicit Literal(double init) |
75 | : i64(bit_cast<int64_t>(init)), type(Type::f64) {} |
76 | // v128 literal from bytes |
77 | explicit Literal(const uint8_t init[16]); |
78 | // v128 literal from lane value literals |
79 | explicit Literal(const std::array<Literal, 16>&); |
80 | explicit Literal(const std::array<Literal, 8>&); |
81 | explicit Literal(const std::array<Literal, 4>&); |
82 | explicit Literal(const std::array<Literal, 2>&); |
83 | explicit Literal(Name func, HeapType type) |
84 | : func(func), type(type, NonNullable) { |
85 | assert(type.isSignature()); |
86 | } |
87 | explicit Literal(std::shared_ptr<GCData> gcData, HeapType type); |
88 | explicit Literal(std::string string); |
89 | Literal(const Literal& other); |
90 | Literal& operator=(const Literal& other); |
91 | ~Literal(); |
92 | |
93 | bool isConcrete() const { return type.isConcrete(); } |
94 | bool isNone() const { return type == Type::none; } |
95 | bool isFunction() const { return type.isFunction(); } |
96 | // Whether this is GC data, that is, something stored on the heap (aside from |
97 | // a null or i31). This includes structs, arrays, and also strings. |
98 | bool isData() const { return type.isData(); } |
99 | bool isString() const { return type.isString(); } |
100 | |
101 | bool isNull() const { return type.isNull(); } |
102 | |
103 | bool isZero() const { |
104 | switch (type.getBasic()) { |
105 | case Type::i32: |
106 | return i32 == 0; |
107 | case Type::i64: |
108 | return i64 == 0LL; |
109 | case Type::f32: |
110 | return bit_cast<float>(i32) == 0.0f; |
111 | case Type::f64: |
112 | return bit_cast<double>(i64) == 0.0; |
113 | case Type::v128: { |
114 | uint8_t zeros[16] = {0}; |
115 | return memcmp(&v128, zeros, 16) == 0; |
116 | } |
117 | default: |
118 | WASM_UNREACHABLE("unexpected type" ); |
119 | } |
120 | } |
121 | bool isNegative() const { |
122 | switch (type.getBasic()) { |
123 | case Type::i32: |
124 | case Type::f32: |
125 | return i32 < 0; |
126 | case Type::i64: |
127 | case Type::f64: |
128 | return i64 < 0; |
129 | default: |
130 | WASM_UNREACHABLE("unexpected type" ); |
131 | } |
132 | } |
133 | bool isSignedMin() const { |
134 | switch (type.getBasic()) { |
135 | case Type::i32: |
136 | return i32 == std::numeric_limits<int32_t>::min(); |
137 | case Type::i64: |
138 | return i64 == std::numeric_limits<int64_t>::min(); |
139 | default: |
140 | WASM_UNREACHABLE("unexpected type" ); |
141 | } |
142 | } |
143 | bool isSignedMax() const { |
144 | switch (type.getBasic()) { |
145 | case Type::i32: |
146 | return i32 == std::numeric_limits<int32_t>::max(); |
147 | case Type::i64: |
148 | return i64 == std::numeric_limits<int64_t>::max(); |
149 | default: |
150 | WASM_UNREACHABLE("unexpected type" ); |
151 | } |
152 | } |
153 | bool isUnsignedMax() const { |
154 | switch (type.getBasic()) { |
155 | case Type::i32: |
156 | return uint32_t(i32) == std::numeric_limits<uint32_t>::max(); |
157 | case Type::i64: |
158 | return uint64_t(i64) == std::numeric_limits<uint64_t>::max(); |
159 | default: |
160 | WASM_UNREACHABLE("unexpected type" ); |
161 | } |
162 | } |
163 | |
164 | static Literals makeZeros(Type type); |
165 | static Literals makeOnes(Type type); |
166 | static Literals makeNegOnes(Type type); |
167 | static Literal makeZero(Type type); |
168 | static Literal makeOne(Type type); |
169 | static Literal makeNegOne(Type type); |
170 | static Literal makeFromInt32(int32_t x, Type type) { |
171 | switch (type.getBasic()) { |
172 | case Type::i32: |
173 | return Literal(int32_t(x)); |
174 | case Type::i64: |
175 | return Literal(int64_t(x)); |
176 | case Type::f32: |
177 | return Literal(float(x)); |
178 | case Type::f64: |
179 | return Literal(double(x)); |
180 | case Type::v128: |
181 | return Literal(std::array<Literal, 4>{{Literal(x), |
182 | Literal(int32_t(0)), |
183 | Literal(int32_t(0)), |
184 | Literal(int32_t(0))}}); |
185 | default: |
186 | WASM_UNREACHABLE("unexpected type" ); |
187 | } |
188 | } |
189 | static Literal makeFromInt64(int64_t x, Type type) { |
190 | switch (type.getBasic()) { |
191 | case Type::i32: |
192 | return Literal(int32_t(x)); |
193 | case Type::i64: |
194 | return Literal(int64_t(x)); |
195 | case Type::f32: |
196 | return Literal(float(x)); |
197 | case Type::f64: |
198 | return Literal(double(x)); |
199 | case Type::v128: |
200 | return Literal( |
201 | std::array<Literal, 2>{{Literal(x), Literal(int64_t(0))}}); |
202 | default: |
203 | WASM_UNREACHABLE("unexpected type" ); |
204 | } |
205 | } |
206 | |
207 | static Literal makeFromMemory(void* p, Type type); |
208 | static Literal makeFromMemory(void* p, const Field& field); |
209 | |
210 | static Literal makeSignedMin(Type type) { |
211 | switch (type.getBasic()) { |
212 | case Type::i32: |
213 | return Literal(std::numeric_limits<int32_t>::min()); |
214 | case Type::i64: |
215 | return Literal(std::numeric_limits<int64_t>::min()); |
216 | default: |
217 | WASM_UNREACHABLE("unexpected type" ); |
218 | } |
219 | } |
220 | static Literal makeSignedMax(Type type) { |
221 | switch (type.getBasic()) { |
222 | case Type::i32: |
223 | return Literal(std::numeric_limits<int32_t>::max()); |
224 | case Type::i64: |
225 | return Literal(std::numeric_limits<int64_t>::max()); |
226 | default: |
227 | WASM_UNREACHABLE("unexpected type" ); |
228 | } |
229 | } |
230 | static Literal makeUnsignedMax(Type type) { |
231 | switch (type.getBasic()) { |
232 | case Type::i32: |
233 | return Literal(std::numeric_limits<uint32_t>::max()); |
234 | case Type::i64: |
235 | return Literal(std::numeric_limits<uint64_t>::max()); |
236 | default: |
237 | WASM_UNREACHABLE("unexpected type" ); |
238 | } |
239 | } |
240 | static Literal makeNull(HeapType type) { |
241 | return Literal(Type(type.getBottom(), Nullable)); |
242 | } |
243 | static Literal makeFunc(Name func, HeapType type) { |
244 | return Literal(func, type); |
245 | } |
246 | static Literal makeI31(int32_t value) { |
247 | auto lit = Literal(Type(HeapType::i31, NonNullable)); |
248 | lit.i32 = value | 0x80000000; |
249 | return lit; |
250 | } |
251 | // Wasm has nondeterministic rules for NaN propagation in some operations. For |
252 | // example. f32.neg is deterministic and just flips the sign, even of a NaN, |
253 | // but f32.add is nondeterministic, and if one or more of the inputs is a NaN, |
254 | // then |
255 | // |
256 | // * if all NaNs are canonical, the output is some arbitrary canonical NaN |
257 | // * otherwise the output is some arbitrary arithmetic NaN |
258 | // |
259 | // (canonical = NaN payload is 1000..000; arithmetic: 1???..???, that is, the |
260 | // high bit is 1 and all others can be 0 or 1) |
261 | // |
262 | // For many things we don't need to care, and can just do a normal C++ add for |
263 | // an f32.add, for example - the wasm rules are specified so that things like |
264 | // that just work (in order for such math to be fast). However, for our |
265 | // optimizer, it is useful to "standardize" NaNs when there is nondeterminism. |
266 | // That is, when there are multiple valid outputs, it's nice to emit the same |
267 | // one consistently, so that it doesn't look like the optimization changed |
268 | // something. In other words, if the valid output of an expression is a set of |
269 | // valid NaNs, and after optimization the output is still that same set, then |
270 | // the optimization is valid. And if the interpreter picks the same NaN in |
271 | // both cases from that identical set then nothing looks wrong to the fuzzer. |
272 | static Literal standardizeNaN(const Literal& input); |
273 | |
274 | Literal castToF32(); |
275 | Literal castToF64(); |
276 | Literal castToI32(); |
277 | Literal castToI64(); |
278 | |
279 | int32_t geti32() const { |
280 | assert(type == Type::i32); |
281 | return i32; |
282 | } |
283 | int32_t geti31(bool signed_ = true) const { |
284 | assert(type.getHeapType() == HeapType::i31); |
285 | // Cast to unsigned for the left shift to avoid undefined behavior. |
286 | return signed_ ? int32_t((uint32_t(i32) << 1)) >> 1 : (i32 & 0x7fffffff); |
287 | } |
288 | int64_t geti64() const { |
289 | assert(type == Type::i64); |
290 | return i64; |
291 | } |
292 | float getf32() const { |
293 | assert(type == Type::f32); |
294 | return bit_cast<float>(i32); |
295 | } |
296 | double getf64() const { |
297 | assert(type == Type::f64); |
298 | return bit_cast<double>(i64); |
299 | } |
300 | std::array<uint8_t, 16> getv128() const; |
301 | Name getFunc() const { |
302 | assert(type.isFunction() && !func.isNull()); |
303 | return func; |
304 | } |
305 | std::shared_ptr<GCData> getGCData() const; |
306 | |
307 | // careful! |
308 | int32_t* geti32Ptr() { |
309 | assert(type == Type::i32); |
310 | return &i32; |
311 | } |
312 | uint8_t* getv128Ptr() { |
313 | assert(type == Type::v128); |
314 | return v128; |
315 | } |
316 | const uint8_t* getv128Ptr() const { |
317 | assert(type == Type::v128); |
318 | return v128; |
319 | } |
320 | |
321 | int32_t reinterpreti32() const { |
322 | assert(type == Type::f32); |
323 | return i32; |
324 | } |
325 | int64_t reinterpreti64() const { |
326 | assert(type == Type::f64); |
327 | return i64; |
328 | } |
329 | float reinterpretf32() const { |
330 | assert(type == Type::i32); |
331 | return bit_cast<float>(i32); |
332 | } |
333 | double reinterpretf64() const { |
334 | assert(type == Type::i64); |
335 | return bit_cast<double>(i64); |
336 | } |
337 | |
338 | int64_t getInteger() const; |
339 | uint64_t getUnsigned() const; |
340 | double getFloat() const; |
341 | // Obtains the bits of a basic value typed literal. |
342 | void getBits(uint8_t (&buf)[16]) const; |
343 | // Equality checks for the type and the bits, so a nan float would |
344 | // be compared bitwise (which means that a Literal containing a nan |
345 | // would be equal to itself, if the bits are equal). |
346 | bool operator==(const Literal& other) const; |
347 | bool operator!=(const Literal& other) const; |
348 | |
349 | bool isNaN(); |
350 | |
351 | static uint32_t NaNPayload(float f); |
352 | static uint64_t NaNPayload(double f); |
353 | static float setQuietNaN(float f); |
354 | static double setQuietNaN(double f); |
355 | |
356 | static void printFloat(std::ostream& o, float f); |
357 | static void printDouble(std::ostream& o, double d); |
358 | static void printVec128(std::ostream& o, const std::array<uint8_t, 16>& v); |
359 | |
360 | Literal countLeadingZeroes() const; |
361 | Literal countTrailingZeroes() const; |
362 | Literal popCount() const; |
363 | |
364 | Literal extendToSI64() const; |
365 | Literal extendToUI64() const; |
366 | Literal extendToF64() const; |
367 | Literal extendS8() const; |
368 | Literal extendS16() const; |
369 | Literal extendS32() const; |
370 | Literal wrapToI32() const; |
371 | |
372 | Literal convertSIToF32() const; |
373 | Literal convertUIToF32() const; |
374 | Literal convertSIToF64() const; |
375 | Literal convertUIToF64() const; |
376 | |
377 | Literal truncSatToSI32() const; |
378 | Literal truncSatToSI64() const; |
379 | Literal truncSatToUI32() const; |
380 | Literal truncSatToUI64() const; |
381 | |
382 | Literal eqz() const; |
383 | Literal neg() const; |
384 | Literal abs() const; |
385 | Literal ceil() const; |
386 | Literal floor() const; |
387 | Literal trunc() const; |
388 | Literal nearbyint() const; |
389 | Literal sqrt() const; |
390 | Literal demote() const; |
391 | |
392 | Literal add(const Literal& other) const; |
393 | Literal sub(const Literal& other) const; |
394 | Literal mul(const Literal& other) const; |
395 | Literal div(const Literal& other) const; |
396 | Literal divS(const Literal& other) const; |
397 | Literal divU(const Literal& other) const; |
398 | Literal remS(const Literal& other) const; |
399 | Literal remU(const Literal& other) const; |
400 | Literal and_(const Literal& other) const; |
401 | Literal or_(const Literal& other) const; |
402 | Literal xor_(const Literal& other) const; |
403 | Literal shl(const Literal& other) const; |
404 | Literal shrS(const Literal& other) const; |
405 | Literal shrU(const Literal& other) const; |
406 | Literal rotL(const Literal& other) const; |
407 | Literal rotR(const Literal& other) const; |
408 | |
409 | // Note that these functions perform equality checks based |
410 | // on the type of the literal, so that (unlike the == operator) |
411 | // a float nan would not be identical to itself. |
412 | Literal eq(const Literal& other) const; |
413 | Literal ne(const Literal& other) const; |
414 | Literal ltS(const Literal& other) const; |
415 | Literal ltU(const Literal& other) const; |
416 | Literal lt(const Literal& other) const; |
417 | Literal leS(const Literal& other) const; |
418 | Literal leU(const Literal& other) const; |
419 | Literal le(const Literal& other) const; |
420 | |
421 | Literal gtS(const Literal& other) const; |
422 | Literal gtU(const Literal& other) const; |
423 | Literal gt(const Literal& other) const; |
424 | Literal geS(const Literal& other) const; |
425 | Literal geU(const Literal& other) const; |
426 | Literal ge(const Literal& other) const; |
427 | |
428 | Literal min(const Literal& other) const; |
429 | Literal max(const Literal& other) const; |
430 | Literal pmin(const Literal& other) const; |
431 | Literal pmax(const Literal& other) const; |
432 | Literal copysign(const Literal& other) const; |
433 | |
434 | // Fused multiply add and subtract. |
435 | // Computes this + (left * right) to infinite precision then round once. |
436 | Literal fma(const Literal& left, const Literal& right) const; |
437 | Literal fms(const Literal& left, const Literal& right) const; |
438 | |
439 | std::array<Literal, 16> getLanesSI8x16() const; |
440 | std::array<Literal, 16> getLanesUI8x16() const; |
441 | std::array<Literal, 8> getLanesSI16x8() const; |
442 | std::array<Literal, 8> getLanesUI16x8() const; |
443 | std::array<Literal, 4> getLanesI32x4() const; |
444 | std::array<Literal, 2> getLanesI64x2() const; |
445 | std::array<Literal, 4> getLanesF32x4() const; |
446 | std::array<Literal, 2> getLanesF64x2() const; |
447 | |
448 | Literal shuffleV8x16(const Literal& other, |
449 | const std::array<uint8_t, 16>& mask) const; |
450 | Literal splatI8x16() const; |
451 | Literal (uint8_t index) const; |
452 | Literal (uint8_t index) const; |
453 | Literal replaceLaneI8x16(const Literal& other, uint8_t index) const; |
454 | Literal splatI16x8() const; |
455 | Literal (uint8_t index) const; |
456 | Literal (uint8_t index) const; |
457 | Literal replaceLaneI16x8(const Literal& other, uint8_t index) const; |
458 | Literal splatI32x4() const; |
459 | Literal (uint8_t index) const; |
460 | Literal replaceLaneI32x4(const Literal& other, uint8_t index) const; |
461 | Literal splatI64x2() const; |
462 | Literal (uint8_t index) const; |
463 | Literal replaceLaneI64x2(const Literal& other, uint8_t index) const; |
464 | Literal splatF32x4() const; |
465 | Literal (uint8_t index) const; |
466 | Literal replaceLaneF32x4(const Literal& other, uint8_t index) const; |
467 | Literal splatF64x2() const; |
468 | Literal (uint8_t index) const; |
469 | Literal replaceLaneF64x2(const Literal& other, uint8_t index) const; |
470 | Literal eqI8x16(const Literal& other) const; |
471 | Literal neI8x16(const Literal& other) const; |
472 | Literal ltSI8x16(const Literal& other) const; |
473 | Literal ltUI8x16(const Literal& other) const; |
474 | Literal gtSI8x16(const Literal& other) const; |
475 | Literal gtUI8x16(const Literal& other) const; |
476 | Literal leSI8x16(const Literal& other) const; |
477 | Literal leUI8x16(const Literal& other) const; |
478 | Literal geSI8x16(const Literal& other) const; |
479 | Literal geUI8x16(const Literal& other) const; |
480 | Literal eqI16x8(const Literal& other) const; |
481 | Literal neI16x8(const Literal& other) const; |
482 | Literal ltSI16x8(const Literal& other) const; |
483 | Literal ltUI16x8(const Literal& other) const; |
484 | Literal gtSI16x8(const Literal& other) const; |
485 | Literal gtUI16x8(const Literal& other) const; |
486 | Literal leSI16x8(const Literal& other) const; |
487 | Literal leUI16x8(const Literal& other) const; |
488 | Literal geSI16x8(const Literal& other) const; |
489 | Literal geUI16x8(const Literal& other) const; |
490 | Literal eqI32x4(const Literal& other) const; |
491 | Literal neI32x4(const Literal& other) const; |
492 | Literal ltSI32x4(const Literal& other) const; |
493 | Literal ltUI32x4(const Literal& other) const; |
494 | Literal gtSI32x4(const Literal& other) const; |
495 | Literal gtUI32x4(const Literal& other) const; |
496 | Literal leSI32x4(const Literal& other) const; |
497 | Literal leUI32x4(const Literal& other) const; |
498 | Literal geSI32x4(const Literal& other) const; |
499 | Literal geUI32x4(const Literal& other) const; |
500 | Literal eqI64x2(const Literal& other) const; |
501 | Literal neI64x2(const Literal& other) const; |
502 | Literal ltSI64x2(const Literal& other) const; |
503 | Literal gtSI64x2(const Literal& other) const; |
504 | Literal leSI64x2(const Literal& other) const; |
505 | Literal geSI64x2(const Literal& other) const; |
506 | Literal eqF32x4(const Literal& other) const; |
507 | Literal neF32x4(const Literal& other) const; |
508 | Literal ltF32x4(const Literal& other) const; |
509 | Literal gtF32x4(const Literal& other) const; |
510 | Literal leF32x4(const Literal& other) const; |
511 | Literal geF32x4(const Literal& other) const; |
512 | Literal eqF64x2(const Literal& other) const; |
513 | Literal neF64x2(const Literal& other) const; |
514 | Literal ltF64x2(const Literal& other) const; |
515 | Literal gtF64x2(const Literal& other) const; |
516 | Literal leF64x2(const Literal& other) const; |
517 | Literal geF64x2(const Literal& other) const; |
518 | Literal notV128() const; |
519 | Literal andV128(const Literal& other) const; |
520 | Literal orV128(const Literal& other) const; |
521 | Literal xorV128(const Literal& other) const; |
522 | Literal anyTrueV128() const; |
523 | Literal bitselectV128(const Literal& left, const Literal& right) const; |
524 | Literal absI8x16() const; |
525 | Literal negI8x16() const; |
526 | Literal allTrueI8x16() const; |
527 | Literal bitmaskI8x16() const; |
528 | Literal shlI8x16(const Literal& other) const; |
529 | Literal shrSI8x16(const Literal& other) const; |
530 | Literal shrUI8x16(const Literal& other) const; |
531 | Literal addI8x16(const Literal& other) const; |
532 | Literal addSaturateSI8x16(const Literal& other) const; |
533 | Literal addSaturateUI8x16(const Literal& other) const; |
534 | Literal subI8x16(const Literal& other) const; |
535 | Literal subSaturateSI8x16(const Literal& other) const; |
536 | Literal subSaturateUI8x16(const Literal& other) const; |
537 | Literal minSI8x16(const Literal& other) const; |
538 | Literal minUI8x16(const Literal& other) const; |
539 | Literal maxSI8x16(const Literal& other) const; |
540 | Literal maxUI8x16(const Literal& other) const; |
541 | Literal avgrUI8x16(const Literal& other) const; |
542 | Literal popcntI8x16() const; |
543 | Literal absI16x8() const; |
544 | Literal negI16x8() const; |
545 | Literal allTrueI16x8() const; |
546 | Literal bitmaskI16x8() const; |
547 | Literal shlI16x8(const Literal& other) const; |
548 | Literal shrSI16x8(const Literal& other) const; |
549 | Literal shrUI16x8(const Literal& other) const; |
550 | Literal addI16x8(const Literal& other) const; |
551 | Literal addSaturateSI16x8(const Literal& other) const; |
552 | Literal addSaturateUI16x8(const Literal& other) const; |
553 | Literal subI16x8(const Literal& other) const; |
554 | Literal subSaturateSI16x8(const Literal& other) const; |
555 | Literal subSaturateUI16x8(const Literal& other) const; |
556 | Literal mulI16x8(const Literal& other) const; |
557 | Literal minSI16x8(const Literal& other) const; |
558 | Literal minUI16x8(const Literal& other) const; |
559 | Literal maxSI16x8(const Literal& other) const; |
560 | Literal maxUI16x8(const Literal& other) const; |
561 | Literal avgrUI16x8(const Literal& other) const; |
562 | Literal q15MulrSatSI16x8(const Literal& other) const; |
563 | Literal extMulLowSI16x8(const Literal& other) const; |
564 | Literal extMulHighSI16x8(const Literal& other) const; |
565 | Literal extMulLowUI16x8(const Literal& other) const; |
566 | Literal extMulHighUI16x8(const Literal& other) const; |
567 | Literal absI32x4() const; |
568 | Literal negI32x4() const; |
569 | Literal allTrueI32x4() const; |
570 | Literal bitmaskI32x4() const; |
571 | Literal shlI32x4(const Literal& other) const; |
572 | Literal shrSI32x4(const Literal& other) const; |
573 | Literal shrUI32x4(const Literal& other) const; |
574 | Literal addI32x4(const Literal& other) const; |
575 | Literal subI32x4(const Literal& other) const; |
576 | Literal mulI32x4(const Literal& other) const; |
577 | Literal minSI32x4(const Literal& other) const; |
578 | Literal minUI32x4(const Literal& other) const; |
579 | Literal maxSI32x4(const Literal& other) const; |
580 | Literal maxUI32x4(const Literal& other) const; |
581 | Literal dotSI8x16toI16x8(const Literal& other) const; |
582 | Literal dotUI8x16toI16x8(const Literal& other) const; |
583 | Literal dotSI16x8toI32x4(const Literal& other) const; |
584 | Literal extMulLowSI32x4(const Literal& other) const; |
585 | Literal extMulHighSI32x4(const Literal& other) const; |
586 | Literal extMulLowUI32x4(const Literal& other) const; |
587 | Literal extMulHighUI32x4(const Literal& other) const; |
588 | Literal absI64x2() const; |
589 | Literal negI64x2() const; |
590 | Literal bitmaskI64x2() const; |
591 | Literal allTrueI64x2() const; |
592 | Literal shlI64x2(const Literal& other) const; |
593 | Literal shrSI64x2(const Literal& other) const; |
594 | Literal shrUI64x2(const Literal& other) const; |
595 | Literal addI64x2(const Literal& other) const; |
596 | Literal subI64x2(const Literal& other) const; |
597 | Literal mulI64x2(const Literal& other) const; |
598 | Literal extMulLowSI64x2(const Literal& other) const; |
599 | Literal extMulHighSI64x2(const Literal& other) const; |
600 | Literal extMulLowUI64x2(const Literal& other) const; |
601 | Literal extMulHighUI64x2(const Literal& other) const; |
602 | Literal absF32x4() const; |
603 | Literal negF32x4() const; |
604 | Literal sqrtF32x4() const; |
605 | Literal addF32x4(const Literal& other) const; |
606 | Literal subF32x4(const Literal& other) const; |
607 | Literal mulF32x4(const Literal& other) const; |
608 | Literal divF32x4(const Literal& other) const; |
609 | Literal minF32x4(const Literal& other) const; |
610 | Literal maxF32x4(const Literal& other) const; |
611 | Literal pminF32x4(const Literal& other) const; |
612 | Literal pmaxF32x4(const Literal& other) const; |
613 | Literal ceilF32x4() const; |
614 | Literal floorF32x4() const; |
615 | Literal truncF32x4() const; |
616 | Literal nearestF32x4() const; |
617 | Literal absF64x2() const; |
618 | Literal negF64x2() const; |
619 | Literal sqrtF64x2() const; |
620 | Literal addF64x2(const Literal& other) const; |
621 | Literal subF64x2(const Literal& other) const; |
622 | Literal mulF64x2(const Literal& other) const; |
623 | Literal divF64x2(const Literal& other) const; |
624 | Literal minF64x2(const Literal& other) const; |
625 | Literal maxF64x2(const Literal& other) const; |
626 | Literal pminF64x2(const Literal& other) const; |
627 | Literal pmaxF64x2(const Literal& other) const; |
628 | Literal ceilF64x2() const; |
629 | Literal floorF64x2() const; |
630 | Literal truncF64x2() const; |
631 | Literal nearestF64x2() const; |
632 | Literal extAddPairwiseToSI16x8() const; |
633 | Literal extAddPairwiseToUI16x8() const; |
634 | Literal extAddPairwiseToSI32x4() const; |
635 | Literal extAddPairwiseToUI32x4() const; |
636 | Literal truncSatToSI32x4() const; |
637 | Literal truncSatToUI32x4() const; |
638 | Literal convertSToF32x4() const; |
639 | Literal convertUToF32x4() const; |
640 | Literal narrowSToI8x16(const Literal& other) const; |
641 | Literal narrowUToI8x16(const Literal& other) const; |
642 | Literal narrowSToI16x8(const Literal& other) const; |
643 | Literal narrowUToI16x8(const Literal& other) const; |
644 | Literal extendLowSToI16x8() const; |
645 | Literal extendHighSToI16x8() const; |
646 | Literal extendLowUToI16x8() const; |
647 | Literal extendHighUToI16x8() const; |
648 | Literal extendLowSToI32x4() const; |
649 | Literal extendHighSToI32x4() const; |
650 | Literal extendLowUToI32x4() const; |
651 | Literal extendHighUToI32x4() const; |
652 | Literal extendLowSToI64x2() const; |
653 | Literal extendHighSToI64x2() const; |
654 | Literal extendLowUToI64x2() const; |
655 | Literal extendHighUToI64x2() const; |
656 | Literal convertLowSToF64x2() const; |
657 | Literal convertLowUToF64x2() const; |
658 | Literal truncSatZeroSToI32x4() const; |
659 | Literal truncSatZeroUToI32x4() const; |
660 | Literal demoteZeroToF32x4() const; |
661 | Literal promoteLowToF64x2() const; |
662 | Literal swizzleI8x16(const Literal& other) const; |
663 | Literal relaxedFmaF32x4(const Literal& left, const Literal& right) const; |
664 | Literal relaxedFmsF32x4(const Literal& left, const Literal& right) const; |
665 | Literal relaxedFmaF64x2(const Literal& left, const Literal& right) const; |
666 | Literal relaxedFmsF64x2(const Literal& left, const Literal& right) const; |
667 | |
668 | Literal externalize() const; |
669 | Literal internalize() const; |
670 | |
671 | private: |
672 | Literal addSatSI8(const Literal& other) const; |
673 | Literal addSatUI8(const Literal& other) const; |
674 | Literal addSatSI16(const Literal& other) const; |
675 | Literal addSatUI16(const Literal& other) const; |
676 | Literal subSatSI8(const Literal& other) const; |
677 | Literal subSatUI8(const Literal& other) const; |
678 | Literal subSatSI16(const Literal& other) const; |
679 | Literal subSatUI16(const Literal& other) const; |
680 | Literal q15MulrSatSI16(const Literal& other) const; |
681 | Literal minInt(const Literal& other) const; |
682 | Literal maxInt(const Literal& other) const; |
683 | Literal minUInt(const Literal& other) const; |
684 | Literal maxUInt(const Literal& other) const; |
685 | Literal avgrUInt(const Literal& other) const; |
686 | }; |
687 | |
688 | class Literals : public SmallVector<Literal, 1> { |
689 | public: |
690 | Literals() = default; |
691 | Literals(std::initializer_list<Literal> init) |
692 | : SmallVector<Literal, 1>(init) { |
693 | #ifndef NDEBUG |
694 | for (auto& lit : init) { |
695 | assert(lit.isConcrete()); |
696 | } |
697 | #endif |
698 | } |
699 | Literals(size_t initialSize) : SmallVector(initialSize) {} |
700 | |
701 | Type getType() { |
702 | if (empty()) { |
703 | return Type::none; |
704 | } |
705 | if (size() == 1) { |
706 | return (*this)[0].type; |
707 | } |
708 | std::vector<Type> types; |
709 | for (auto& val : *this) { |
710 | types.push_back(val.type); |
711 | } |
712 | return Type(types); |
713 | } |
714 | bool isNone() { return size() == 0; } |
715 | bool isConcrete() { return size() != 0; } |
716 | }; |
717 | |
718 | std::ostream& operator<<(std::ostream& o, wasm::Literal literal); |
719 | std::ostream& operator<<(std::ostream& o, wasm::Literals literals); |
720 | |
721 | // A GC Struct, Array, or String is a set of values with a type saying how it |
722 | // should be interpreted. |
723 | struct GCData { |
724 | // The type of this struct, array, or string. |
725 | HeapType type; |
726 | |
727 | // The element or field values. |
728 | Literals values; |
729 | |
730 | GCData(HeapType type, Literals values) : type(type), values(values) {} |
731 | }; |
732 | |
733 | } // namespace wasm |
734 | |
735 | namespace std { |
736 | template<> struct hash<wasm::Literal> { |
737 | size_t operator()(const wasm::Literal& a) const { |
738 | auto digest = wasm::hash(a.type); |
739 | if (a.type.isBasic()) { |
740 | switch (a.type.getBasic()) { |
741 | case wasm::Type::i32: |
742 | wasm::rehash(digest, a.geti32()); |
743 | return digest; |
744 | case wasm::Type::f32: |
745 | wasm::rehash(digest, a.reinterpreti32()); |
746 | return digest; |
747 | case wasm::Type::i64: |
748 | wasm::rehash(digest, a.geti64()); |
749 | return digest; |
750 | case wasm::Type::f64: |
751 | wasm::rehash(digest, a.reinterpreti64()); |
752 | return digest; |
753 | case wasm::Type::v128: |
754 | uint64_t chunks[2]; |
755 | memcpy(&chunks, a.getv128Ptr(), 16); |
756 | wasm::rehash(digest, chunks[0]); |
757 | wasm::rehash(digest, chunks[1]); |
758 | return digest; |
759 | case wasm::Type::none: |
760 | case wasm::Type::unreachable: |
761 | break; |
762 | } |
763 | } else if (a.type.isRef()) { |
764 | if (a.isNull()) { |
765 | return digest; |
766 | } |
767 | if (a.type.isFunction()) { |
768 | wasm::rehash(digest, a.getFunc()); |
769 | return digest; |
770 | } |
771 | if (a.type.getHeapType() == wasm::HeapType::i31) { |
772 | wasm::rehash(digest, a.geti31(true)); |
773 | return digest; |
774 | } |
775 | if (a.type.isString()) { |
776 | auto& values = a.getGCData()->values; |
777 | wasm::rehash(digest, values.size()); |
778 | for (auto c : values) { |
779 | wasm::rehash(digest, c.getInteger()); |
780 | } |
781 | return digest; |
782 | } |
783 | // other non-null reference type literals cannot represent concrete |
784 | // values, i.e. there is no concrete anyref or eqref other than null. |
785 | WASM_UNREACHABLE("unexpected type" ); |
786 | } |
787 | WASM_UNREACHABLE("unexpected type" ); |
788 | } |
789 | }; |
790 | template<> struct hash<wasm::Literals> { |
791 | size_t operator()(const wasm::Literals& a) const { |
792 | auto digest = wasm::hash(a.size()); |
793 | for (const auto& lit : a) { |
794 | wasm::rehash(digest, lit); |
795 | } |
796 | return digest; |
797 | } |
798 | }; |
799 | |
800 | } // namespace std |
801 | |
802 | #endif // wasm_literal_h |
803 | |