Add more store instructions

This commit is contained in:
Jef
2019-03-06 14:03:40 +01:00
parent e99417fb1c
commit a4e878da75
6 changed files with 335 additions and 111 deletions

View File

@@ -47,7 +47,7 @@ impl From<SignlessType> for Option<GPRType> {
} }
impl GPR { impl GPR {
fn type_(&self) -> GPRType { fn type_(self) -> GPRType {
match self { match self {
GPR::Rq(_) => GPRType::Rq, GPR::Rq(_) => GPRType::Rq,
GPR::Rx(_) => GPRType::Rx, GPR::Rx(_) => GPRType::Rx,
@@ -73,8 +73,8 @@ pub fn arg_locs(types: impl IntoIterator<Item = SignlessType>) -> Vec<CCLoc> {
let types = types.into_iter(); let types = types.into_iter();
let mut out = Vec::with_capacity(types.size_hint().0); let mut out = Vec::with_capacity(types.size_hint().0);
// TODO: VmCtx is in the first register // TODO: VmCtx is in the first register
let mut int_gpr_iter = INTEGER_ARGS_IN_GPRS.into_iter(); let mut int_gpr_iter = INTEGER_ARGS_IN_GPRS.iter();
let mut float_gpr_iter = FLOAT_ARGS_IN_GPRS.into_iter(); let mut float_gpr_iter = FLOAT_ARGS_IN_GPRS.iter();
let mut stack_idx = 0; let mut stack_idx = 0;
for ty in types { for ty in types {
@@ -102,8 +102,8 @@ pub fn ret_locs(types: impl IntoIterator<Item = SignlessType>) -> Vec<CCLoc> {
let types = types.into_iter(); let types = types.into_iter();
let mut out = Vec::with_capacity(types.size_hint().0); let mut out = Vec::with_capacity(types.size_hint().0);
// TODO: VmCtx is in the first register // TODO: VmCtx is in the first register
let mut int_gpr_iter = INTEGER_RETURN_GPRS.into_iter(); let mut int_gpr_iter = INTEGER_RETURN_GPRS.iter();
let mut float_gpr_iter = FLOAT_RETURN_GPRS.into_iter(); let mut float_gpr_iter = FLOAT_RETURN_GPRS.iter();
for ty in types { for ty in types {
match ty { match ty {
@@ -1224,40 +1224,43 @@ macro_rules! binop {
}; };
($name:ident, $instr:ident, $const_fallback:expr, $reg_ty:ident, $reg_fn:ident, $ty:expr, $imm_fn:ident, $direct_imm:expr, $map_op:expr) => { ($name:ident, $instr:ident, $const_fallback:expr, $reg_ty:ident, $reg_fn:ident, $ty:expr, $imm_fn:ident, $direct_imm:expr, $map_op:expr) => {
pub fn $name(&mut self) { pub fn $name(&mut self) {
let op0 = self.pop(); let right = self.pop();
let op1 = self.pop(); let left = self.pop();
if let Some(i1) = op1.$imm_fn() { if let Some(i1) = left.$imm_fn() {
if let Some(i0) = op0.$imm_fn() { if let Some(i0) = right.$imm_fn() {
self.block_state.stack.push(ValueLocation::Immediate($const_fallback(i1, i0).into())); self.block_state.stack.push(ValueLocation::Immediate($const_fallback(i1, i0).into()));
return; return;
} }
} }
let (op1, op0) = $map_op(op1, op0); let (left, mut right) = $map_op(left, right);
let op1 = self.into_temp_reg($ty, op1); let left = self.into_temp_reg($ty, left);
match op0 { match right {
ValueLocation::Reg(reg) => { ValueLocation::Reg(_) => {
// This handles the case where we (for example) have a float in an `Rq` reg
let right_reg = self.into_reg($ty, right);
right = ValueLocation::Reg(right_reg);
dynasm!(self.asm dynasm!(self.asm
; $instr $reg_ty(op1.$reg_fn().unwrap()), $reg_ty(reg.$reg_fn().unwrap()) ; $instr $reg_ty(left.$reg_fn().unwrap()), $reg_ty(right_reg.$reg_fn().unwrap())
); );
} }
ValueLocation::Stack(offset) => { ValueLocation::Stack(offset) => {
let offset = self.adjusted_offset(offset); let offset = self.adjusted_offset(offset);
dynasm!(self.asm dynasm!(self.asm
; $instr $reg_ty(op1.$reg_fn().unwrap()), [rsp + offset] ; $instr $reg_ty(left.$reg_fn().unwrap()), [rsp + offset]
); );
} }
ValueLocation::Immediate(i) => { ValueLocation::Immediate(i) => {
if let Some(i) = i.as_int().and_then(|i| i.try_into()) { if let Some(i) = i.as_int().and_then(|i| i.try_into()) {
$direct_imm(self, op1, i); $direct_imm(self, left, i);
} else { } else {
let scratch = self.block_state.regs.take($ty); let scratch = self.block_state.regs.take($ty);
self.immediate_to_reg(scratch, i); self.immediate_to_reg(scratch, i);
dynasm!(self.asm dynasm!(self.asm
; $instr $reg_ty(op1.$reg_fn().unwrap()), $reg_ty(scratch.$reg_fn().unwrap()) ; $instr $reg_ty(left.$reg_fn().unwrap()), $reg_ty(scratch.$reg_fn().unwrap())
); );
self.block_state.regs.release(scratch); self.block_state.regs.release(scratch);
@@ -1265,15 +1268,15 @@ macro_rules! binop {
} }
} }
self.free_value(op0); self.free_value(right);
self.push(ValueLocation::Reg(op1)); self.push(ValueLocation::Reg(left));
} }
} }
} }
macro_rules! load { macro_rules! load {
($name:ident, $reg_ty:ident, $instruction_name:expr, $out_ty:expr) => { (@inner $name:ident, $reg_ty:ident, $emit_fn:expr) => {
pub fn $name(&mut self, offset: u32) -> Result<(), Error> { pub fn $name(&mut self, ty: impl Into<GPRType>, offset: u32) -> Result<(), Error> {
fn load_to_reg<_M: ModuleContext>( fn load_to_reg<_M: ModuleContext>(
ctx: &mut Context<_M>, ctx: &mut Context<_M>,
dst: GPR, dst: GPR,
@@ -1284,18 +1287,7 @@ macro_rules! load {
dynasm!(ctx.asm dynasm!(ctx.asm
; mov Rq(mem_ptr_reg.rq().unwrap()), [Rq(VMCTX) + vmctx_mem_ptr_offset] ; mov Rq(mem_ptr_reg.rq().unwrap()), [Rq(VMCTX) + vmctx_mem_ptr_offset]
); );
match runtime_offset { $emit_fn(ctx, dst, mem_ptr_reg, runtime_offset, offset);
Ok(imm) => {
dynasm!(ctx.asm
; mov $reg_ty(dst.rq().unwrap()), [Rq(mem_ptr_reg.rq().unwrap()) + offset + imm]
);
}
Err(offset_reg) => {
dynasm!(ctx.asm
; mov $reg_ty(dst.rq().unwrap()), [Rq(mem_ptr_reg.rq().unwrap()) + Rq(offset_reg.rq().unwrap()) + offset]
);
}
}
ctx.block_state.regs.release(mem_ptr_reg); ctx.block_state.regs.release(mem_ptr_reg);
} }
@@ -1303,7 +1295,7 @@ macro_rules! load {
let base = self.pop(); let base = self.pop();
let temp = self.block_state.regs.take($out_ty); let temp = self.block_state.regs.take(ty);
match base { match base {
ValueLocation::Immediate(i) => { ValueLocation::Immediate(i) => {
@@ -1320,11 +1312,61 @@ macro_rules! load {
Ok(()) Ok(())
} }
} };
($name:ident, $reg_ty:ident, NONE) => {
load!(@inner
$name,
$reg_ty,
|ctx: &mut Context<_>, dst: GPR, mem_ptr_reg: GPR, runtime_offset: Result<i32, GPR>, offset: i32| {
match runtime_offset {
Ok(imm) => {
dynasm!(ctx.asm
; mov $reg_ty(dst.rq().unwrap()), [Rq(mem_ptr_reg.rq().unwrap()) + offset + imm]
);
}
Err(offset_reg) => {
dynasm!(ctx.asm
; mov $reg_ty(dst.rq().unwrap()), [Rq(mem_ptr_reg.rq().unwrap()) + Rq(offset_reg.rq().unwrap()) + offset]
);
}
}
}
);
};
($name:ident, $reg_ty:ident, $xmm_instr:ident) => {
load!(@inner
$name,
$reg_ty,
|ctx: &mut Context<_>, dst: GPR, mem_ptr_reg: GPR, runtime_offset: Result<i32, GPR>, offset: i32| {
match (dst, runtime_offset) {
(GPR::Rq(r), Ok(imm)) => {
dynasm!(ctx.asm
; mov $reg_ty(r), [Rq(mem_ptr_reg.rq().unwrap()) + offset + imm]
);
}
(GPR::Rx(r), Ok(imm)) => {
dynasm!(ctx.asm
; $xmm_instr Rx(r), [Rq(mem_ptr_reg.rq().unwrap()) + offset + imm]
);
}
(GPR::Rq(r), Err(offset_reg)) => {
dynasm!(ctx.asm
; mov $reg_ty(r), [Rq(mem_ptr_reg.rq().unwrap()) + Rq(offset_reg.rq().unwrap()) + offset]
);
}
(GPR::Rx(r), Err(offset_reg)) => {
dynasm!(ctx.asm
; $xmm_instr Rx(r), [Rq(mem_ptr_reg.rq().unwrap()) + Rq(offset_reg.rq().unwrap()) + offset]
);
}
}
}
);
};
} }
macro_rules! store { macro_rules! store {
($name:ident, $reg_ty:ident, $size:ident, $instruction_name:expr, $in_ty:expr) => { (@inner $name:ident, $int_reg_ty:ident, $match_offset:expr, $size:ident) => {
pub fn $name(&mut self, offset: u32) -> Result<(), Error> { pub fn $name(&mut self, offset: u32) -> Result<(), Error> {
fn store_from_reg<_M: ModuleContext>( fn store_from_reg<_M: ModuleContext>(
ctx: &mut Context<_M>, ctx: &mut Context<_M>,
@@ -1332,23 +1374,14 @@ macro_rules! store {
(offset, runtime_offset): (i32, Result<i32, GPR>) (offset, runtime_offset): (i32, Result<i32, GPR>)
) { ) {
let vmctx_mem_ptr_offset = ctx.module_context.offset_of_memory_ptr() as i32; let vmctx_mem_ptr_offset = ctx.module_context.offset_of_memory_ptr() as i32;
let mem_ptr_reg = ctx.block_state.regs.take(I64); let mem_ptr_reg = ctx.block_state.regs.take(GPRType::Rq);
dynasm!(ctx.asm dynasm!(ctx.asm
; mov Rq(mem_ptr_reg.rq().unwrap()), [Rq(VMCTX) + vmctx_mem_ptr_offset] ; mov Rq(mem_ptr_reg.rq().unwrap()), [Rq(VMCTX) + vmctx_mem_ptr_offset]
); );
match runtime_offset { let src = $match_offset(ctx, mem_ptr_reg, runtime_offset, offset, src);
Ok(imm) => {
dynasm!(ctx.asm
; mov [Rq(mem_ptr_reg.rq().unwrap()) + offset + imm], $reg_ty(src.rq().unwrap())
);
}
Err(offset_reg) => {
dynasm!(ctx.asm
; mov [Rq(mem_ptr_reg.rq().unwrap()) + Rq(offset_reg.rq().unwrap()) + offset], $reg_ty(src.rq().unwrap())
);
}
}
ctx.block_state.regs.release(mem_ptr_reg); ctx.block_state.regs.release(mem_ptr_reg);
ctx.block_state.regs.release(src);
} }
assert!(offset <= i32::max_value() as u32); assert!(offset <= i32::max_value() as u32);
@@ -1356,9 +1389,7 @@ macro_rules! store {
let src = self.pop(); let src = self.pop();
let base = self.pop(); let base = self.pop();
let src_reg = self.into_reg($in_ty, src); let src_reg = self.into_reg(None, src);
// TODO
debug_assert!(stringify!($reg_ty) == "Rq" || stringify!($reg_ty) == "Rd");
match base { match base {
ValueLocation::Immediate(i) => { ValueLocation::Immediate(i) => {
@@ -1371,11 +1402,67 @@ macro_rules! store {
} }
} }
self.block_state.regs.release(src_reg);
Ok(()) Ok(())
} }
} };
($name:ident, $int_reg_ty:ident, NONE, $size:ident) => {
store!(@inner
$name,
$int_reg_ty,
|ctx: &mut Context<_>, mem_ptr_reg: GPR, runtime_offset: Result<i32, GPR>, offset: i32, src| {
let src_reg = ctx.into_temp_reg(GPRType::Rq, ValueLocation::Reg(src));
match runtime_offset {
Ok(imm) => {
dynasm!(ctx.asm
; mov [Rq(mem_ptr_reg.rq().unwrap()) + offset + imm], $int_reg_ty(src_reg.rq().unwrap())
);
}
Err(offset_reg) => {
dynasm!(ctx.asm
; mov [Rq(mem_ptr_reg.rq().unwrap()) + Rq(offset_reg.rq().unwrap()) + offset], $int_reg_ty(src_reg.rq().unwrap())
);
}
}
src_reg
},
$size
);
};
($name:ident, $int_reg_ty:ident, $xmm_instr:ident, $size:ident) => {
store!(@inner
$name,
$int_reg_ty,
|ctx: &mut Context<_>, mem_ptr_reg: GPR, runtime_offset: Result<i32, GPR>, offset: i32, src| {
match (runtime_offset, src) {
(Ok(imm), GPR::Rq(r)) => {
dynasm!(ctx.asm
; mov [Rq(mem_ptr_reg.rq().unwrap()) + offset + imm], $int_reg_ty(r)
);
}
(Ok(imm), GPR::Rx(r)) => {
dynasm!(ctx.asm
; $xmm_instr [Rq(mem_ptr_reg.rq().unwrap()) + offset + imm], Rx(r)
);
}
(Err(offset_reg), GPR::Rq(r)) => {
dynasm!(ctx.asm
; mov [Rq(mem_ptr_reg.rq().unwrap()) + Rq(offset_reg.rq().unwrap()) + offset], $int_reg_ty(r)
);
}
(Err(offset_reg), GPR::Rx(r)) => {
dynasm!(ctx.asm
; $xmm_instr [Rq(mem_ptr_reg.rq().unwrap()) + Rq(offset_reg.rq().unwrap()) + offset], Rx(r)
);
}
}
src
},
$size
);
};
} }
trait TryInto<O> { trait TryInto<O> {
@@ -1442,6 +1529,21 @@ impl<M: ModuleContext> Context<'_, M> {
(self.block_state.depth.0 as i32 + offset) * WORD_SIZE as i32 (self.block_state.depth.0 as i32 + offset) * WORD_SIZE as i32
} }
fn zero_reg(&mut self, reg: GPR) {
match reg {
GPR::Rq(r) => {
dynasm!(self.asm
; xor Rq(r), Rq(r)
);
}
GPR::Rx(r) => {
dynasm!(self.asm
; pxor Rx(r), Rx(r)
);
}
}
}
cmp_i32!(i32_eq, sete, sete, |a, b| a == b); cmp_i32!(i32_eq, sete, sete, |a, b| a == b);
cmp_i32!(i32_neq, setne, setne, |a, b| a != b); cmp_i32!(i32_neq, setne, setne, |a, b| a != b);
// `dynasm-rs` inexplicably doesn't support setb but `setnae` (and `setc`) are synonymous // `dynasm-rs` inexplicably doesn't support setb but `setnae` (and `setc`) are synonymous
@@ -1888,10 +1990,15 @@ impl<M: ModuleContext> Context<'_, M> {
self.block_state.depth = cc.stack_depth; self.block_state.depth = cc.stack_depth;
} }
load!(i32_load, Rd, "i32.load", I32); load!(load8, Rb, NONE);
load!(i64_load, Rq, "i64.load", I64); load!(load16, Rw, NONE);
store!(i32_store, Rd, DWORD, "i32.store", I32); load!(load32, Rd, movd);
store!(i64_store, Rq, QWORD, "i64.store", I64); load!(load64, Rq, movq);
store!(store8, Rb, NONE, DWORD);
store!(store16, Rw, NONE, QWORD);
store!(store32, Rd, movd, DWORD);
store!(store64, Rq, movq, QWORD);
fn push_physical(&mut self, value: ValueLocation) -> ValueLocation { fn push_physical(&mut self, value: ValueLocation) -> ValueLocation {
self.block_state.depth.reserve(1); self.block_state.depth.reserve(1);
@@ -2166,11 +2273,7 @@ impl<M: ModuleContext> Context<'_, M> {
}; };
self.free_value(quotient); self.free_value(quotient);
let should_save_rax = if self.block_state.regs.is_free(RAX) { let should_save_rax = !self.block_state.regs.is_free(RAX);
false
} else {
true
};
if let ValueLocation::Reg(r) = quotient { if let ValueLocation::Reg(r) = quotient {
self.block_state.regs.mark_used(r); self.block_state.regs.mark_used(r);
@@ -2874,4 +2977,3 @@ impl<M: ModuleContext> Context<'_, M> {
label label
} }
} }

View File

@@ -113,13 +113,7 @@ where
}, },
); );
loop { while let Some(op) = body.next() {
let op = if let Some(op) = body.next() {
op
} else {
break;
};
if let Some(Operator::Label(label)) = body.peek() { if let Some(Operator::Label(label)) = body.peek() {
let block = blocks let block = blocks
.get_mut(&BrTarget::Label(label.clone())) .get_mut(&BrTarget::Label(label.clone()))
@@ -313,19 +307,16 @@ where
use itertools::Itertools; use itertools::Itertools;
let (def, params) = { let (def, params) = {
let def = blocks.get(&default).unwrap(); let def = &blocks[&default];
( (
if def.is_next { if def.is_next { None } else { Some(def.label) },
None def.params,
} else {
Some(def.label)
},
def.params.clone()
) )
}; };
let target_labels = targets.iter() let target_labels = targets
.map(|target| blocks.get(target).unwrap().label) .iter()
.map(|target| blocks[target].label)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
ctx.br_table(target_labels, def, |ctx| { ctx.br_table(target_labels, def, |ctx| {
@@ -438,10 +429,25 @@ where
Operator::Le(SF64) => ctx.f64_le(), Operator::Le(SF64) => ctx.f64_le(),
Operator::Drop(range) => ctx.drop(range), Operator::Drop(range) => ctx.drop(range),
Operator::Const(val) => ctx.const_(val), Operator::Const(val) => ctx.const_(val),
Operator::Load { ty: I32, memarg } => ctx.i32_load(memarg.offset)?, Operator::Load8 { ty: _, memarg } => ctx.load8(GPRType::Rq, memarg.offset)?,
Operator::Load { ty: I64, memarg } => ctx.i64_load(memarg.offset)?, Operator::Load16 { ty: _, memarg } => ctx.load16(GPRType::Rq, memarg.offset)?,
Operator::Store { ty: I32, memarg } => ctx.i32_store(memarg.offset)?, Operator::Load { ty: ty @ I32, memarg } | Operator::Load { ty: ty @ F32, memarg } => ctx.load32(ty, memarg.offset)?,
Operator::Store { ty: I64, memarg } => ctx.i64_store(memarg.offset)?, Operator::Load { ty: ty @ I64, memarg } | Operator::Load { ty: ty @ F64, memarg } => ctx.load64(ty, memarg.offset)?,
Operator::Store8 { ty: _, memarg } => {
ctx.store8(memarg.offset)?
}
Operator::Store16 { ty: _, memarg } => {
ctx.store16(memarg.offset)?
}
Operator::Store32 { memarg } => {
ctx.store32(memarg.offset)?
}
Operator::Store { ty: I32, memarg } | Operator::Store { ty: F32, memarg } => {
ctx.store32(memarg.offset)?
}
Operator::Store { ty: I64, memarg } | Operator::Store { ty: F64, memarg } => {
ctx.store64(memarg.offset)?
}
Operator::Select => { Operator::Select => {
ctx.select(); ctx.select();
} }

View File

@@ -5,7 +5,7 @@
never_type, never_type,
alloc_layout_extra, alloc_layout_extra,
try_from, try_from,
try_trait, try_trait
)] )]
#![plugin(dynasm)] #![plugin(dynasm)]

View File

@@ -657,7 +657,7 @@ where
} }
write!(f, "], {}", default) write!(f, "], {}", default)
}, }
Operator::Call { function_index } => write!(f, "call {}", function_index), Operator::Call { function_index } => write!(f, "call {}", function_index),
Operator::CallIndirect { .. } => write!(f, "call_indirect"), Operator::CallIndirect { .. } => write!(f, "call_indirect"),
Operator::Drop(range) => { Operator::Drop(range) => {
@@ -803,9 +803,8 @@ impl ControlFrame {
} }
fn mark_branched_to(&mut self) { fn mark_branched_to(&mut self) {
match &mut self.kind { if let ControlFrameKind::Block { needs_end_label } = &mut self.kind {
ControlFrameKind::Block { needs_end_label } => *needs_end_label = true, *needs_end_label = true
_ => {}
} }
} }
@@ -1318,10 +1317,7 @@ where
} }
if let Some(consts) = self.consts_to_emit.take() { if let Some(consts) = self.consts_to_emit.take() {
return Some(Ok(consts return Some(Ok(consts.into_iter().map(Operator::Const).collect()));
.into_iter()
.map(|value| Operator::Const(value))
.collect()));
} }
if self.unreachable { if self.unreachable {
@@ -1564,7 +1560,6 @@ where
.map(Operator::Drop) .map(Operator::Drop)
.into_iter() .into_iter()
.chain(None) .chain(None)
.into_iter()
.chain(None) .chain(None)
}) })
} }
@@ -1617,7 +1612,7 @@ where
Err(e) => return Some(Err(e)), Err(e) => return Some(Err(e)),
}; };
let targets = entries let targets = entries
.into_iter() .iter()
.map(|depth| { .map(|depth| {
let block = self.nth_block_mut(*depth as _); let block = self.nth_block_mut(*depth as _);
block.mark_branched_to(); block.mark_branched_to();

View File

@@ -1202,19 +1202,144 @@ fn br_table() {
translated.disassemble(); translated.disassemble();
println!("as-block-first"); println!("as-block-first");
assert_eq!( assert_eq!(translated.execute_func::<_, ()>(0, ()), Ok(()),);
translated.execute_func::<_, ()>(0, ()),
Ok(()),
);
println!("as-block-mid"); println!("as-block-mid");
assert_eq!( assert_eq!(translated.execute_func::<_, ()>(1, ()), Ok(()),);
translated.execute_func::<_, ()>(1, ()),
Ok(()),
);
println!("as-block-last"); println!("as-block-last");
assert_eq!(translated.execute_func::<_, ()>(2, ()), Ok(()),);
}
#[test]
fn f32_storage() {
const CODE: &str = r#"
(module
(memory (data "\00\00\a0\7f"))
(func (result f32)
(f32.load (i32.const 0))
)
(func (result i32)
(i32.load (i32.const 0))
)
(func
(f32.store (i32.const 0) (f32.const nan:0x200000))
)
(func
(i32.store (i32.const 0) (i32.const 0x7fa00000))
)
(func
(i32.store (i32.const 0) (i32.const 0))
)
)
"#;
const EXPECTED: u32 = 0x7fa00000;
let translated = translate_wat(CODE);
translated.disassemble();
// TODO: We don't support the data section with Lightbeam's test runtime
assert!(translated.execute_func::<(), ()>(2, ()).is_ok());
assert_eq!(translated.execute_func::<(), u32>(1, ()), Ok(EXPECTED));
assert_eq!( assert_eq!(
translated.execute_func::<_, ()>(2, ()), translated
Ok(()), .execute_func::<(), f32>(0, ())
.map(|f| f.to_bits()),
Ok(EXPECTED)
);
assert!(translated.execute_func::<(), ()>(4, ()).is_ok());
assert_eq!(translated.execute_func::<(), u32>(1, ()), Ok(0));
assert_eq!(
translated
.execute_func::<(), f32>(0, ())
.map(|f| f.to_bits()),
Ok(0)
);
assert!(translated.execute_func::<(), ()>(2, ()).is_ok());
assert_eq!(translated.execute_func::<(), u32>(1, ()), Ok(EXPECTED));
assert_eq!(
translated
.execute_func::<(), f32>(0, ())
.map(|f| f.to_bits()),
Ok(EXPECTED)
);
assert!(translated.execute_func::<(), ()>(4, ()).is_ok());
assert_eq!(translated.execute_func::<(), u32>(1, ()), Ok(0));
assert_eq!(
translated
.execute_func::<(), f32>(0, ())
.map(|f| f.to_bits()),
Ok(0)
);
assert!(translated.execute_func::<(), ()>(3, ()).is_ok());
assert_eq!(translated.execute_func::<(), u32>(1, ()), Ok(EXPECTED));
assert_eq!(
translated
.execute_func::<(), f32>(0, ())
.map(|f| f.to_bits()),
Ok(EXPECTED)
);
}
#[test]
fn f64_storage() {
const CODE: &str = r#"
(module
(memory (data "\00\00\00\00\00\00\f4\7f"))
(func (export "f64.load") (result f64) (f64.load (i32.const 0)))
(func (export "i64.load") (result i64) (i64.load (i32.const 0)))
(func (export "f64.store") (f64.store (i32.const 0) (f64.const nan:0x4000000000000)))
(func (export "i64.store") (i64.store (i32.const 0) (i64.const 0x7ff4000000000000)))
(func (export "reset") (i64.store (i32.const 0) (i64.const 0)))
)
"#;
const EXPECTED: u64 = 0x7ff4000000000000;
let translated = translate_wat(CODE);
translated.disassemble();
// TODO: We don't support the data section with Lightbeam's test runtime
assert!(translated.execute_func::<(), ()>(2, ()).is_ok());
assert_eq!(translated.execute_func::<(), u64>(1, ()), Ok(EXPECTED));
assert_eq!(
translated
.execute_func::<(), f64>(0, ())
.map(|f| f.to_bits()),
Ok(EXPECTED)
);
assert!(translated.execute_func::<(), ()>(4, ()).is_ok());
assert_eq!(translated.execute_func::<(), u64>(1, ()), Ok(0));
assert_eq!(
translated
.execute_func::<(), f64>(0, ())
.map(|f| f.to_bits()),
Ok(0)
);
assert!(translated.execute_func::<(), ()>(2, ()).is_ok());
assert_eq!(translated.execute_func::<(), u64>(1, ()), Ok(EXPECTED));
assert_eq!(
translated
.execute_func::<(), f64>(0, ())
.map(|f| f.to_bits()),
Ok(EXPECTED)
);
assert!(translated.execute_func::<(), ()>(4, ()).is_ok());
assert_eq!(translated.execute_func::<(), u64>(1, ()), Ok(0));
assert_eq!(
translated
.execute_func::<(), f64>(0, ())
.map(|f| f.to_bits()),
Ok(0)
);
assert!(translated.execute_func::<(), ()>(3, ()).is_ok());
assert_eq!(translated.execute_func::<(), u64>(1, ()), Ok(EXPECTED));
assert_eq!(
translated
.execute_func::<(), f64>(0, ())
.map(|f| f.to_bits()),
Ok(EXPECTED)
); );
} }

View File

@@ -116,11 +116,7 @@ pub fn code(
for (idx, body) in code.into_iter().enumerate() { for (idx, body) in code.into_iter().enumerate() {
let body = body?; let body = body?;
function_body::translate_wasm( function_body::translate_wasm(&mut session, idx as u32, &body)?;
&mut session,
idx as u32,
&body,
)?;
} }
Ok(session.into_translated_code_section()?) Ok(session.into_translated_code_section()?)