Skip to content

Commit bd958bc

Browse files
authored
feat: add to/from f64/f32 instructions (arcjet#115)
1 parent 8bf2a66 commit bd958bc

6 files changed

Lines changed: 156 additions & 9 deletions

File tree

cmd/gravity/src/codegen/func.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ use crate::{
1010
go::{
1111
GoIdentifier, GoResult, GoType, Operand, comment,
1212
imports::{
13-
ERRORS_NEW, WAZERO_API_DECODE_I32, WAZERO_API_DECODE_U32, WAZERO_API_ENCODE_I32,
14-
WAZERO_API_ENCODE_U32,
13+
ERRORS_NEW, WAZERO_API_DECODE_F32, WAZERO_API_DECODE_F64, WAZERO_API_DECODE_I32,
14+
WAZERO_API_DECODE_U32, WAZERO_API_ENCODE_F32, WAZERO_API_ENCODE_F64,
15+
WAZERO_API_ENCODE_I32, WAZERO_API_ENCODE_U32,
1516
},
1617
},
1718
resolve_type, resolve_wasm_type,
@@ -1120,8 +1121,26 @@ impl Bindgen for Func<'_> {
11201121
}
11211122
results.push(Operand::SingleValue(value))
11221123
}
1123-
Instruction::CoreF32FromF32 => todo!("implement instruction: {inst:?}"),
1124-
Instruction::CoreF64FromF64 => todo!("implement instruction: {inst:?}"),
1124+
Instruction::CoreF32FromF32 => {
1125+
let tmp = self.tmp();
1126+
let result = &format!("result{tmp}");
1127+
let operand = &operands[0];
1128+
quote_in! { self.body =>
1129+
$['\r']
1130+
$result := $WAZERO_API_ENCODE_F32($operand)
1131+
};
1132+
results.push(Operand::SingleValue(result.into()));
1133+
}
1134+
Instruction::CoreF64FromF64 => {
1135+
let tmp = self.tmp();
1136+
let result = &format!("result{tmp}");
1137+
let operand = &operands[0];
1138+
quote_in! { self.body =>
1139+
$['\r']
1140+
$result := $WAZERO_API_ENCODE_F64($operand)
1141+
};
1142+
results.push(Operand::SingleValue(result.into()));
1143+
}
11251144
// TODO: Validate the Go cast truncates the upper bits in the I32
11261145
Instruction::S8FromI32 => {
11271146
let tmp = self.tmp();
@@ -1179,8 +1198,26 @@ impl Bindgen for Func<'_> {
11791198
Instruction::S64FromI64 => todo!("implement instruction: {inst:?}"),
11801199
Instruction::U64FromI64 => todo!("implement instruction: {inst:?}"),
11811200
Instruction::CharFromI32 => todo!("implement instruction: {inst:?}"),
1182-
Instruction::F32FromCoreF32 => todo!("implement instruction: {inst:?}"),
1183-
Instruction::F64FromCoreF64 => todo!("implement instruction: {inst:?}"),
1201+
Instruction::F32FromCoreF32 => {
1202+
let tmp = self.tmp();
1203+
let result = &format!("result{tmp}");
1204+
let operand = &operands[0];
1205+
quote_in! { self.body =>
1206+
$['\r']
1207+
$result := $WAZERO_API_DECODE_F32($operand)
1208+
};
1209+
results.push(Operand::SingleValue(result.into()));
1210+
}
1211+
Instruction::F64FromCoreF64 => {
1212+
let tmp = self.tmp();
1213+
let result = &format!("result{tmp}");
1214+
let operand = &operands[0];
1215+
quote_in! { self.body =>
1216+
$['\r']
1217+
$result := $WAZERO_API_DECODE_F64($operand)
1218+
};
1219+
results.push(Operand::SingleValue(result.into()));
1220+
}
11841221
Instruction::TupleLower { .. } => todo!("implement instruction: {inst:?}"),
11851222
Instruction::TupleLift { .. } => todo!("implement instruction: {inst:?}"),
11861223
Instruction::FlagsLower { .. } => todo!("implement instruction: {inst:?}"),

cmd/gravity/src/go/imports.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,11 @@ pub static WAZERO_API_ENCODE_I32: GoImport =
2828
GoImport("github.com/tetratelabs/wazero/api", "EncodeI32");
2929
pub static WAZERO_API_DECODE_I32: GoImport =
3030
GoImport("github.com/tetratelabs/wazero/api", "DecodeI32");
31+
pub static WAZERO_API_ENCODE_F32: GoImport =
32+
GoImport("github.com/tetratelabs/wazero/api", "EncodeF32");
33+
pub static WAZERO_API_DECODE_F32: GoImport =
34+
GoImport("github.com/tetratelabs/wazero/api", "DecodeF32");
35+
pub static WAZERO_API_ENCODE_F64: GoImport =
36+
GoImport("github.com/tetratelabs/wazero/api", "EncodeF64");
37+
pub static WAZERO_API_DECODE_F64: GoImport =
38+
GoImport("github.com/tetratelabs/wazero/api", "DecodeF64");

cmd/gravity/tests/cmd/instructions.stdout

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,37 @@ func (i *InstructionsInstance) U32Roundtrip(
184184
return result2
185185
}
186186

187+
func (i *InstructionsInstance) F32Roundtrip(
188+
ctx context.Context,
189+
val float32,
190+
) float32 {
191+
arg0 := val
192+
result0 := api.EncodeF32(arg0)
193+
raw1, err1 := i.module.ExportedFunction("f32-roundtrip").Call(ctx, uint64(result0))
194+
// The return type doesn't contain an error so we panic if one is encountered
195+
if err1 != nil {
196+
panic(err1)
197+
}
198+
199+
results1 := raw1[0]
200+
result2 := api.DecodeF32(results1)
201+
return result2
202+
}
203+
204+
func (i *InstructionsInstance) F64Roundtrip(
205+
ctx context.Context,
206+
val float64,
207+
) float64 {
208+
arg0 := val
209+
result0 := api.EncodeF64(arg0)
210+
raw1, err1 := i.module.ExportedFunction("f64-roundtrip").Call(ctx, uint64(result0))
211+
// The return type doesn't contain an error so we panic if one is encountered
212+
if err1 != nil {
213+
panic(err1)
214+
}
215+
216+
results1 := raw1[0]
217+
result2 := api.DecodeF64(results1)
218+
return result2
219+
}
220+

examples/instructions/instructions_test.go

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package instructions
22

33
import (
4+
"fmt"
45
"iter"
56
"math"
7+
"math/rand/v2"
68
"testing"
79
)
810

9-
func inclusive[Num interface { ~int8 | ~uint8 | ~int16 | ~uint16 }](start Num, end Num) iter.Seq[Num] {
11+
func inclusive[Num interface {
12+
~int8 | ~uint8 | ~int16 | ~uint16
13+
}](start Num, end Num) iter.Seq[Num] {
1014
return func(yield func(v Num) bool) {
1115
var next Num = start
1216
for {
@@ -21,7 +25,7 @@ func inclusive[Num interface { ~int8 | ~uint8 | ~int16 | ~uint16 }](start Num, e
2125
}
2226
}
2327
}
24-
func inclusiveStep[Num interface { ~int32 | ~uint32 }](start Num, end Num, step Num) iter.Seq[Num] {
28+
func inclusiveStep[Num interface{ ~int32 | ~uint32 }](start Num, end Num, step Num) iter.Seq[Num] {
2529
return func(yield func(v Num) bool) {
2630
var next Num = start
2731
for {
@@ -32,7 +36,7 @@ func inclusiveStep[Num interface { ~int32 | ~uint32 }](start Num, end Num, step
3236
return
3337
}
3438

35-
if end - step > next {
39+
if end-step > next {
3640
next += step
3741
} else {
3842
next = end
@@ -166,3 +170,55 @@ func Test_U32Roundtrip(t *testing.T) {
166170
}
167171
}
168172
}
173+
174+
func Test_F32Roundtrip(t *testing.T) {
175+
fac, err := NewInstructionsFactory(t.Context())
176+
if err != nil {
177+
t.Fatal(err)
178+
}
179+
defer fac.Close(t.Context())
180+
181+
ins, err := fac.Instantiate(t.Context())
182+
if err != nil {
183+
t.Fatal(err)
184+
}
185+
defer ins.Close(t.Context())
186+
187+
// Generate a bunch of random floats and check they all roundtrip correctly.
188+
seed := 123456
189+
rng := rand.New(rand.NewPCG(uint64(seed), uint64(seed)))
190+
for i := range 1000 {
191+
t.Run(fmt.Sprintf("i: %d", i), func(t *testing.T) {
192+
expected := rng.Float32()
193+
if actual := ins.F32Roundtrip(t.Context(), expected); actual != expected {
194+
t.Errorf("expected: %f, but got: %f", expected, actual)
195+
}
196+
})
197+
}
198+
}
199+
200+
func Test_F64Roundtrip(t *testing.T) {
201+
fac, err := NewInstructionsFactory(t.Context())
202+
if err != nil {
203+
t.Fatal(err)
204+
}
205+
defer fac.Close(t.Context())
206+
207+
ins, err := fac.Instantiate(t.Context())
208+
if err != nil {
209+
t.Fatal(err)
210+
}
211+
defer ins.Close(t.Context())
212+
213+
// Generate a bunch of random floats and check they all roundtrip correctly.
214+
seed := 123456
215+
rng := rand.New(rand.NewPCG(uint64(seed), uint64(seed)))
216+
for i := range 1000 {
217+
t.Run(fmt.Sprintf("i: %d", i), func(t *testing.T) {
218+
expected := rng.Float64()
219+
if actual := ins.F64Roundtrip(t.Context(), expected); actual != expected {
220+
t.Errorf("expected: %f, but got: %f", expected, actual)
221+
}
222+
})
223+
}
224+
}

examples/instructions/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,12 @@ impl Guest for InstructionsWorld {
3131
assert!((u32::MIN..=u32::MAX).contains(&val));
3232
val
3333
}
34+
fn f32_roundtrip(val: f32) -> f32 {
35+
assert!((f32::MIN..=f32::MAX).contains(&val));
36+
val
37+
}
38+
fn f64_roundtrip(val: f64) -> f64 {
39+
assert!((f64::MIN..=f64::MAX).contains(&val));
40+
val
41+
}
3442
}

examples/instructions/wit/instructions.wit

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@ world instructions {
1212
export s32-roundtrip: func(val: s32) -> s32;
1313

1414
export u32-roundtrip: func(val: u32) -> u32;
15+
16+
export f32-roundtrip: func(val: f32) -> f32;
17+
18+
export f64-roundtrip: func(val: f64) -> f64;
1519
}

0 commit comments

Comments
 (0)