Skip to content

Commit 0e3e863

Browse files
authored
Move float-to-int conversion libcalls into compiled code (#9679)
This commit moves these conversion libcalls into compiled code to make them easier to work with on Pulley since there's no need to manage the hostcall boundary. This should in theory also speed things up slightly relative to actually calling out to the libcall itself.
1 parent c52b941 commit 0e3e863

File tree

5 files changed

+35
-110
lines changed

5 files changed

+35
-110
lines changed

crates/cranelift/src/func_environ.rs

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::translate::{
44
};
55
use crate::{gc, BuiltinFunctionSignatures, TRAP_INTERNAL_ASSERT};
66
use cranelift_codegen::cursor::FuncCursor;
7-
use cranelift_codegen::ir::condcodes::IntCC;
7+
use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
88
use cranelift_codegen::ir::immediates::{Imm64, Offset32};
99
use cranelift_codegen::ir::pcc::Fact;
1010
use cranelift_codegen::ir::types::*;
@@ -1103,31 +1103,41 @@ impl<'module_environment> FuncEnvironment<'module_environment> {
11031103
self.conditionally_trap(builder, is_integer_overflow, ir::TrapCode::INTEGER_OVERFLOW);
11041104
}
11051105

1106-
/// Helper used when `!self.signals_based_traps()` is enabled to perform
1107-
/// trapping float-to-int conversions.
1108-
fn fcvt_to_int(
1106+
/// Helper used when `!self.signals_based_traps()` is enabled to guard the
1107+
/// traps from float-to-int conversions.
1108+
fn guard_fcvt_to_int(
11091109
&mut self,
11101110
builder: &mut FunctionBuilder,
11111111
ty: ir::Type,
11121112
val: ir::Value,
1113-
i32: fn(&mut Self, &mut Function) -> ir::FuncRef,
1114-
i64: fn(&mut Self, &mut Function) -> ir::FuncRef,
1115-
) -> ir::Value {
1113+
range32: (f64, f64),
1114+
range64: (f64, f64),
1115+
) {
11161116
assert!(!self.signals_based_traps());
11171117
let val_ty = builder.func.dfg.value_type(val);
11181118
let val = if val_ty == F64 {
11191119
val
11201120
} else {
11211121
builder.ins().fpromote(F64, val)
11221122
};
1123-
let libcall = match ty {
1124-
I32 => i32(self, &mut builder.func),
1125-
I64 => i64(self, &mut builder.func),
1123+
let isnan = builder.ins().fcmp(FloatCC::NotEqual, val, val);
1124+
self.trapnz(builder, isnan, ir::TrapCode::BAD_CONVERSION_TO_INTEGER);
1125+
let val = builder.ins().trunc(val);
1126+
let (lower_bound, upper_bound) = match ty {
1127+
I32 => range32,
1128+
I64 => range64,
11261129
_ => unreachable!(),
11271130
};
1128-
let vmctx = self.vmctx_val(&mut builder.cursor());
1129-
let call = builder.ins().call(libcall, &[vmctx, val]);
1130-
*builder.func.dfg.inst_results(call).first().unwrap()
1131+
let lower_bound = builder.ins().f64const(lower_bound);
1132+
let too_small = builder
1133+
.ins()
1134+
.fcmp(FloatCC::LessThanOrEqual, val, lower_bound);
1135+
self.trapnz(builder, too_small, ir::TrapCode::INTEGER_OVERFLOW);
1136+
let upper_bound = builder.ins().f64const(upper_bound);
1137+
let too_large = builder
1138+
.ins()
1139+
.fcmp(FloatCC::GreaterThanOrEqual, val, upper_bound);
1140+
self.trapnz(builder, too_large, ir::TrapCode::INTEGER_OVERFLOW);
11311141
}
11321142

11331143
/// Get the `ir::Type` for a `VMSharedTypeIndex`.
@@ -3338,17 +3348,16 @@ impl<'module_environment> crate::translate::FuncEnvironment
33383348
) -> ir::Value {
33393349
// NB: for now avoid translating this entire instruction to CLIF and
33403350
// just do it in a libcall.
3341-
if self.signals_based_traps() {
3342-
builder.ins().fcvt_to_sint(ty, val)
3343-
} else {
3344-
self.fcvt_to_int(
3351+
if !self.signals_based_traps() {
3352+
self.guard_fcvt_to_int(
33453353
builder,
33463354
ty,
33473355
val,
3348-
|me, func| me.builtin_functions.f64_to_i32(func),
3349-
|me, func| me.builtin_functions.f64_to_i64(func),
3350-
)
3356+
(-2147483649.0, 2147483648.0),
3357+
(-9223372036854777856.0, 9223372036854775808.0),
3358+
);
33513359
}
3360+
builder.ins().fcvt_to_sint(ty, val)
33523361
}
33533362

33543363
fn translate_fcvt_to_uint(
@@ -3357,19 +3366,16 @@ impl<'module_environment> crate::translate::FuncEnvironment
33573366
ty: ir::Type,
33583367
val: ir::Value,
33593368
) -> ir::Value {
3360-
// NB: for now avoid translating this entire instruction to CLIF and
3361-
// just do it in a libcall.
3362-
if self.signals_based_traps() {
3363-
builder.ins().fcvt_to_uint(ty, val)
3364-
} else {
3365-
self.fcvt_to_int(
3369+
if !self.signals_based_traps() {
3370+
self.guard_fcvt_to_int(
33663371
builder,
33673372
ty,
33683373
val,
3369-
|me, func| me.builtin_functions.f64_to_u32(func),
3370-
|me, func| me.builtin_functions.f64_to_u64(func),
3371-
)
3374+
(-1.0, 4294967296.0),
3375+
(-1.0, 18446744073709551616.0),
3376+
);
33723377
}
3378+
builder.ins().fcvt_to_uint(ty, val)
33733379
}
33743380
}
33753381

crates/cranelift/src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -386,10 +386,6 @@ impl BuiltinFunctionSignatures {
386386
AbiParam::new(ir::types::I64)
387387
}
388388

389-
fn f64(&self) -> AbiParam {
390-
AbiParam::new(ir::types::F64)
391-
}
392-
393389
fn u8(&self) -> AbiParam {
394390
AbiParam::new(ir::types::I8)
395391
}

crates/environ/src/builtin.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -198,16 +198,6 @@ macro_rules! foreach_builtin_function {
198198

199199
// Raises an unconditional trap.
200200
trap(vmctx: vmctx, code: u8);
201-
202-
// Implementation of `i{32,64}.trunc_f{32,64}_{u,s}` when host trap
203-
// handlers are disabled. These will raise a trap if necessary. Note
204-
// that f32 inputs are always converted to f64 as the argument. Also
205-
// note that the signed-ness of the result is not reflected in the
206-
// type here.
207-
f64_to_i64(vmctx: vmctx, float: f64) -> i64;
208-
f64_to_u64(vmctx: vmctx, float: f64) -> i64;
209-
f64_to_i32(vmctx: vmctx, float: f64) -> i32;
210-
f64_to_u32(vmctx: vmctx, float: f64) -> i32;
211201
}
212202
};
213203
}

crates/wasmtime/src/runtime/vm/libcalls.rs

Lines changed: 0 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ use crate::runtime::vm::{Instance, TrapReason, VMGcRef, VMStore};
6161
use core::ptr::NonNull;
6262
#[cfg(feature = "threads")]
6363
use core::time::Duration;
64-
use wasmtime_environ::Unsigned;
6564
use wasmtime_environ::{DataIndex, ElemIndex, FuncIndex, MemoryIndex, TableIndex, Trap};
6665
#[cfg(feature = "wmemcheck")]
6766
use wasmtime_wmemcheck::AccessError::{
@@ -143,7 +142,6 @@ pub mod raw {
143142

144143
(@ty i32) => (u32);
145144
(@ty i64) => (u64);
146-
(@ty f64) => (f64);
147145
(@ty u8) => (u8);
148146
(@ty reference) => (u32);
149147
(@ty pointer) => (*mut u8);
@@ -1257,70 +1255,6 @@ fn trap(_store: &mut dyn VMStore, _instance: &mut Instance, code: u8) -> Result<
12571255
))
12581256
}
12591257

1260-
fn f64_to_i64(
1261-
_store: &mut dyn VMStore,
1262-
_instance: &mut Instance,
1263-
val: f64,
1264-
) -> Result<u64, TrapReason> {
1265-
if val.is_nan() {
1266-
return Err(TrapReason::Wasm(Trap::BadConversionToInteger));
1267-
}
1268-
let val = relocs::truncf64(val);
1269-
if val <= -9223372036854777856.0 || val >= 9223372036854775808.0 {
1270-
return Err(TrapReason::Wasm(Trap::IntegerOverflow));
1271-
}
1272-
#[allow(clippy::cast_possible_truncation)]
1273-
return Ok((val as i64).unsigned());
1274-
}
1275-
1276-
fn f64_to_u64(
1277-
_store: &mut dyn VMStore,
1278-
_instance: &mut Instance,
1279-
val: f64,
1280-
) -> Result<u64, TrapReason> {
1281-
if val.is_nan() {
1282-
return Err(TrapReason::Wasm(Trap::BadConversionToInteger));
1283-
}
1284-
let val = relocs::truncf64(val);
1285-
if val <= -1.0 || val >= 18446744073709551616.0 {
1286-
return Err(TrapReason::Wasm(Trap::IntegerOverflow));
1287-
}
1288-
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
1289-
return Ok(val as u64);
1290-
}
1291-
1292-
fn f64_to_i32(
1293-
_store: &mut dyn VMStore,
1294-
_instance: &mut Instance,
1295-
val: f64,
1296-
) -> Result<u32, TrapReason> {
1297-
if val.is_nan() {
1298-
return Err(TrapReason::Wasm(Trap::BadConversionToInteger));
1299-
}
1300-
let val = relocs::truncf64(val);
1301-
if val <= -2147483649.0 || val >= 2147483648.0 {
1302-
return Err(TrapReason::Wasm(Trap::IntegerOverflow));
1303-
}
1304-
#[allow(clippy::cast_possible_truncation)]
1305-
return Ok((val as i32).unsigned());
1306-
}
1307-
1308-
fn f64_to_u32(
1309-
_store: &mut dyn VMStore,
1310-
_instance: &mut Instance,
1311-
val: f64,
1312-
) -> Result<u32, TrapReason> {
1313-
if val.is_nan() {
1314-
return Err(TrapReason::Wasm(Trap::BadConversionToInteger));
1315-
}
1316-
let val = relocs::truncf64(val);
1317-
if val <= -1.0 || val >= 4294967296.0 {
1318-
return Err(TrapReason::Wasm(Trap::IntegerOverflow));
1319-
}
1320-
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
1321-
return Ok(val as u32);
1322-
}
1323-
13241258
/// This module contains functions which are used for resolving relocations at
13251259
/// runtime if necessary.
13261260
///

crates/wasmtime/src/runtime/vm/vmcontext.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,6 @@ macro_rules! define_builtin_array {
796796

797797
(@ty i32) => (u32);
798798
(@ty i64) => (u64);
799-
(@ty f64) => (f64);
800799
(@ty u8) => (u8);
801800
(@ty reference) => (u32);
802801
(@ty pointer) => (*mut u8);

0 commit comments

Comments
 (0)