Skip to content

Commit 12c17c2

Browse files
committed
Fixes FP rounding issue and adds tests
The issue was caused becuase cranelift compilation assume SSE2 even for the where as rust compiler doesn't include these instructions by default. This means when transitioning through wasmtime libcalls the parameters are lost since wasm is using SSE2 instructions and wasmtime isn't. The more advance SSE intructions require a seperate pr in HL core that is needed to enable them. Signed-off-by: James Sturtevant <[email protected]>
1 parent 6c90e4b commit 12c17c2

File tree

7 files changed

+124
-2
lines changed

7 files changed

+124
-2
lines changed

Justfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ examples-ci target=default-target features="": (build-rust-wasm-examples target)
100100
cargo run {{ if features =="" {''} else {"--no-default-features -F function_call_metrics," + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} --example metrics
101101
cargo run {{ if features =="" {"--no-default-features --features kvm,mshv3"} else {"--no-default-features -F function_call_metrics," + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} --example metrics
102102

103-
examples-components target=default-target features="": (build-rust-component-examples target)
104-
{{ wit-world }} cargo run {{ if features =="" {''} else {"--no-default-features -F " + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} --example component_example
103+
examples-components target=default-target features="": (build-rust-component-examples target) (build-wasm-examples target)
104+
{{ wit-world }} cargo run {{ if features =="" {''} else {"--no-default-features -F kvm -F " + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} --example component_example
105+
{{ wit-world-c }} cargo run {{ if features =="" {''} else {"--no-default-features -F kvm -F " + features } }} --profile={{ if target == "debug" {"dev"} else { target } }} --example c-component
105106

106107
# warning, compares to and then OVERWRITES the given baseline
107108
bench-ci baseline target="release" features="":
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use examples_common::get_wasm_module_path;
2+
use hyperlight_wasm::SandboxBuilder;
3+
4+
use crate::bindings::example::runcomponent::Guest;
5+
6+
extern crate alloc;
7+
mod bindings {
8+
hyperlight_component_macro::host_bindgen!(
9+
"../../src/wasmsamples/components/runcomponent-world.wasm"
10+
);
11+
}
12+
13+
pub struct State {}
14+
impl State {
15+
pub fn new() -> Self {
16+
State {}
17+
}
18+
}
19+
20+
impl Default for State {
21+
fn default() -> Self {
22+
Self::new()
23+
}
24+
}
25+
26+
impl bindings::example::runcomponent::Host for State {
27+
fn r#get_time_since_boot_microsecond(&mut self) -> i64 {
28+
let res = std::time::SystemTime::now()
29+
.duration_since(std::time::SystemTime::UNIX_EPOCH)
30+
.unwrap()
31+
.as_micros();
32+
i64::try_from(res).unwrap()
33+
}
34+
}
35+
36+
impl bindings::example::runcomponent::RuncomponentImports for State {
37+
type Host = State;
38+
39+
fn r#host(&mut self) -> impl ::core::borrow::BorrowMut<Self::Host> {
40+
self
41+
}
42+
}
43+
44+
fn main() {
45+
let state = State::new();
46+
let mut sandbox = SandboxBuilder::new()
47+
.with_guest_input_buffer_size(70000000)
48+
.with_guest_heap_size(200000000)
49+
.with_guest_stack_size(100000000)
50+
//.with_debugging_enabled(8080)
51+
.build()
52+
.unwrap();
53+
let rt = bindings::register_host_functions(&mut sandbox, state);
54+
55+
let sb = sandbox.load_runtime().unwrap();
56+
57+
let mod_path = get_wasm_module_path("runcomponent.aot").unwrap();
58+
let sb = sb.load_module(mod_path).unwrap();
59+
60+
let mut wrapped = bindings::RuncomponentSandbox { sb, rt };
61+
let instance = bindings::example::runcomponent::RuncomponentExports::guest(&mut wrapped);
62+
let echo = instance.echo("Hello World!".to_string());
63+
println!("{}", echo);
64+
65+
let result = instance.round_to_nearest_int(1.331, 24.0);
66+
println!("rounded result {}", result);
67+
assert_eq!(result, 32);
68+
}

src/hyperlight_wasm/examples/helloworld/main.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,37 @@ fn main() -> Result<()> {
8383
);
8484
}
8585
}
86+
87+
let tests = [
88+
(1.331, 24.0, 32),
89+
(std::f32::consts::PI, std::f32::consts::E, 9),
90+
(-5.7, 10.3, -59),
91+
(0.0, 0.0, 0),
92+
(99.999, 0.001, 0),
93+
(-std::f32::consts::PI, -2.86, 9),
94+
(1.5, 1.5, 2),
95+
];
96+
let mut sandbox = SandboxBuilder::new().build()?;
97+
sandbox
98+
.register(
99+
"GetTimeSinceBootMicrosecond",
100+
get_time_since_boot_microsecond,
101+
)
102+
.unwrap();
103+
let wasm_sandbox = sandbox.load_runtime()?;
104+
let mod_path = get_wasm_module_path("RunWasm.aot")?;
105+
let mut loaded_wasm_sandbox = wasm_sandbox.load_module(mod_path)?;
106+
let snapshot = loaded_wasm_sandbox.snapshot()?;
107+
108+
for (idx, case) in tests.iter().enumerate() {
109+
let (a, b, expected_result): (f32, f32, i32) = *case;
110+
let result: i32 = loaded_wasm_sandbox.call_guest_function("RoundToNearestInt", (a, b))?;
111+
assert_eq!(
112+
result, expected_result,
113+
"RoundToInt test case {idx} failed: got {}, expected {}",
114+
result, expected_result
115+
);
116+
loaded_wasm_sandbox.restore(&snapshot)?
117+
}
86118
Ok(())
87119
}

src/wasm_runtime/.cargo/config.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ rustflags = [
77
"code-model=small",
88
"-C",
99
"link-args=-e entrypoint",
10+
"-C",
11+
"target-feature=-soft-float,+sse,+sse2"
1012
]
1113
linker = "rust-lld"
1214

src/wasmsamples/RunWasm.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ limitations under the License.
2020
#include <limits.h>
2121
#include <stdint.h>
2222
#include <ctype.h>
23+
#include <math.h>
2324

2425
int HostPrint(char* msg); // Implementation of this will be available in the native host
2526

@@ -129,3 +130,12 @@ int KeepCPUBusy(int ms)
129130
printf("Kept CPU busy for %d ms using %d iterations of fib(10) %d|toreach max = %d|", ms, iter, INT_MAX, INT_MAX-iter);
130131
return ms;
131132
}
133+
134+
__attribute__((export_name("RoundToNearestInt")))
135+
int RoundToNearestInt(float a, float b)
136+
{
137+
float c = a*b;
138+
float r = lrintf(c);
139+
printf("rounded answer: %f\n", r);
140+
return r;
141+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
#include "bindings/runcomponent.h"
22
#include <stdlib.h>
33
#include <string.h>
4+
#include <math.h>
45

56
void exports_example_runcomponent_guest_echo(runcomponent_string_t *msg, runcomponent_string_t *ret)
67
{
78
ret->len = msg->len;
89
ret->ptr = (uint8_t *) malloc(ret->len);
910
memcpy(ret->ptr, msg->ptr, ret->len);
1011
runcomponent_string_free(msg);
12+
}
13+
14+
int32_t exports_example_runcomponent_guest_round_to_nearest_int(float a, float b)
15+
{
16+
float c = a*b;
17+
float r = lrintf(c);
18+
return r;
1119
}

src/wasmsamples/components/runcomponent.wit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package example:runcomponent;
22

33
interface guest {
44
echo: func(msg: string) -> string;
5+
round-to-nearest-int: func(a: f32, b: f32) -> s32;
56
}
67

78
interface host {

0 commit comments

Comments
 (0)