Skip to content

Implement nontrapping-f2i proposal #1651

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/asc.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand All @@ -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.",
Expand Down
20 changes: 12 additions & 8 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand All @@ -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);
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions tests/compiler/features/nontrapping-f2i.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"features": [
"nontrapping-f2i"
],
"asc_flags": [
"--explicitStart"
]
}
15 changes: 15 additions & 0 deletions tests/compiler/features/nontrapping-f2i.optimized.wat
Original file line number Diff line number Diff line change
@@ -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
)
)
39 changes: 39 additions & 0 deletions tests/compiler/features/nontrapping-f2i.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// f32->i32
assert(<i32>f32.MAX_VALUE == i32.MAX_VALUE);
assert(<i32>-f32.MAX_VALUE == i32.MIN_VALUE);
assert(<i32>f32.NaN == 0);

// f32->i64
assert(<i64>f32.MAX_VALUE == i64.MAX_VALUE);
assert(<i64>-f32.MAX_VALUE == i64.MIN_VALUE);
assert(<i64>f32.NaN == 0);

// f32->u32
assert(<u32>f32.MAX_VALUE == u32.MAX_VALUE);
assert(<u32>-f32.MAX_VALUE == u32.MIN_VALUE);
assert(<u32>f32.NaN == 0);

// f32->u64
assert(<u64>f32.MAX_VALUE == u64.MAX_VALUE);
assert(<u64>-f32.MAX_VALUE == u64.MIN_VALUE);
assert(<u64>f32.NaN == 0);

// f64->i32
assert(<i32>f64.MAX_VALUE == i32.MAX_VALUE);
assert(<i32>-f64.MAX_VALUE == i32.MIN_VALUE);
assert(<i32>f64.NaN == 0);

// f64->i64
assert(<i64>f64.MAX_VALUE == i64.MAX_VALUE);
assert(<i64>-f64.MAX_VALUE == i64.MIN_VALUE);
assert(<i64>f64.NaN == 0);

// f64->u32
assert(<u32>f64.MAX_VALUE == u32.MAX_VALUE);
assert(<u32>-f64.MAX_VALUE == u32.MIN_VALUE);
assert(<u32>f64.NaN == 0);

// f64->u64
assert(<u64>f64.MAX_VALUE == u64.MAX_VALUE);
assert(<u64>-f64.MAX_VALUE == u64.MIN_VALUE);
assert(<u64>f64.NaN == 0);
162 changes: 162 additions & 0 deletions tests/compiler/features/nontrapping-f2i.untouched.wat
Original file line number Diff line number Diff line change
@@ -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
)
)
5 changes: 5 additions & 0 deletions tests/features.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"mutable-globals": {
},
"nontrapping-f2i": {
"asc_flags": [
"--enable nontrapping-f2i"
]
},
"simd": {
"asc_flags": [
"--enable simd"
Expand Down