]> git.proxmox.com Git - rustc.git/blob - src/binaryen/src/wasm/literal.cpp
New upstream version 1.23.0+dfsg1
[rustc.git] / src / binaryen / src / wasm / literal.cpp
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 "pretty_printing.h"
24 #include "support/bits.h"
25
26 namespace wasm {
27
28 Literal Literal::castToF32() {
29 assert(type == WasmType::i32);
30 Literal ret(i32);
31 ret.type = WasmType::f32;
32 return ret;
33 }
34
35 Literal Literal::castToF64() {
36 assert(type == WasmType::i64);
37 Literal ret(i64);
38 ret.type = WasmType::f64;
39 return ret;
40 }
41
42 Literal Literal::castToI32() {
43 assert(type == WasmType::f32);
44 Literal ret(i32);
45 ret.type = WasmType::i32;
46 return ret;
47 }
48
49 Literal Literal::castToI64() {
50 assert(type == WasmType::f64);
51 Literal ret(i64);
52 ret.type = WasmType::i64;
53 return ret;
54 }
55
56 int64_t Literal::getInteger() const {
57 switch (type) {
58 case WasmType::i32: return i32;
59 case WasmType::i64: return i64;
60 default: abort();
61 }
62 }
63
64 double Literal::getFloat() const {
65 switch (type) {
66 case WasmType::f32: return getf32();
67 case WasmType::f64: return getf64();
68 default: abort();
69 }
70 }
71
72 int64_t Literal::getBits() const {
73 switch (type) {
74 case WasmType::i32: case WasmType::f32: return i32;
75 case WasmType::i64: case WasmType::f64: return i64;
76 default: abort();
77 }
78 }
79
80 bool Literal::operator==(const Literal& other) const {
81 if (type != other.type) return false;
82 switch (type) {
83 case WasmType::none: return true;
84 case WasmType::i32: return i32 == other.i32;
85 case WasmType::f32: return getf32() == other.getf32();
86 case WasmType::i64: return i64 == other.i64;
87 case WasmType::f64: return getf64() == other.getf64();
88 default: abort();
89 }
90 }
91
92 bool Literal::operator!=(const Literal& other) const {
93 return !(*this == other);
94 }
95
96 bool Literal::bitwiseEqual(const Literal& other) const {
97 if (type != other.type) return false;
98 if (type == none) return true;
99 return getBits() == other.getBits();
100 }
101
102 uint32_t Literal::NaNPayload(float f) {
103 assert(std::isnan(f) && "expected a NaN");
104 // SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF
105 // NaN has all-one exponent and non-zero fraction.
106 return ~0xff800000u & bit_cast<uint32_t>(f);
107 }
108
109 uint64_t Literal::NaNPayload(double f) {
110 assert(std::isnan(f) && "expected a NaN");
111 // SEEEEEEE EEEEFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
112 // NaN has all-one exponent and non-zero fraction.
113 return ~0xfff0000000000000ull & bit_cast<uint64_t>(f);
114 }
115
116 float Literal::setQuietNaN(float f) {
117 assert(std::isnan(f) && "expected a NaN");
118 // An SNaN is a NaN with the most significant fraction bit clear.
119 return bit_cast<float>(0x00400000u | bit_cast<uint32_t>(f));
120 }
121
122 double Literal::setQuietNaN(double f) {
123 assert(std::isnan(f) && "expected a NaN");
124 // An SNaN is a NaN with the most significant fraction bit clear.
125 return bit_cast<double>(0x0008000000000000ull | bit_cast<uint64_t>(f));
126 }
127
128 void Literal::printFloat(std::ostream &o, float f) {
129 if (std::isnan(f)) {
130 const char* sign = std::signbit(f) ? "-" : "";
131 o << sign << "nan";
132 if (uint32_t payload = NaNPayload(f)) {
133 o << ":0x" << std::hex << payload << std::dec;
134 }
135 return;
136 }
137 printDouble(o, f);
138 }
139
140 void Literal::printDouble(std::ostream& o, double d) {
141 if (d == 0 && std::signbit(d)) {
142 o << "-0";
143 return;
144 }
145 if (std::isnan(d)) {
146 const char* sign = std::signbit(d) ? "-" : "";
147 o << sign << "nan";
148 if (uint64_t payload = NaNPayload(d)) {
149 o << ":0x" << std::hex << payload << std::dec;
150 }
151 return;
152 }
153 if (!std::isfinite(d)) {
154 o << (std::signbit(d) ? "-inf" : "inf");
155 return;
156 }
157 const char* text = cashew::JSPrinter::numToString(d);
158 // spec interpreter hates floats starting with '.'
159 if (text[0] == '.') {
160 o << '0';
161 } else if (text[0] == '-' && text[1] == '.') {
162 o << "-0";
163 text++;
164 }
165 o << text;
166 }
167
168 std::ostream& operator<<(std::ostream& o, Literal literal) {
169 o << '(';
170 prepareMinorColor(o) << printWasmType(literal.type) << ".const ";
171 switch (literal.type) {
172 case none: o << "?"; break;
173 case WasmType::i32: o << literal.i32; break;
174 case WasmType::i64: o << literal.i64; break;
175 case WasmType::f32: literal.printFloat(o, literal.getf32()); break;
176 case WasmType::f64: literal.printDouble(o, literal.getf64()); break;
177 default: WASM_UNREACHABLE();
178 }
179 restoreNormalColor(o);
180 return o << ')';
181 }
182
183 Literal Literal::countLeadingZeroes() const {
184 if (type == WasmType::i32) return Literal((int32_t)CountLeadingZeroes(i32));
185 if (type == WasmType::i64) return Literal((int64_t)CountLeadingZeroes(i64));
186 WASM_UNREACHABLE();
187 }
188
189 Literal Literal::countTrailingZeroes() const {
190 if (type == WasmType::i32) return Literal((int32_t)CountTrailingZeroes(i32));
191 if (type == WasmType::i64) return Literal((int64_t)CountTrailingZeroes(i64));
192 WASM_UNREACHABLE();
193 }
194
195 Literal Literal::popCount() const {
196 if (type == WasmType::i32) return Literal((int32_t)PopCount(i32));
197 if (type == WasmType::i64) return Literal((int64_t)PopCount(i64));
198 WASM_UNREACHABLE();
199 }
200
201 Literal Literal::extendToSI64() const {
202 assert(type == WasmType::i32);
203 return Literal((int64_t)i32);
204 }
205
206 Literal Literal::extendToUI64() const {
207 assert(type == WasmType::i32);
208 return Literal((uint64_t)(uint32_t)i32);
209 }
210
211 Literal Literal::extendToF64() const {
212 assert(type == WasmType::f32);
213 return Literal(double(getf32()));
214 }
215
216 Literal Literal::truncateToI32() const {
217 assert(type == WasmType::i64);
218 return Literal((int32_t)i64);
219 }
220
221 Literal Literal::truncateToF32() const {
222 assert(type == WasmType::f64);
223 return Literal(float(getf64()));
224 }
225
226 Literal Literal::convertSToF32() const {
227 if (type == WasmType::i32) return Literal(float(i32));
228 if (type == WasmType::i64) return Literal(float(i64));
229 WASM_UNREACHABLE();
230 }
231
232 Literal Literal::convertUToF32() const {
233 if (type == WasmType::i32) return Literal(float(uint32_t(i32)));
234 if (type == WasmType::i64) return Literal(float(uint64_t(i64)));
235 WASM_UNREACHABLE();
236 }
237
238 Literal Literal::convertSToF64() const {
239 if (type == WasmType::i32) return Literal(double(i32));
240 if (type == WasmType::i64) return Literal(double(i64));
241 WASM_UNREACHABLE();
242 }
243
244 Literal Literal::convertUToF64() const {
245 if (type == WasmType::i32) return Literal(double(uint32_t(i32)));
246 if (type == WasmType::i64) return Literal(double(uint64_t(i64)));
247 WASM_UNREACHABLE();
248 }
249
250 Literal Literal::neg() const {
251 switch (type) {
252 case WasmType::i32: return Literal(i32 ^ 0x80000000);
253 case WasmType::i64: return Literal(int64_t(i64 ^ 0x8000000000000000ULL));
254 case WasmType::f32: return Literal(i32 ^ 0x80000000).castToF32();
255 case WasmType::f64: return Literal(int64_t(i64 ^ 0x8000000000000000ULL)).castToF64();
256 default: WASM_UNREACHABLE();
257 }
258 }
259
260 Literal Literal::abs() const {
261 switch (type) {
262 case WasmType::i32: return Literal(i32 & 0x7fffffff);
263 case WasmType::i64: return Literal(int64_t(i64 & 0x7fffffffffffffffULL));
264 case WasmType::f32: return Literal(i32 & 0x7fffffff).castToF32();
265 case WasmType::f64: return Literal(int64_t(i64 & 0x7fffffffffffffffULL)).castToF64();
266 default: WASM_UNREACHABLE();
267 }
268 }
269
270 Literal Literal::ceil() const {
271 switch (type) {
272 case WasmType::f32: return Literal(std::ceil(getf32()));
273 case WasmType::f64: return Literal(std::ceil(getf64()));
274 default: WASM_UNREACHABLE();
275 }
276 }
277
278 Literal Literal::floor() const {
279 switch (type) {
280 case WasmType::f32: return Literal(std::floor(getf32()));
281 case WasmType::f64: return Literal(std::floor(getf64()));
282 default: WASM_UNREACHABLE();
283 }
284 }
285
286 Literal Literal::trunc() const {
287 switch (type) {
288 case WasmType::f32: return Literal(std::trunc(getf32()));
289 case WasmType::f64: return Literal(std::trunc(getf64()));
290 default: WASM_UNREACHABLE();
291 }
292 }
293
294 Literal Literal::nearbyint() const {
295 switch (type) {
296 case WasmType::f32: return Literal(std::nearbyint(getf32()));
297 case WasmType::f64: return Literal(std::nearbyint(getf64()));
298 default: WASM_UNREACHABLE();
299 }
300 }
301
302 Literal Literal::sqrt() const {
303 switch (type) {
304 case WasmType::f32: return Literal(std::sqrt(getf32()));
305 case WasmType::f64: return Literal(std::sqrt(getf64()));
306 default: WASM_UNREACHABLE();
307 }
308 }
309
310 Literal Literal::add(const Literal& other) const {
311 switch (type) {
312 case WasmType::i32: return Literal(uint32_t(i32) + uint32_t(other.i32));
313 case WasmType::i64: return Literal(uint64_t(i64) + uint64_t(other.i64));
314 case WasmType::f32: return Literal(getf32() + other.getf32());
315 case WasmType::f64: return Literal(getf64() + other.getf64());
316 default: WASM_UNREACHABLE();
317 }
318 }
319
320 Literal Literal::sub(const Literal& other) const {
321 switch (type) {
322 case WasmType::i32: return Literal(uint32_t(i32) - uint32_t(other.i32));
323 case WasmType::i64: return Literal(uint64_t(i64) - uint64_t(other.i64));
324 case WasmType::f32: return Literal(getf32() - other.getf32());
325 case WasmType::f64: return Literal(getf64() - other.getf64());
326 default: WASM_UNREACHABLE();
327 }
328 }
329
330 Literal Literal::mul(const Literal& other) const {
331 switch (type) {
332 case WasmType::i32: return Literal(uint32_t(i32) * uint32_t(other.i32));
333 case WasmType::i64: return Literal(uint64_t(i64) * uint64_t(other.i64));
334 case WasmType::f32: return Literal(getf32() * other.getf32());
335 case WasmType::f64: return Literal(getf64() * other.getf64());
336 default: WASM_UNREACHABLE();
337 }
338 }
339
340 Literal Literal::div(const Literal& other) const {
341 switch (type) {
342 case WasmType::f32: {
343 float lhs = getf32(), rhs = other.getf32();
344 float sign = std::signbit(lhs) == std::signbit(rhs) ? 0.f : -0.f;
345 switch (std::fpclassify(rhs)) {
346 case FP_ZERO:
347 switch (std::fpclassify(lhs)) {
348 case FP_NAN: return Literal(setQuietNaN(lhs));
349 case FP_ZERO: return Literal(std::copysign(std::numeric_limits<float>::quiet_NaN(), sign));
350 case FP_NORMAL: // fallthrough
351 case FP_SUBNORMAL: // fallthrough
352 case FP_INFINITE: return Literal(std::copysign(std::numeric_limits<float>::infinity(), sign));
353 default: WASM_UNREACHABLE();
354 }
355 case FP_NAN: // fallthrough
356 case FP_INFINITE: // fallthrough
357 case FP_NORMAL: // fallthrough
358 case FP_SUBNORMAL: return Literal(lhs / rhs);
359 default: WASM_UNREACHABLE();
360 }
361 }
362 case WasmType::f64: {
363 double lhs = getf64(), rhs = other.getf64();
364 double sign = std::signbit(lhs) == std::signbit(rhs) ? 0. : -0.;
365 switch (std::fpclassify(rhs)) {
366 case FP_ZERO:
367 switch (std::fpclassify(lhs)) {
368 case FP_NAN: return Literal(setQuietNaN(lhs));
369 case FP_ZERO: return Literal(std::copysign(std::numeric_limits<double>::quiet_NaN(), sign));
370 case FP_NORMAL: // fallthrough
371 case FP_SUBNORMAL: // fallthrough
372 case FP_INFINITE: return Literal(std::copysign(std::numeric_limits<double>::infinity(), sign));
373 default: WASM_UNREACHABLE();
374 }
375 case FP_NAN: // fallthrough
376 case FP_INFINITE: // fallthrough
377 case FP_NORMAL: // fallthrough
378 case FP_SUBNORMAL: return Literal(lhs / rhs);
379 default: WASM_UNREACHABLE();
380 }
381 }
382 default: WASM_UNREACHABLE();
383 }
384 }
385
386 Literal Literal::divS(const Literal& other) const {
387 switch (type) {
388 case WasmType::i32: return Literal(i32 / other.i32);
389 case WasmType::i64: return Literal(i64 / other.i64);
390 default: WASM_UNREACHABLE();
391 }
392 }
393
394 Literal Literal::divU(const Literal& other) const {
395 switch (type) {
396 case WasmType::i32: return Literal(uint32_t(i32) / uint32_t(other.i32));
397 case WasmType::i64: return Literal(uint64_t(i64) / uint64_t(other.i64));
398 default: WASM_UNREACHABLE();
399 }
400 }
401
402 Literal Literal::remS(const Literal& other) const {
403 switch (type) {
404 case WasmType::i32: return Literal(i32 % other.i32);
405 case WasmType::i64: return Literal(i64 % other.i64);
406 default: WASM_UNREACHABLE();
407 }
408 }
409
410 Literal Literal::remU(const Literal& other) const {
411 switch (type) {
412 case WasmType::i32: return Literal(uint32_t(i32) % uint32_t(other.i32));
413 case WasmType::i64: return Literal(uint64_t(i64) % uint64_t(other.i64));
414 default: WASM_UNREACHABLE();
415 }
416 }
417
418 Literal Literal::and_(const Literal& other) const {
419 switch (type) {
420 case WasmType::i32: return Literal(i32 & other.i32);
421 case WasmType::i64: return Literal(i64 & other.i64);
422 default: WASM_UNREACHABLE();
423 }
424 }
425
426 Literal Literal::or_(const Literal& other) const {
427 switch (type) {
428 case WasmType::i32: return Literal(i32 | other.i32);
429 case WasmType::i64: return Literal(i64 | other.i64);
430 default: WASM_UNREACHABLE();
431 }
432 }
433
434 Literal Literal::xor_(const Literal& other) const {
435 switch (type) {
436 case WasmType::i32: return Literal(i32 ^ other.i32);
437 case WasmType::i64: return Literal(i64 ^ other.i64);
438 default: WASM_UNREACHABLE();
439 }
440 }
441
442 Literal Literal::shl(const Literal& other) const {
443 switch (type) {
444 case WasmType::i32: return Literal(uint32_t(i32) << shiftMask(other.i32));
445 case WasmType::i64: return Literal(uint64_t(i64) << shiftMask(other.i64));
446 default: WASM_UNREACHABLE();
447 }
448 }
449
450 Literal Literal::shrS(const Literal& other) const {
451 switch (type) {
452 case WasmType::i32: return Literal(i32 >> shiftMask(other.i32));
453 case WasmType::i64: return Literal(i64 >> shiftMask(other.i64));
454 default: WASM_UNREACHABLE();
455 }
456 }
457
458 Literal Literal::shrU(const Literal& other) const {
459 switch (type) {
460 case WasmType::i32: return Literal(uint32_t(i32) >> shiftMask(other.i32));
461 case WasmType::i64: return Literal(uint64_t(i64) >> shiftMask(other.i64));
462 default: WASM_UNREACHABLE();
463 }
464 }
465
466 Literal Literal::rotL(const Literal& other) const {
467 switch (type) {
468 case WasmType::i32: return Literal(RotateLeft(uint32_t(i32), uint32_t(other.i32)));
469 case WasmType::i64: return Literal(RotateLeft(uint64_t(i64), uint64_t(other.i64)));
470 default: WASM_UNREACHABLE();
471 }
472 }
473
474 Literal Literal::rotR(const Literal& other) const {
475 switch (type) {
476 case WasmType::i32: return Literal(RotateRight(uint32_t(i32), uint32_t(other.i32)));
477 case WasmType::i64: return Literal(RotateRight(uint64_t(i64), uint64_t(other.i64)));
478 default: WASM_UNREACHABLE();
479 }
480 }
481
482 Literal Literal::eq(const Literal& other) const {
483 switch (type) {
484 case WasmType::i32: return Literal(i32 == other.i32);
485 case WasmType::i64: return Literal(i64 == other.i64);
486 case WasmType::f32: return Literal(getf32() == other.getf32());
487 case WasmType::f64: return Literal(getf64() == other.getf64());
488 default: WASM_UNREACHABLE();
489 }
490 }
491
492 Literal Literal::ne(const Literal& other) const {
493 switch (type) {
494 case WasmType::i32: return Literal(i32 != other.i32);
495 case WasmType::i64: return Literal(i64 != other.i64);
496 case WasmType::f32: return Literal(getf32() != other.getf32());
497 case WasmType::f64: return Literal(getf64() != other.getf64());
498 default: WASM_UNREACHABLE();
499 }
500 }
501
502 Literal Literal::ltS(const Literal& other) const {
503 switch (type) {
504 case WasmType::i32: return Literal(i32 < other.i32);
505 case WasmType::i64: return Literal(i64 < other.i64);
506 default: WASM_UNREACHABLE();
507 }
508 }
509
510 Literal Literal::ltU(const Literal& other) const {
511 switch (type) {
512 case WasmType::i32: return Literal(uint32_t(i32) < uint32_t(other.i32));
513 case WasmType::i64: return Literal(uint64_t(i64) < uint64_t(other.i64));
514 default: WASM_UNREACHABLE();
515 }
516 }
517
518 Literal Literal::lt(const Literal& other) const {
519 switch (type) {
520 case WasmType::f32: return Literal(getf32() < other.getf32());
521 case WasmType::f64: return Literal(getf64() < other.getf64());
522 default: WASM_UNREACHABLE();
523 }
524 }
525
526 Literal Literal::leS(const Literal& other) const {
527 switch (type) {
528 case WasmType::i32: return Literal(i32 <= other.i32);
529 case WasmType::i64: return Literal(i64 <= other.i64);
530 default: WASM_UNREACHABLE();
531 }
532 }
533
534 Literal Literal::leU(const Literal& other) const {
535 switch (type) {
536 case WasmType::i32: return Literal(uint32_t(i32) <= uint32_t(other.i32));
537 case WasmType::i64: return Literal(uint64_t(i64) <= uint64_t(other.i64));
538 default: WASM_UNREACHABLE();
539 }
540 }
541
542 Literal Literal::le(const Literal& other) const {
543 switch (type) {
544 case WasmType::f32: return Literal(getf32() <= other.getf32());
545 case WasmType::f64: return Literal(getf64() <= other.getf64());
546 default: WASM_UNREACHABLE();
547 }
548 }
549
550 Literal Literal::gtS(const Literal& other) const {
551 switch (type) {
552 case WasmType::i32: return Literal(i32 > other.i32);
553 case WasmType::i64: return Literal(i64 > other.i64);
554 default: WASM_UNREACHABLE();
555 }
556 }
557
558 Literal Literal::gtU(const Literal& other) const {
559 switch (type) {
560 case WasmType::i32: return Literal(uint32_t(i32) > uint32_t(other.i32));
561 case WasmType::i64: return Literal(uint64_t(i64) > uint64_t(other.i64));
562 default: WASM_UNREACHABLE();
563 }
564 }
565
566 Literal Literal::gt(const Literal& other) const {
567 switch (type) {
568 case WasmType::f32: return Literal(getf32() > other.getf32());
569 case WasmType::f64: return Literal(getf64() > other.getf64());
570 default: WASM_UNREACHABLE();
571 }
572 }
573
574 Literal Literal::geS(const Literal& other) const {
575 switch (type) {
576 case WasmType::i32: return Literal(i32 >= other.i32);
577 case WasmType::i64: return Literal(i64 >= other.i64);
578 default: WASM_UNREACHABLE();
579 }
580 }
581
582 Literal Literal::geU(const Literal& other) const {
583 switch (type) {
584 case WasmType::i32: return Literal(uint32_t(i32) >= uint32_t(other.i32));
585 case WasmType::i64: return Literal(uint64_t(i64) >= uint64_t(other.i64));
586 default: WASM_UNREACHABLE();
587 }
588 }
589
590 Literal Literal::ge(const Literal& other) const {
591 switch (type) {
592 case WasmType::f32: return Literal(getf32() >= other.getf32());
593 case WasmType::f64: return Literal(getf64() >= other.getf64());
594 default: WASM_UNREACHABLE();
595 }
596 }
597
598 Literal Literal::min(const Literal& other) const {
599 switch (type) {
600 case WasmType::f32: {
601 auto l = getf32(), r = other.getf32();
602 if (l == r && l == 0) return Literal(std::signbit(l) ? l : r);
603 auto result = std::min(l, r);
604 bool lnan = std::isnan(l), rnan = std::isnan(r);
605 if (!std::isnan(result) && !lnan && !rnan) return Literal(result);
606 if (!lnan && !rnan) return Literal((int32_t)0x7fc00000).castToF32();
607 return Literal(lnan ? l : r).castToI32().or_(Literal(0xc00000)).castToF32();
608 }
609 case WasmType::f64: {
610 auto l = getf64(), r = other.getf64();
611 if (l == r && l == 0) return Literal(std::signbit(l) ? l : r);
612 auto result = std::min(l, r);
613 bool lnan = std::isnan(l), rnan = std::isnan(r);
614 if (!std::isnan(result) && !lnan && !rnan) return Literal(result);
615 if (!lnan && !rnan) return Literal((int64_t)0x7ff8000000000000LL).castToF64();
616 return Literal(lnan ? l : r).castToI64().or_(Literal(int64_t(0x8000000000000LL))).castToF64();
617 }
618 default: WASM_UNREACHABLE();
619 }
620 }
621
622 Literal Literal::max(const Literal& other) const {
623 switch (type) {
624 case WasmType::f32: {
625 auto l = getf32(), r = other.getf32();
626 if (l == r && l == 0) return Literal(std::signbit(l) ? r : l);
627 auto result = std::max(l, r);
628 bool lnan = std::isnan(l), rnan = std::isnan(r);
629 if (!std::isnan(result) && !lnan && !rnan) return Literal(result);
630 if (!lnan && !rnan) return Literal((int32_t)0x7fc00000).castToF32();
631 return Literal(lnan ? l : r).castToI32().or_(Literal(0xc00000)).castToF32();
632 }
633 case WasmType::f64: {
634 auto l = getf64(), r = other.getf64();
635 if (l == r && l == 0) return Literal(std::signbit(l) ? r : l);
636 auto result = std::max(l, r);
637 bool lnan = std::isnan(l), rnan = std::isnan(r);
638 if (!std::isnan(result) && !lnan && !rnan) return Literal(result);
639 if (!lnan && !rnan) return Literal((int64_t)0x7ff8000000000000LL).castToF64();
640 return Literal(lnan ? l : r).castToI64().or_(Literal(int64_t(0x8000000000000LL))).castToF64();
641 }
642 default: WASM_UNREACHABLE();
643 }
644 }
645
646 Literal Literal::copysign(const Literal& other) const {
647 // operate on bits directly, to avoid signalling bit being set on a float
648 switch (type) {
649 case WasmType::f32: return Literal((i32 & 0x7fffffff) | (other.i32 & 0x80000000)).castToF32(); break;
650 case WasmType::f64: return Literal((i64 & 0x7fffffffffffffffUL) | (other.i64 & 0x8000000000000000UL)).castToF64(); break;
651 default: WASM_UNREACHABLE();
652 }
653 }
654
655 } // namespace wasm