Add support for math libcalls.
This commit is contained in:
@@ -56,6 +56,8 @@ impl binemit::RelocSink for RelocSink {
|
||||
RelocationTarget::MemoryGrow
|
||||
} else if *name == ExternalName::testcase("wasmtime_memory_size") {
|
||||
RelocationTarget::MemorySize
|
||||
} else if let ExternalName::LibCall(libcall) = *name {
|
||||
RelocationTarget::LibCall(libcall)
|
||||
} else {
|
||||
panic!("unrecognized external name")
|
||||
};
|
||||
@@ -103,6 +105,8 @@ pub struct Relocation {
|
||||
pub enum RelocationTarget {
|
||||
/// The user function index.
|
||||
UserFunc(FuncIndex),
|
||||
/// A compiler-generated libcall.
|
||||
LibCall(ir::LibCall),
|
||||
/// Function for growing the default memory by the specified amount of pages.
|
||||
MemoryGrow,
|
||||
/// Function for query current size of the default linear memory.
|
||||
|
||||
@@ -64,6 +64,21 @@ fn relocate<F>(
|
||||
},
|
||||
RelocationTarget::MemoryGrow => wasmtime_memory_grow as usize,
|
||||
RelocationTarget::MemorySize => wasmtime_memory_size as usize,
|
||||
RelocationTarget::LibCall(libcall) => {
|
||||
use cranelift_codegen::ir::LibCall::*;
|
||||
use libcalls::*;
|
||||
match libcall {
|
||||
CeilF32 => wasmtime_f32_ceil as usize,
|
||||
FloorF32 => wasmtime_f32_floor as usize,
|
||||
TruncF32 => wasmtime_f32_trunc as usize,
|
||||
NearestF32 => wasmtime_f32_nearest as usize,
|
||||
CeilF64 => wasmtime_f64_ceil as usize,
|
||||
FloorF64 => wasmtime_f64_floor as usize,
|
||||
TruncF64 => wasmtime_f64_trunc as usize,
|
||||
NearestF64 => wasmtime_f64_nearest as usize,
|
||||
other => panic!("unexpected libcall: {}", other),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let body = &mut compilation.functions[i];
|
||||
|
||||
@@ -48,6 +48,7 @@ mod code;
|
||||
mod execute;
|
||||
mod instance;
|
||||
mod invoke;
|
||||
mod libcalls;
|
||||
mod memory;
|
||||
mod mmap;
|
||||
mod signalhandlers;
|
||||
|
||||
73
lib/execute/src/libcalls.rs
Normal file
73
lib/execute/src/libcalls.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
//! Runtime library calls. Note that the JIT may sometimes perform these inline
|
||||
//! rather than calling them, particularly when CPUs have special instructions
|
||||
//! which compute them directly.
|
||||
|
||||
pub extern "C" fn wasmtime_f32_ceil(x: f32) -> f32 {
|
||||
x.ceil()
|
||||
}
|
||||
|
||||
pub extern "C" fn wasmtime_f32_floor(x: f32) -> f32 {
|
||||
x.floor()
|
||||
}
|
||||
|
||||
pub extern "C" fn wasmtime_f32_trunc(x: f32) -> f32 {
|
||||
x.trunc()
|
||||
}
|
||||
|
||||
pub extern "C" fn wasmtime_f32_nearest(x: f32) -> f32 {
|
||||
// Rust doesn't have a nearest function, so do it manually.
|
||||
if x == 0.0 {
|
||||
// Preserve the sign of zero.
|
||||
x
|
||||
} else {
|
||||
// Nearest is either ceil or floor depending on which is nearest or even.
|
||||
let u = x.ceil();
|
||||
let d = x.floor();
|
||||
let um = (x - u).abs();
|
||||
let dm = (x - d).abs();
|
||||
if um < dm
|
||||
|| (um == dm && {
|
||||
let h = u / 2.;
|
||||
h.floor() == h
|
||||
}) {
|
||||
u
|
||||
} else {
|
||||
d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn wasmtime_f64_ceil(x: f64) -> f64 {
|
||||
x.ceil()
|
||||
}
|
||||
|
||||
pub extern "C" fn wasmtime_f64_floor(x: f64) -> f64 {
|
||||
x.floor()
|
||||
}
|
||||
|
||||
pub extern "C" fn wasmtime_f64_trunc(x: f64) -> f64 {
|
||||
x.trunc()
|
||||
}
|
||||
|
||||
pub extern "C" fn wasmtime_f64_nearest(x: f64) -> f64 {
|
||||
// Rust doesn't have a nearest function, so do it manually.
|
||||
if x == 0.0 {
|
||||
// Preserve the sign of zero.
|
||||
x
|
||||
} else {
|
||||
// Nearest is either ceil or floor depending on which is nearest or even.
|
||||
let u = x.ceil();
|
||||
let d = x.floor();
|
||||
let um = (x - u).abs();
|
||||
let dm = (x - d).abs();
|
||||
if um < dm
|
||||
|| (um == dm && {
|
||||
let h = u / 2.;
|
||||
h.floor() == h
|
||||
}) {
|
||||
u
|
||||
} else {
|
||||
d
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user