From 4d8122eedd39b107cea1093c4f1f74aca2e1af47 Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 31 Jan 2021 19:58:26 +0100 Subject: [PATCH 1/2] Implement nontrapping-f2i proposal --- cli/asc.json | 2 +- src/compiler.ts | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/cli/asc.json b/cli/asc.json index 16e85fc8ca..f94fb9fed9 100644 --- a/cli/asc.json +++ b/cli/asc.json @@ -210,6 +210,7 @@ "Enables WebAssembly features being disabled by default.", "", " sign-extension Sign-extension operations", + " nontrapping-f2i Non-trapping float to integer ops.", " bulk-memory Bulk memory operations.", " simd SIMD types and operations.", " threads Threading and atomic operations.", @@ -218,7 +219,6 @@ "" ], "TODO_doesNothingYet": [ - " nontrapping-f2i Non-trapping float to integer ops.", " exception-handling Exception handling.", " tail-calls Tail call operations.", " multi-value Multi value types.", diff --git a/src/compiler.ts b/src/compiler.ts index ebc98fb333..77f351dba3 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -3603,16 +3603,18 @@ export class Compiler extends DiagnosticEmitter { if (toType.isBooleanValue) { expr = this.makeIsTrueish(expr, Type.f32, reportNode); } else if (toType.isSignedIntegerValue) { + let saturating = this.options.hasFeature(Feature.NONTRAPPING_F2I); if (toType.isLongIntegerValue) { - expr = module.unary(UnaryOp.TruncF32ToI64, expr); + expr = module.unary(saturating ? UnaryOp.TruncF32ToI64Sat : UnaryOp.TruncF32ToI64, expr); } else { - expr = module.unary(UnaryOp.TruncF32ToI32, expr); + expr = module.unary(saturating ? UnaryOp.TruncF32ToI32Sat : UnaryOp.TruncF32ToI32, expr); } } else { + let saturating = this.options.hasFeature(Feature.NONTRAPPING_F2I); if (toType.isLongIntegerValue) { - expr = module.unary(UnaryOp.TruncF32ToU64, expr); + expr = module.unary(saturating ? UnaryOp.TruncF32ToU64Sat : UnaryOp.TruncF32ToU64, expr); } else { - expr = module.unary(UnaryOp.TruncF32ToU32, expr); + expr = module.unary(saturating ? UnaryOp.TruncF32ToU32Sat : UnaryOp.TruncF32ToU32, expr); } } @@ -3621,16 +3623,18 @@ export class Compiler extends DiagnosticEmitter { if (toType.isBooleanValue) { expr = this.makeIsTrueish(expr, Type.f64, reportNode); } else if (toType.isSignedIntegerValue) { + let saturating = this.options.hasFeature(Feature.NONTRAPPING_F2I); if (toType.isLongIntegerValue) { - expr = module.unary(UnaryOp.TruncF64ToI64, expr); + expr = module.unary(saturating ? UnaryOp.TruncF64ToI64Sat : UnaryOp.TruncF64ToI64, expr); } else { - expr = module.unary(UnaryOp.TruncF64ToI32, expr); + expr = module.unary(saturating ? UnaryOp.TruncF64ToI32Sat : UnaryOp.TruncF64ToI32, expr); } } else { + let saturating = this.options.hasFeature(Feature.NONTRAPPING_F2I); if (toType.isLongIntegerValue) { - expr = module.unary(UnaryOp.TruncF64ToU64, expr); + expr = module.unary(saturating ? UnaryOp.TruncF64ToU64Sat : UnaryOp.TruncF64ToU64, expr); } else { - expr = module.unary(UnaryOp.TruncF64ToU32, expr); + expr = module.unary(saturating ? UnaryOp.TruncF64ToU32Sat : UnaryOp.TruncF64ToU32, expr); } } } From 0025f77230630a1d4f862125cf54730d1c94da2e Mon Sep 17 00:00:00 2001 From: dcode Date: Sun, 31 Jan 2021 20:15:05 +0100 Subject: [PATCH 2/2] add test --- tests/compiler/features/nontrapping-f2i.json | 8 + .../features/nontrapping-f2i.optimized.wat | 15 ++ tests/compiler/features/nontrapping-f2i.ts | 39 +++++ .../features/nontrapping-f2i.untouched.wat | 162 ++++++++++++++++++ tests/features.json | 5 + 5 files changed, 229 insertions(+) create mode 100644 tests/compiler/features/nontrapping-f2i.json create mode 100644 tests/compiler/features/nontrapping-f2i.optimized.wat create mode 100644 tests/compiler/features/nontrapping-f2i.ts create mode 100644 tests/compiler/features/nontrapping-f2i.untouched.wat diff --git a/tests/compiler/features/nontrapping-f2i.json b/tests/compiler/features/nontrapping-f2i.json new file mode 100644 index 0000000000..1e3d40d020 --- /dev/null +++ b/tests/compiler/features/nontrapping-f2i.json @@ -0,0 +1,8 @@ +{ + "features": [ + "nontrapping-f2i" + ], + "asc_flags": [ + "--explicitStart" + ] +} diff --git a/tests/compiler/features/nontrapping-f2i.optimized.wat b/tests/compiler/features/nontrapping-f2i.optimized.wat new file mode 100644 index 0000000000..6c2feda274 --- /dev/null +++ b/tests/compiler/features/nontrapping-f2i.optimized.wat @@ -0,0 +1,15 @@ +(module + (type $none_=>_none (func)) + (memory $0 0) + (global $~started (mut i32) (i32.const 0)) + (export "memory" (memory $0)) + (export "_start" (func $~start)) + (func $~start + global.get $~started + if + return + end + i32.const 1 + global.set $~started + ) +) diff --git a/tests/compiler/features/nontrapping-f2i.ts b/tests/compiler/features/nontrapping-f2i.ts new file mode 100644 index 0000000000..d6b6b496ec --- /dev/null +++ b/tests/compiler/features/nontrapping-f2i.ts @@ -0,0 +1,39 @@ +// f32->i32 +assert(f32.MAX_VALUE == i32.MAX_VALUE); +assert(-f32.MAX_VALUE == i32.MIN_VALUE); +assert(f32.NaN == 0); + +// f32->i64 +assert(f32.MAX_VALUE == i64.MAX_VALUE); +assert(-f32.MAX_VALUE == i64.MIN_VALUE); +assert(f32.NaN == 0); + +// f32->u32 +assert(f32.MAX_VALUE == u32.MAX_VALUE); +assert(-f32.MAX_VALUE == u32.MIN_VALUE); +assert(f32.NaN == 0); + +// f32->u64 +assert(f32.MAX_VALUE == u64.MAX_VALUE); +assert(-f32.MAX_VALUE == u64.MIN_VALUE); +assert(f32.NaN == 0); + +// f64->i32 +assert(f64.MAX_VALUE == i32.MAX_VALUE); +assert(-f64.MAX_VALUE == i32.MIN_VALUE); +assert(f64.NaN == 0); + +// f64->i64 +assert(f64.MAX_VALUE == i64.MAX_VALUE); +assert(-f64.MAX_VALUE == i64.MIN_VALUE); +assert(f64.NaN == 0); + +// f64->u32 +assert(f64.MAX_VALUE == u32.MAX_VALUE); +assert(-f64.MAX_VALUE == u32.MIN_VALUE); +assert(f64.NaN == 0); + +// f64->u64 +assert(f64.MAX_VALUE == u64.MAX_VALUE); +assert(-f64.MAX_VALUE == u64.MIN_VALUE); +assert(f64.NaN == 0); diff --git a/tests/compiler/features/nontrapping-f2i.untouched.wat b/tests/compiler/features/nontrapping-f2i.untouched.wat new file mode 100644 index 0000000000..14cced1647 --- /dev/null +++ b/tests/compiler/features/nontrapping-f2i.untouched.wat @@ -0,0 +1,162 @@ +(module + (type $none_=>_none (func)) + (memory $0 0) + (table $0 1 funcref) + (global $~lib/builtins/f32.MAX_VALUE f32 (f32.const 3402823466385288598117041e14)) + (global $~lib/builtins/i32.MAX_VALUE i32 (i32.const 2147483647)) + (global $~lib/builtins/i32.MIN_VALUE i32 (i32.const -2147483648)) + (global $~lib/builtins/f32.NaN f32 (f32.const nan:0x400000)) + (global $~lib/builtins/i64.MAX_VALUE i64 (i64.const 9223372036854775807)) + (global $~lib/builtins/i64.MIN_VALUE i64 (i64.const -9223372036854775808)) + (global $~lib/builtins/u32.MAX_VALUE i32 (i32.const -1)) + (global $~lib/builtins/u32.MIN_VALUE i32 (i32.const 0)) + (global $~lib/builtins/u64.MAX_VALUE i64 (i64.const -1)) + (global $~lib/builtins/u64.MIN_VALUE i64 (i64.const 0)) + (global $~lib/builtins/f64.MAX_VALUE f64 (f64.const 1797693134862315708145274e284)) + (global $~lib/builtins/f64.NaN f64 (f64.const nan:0x8000000000000)) + (global $~lib/memory/__data_end i32 (i32.const 8)) + (global $~lib/memory/__stack_pointer (mut i32) (i32.const 16392)) + (global $~lib/memory/__heap_base i32 (i32.const 16392)) + (global $~started (mut i32) (i32.const 0)) + (export "memory" (memory $0)) + (export "_start" (func $~start)) + (func $start:features/nontrapping-f2i + global.get $~lib/builtins/f32.MAX_VALUE + i32.trunc_sat_f32_s + global.get $~lib/builtins/i32.MAX_VALUE + i32.eq + drop + global.get $~lib/builtins/f32.MAX_VALUE + f32.neg + i32.trunc_sat_f32_s + global.get $~lib/builtins/i32.MIN_VALUE + i32.eq + drop + global.get $~lib/builtins/f32.NaN + i32.trunc_sat_f32_s + i32.const 0 + i32.eq + drop + global.get $~lib/builtins/f32.MAX_VALUE + i64.trunc_sat_f32_s + global.get $~lib/builtins/i64.MAX_VALUE + i64.eq + drop + global.get $~lib/builtins/f32.MAX_VALUE + f32.neg + i64.trunc_sat_f32_s + global.get $~lib/builtins/i64.MIN_VALUE + i64.eq + drop + global.get $~lib/builtins/f32.NaN + i64.trunc_sat_f32_s + i64.const 0 + i64.eq + drop + global.get $~lib/builtins/f32.MAX_VALUE + i32.trunc_sat_f32_u + global.get $~lib/builtins/u32.MAX_VALUE + i32.eq + drop + global.get $~lib/builtins/f32.MAX_VALUE + f32.neg + i32.trunc_sat_f32_u + global.get $~lib/builtins/u32.MIN_VALUE + i32.eq + drop + global.get $~lib/builtins/f32.NaN + i32.trunc_sat_f32_u + i32.const 0 + i32.eq + drop + global.get $~lib/builtins/f32.MAX_VALUE + i64.trunc_sat_f32_u + global.get $~lib/builtins/u64.MAX_VALUE + i64.eq + drop + global.get $~lib/builtins/f32.MAX_VALUE + f32.neg + i64.trunc_sat_f32_u + global.get $~lib/builtins/u64.MIN_VALUE + i64.eq + drop + global.get $~lib/builtins/f32.NaN + i64.trunc_sat_f32_u + i64.const 0 + i64.eq + drop + global.get $~lib/builtins/f64.MAX_VALUE + i32.trunc_sat_f64_s + global.get $~lib/builtins/i32.MAX_VALUE + i32.eq + drop + global.get $~lib/builtins/f64.MAX_VALUE + f64.neg + i32.trunc_sat_f64_s + global.get $~lib/builtins/i32.MIN_VALUE + i32.eq + drop + global.get $~lib/builtins/f64.NaN + i32.trunc_sat_f64_s + i32.const 0 + i32.eq + drop + global.get $~lib/builtins/f64.MAX_VALUE + i64.trunc_sat_f64_s + global.get $~lib/builtins/i64.MAX_VALUE + i64.eq + drop + global.get $~lib/builtins/f64.MAX_VALUE + f64.neg + i64.trunc_sat_f64_s + global.get $~lib/builtins/i64.MIN_VALUE + i64.eq + drop + global.get $~lib/builtins/f64.NaN + i64.trunc_sat_f64_s + i64.const 0 + i64.eq + drop + global.get $~lib/builtins/f64.MAX_VALUE + i32.trunc_sat_f64_u + global.get $~lib/builtins/u32.MAX_VALUE + i32.eq + drop + global.get $~lib/builtins/f64.MAX_VALUE + f64.neg + i32.trunc_sat_f64_u + global.get $~lib/builtins/u32.MIN_VALUE + i32.eq + drop + global.get $~lib/builtins/f64.NaN + i32.trunc_sat_f64_u + i32.const 0 + i32.eq + drop + global.get $~lib/builtins/f64.MAX_VALUE + i64.trunc_sat_f64_u + global.get $~lib/builtins/u64.MAX_VALUE + i64.eq + drop + global.get $~lib/builtins/f64.MAX_VALUE + f64.neg + i64.trunc_sat_f64_u + global.get $~lib/builtins/u64.MIN_VALUE + i64.eq + drop + global.get $~lib/builtins/f64.NaN + i64.trunc_sat_f64_u + i64.const 0 + i64.eq + drop + ) + (func $~start + global.get $~started + if + return + end + i32.const 1 + global.set $~started + call $start:features/nontrapping-f2i + ) +) diff --git a/tests/features.json b/tests/features.json index 1b6955a32d..b72f470bd9 100644 --- a/tests/features.json +++ b/tests/features.json @@ -1,6 +1,11 @@ { "mutable-globals": { }, + "nontrapping-f2i": { + "asc_flags": [ + "--enable nontrapping-f2i" + ] + }, "simd": { "asc_flags": [ "--enable simd"