Add support for math libcalls.

This commit is contained in:
Dan Gohman
2018-12-03 04:01:48 -08:00
parent bd69768e0d
commit 4c47ce9b53
4 changed files with 93 additions and 0 deletions

View File

@@ -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.

View File

@@ -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];

View File

@@ -48,6 +48,7 @@ mod code;
mod execute;
mod instance;
mod invoke;
mod libcalls;
mod memory;
mod mmap;
mod signalhandlers;

View 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
}
}
}