Add support for math libcalls.
This commit is contained in:
@@ -56,6 +56,8 @@ impl binemit::RelocSink for RelocSink {
|
|||||||
RelocationTarget::MemoryGrow
|
RelocationTarget::MemoryGrow
|
||||||
} else if *name == ExternalName::testcase("wasmtime_memory_size") {
|
} else if *name == ExternalName::testcase("wasmtime_memory_size") {
|
||||||
RelocationTarget::MemorySize
|
RelocationTarget::MemorySize
|
||||||
|
} else if let ExternalName::LibCall(libcall) = *name {
|
||||||
|
RelocationTarget::LibCall(libcall)
|
||||||
} else {
|
} else {
|
||||||
panic!("unrecognized external name")
|
panic!("unrecognized external name")
|
||||||
};
|
};
|
||||||
@@ -103,6 +105,8 @@ pub struct Relocation {
|
|||||||
pub enum RelocationTarget {
|
pub enum RelocationTarget {
|
||||||
/// The user function index.
|
/// The user function index.
|
||||||
UserFunc(FuncIndex),
|
UserFunc(FuncIndex),
|
||||||
|
/// A compiler-generated libcall.
|
||||||
|
LibCall(ir::LibCall),
|
||||||
/// Function for growing the default memory by the specified amount of pages.
|
/// Function for growing the default memory by the specified amount of pages.
|
||||||
MemoryGrow,
|
MemoryGrow,
|
||||||
/// Function for query current size of the default linear memory.
|
/// 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::MemoryGrow => wasmtime_memory_grow as usize,
|
||||||
RelocationTarget::MemorySize => wasmtime_memory_size 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];
|
let body = &mut compilation.functions[i];
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ mod code;
|
|||||||
mod execute;
|
mod execute;
|
||||||
mod instance;
|
mod instance;
|
||||||
mod invoke;
|
mod invoke;
|
||||||
|
mod libcalls;
|
||||||
mod memory;
|
mod memory;
|
||||||
mod mmap;
|
mod mmap;
|
||||||
mod signalhandlers;
|
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