Skip to content

Commit 11094c5

Browse files
authored
Add optimized for size float to bool conversion path (#2445)
1 parent 114fd03 commit 11094c5

File tree

5 files changed

+142
-28
lines changed

5 files changed

+142
-28
lines changed

Diff for: src/compiler.ts

+64-28
Original file line numberDiff line numberDiff line change
@@ -9885,38 +9885,74 @@ export class Compiler extends DiagnosticEmitter {
98859885
: expr;
98869886
}
98879887
case TypeKind.F32: {
9888-
// 0 < abs(bitCast(x)) <= bitCast(Infinity) or
9889-
// (reinterpret<u32>(x) & 0x7FFFFFFF) - 1 <= 0x7F800000 - 1
9890-
//
9891-
// and finally:
9892-
// (reinterpret<u32>(x) << 1) - (1 << 1) <= ((0x7F800000 - 1) << 1)
9893-
return module.binary(BinaryOp.LeU32,
9894-
module.binary(BinaryOp.SubI32,
9895-
module.binary(BinaryOp.ShlI32,
9896-
module.unary(UnaryOp.ReinterpretF32ToI32, expr),
9897-
module.i32(1)
9888+
let options = this.options;
9889+
if (
9890+
options.shrinkLevelHint > 1 &&
9891+
options.hasFeature(Feature.NONTRAPPING_F2I)
9892+
) {
9893+
// Use more compact but slower 5-byte (3 bytes in best case) approach
9894+
// !!(i32.trunc_sat_f32_u(f32.ceil(f32.abs(x))))
9895+
return module.unary(UnaryOp.EqzI32,
9896+
module.unary(UnaryOp.EqzI32,
9897+
module.unary(UnaryOp.TruncSatF32ToU32,
9898+
module.unary(UnaryOp.CeilF32,
9899+
module.unary(UnaryOp.AbsF32, expr)
9900+
)
9901+
)
9902+
)
9903+
);
9904+
} else {
9905+
// 0 < abs(bitCast(x)) <= bitCast(Infinity) or
9906+
// (reinterpret<u32>(x) & 0x7FFFFFFF) - 1 <= 0x7F800000 - 1
9907+
//
9908+
// and finally:
9909+
// (reinterpret<u32>(x) << 1) - (1 << 1) <= ((0x7F800000 - 1) << 1)
9910+
return module.binary(BinaryOp.LeU32,
9911+
module.binary(BinaryOp.SubI32,
9912+
module.binary(BinaryOp.ShlI32,
9913+
module.unary(UnaryOp.ReinterpretF32ToI32, expr),
9914+
module.i32(1)
9915+
),
9916+
module.i32(2) // 1 << 1
98989917
),
9899-
module.i32(2) // 1 << 1
9900-
),
9901-
module.i32(0xFEFFFFFE) // (0x7F800000 - 1) << 1
9902-
);
9918+
module.i32(0xFEFFFFFE) // (0x7F800000 - 1) << 1
9919+
);
9920+
}
99039921
}
99049922
case TypeKind.F64: {
9905-
// 0 < abs(bitCast(x)) <= bitCast(Infinity) or
9906-
// (reinterpret<u64>(x) & 0x7FFFFFFFFFFFFFFF) - 1 <= 0x7FF0000000000000 - 1
9907-
//
9908-
// and finally:
9909-
// (reinterpret<u64>(x) << 1) - (1 << 1) <= ((0x7FF0000000000000 - 1) << 1)
9910-
return module.binary(BinaryOp.LeU64,
9911-
module.binary(BinaryOp.SubI64,
9912-
module.binary(BinaryOp.ShlI64,
9913-
module.unary(UnaryOp.ReinterpretF64ToI64, expr),
9914-
module.i64(1)
9923+
let options = this.options;
9924+
if (
9925+
options.shrinkLevelHint > 1 &&
9926+
options.hasFeature(Feature.NONTRAPPING_F2I)
9927+
) {
9928+
// Use more compact but slower 5-byte (3 bytes in best case) approach
9929+
// !!(i32.trunc_sat_f64_u(f64.ceil(f64.abs(x))))
9930+
return module.unary(UnaryOp.EqzI32,
9931+
module.unary(UnaryOp.EqzI32,
9932+
module.unary(UnaryOp.TruncSatF64ToU32,
9933+
module.unary(UnaryOp.CeilF64,
9934+
module.unary(UnaryOp.AbsF64, expr)
9935+
)
9936+
)
9937+
)
9938+
);
9939+
} else {
9940+
// 0 < abs(bitCast(x)) <= bitCast(Infinity) or
9941+
// (reinterpret<u64>(x) & 0x7FFFFFFFFFFFFFFF) - 1 <= 0x7FF0000000000000 - 1
9942+
//
9943+
// and finally:
9944+
// (reinterpret<u64>(x) << 1) - (1 << 1) <= ((0x7FF0000000000000 - 1) << 1)
9945+
return module.binary(BinaryOp.LeU64,
9946+
module.binary(BinaryOp.SubI64,
9947+
module.binary(BinaryOp.ShlI64,
9948+
module.unary(UnaryOp.ReinterpretF64ToI64, expr),
9949+
module.i64(1)
9950+
),
9951+
module.i64(2) // 1 << 1
99159952
),
9916-
module.i64(2) // 1 << 1
9917-
),
9918-
module.i64(0xFFFFFFFE, 0xFFDFFFFF) // (0x7FF0000000000000 - 1) << 1
9919-
);
9953+
module.i64(0xFFFFFFFE, 0xFFDFFFFF) // (0x7FF0000000000000 - 1) << 1
9954+
);
9955+
}
99209956
}
99219957
case TypeKind.V128: {
99229958
return module.unary(UnaryOp.AnyTrueV128, expr);

Diff for: tests/compiler/bool-Oz.debug.wat

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
(module
2+
(memory $0 1)
3+
(data (i32.const 12) ",")
4+
(data (i32.const 24) "\01\00\00\00\14\00\00\00b\00o\00o\00l\00-\00O\00z\00.\00t\00s")
5+
(export "memory" (memory $0))
6+
)

Diff for: tests/compiler/bool-Oz.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"asc_flags": [
3+
"-Oz"
4+
]
5+
}

Diff for: tests/compiler/bool-Oz.release.wat

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
(module
2+
(memory $0 1)
3+
(data (i32.const 12) ",")
4+
(data (i32.const 24) "\01\00\00\00\14\00\00\00b\00o\00o\00l\00-\00O\00z\00.\00t\00s")
5+
(export "memory" (memory $0))
6+
)

Diff for: tests/compiler/bool-Oz.ts

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
var f = <f32>2;
2+
assert(<bool>f == true);
3+
var f0 = <f32>+0.0;
4+
assert(<bool>f0 == false);
5+
var f1 = <f32>-0.0;
6+
assert(<bool>f1 == false);
7+
var f2 = <f32>+NaN;
8+
assert(<bool>f2 == false);
9+
var f3 = <f32>-NaN;
10+
assert(<bool>f3 == false);
11+
var f4 = +f32.MAX_VALUE;
12+
assert(<bool>f4 == true);
13+
var f5 = -f32.MAX_VALUE;
14+
assert(<bool>f5 == true);
15+
var f6 = <f32>+Infinity;
16+
assert(<bool>f6 == true);
17+
var f7 = <f32>-Infinity;
18+
assert(<bool>f7 == true);
19+
var f8 = +f32.MIN_VALUE;
20+
assert(<bool>f8 == true);
21+
var f9 = -f32.MIN_VALUE;
22+
assert(<bool>f9 == true);
23+
var f10 = reinterpret<f32>(1);
24+
assert(<bool>f10 == true);
25+
var f11 = reinterpret<f32>(0x7F800000 - 1);
26+
assert(<bool>f11 == true);
27+
var f12 = reinterpret<f32>(0x7F800000 + 1);
28+
assert(<bool>f12 == false);
29+
var f13 = reinterpret<f32>(0xFF800000 + 1);
30+
assert(<bool>f13 == false);
31+
32+
var F = <f64>2;
33+
assert(<bool>F == true);
34+
var F0 = <f64>+0.0;
35+
assert(<bool>F0 == false);
36+
var F1 = <f64>-0.0;
37+
assert(<bool>F1 == false);
38+
var F2 = <f64>+NaN;
39+
assert(<bool>F2 == false);
40+
var F3 = <f64>-NaN;
41+
assert(<bool>F3 == false);
42+
var F4 = +f64.MAX_VALUE;
43+
assert(<bool>F4 == true);
44+
var F5 = -f64.MAX_VALUE;
45+
assert(<bool>F5 == true);
46+
var F6 = +Infinity;
47+
assert(<bool>F6 == true);
48+
var F7 = -Infinity;
49+
assert(<bool>F7 == true);
50+
var F8 = +f64.MIN_VALUE;
51+
assert(<bool>F8 == true);
52+
var F9 = -f64.MIN_VALUE;
53+
assert(<bool>F9 == true);
54+
var F10 = reinterpret<f64>(1);
55+
assert(<bool>F10 == true);
56+
var F11 = reinterpret<f64>(0x7FF0000000000000 - 1);
57+
assert(<bool>F11 == true);
58+
var F12 = reinterpret<f64>(0x7FF0000000000000 + 1);
59+
assert(<bool>F12 == false);
60+
var F13 = reinterpret<f64>(0xFFF0000000000000 + 1);
61+
assert(<bool>F13 == false);

0 commit comments

Comments
 (0)