From 4c47ce9b5356743277df427b93c59b19335e51dd Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 3 Dec 2018 04:01:48 -0800 Subject: [PATCH] Add support for math libcalls. --- lib/environ/src/compilation.rs | 4 ++ lib/execute/src/execute.rs | 15 +++++++ lib/execute/src/lib.rs | 1 + lib/execute/src/libcalls.rs | 73 ++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 lib/execute/src/libcalls.rs diff --git a/lib/environ/src/compilation.rs b/lib/environ/src/compilation.rs index 427bee39c0..ed4c5798a6 100644 --- a/lib/environ/src/compilation.rs +++ b/lib/environ/src/compilation.rs @@ -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. diff --git a/lib/execute/src/execute.rs b/lib/execute/src/execute.rs index c4310c5b33..8dd1bef775 100644 --- a/lib/execute/src/execute.rs +++ b/lib/execute/src/execute.rs @@ -64,6 +64,21 @@ fn relocate( }, 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]; diff --git a/lib/execute/src/lib.rs b/lib/execute/src/lib.rs index 537de949b4..0d26a99040 100644 --- a/lib/execute/src/lib.rs +++ b/lib/execute/src/lib.rs @@ -48,6 +48,7 @@ mod code; mod execute; mod instance; mod invoke; +mod libcalls; mod memory; mod mmap; mod signalhandlers; diff --git a/lib/execute/src/libcalls.rs b/lib/execute/src/libcalls.rs new file mode 100644 index 0000000000..f4166c2a64 --- /dev/null +++ b/lib/execute/src/libcalls.rs @@ -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 + } + } +}