]>
git.proxmox.com Git - rustc.git/blob - src/binaryen/src/wasm/literal.cpp
2 * Copyright 2016 WebAssembly Community Group participants
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include "emscripten-optimizer/simple_ast.h"
23 #include "pretty_printing.h"
24 #include "support/bits.h"
28 Literal
Literal::castToF32() {
29 assert(type
== WasmType::i32
);
31 ret
.type
= WasmType::f32
;
35 Literal
Literal::castToF64() {
36 assert(type
== WasmType::i64
);
38 ret
.type
= WasmType::f64
;
42 Literal
Literal::castToI32() {
43 assert(type
== WasmType::f32
);
45 ret
.type
= WasmType::i32
;
49 Literal
Literal::castToI64() {
50 assert(type
== WasmType::f64
);
52 ret
.type
= WasmType::i64
;
56 int64_t Literal::getInteger() const {
58 case WasmType::i32
: return i32
;
59 case WasmType::i64
: return i64
;
64 double Literal::getFloat() const {
66 case WasmType::f32
: return getf32();
67 case WasmType::f64
: return getf64();
72 int64_t Literal::getBits() const {
74 case WasmType::i32
: case WasmType::f32
: return i32
;
75 case WasmType::i64
: case WasmType::f64
: return i64
;
80 bool Literal::operator==(const Literal
& other
) const {
81 if (type
!= other
.type
) return false;
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();
92 bool Literal::operator!=(const Literal
& other
) const {
93 return !(*this == other
);
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();
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
);
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
);
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
));
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
));
128 void Literal::printFloat(std::ostream
&o
, float f
) {
130 const char* sign
= std::signbit(f
) ? "-" : "";
132 if (uint32_t payload
= NaNPayload(f
)) {
133 o
<< ":0x" << std::hex
<< payload
<< std::dec
;
140 void Literal::printDouble(std::ostream
& o
, double d
) {
141 if (d
== 0 && std::signbit(d
)) {
146 const char* sign
= std::signbit(d
) ? "-" : "";
148 if (uint64_t payload
= NaNPayload(d
)) {
149 o
<< ":0x" << std::hex
<< payload
<< std::dec
;
153 if (!std::isfinite(d
)) {
154 o
<< (std::signbit(d
) ? "-inf" : "inf");
157 const char* text
= cashew::JSPrinter::numToString(d
);
158 // spec interpreter hates floats starting with '.'
159 if (text
[0] == '.') {
161 } else if (text
[0] == '-' && text
[1] == '.') {
168 std::ostream
& operator<<(std::ostream
& o
, Literal literal
) {
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();
179 restoreNormalColor(o
);
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
));
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
));
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
));
201 Literal
Literal::extendToSI64() const {
202 assert(type
== WasmType::i32
);
203 return Literal((int64_t)i32
);
206 Literal
Literal::extendToUI64() const {
207 assert(type
== WasmType::i32
);
208 return Literal((uint64_t)(uint32_t)i32
);
211 Literal
Literal::extendToF64() const {
212 assert(type
== WasmType::f32
);
213 return Literal(double(getf32()));
216 Literal
Literal::truncateToI32() const {
217 assert(type
== WasmType::i64
);
218 return Literal((int32_t)i64
);
221 Literal
Literal::truncateToF32() const {
222 assert(type
== WasmType::f64
);
223 return Literal(float(getf64()));
226 Literal
Literal::convertSToF32() const {
227 if (type
== WasmType::i32
) return Literal(float(i32
));
228 if (type
== WasmType::i64
) return Literal(float(i64
));
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
)));
238 Literal
Literal::convertSToF64() const {
239 if (type
== WasmType::i32
) return Literal(double(i32
));
240 if (type
== WasmType::i64
) return Literal(double(i64
));
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
)));
250 Literal
Literal::neg() const {
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();
260 Literal
Literal::abs() const {
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();
270 Literal
Literal::ceil() const {
272 case WasmType::f32
: return Literal(std::ceil(getf32()));
273 case WasmType::f64
: return Literal(std::ceil(getf64()));
274 default: WASM_UNREACHABLE();
278 Literal
Literal::floor() const {
280 case WasmType::f32
: return Literal(std::floor(getf32()));
281 case WasmType::f64
: return Literal(std::floor(getf64()));
282 default: WASM_UNREACHABLE();
286 Literal
Literal::trunc() const {
288 case WasmType::f32
: return Literal(std::trunc(getf32()));
289 case WasmType::f64
: return Literal(std::trunc(getf64()));
290 default: WASM_UNREACHABLE();
294 Literal
Literal::nearbyint() const {
296 case WasmType::f32
: return Literal(std::nearbyint(getf32()));
297 case WasmType::f64
: return Literal(std::nearbyint(getf64()));
298 default: WASM_UNREACHABLE();
302 Literal
Literal::sqrt() const {
304 case WasmType::f32
: return Literal(std::sqrt(getf32()));
305 case WasmType::f64
: return Literal(std::sqrt(getf64()));
306 default: WASM_UNREACHABLE();
310 Literal
Literal::add(const Literal
& other
) const {
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();
320 Literal
Literal::sub(const Literal
& other
) const {
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();
330 Literal
Literal::mul(const Literal
& other
) const {
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();
340 Literal
Literal::div(const Literal
& other
) const {
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
)) {
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();
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();
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
)) {
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();
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();
382 default: WASM_UNREACHABLE();
386 Literal
Literal::divS(const Literal
& other
) const {
388 case WasmType::i32
: return Literal(i32
/ other
.i32
);
389 case WasmType::i64
: return Literal(i64
/ other
.i64
);
390 default: WASM_UNREACHABLE();
394 Literal
Literal::divU(const Literal
& other
) const {
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();
402 Literal
Literal::remS(const Literal
& other
) const {
404 case WasmType::i32
: return Literal(i32
% other
.i32
);
405 case WasmType::i64
: return Literal(i64
% other
.i64
);
406 default: WASM_UNREACHABLE();
410 Literal
Literal::remU(const Literal
& other
) const {
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();
418 Literal
Literal::and_(const Literal
& other
) const {
420 case WasmType::i32
: return Literal(i32
& other
.i32
);
421 case WasmType::i64
: return Literal(i64
& other
.i64
);
422 default: WASM_UNREACHABLE();
426 Literal
Literal::or_(const Literal
& other
) const {
428 case WasmType::i32
: return Literal(i32
| other
.i32
);
429 case WasmType::i64
: return Literal(i64
| other
.i64
);
430 default: WASM_UNREACHABLE();
434 Literal
Literal::xor_(const Literal
& other
) const {
436 case WasmType::i32
: return Literal(i32
^ other
.i32
);
437 case WasmType::i64
: return Literal(i64
^ other
.i64
);
438 default: WASM_UNREACHABLE();
442 Literal
Literal::shl(const Literal
& other
) const {
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();
450 Literal
Literal::shrS(const Literal
& other
) const {
452 case WasmType::i32
: return Literal(i32
>> shiftMask(other
.i32
));
453 case WasmType::i64
: return Literal(i64
>> shiftMask(other
.i64
));
454 default: WASM_UNREACHABLE();
458 Literal
Literal::shrU(const Literal
& other
) const {
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();
466 Literal
Literal::rotL(const Literal
& other
) const {
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();
474 Literal
Literal::rotR(const Literal
& other
) const {
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();
482 Literal
Literal::eq(const Literal
& other
) const {
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();
492 Literal
Literal::ne(const Literal
& other
) const {
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();
502 Literal
Literal::ltS(const Literal
& other
) const {
504 case WasmType::i32
: return Literal(i32
< other
.i32
);
505 case WasmType::i64
: return Literal(i64
< other
.i64
);
506 default: WASM_UNREACHABLE();
510 Literal
Literal::ltU(const Literal
& other
) const {
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();
518 Literal
Literal::lt(const Literal
& other
) const {
520 case WasmType::f32
: return Literal(getf32() < other
.getf32());
521 case WasmType::f64
: return Literal(getf64() < other
.getf64());
522 default: WASM_UNREACHABLE();
526 Literal
Literal::leS(const Literal
& other
) const {
528 case WasmType::i32
: return Literal(i32
<= other
.i32
);
529 case WasmType::i64
: return Literal(i64
<= other
.i64
);
530 default: WASM_UNREACHABLE();
534 Literal
Literal::leU(const Literal
& other
) const {
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();
542 Literal
Literal::le(const Literal
& other
) const {
544 case WasmType::f32
: return Literal(getf32() <= other
.getf32());
545 case WasmType::f64
: return Literal(getf64() <= other
.getf64());
546 default: WASM_UNREACHABLE();
550 Literal
Literal::gtS(const Literal
& other
) const {
552 case WasmType::i32
: return Literal(i32
> other
.i32
);
553 case WasmType::i64
: return Literal(i64
> other
.i64
);
554 default: WASM_UNREACHABLE();
558 Literal
Literal::gtU(const Literal
& other
) const {
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();
566 Literal
Literal::gt(const Literal
& other
) const {
568 case WasmType::f32
: return Literal(getf32() > other
.getf32());
569 case WasmType::f64
: return Literal(getf64() > other
.getf64());
570 default: WASM_UNREACHABLE();
574 Literal
Literal::geS(const Literal
& other
) const {
576 case WasmType::i32
: return Literal(i32
>= other
.i32
);
577 case WasmType::i64
: return Literal(i64
>= other
.i64
);
578 default: WASM_UNREACHABLE();
582 Literal
Literal::geU(const Literal
& other
) const {
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();
590 Literal
Literal::ge(const Literal
& other
) const {
592 case WasmType::f32
: return Literal(getf32() >= other
.getf32());
593 case WasmType::f64
: return Literal(getf64() >= other
.getf64());
594 default: WASM_UNREACHABLE();
598 Literal
Literal::min(const Literal
& other
) const {
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();
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();
618 default: WASM_UNREACHABLE();
622 Literal
Literal::max(const Literal
& other
) const {
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();
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();
642 default: WASM_UNREACHABLE();
646 Literal
Literal::copysign(const Literal
& other
) const {
647 // operate on bits directly, to avoid signalling bit being set on a float
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();