Skip to content

Commit

Permalink
feat: translate Wasm memory.copy op
Browse files Browse the repository at this point in the history
  • Loading branch information
greenhat committed Jan 26, 2024
1 parent ab28b4a commit 873af55
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 11 deletions.
38 changes: 27 additions & 11 deletions frontend-wasm/src/code_translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@ pub fn translate_operator(
// Return total Miden memory size
state.push1(builder.ins().i32(mem_total_pages(), span));
}
/******************************* Bulk memory operations *********************************/
Operator::MemoryCopy { dst_mem, src_mem } => {
// See semantics at https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md#memorycopy-instruction
if *src_mem == 0 && src_mem == dst_mem {
let len = state.pop1();
let src_i32 = state.pop1();
let dst_i32 = state.pop1();
let dst = prepare_addr(dst_i32, &U8, None, builder, span);
let src = prepare_addr(src_i32, &U8, None, builder, span);
builder.ins().memcpy(src, dst, len, span);
} else {
unsupported_diag!(diagnostics, "MemoryCopy: only single memory is supported");
}
}
/******************************* Load instructions ***********************************/
Operator::I32Load8U { memarg } => {
translate_load_zext(U8, I32, memarg, state, builder, span)
Expand Down Expand Up @@ -534,7 +548,7 @@ fn translate_load(
span: SourceSpan,
) {
let addr_int = state.pop1();
let addr = prepare_addr(addr_int, &ptr_ty, memarg, builder, span);
let addr = prepare_addr(addr_int, &ptr_ty, Some(memarg), builder, span);
state.push1(builder.ins().load(addr, span));
}

Expand All @@ -547,7 +561,7 @@ fn translate_load_sext(
span: SourceSpan,
) {
let addr_int = state.pop1();
let addr = prepare_addr(addr_int, &ptr_ty, memarg, builder, span);
let addr = prepare_addr(addr_int, &ptr_ty, Some(memarg), builder, span);
let val = builder.ins().load(addr, span);
let sext_val = builder.ins().sext(val, sext_ty, span);
state.push1(sext_val);
Expand All @@ -563,7 +577,7 @@ fn translate_load_zext(
) {
assert!(ptr_ty.is_unsigned_integer());
let addr_int = state.pop1();
let addr = prepare_addr(addr_int, &ptr_ty, memarg, builder, span);
let addr = prepare_addr(addr_int, &ptr_ty, Some(memarg), builder, span);
let val = builder.ins().load(addr, span);
let sext_val = builder.ins().zext(val, zext_ty, span);
state.push1(sext_val);
Expand All @@ -583,14 +597,14 @@ fn translate_store(
} else {
val
};
let addr = prepare_addr(addr_int, &ptr_ty, memarg, builder, span);
let addr = prepare_addr(addr_int, &ptr_ty, Some(memarg), builder, span);
builder.ins().store(addr, arg, span);
}

fn prepare_addr(
addr_int: Value,
ptr_ty: &Type,
memarg: &MemArg,
memarg: Option<&MemArg>,
builder: &mut FunctionBuilderExt,
span: SourceSpan,
) -> Value {
Expand All @@ -600,12 +614,14 @@ fn prepare_addr(
} else {
builder.ins().cast(addr_int, U32, span)
};
let full_addr_int = if memarg.offset != 0 {
builder
.ins()
.add_imm_checked(addr_u32, Immediate::U32(memarg.offset as u32), span)
} else {
addr_u32
let mut full_addr_int = addr_u32;
if let Some(memarg) = memarg {
if memarg.offset != 0 {
full_addr_int =
builder
.ins()
.add_imm_checked(addr_u32, Immediate::U32(memarg.offset as u32), span);
}
};
builder
.ins()
Expand Down
22 changes: 22 additions & 0 deletions frontend-wasm/src/code_translator/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,28 @@ fn memory_size() {
)
}

#[test]
fn memory_copy() {
check_op(
r#"
i32.const 20 ;; dst
i32.const 10 ;; src
i32.const 1 ;; len
memory.copy
"#,
expect![[r#"
v0 = const.i32 20 : i32;
v1 = const.i32 10 : i32;
v2 = const.i32 1 : i32;
v3 = cast v0 : u32;
v4 = inttoptr v3 : *mut u8;
v5 = cast v1 : u32;
v6 = inttoptr v5 : *mut u8;
memcpy v6, v4, v2;
"#]],
)
}

#[test]
fn i32_load8_u() {
check_op(
Expand Down

0 comments on commit 873af55

Please sign in to comment.