mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-25 22:51:32 +00:00
Add memory opcodes and test.
This commit is contained in:
90
examples/single_pass_tests/memory.wat
Normal file
90
examples/single_pass_tests/memory.wat
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
(module
|
||||||
|
(memory 1)
|
||||||
|
(func $main (export "main")
|
||||||
|
(call $test_stack_layout)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $test_stack_layout
|
||||||
|
(local $addr i32)
|
||||||
|
(set_local $addr (i32.const 16))
|
||||||
|
|
||||||
|
(i32.store (get_local $addr) (i32.const 10))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 655360))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 11))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 720896))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 12))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 786432))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 13))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 851968))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 14))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 917504))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 15))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 983040))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 16))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1048576))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 17))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1114112))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 18))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1179648))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(i32.const 1)
|
||||||
|
(i32.store (get_local $addr) (i32.const 19))
|
||||||
|
(if (i32.eq (i32.load (i32.const 14)) (i32.const 1245184))
|
||||||
|
(then)
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
(drop)
|
||||||
|
)
|
||||||
|
)
|
@ -596,9 +596,10 @@ impl X64FunctionCode {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_pop_into_ax(
|
fn emit_pop_into_reg(
|
||||||
assembler: &mut Assembler,
|
assembler: &mut Assembler,
|
||||||
value_stack: &mut ValueStack,
|
value_stack: &mut ValueStack,
|
||||||
|
target: Register,
|
||||||
) -> Result<WpType, CodegenError> {
|
) -> Result<WpType, CodegenError> {
|
||||||
let val = value_stack.pop()?;
|
let val = value_stack.pop()?;
|
||||||
match val.location {
|
match val.location {
|
||||||
@ -606,13 +607,13 @@ impl X64FunctionCode {
|
|||||||
let reg = Register::from_scratch_reg(x);
|
let reg = Register::from_scratch_reg(x);
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; mov rax, Rq(reg as u8)
|
; mov Rq(target as u8), Rq(reg as u8)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ValueLocation::Stack => {
|
ValueLocation::Stack => {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; pop rax
|
; pop Rq(target as u8)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -620,10 +621,18 @@ impl X64FunctionCode {
|
|||||||
Ok(val.ty)
|
Ok(val.ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_push_from_ax(
|
fn emit_pop_into_ax(
|
||||||
|
assembler: &mut Assembler,
|
||||||
|
value_stack: &mut ValueStack,
|
||||||
|
) -> Result<WpType, CodegenError> {
|
||||||
|
Self::emit_pop_into_reg(assembler, value_stack, Register::RAX)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_push_from_reg(
|
||||||
assembler: &mut Assembler,
|
assembler: &mut Assembler,
|
||||||
value_stack: &mut ValueStack,
|
value_stack: &mut ValueStack,
|
||||||
ty: WpType,
|
ty: WpType,
|
||||||
|
source: Register,
|
||||||
) -> Result<(), CodegenError> {
|
) -> Result<(), CodegenError> {
|
||||||
let loc = value_stack.push(ty);
|
let loc = value_stack.push(ty);
|
||||||
match loc {
|
match loc {
|
||||||
@ -631,13 +640,13 @@ impl X64FunctionCode {
|
|||||||
let reg = Register::from_scratch_reg(x);
|
let reg = Register::from_scratch_reg(x);
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; mov Rq(reg as u8), rax
|
; mov Rq(reg as u8), Rq(source as u8)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ValueLocation::Stack => {
|
ValueLocation::Stack => {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; push rax
|
; push Rq(source as u8)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -645,6 +654,14 @@ impl X64FunctionCode {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_push_from_ax(
|
||||||
|
assembler: &mut Assembler,
|
||||||
|
value_stack: &mut ValueStack,
|
||||||
|
ty: WpType,
|
||||||
|
) -> Result<(), CodegenError> {
|
||||||
|
Self::emit_push_from_reg(assembler, value_stack, ty, Register::RAX)
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_leave_frame(
|
fn emit_leave_frame(
|
||||||
assembler: &mut Assembler,
|
assembler: &mut Assembler,
|
||||||
frame: &ControlFrame,
|
frame: &ControlFrame,
|
||||||
@ -1041,24 +1058,108 @@ impl X64FunctionCode {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_memory_load<F: FnOnce(&mut Assembler)>(
|
fn emit_memory_load<F: FnOnce(&mut Assembler, Register)>(
|
||||||
assembler: &mut Assembler,
|
assembler: &mut Assembler,
|
||||||
value_stack: &mut ValueStack,
|
value_stack: &mut ValueStack,
|
||||||
f: F,
|
f: F,
|
||||||
out_ty: WpType,
|
out_ty: WpType,
|
||||||
) -> Result<(), CodegenError> {
|
) -> Result<(), CodegenError> {
|
||||||
let ty = Self::emit_pop_into_ax(assembler, value_stack)?;
|
let addr_info = value_stack.pop()?;
|
||||||
if ty != WpType::I32 {
|
let out_loc = value_stack.push(out_ty);
|
||||||
|
|
||||||
|
if addr_info.ty != WpType::I32 {
|
||||||
return Err(CodegenError {
|
return Err(CodegenError {
|
||||||
message: "memory address must be i32",
|
message: "memory address must be i32",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
dynasm!(
|
|
||||||
assembler
|
assert_eq!(out_loc, addr_info.location);
|
||||||
; add rax, r15
|
|
||||||
);
|
match addr_info.location {
|
||||||
f(assembler);
|
ValueLocation::Register(x) => {
|
||||||
Self::emit_push_from_ax(assembler, value_stack, out_ty)?;
|
let reg = Register::from_scratch_reg(x);
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; add Rq(reg as u8), r15
|
||||||
|
);
|
||||||
|
f(assembler, reg);
|
||||||
|
}
|
||||||
|
ValueLocation::Stack => {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; pop rax
|
||||||
|
; add rax, r15
|
||||||
|
);
|
||||||
|
f(assembler, Register::RAX);
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; push rax
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_memory_store<F: FnOnce(&mut Assembler, Register, Register)>(
|
||||||
|
assembler: &mut Assembler,
|
||||||
|
value_stack: &mut ValueStack,
|
||||||
|
f: F,
|
||||||
|
value_ty: WpType,
|
||||||
|
) -> Result<(), CodegenError> {
|
||||||
|
let value_info = value_stack.pop()?;
|
||||||
|
let addr_info = value_stack.pop()?;
|
||||||
|
|
||||||
|
if addr_info.ty != WpType::I32 {
|
||||||
|
return Err(CodegenError {
|
||||||
|
message: "memory address must be i32",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if value_info.ty != value_ty {
|
||||||
|
return Err(CodegenError {
|
||||||
|
message: "value type mismatch",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
match value_info.location {
|
||||||
|
ValueLocation::Register(x) => {
|
||||||
|
let value_reg = Register::from_scratch_reg(x);
|
||||||
|
let addr_reg =
|
||||||
|
Register::from_scratch_reg(addr_info.location.get_register().unwrap()); // must be a register
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; add Rq(addr_reg as u8), r15
|
||||||
|
);
|
||||||
|
f(assembler, addr_reg, value_reg);
|
||||||
|
}
|
||||||
|
ValueLocation::Stack => {
|
||||||
|
match addr_info.location {
|
||||||
|
ValueLocation::Register(x) => {
|
||||||
|
let addr_reg = Register::from_scratch_reg(x);
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; add Rq(addr_reg as u8), r15
|
||||||
|
; pop rax
|
||||||
|
);
|
||||||
|
f(assembler, addr_reg, Register::RAX);
|
||||||
|
}
|
||||||
|
ValueLocation::Stack => {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov [rsp - 8], rcx // red zone
|
||||||
|
; pop rax // value
|
||||||
|
; pop rcx // address
|
||||||
|
; add rcx, r15
|
||||||
|
);
|
||||||
|
f(assembler, Register::RCX, Register::RAX);
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov rcx, [rsp - 24]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1802,10 +1903,10 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
Self::emit_memory_load(
|
Self::emit_memory_load(
|
||||||
assembler,
|
assembler,
|
||||||
&mut self.value_stack,
|
&mut self.value_stack,
|
||||||
|assembler| {
|
|assembler, reg| {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; mov eax, [rax + memarg.offset as i32]
|
; mov Rd(reg as u8), [Rq(reg as u8) + memarg.offset as i32]
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
WpType::I32,
|
WpType::I32,
|
||||||
@ -1815,10 +1916,10 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
Self::emit_memory_load(
|
Self::emit_memory_load(
|
||||||
assembler,
|
assembler,
|
||||||
&mut self.value_stack,
|
&mut self.value_stack,
|
||||||
|assembler| {
|
|assembler, reg| {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; movzx eax, BYTE [rax + memarg.offset as i32]
|
; movzx Rd(reg as u8), BYTE [Rq(reg as u8) + memarg.offset as i32]
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
WpType::I32,
|
WpType::I32,
|
||||||
@ -1828,10 +1929,10 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
Self::emit_memory_load(
|
Self::emit_memory_load(
|
||||||
assembler,
|
assembler,
|
||||||
&mut self.value_stack,
|
&mut self.value_stack,
|
||||||
|assembler| {
|
|assembler, reg| {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; movsx eax, BYTE [rax + memarg.offset as i32]
|
; movsx Rd(reg as u8), BYTE [Rq(reg as u8) + memarg.offset as i32]
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
WpType::I32,
|
WpType::I32,
|
||||||
@ -1841,10 +1942,10 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
Self::emit_memory_load(
|
Self::emit_memory_load(
|
||||||
assembler,
|
assembler,
|
||||||
&mut self.value_stack,
|
&mut self.value_stack,
|
||||||
|assembler| {
|
|assembler, reg| {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; movzx eax, WORD [rax + memarg.offset as i32]
|
; movzx Rd(reg as u8), WORD [Rq(reg as u8) + memarg.offset as i32]
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
WpType::I32,
|
WpType::I32,
|
||||||
@ -1854,10 +1955,49 @@ impl FunctionCodeGenerator for X64FunctionCode {
|
|||||||
Self::emit_memory_load(
|
Self::emit_memory_load(
|
||||||
assembler,
|
assembler,
|
||||||
&mut self.value_stack,
|
&mut self.value_stack,
|
||||||
|assembler| {
|
|assembler, reg| {
|
||||||
dynasm!(
|
dynasm!(
|
||||||
assembler
|
assembler
|
||||||
; movsx eax, WORD [rax + memarg.offset as i32]
|
; movsx Rd(reg as u8), WORD [Rq(reg as u8) + memarg.offset as i32]
|
||||||
|
);
|
||||||
|
},
|
||||||
|
WpType::I32,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Operator::I32Store { memarg } => {
|
||||||
|
Self::emit_memory_store(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, addr_reg, value_reg| {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov [Rq(addr_reg as u8) + memarg.offset as i32], Rd(value_reg as u8)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
WpType::I32,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Operator::I32Store8 { memarg } => {
|
||||||
|
Self::emit_memory_store(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, addr_reg, value_reg| {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov [Rq(addr_reg as u8) + memarg.offset as i32], Rb(value_reg as u8)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
WpType::I32,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Operator::I32Store16 { memarg } => {
|
||||||
|
Self::emit_memory_store(
|
||||||
|
assembler,
|
||||||
|
&mut self.value_stack,
|
||||||
|
|assembler, addr_reg, value_reg| {
|
||||||
|
dynasm!(
|
||||||
|
assembler
|
||||||
|
; mov [Rq(addr_reg as u8) + memarg.offset as i32], Rw(value_reg as u8)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
WpType::I32,
|
WpType::I32,
|
||||||
|
Reference in New Issue
Block a user