diff --git a/src/compiler.ts b/src/compiler.ts index 16454f998c..d4874a1340 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -9883,38 +9883,74 @@ export class Compiler extends DiagnosticEmitter { : expr; } case TypeKind.F32: { - // 0 < abs(bitCast(x)) <= bitCast(Infinity) or - // (reinterpret(x) & 0x7FFFFFFF) - 1 <= 0x7F800000 - 1 - // - // and finally: - // (reinterpret(x) << 1) - (1 << 1) <= ((0x7F800000 - 1) << 1) - return module.binary(BinaryOp.LeU32, - module.binary(BinaryOp.SubI32, - module.binary(BinaryOp.ShlI32, - module.unary(UnaryOp.ReinterpretF32ToI32, expr), - module.i32(1) + let options = this.options; + if ( + options.shrinkLevelHint > 1 && + options.hasFeature(Feature.NONTRAPPING_F2I) + ) { + // Use more compact but slower 5-byte (3 bytes in best case) approach + // !!(i32.trunc_sat_f32_u(f32.ceil(f32.abs(x)))) + return module.unary(UnaryOp.EqzI32, + module.unary(UnaryOp.EqzI32, + module.unary(UnaryOp.TruncSatF32ToU32, + module.unary(UnaryOp.CeilF32, + module.unary(UnaryOp.AbsF32, expr) + ) + ) + ) + ); + } else { + // 0 < abs(bitCast(x)) <= bitCast(Infinity) or + // (reinterpret(x) & 0x7FFFFFFF) - 1 <= 0x7F800000 - 1 + // + // and finally: + // (reinterpret(x) << 1) - (1 << 1) <= ((0x7F800000 - 1) << 1) + return module.binary(BinaryOp.LeU32, + module.binary(BinaryOp.SubI32, + module.binary(BinaryOp.ShlI32, + module.unary(UnaryOp.ReinterpretF32ToI32, expr), + module.i32(1) + ), + module.i32(2) // 1 << 1 ), - module.i32(2) // 1 << 1 - ), - module.i32(0xFEFFFFFE) // (0x7F800000 - 1) << 1 - ); + module.i32(0xFEFFFFFE) // (0x7F800000 - 1) << 1 + ); + } } case TypeKind.F64: { - // 0 < abs(bitCast(x)) <= bitCast(Infinity) or - // (reinterpret(x) & 0x7FFFFFFFFFFFFFFF) - 1 <= 0x7FF0000000000000 - 1 - // - // and finally: - // (reinterpret(x) << 1) - (1 << 1) <= ((0x7FF0000000000000 - 1) << 1) - return module.binary(BinaryOp.LeU64, - module.binary(BinaryOp.SubI64, - module.binary(BinaryOp.ShlI64, - module.unary(UnaryOp.ReinterpretF64ToI64, expr), - module.i64(1) + let options = this.options; + if ( + options.shrinkLevelHint > 1 && + options.hasFeature(Feature.NONTRAPPING_F2I) + ) { + // Use more compact but slower 5-byte (3 bytes in best case) approach + // !!(i32.trunc_sat_f64_u(f64.ceil(f64.abs(x)))) + return module.unary(UnaryOp.EqzI32, + module.unary(UnaryOp.EqzI32, + module.unary(UnaryOp.TruncSatF64ToU32, + module.unary(UnaryOp.CeilF64, + module.unary(UnaryOp.AbsF64, expr) + ) + ) + ) + ); + } else { + // 0 < abs(bitCast(x)) <= bitCast(Infinity) or + // (reinterpret(x) & 0x7FFFFFFFFFFFFFFF) - 1 <= 0x7FF0000000000000 - 1 + // + // and finally: + // (reinterpret(x) << 1) - (1 << 1) <= ((0x7FF0000000000000 - 1) << 1) + return module.binary(BinaryOp.LeU64, + module.binary(BinaryOp.SubI64, + module.binary(BinaryOp.ShlI64, + module.unary(UnaryOp.ReinterpretF64ToI64, expr), + module.i64(1) + ), + module.i64(2) // 1 << 1 ), - module.i64(2) // 1 << 1 - ), - module.i64(0xFFFFFFFE, 0xFFDFFFFF) // (0x7FF0000000000000 - 1) << 1 - ); + module.i64(0xFFFFFFFE, 0xFFDFFFFF) // (0x7FF0000000000000 - 1) << 1 + ); + } } case TypeKind.V128: { return module.unary(UnaryOp.AnyTrueV128, expr); diff --git a/tests/compiler/bool-Oz.debug.wat b/tests/compiler/bool-Oz.debug.wat new file mode 100644 index 0000000000..1ef9ba2bc2 --- /dev/null +++ b/tests/compiler/bool-Oz.debug.wat @@ -0,0 +1,6 @@ +(module + (memory $0 1) + (data (i32.const 12) ",") + (data (i32.const 24) "\01\00\00\00\14\00\00\00b\00o\00o\00l\00-\00O\00z\00.\00t\00s") + (export "memory" (memory $0)) +) diff --git a/tests/compiler/bool-Oz.json b/tests/compiler/bool-Oz.json new file mode 100644 index 0000000000..e8dc22c998 --- /dev/null +++ b/tests/compiler/bool-Oz.json @@ -0,0 +1,5 @@ +{ + "asc_flags": [ + "-Oz" + ] +} diff --git a/tests/compiler/bool-Oz.release.wat b/tests/compiler/bool-Oz.release.wat new file mode 100644 index 0000000000..1ef9ba2bc2 --- /dev/null +++ b/tests/compiler/bool-Oz.release.wat @@ -0,0 +1,6 @@ +(module + (memory $0 1) + (data (i32.const 12) ",") + (data (i32.const 24) "\01\00\00\00\14\00\00\00b\00o\00o\00l\00-\00O\00z\00.\00t\00s") + (export "memory" (memory $0)) +) diff --git a/tests/compiler/bool-Oz.ts b/tests/compiler/bool-Oz.ts new file mode 100644 index 0000000000..5b54f755c0 --- /dev/null +++ b/tests/compiler/bool-Oz.ts @@ -0,0 +1,61 @@ +var f = 2; +assert(f == true); +var f0 = +0.0; +assert(f0 == false); +var f1 = -0.0; +assert(f1 == false); +var f2 = +NaN; +assert(f2 == false); +var f3 = -NaN; +assert(f3 == false); +var f4 = +f32.MAX_VALUE; +assert(f4 == true); +var f5 = -f32.MAX_VALUE; +assert(f5 == true); +var f6 = +Infinity; +assert(f6 == true); +var f7 = -Infinity; +assert(f7 == true); +var f8 = +f32.MIN_VALUE; +assert(f8 == true); +var f9 = -f32.MIN_VALUE; +assert(f9 == true); +var f10 = reinterpret(1); +assert(f10 == true); +var f11 = reinterpret(0x7F800000 - 1); +assert(f11 == true); +var f12 = reinterpret(0x7F800000 + 1); +assert(f12 == false); +var f13 = reinterpret(0xFF800000 + 1); +assert(f13 == false); + +var F = 2; +assert(F == true); +var F0 = +0.0; +assert(F0 == false); +var F1 = -0.0; +assert(F1 == false); +var F2 = +NaN; +assert(F2 == false); +var F3 = -NaN; +assert(F3 == false); +var F4 = +f64.MAX_VALUE; +assert(F4 == true); +var F5 = -f64.MAX_VALUE; +assert(F5 == true); +var F6 = +Infinity; +assert(F6 == true); +var F7 = -Infinity; +assert(F7 == true); +var F8 = +f64.MIN_VALUE; +assert(F8 == true); +var F9 = -f64.MIN_VALUE; +assert(F9 == true); +var F10 = reinterpret(1); +assert(F10 == true); +var F11 = reinterpret(0x7FF0000000000000 - 1); +assert(F11 == true); +var F12 = reinterpret(0x7FF0000000000000 + 1); +assert(F12 == false); +var F13 = reinterpret(0xFFF0000000000000 + 1); +assert(F13 == false);