Skip to content

Commit

Permalink
Merge pull request #2296 from wasmerio/feature/bulk-memory
Browse files Browse the repository at this point in the history
Implement bulk memory instructions
  • Loading branch information
syrusakbary authored May 6, 2021
2 parents b7321a5 + ac1f331 commit 77fa434
Show file tree
Hide file tree
Showing 5 changed files with 320 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C
## **[Unreleased]**

### Added
- [#2296](https://github.com/wasmerio/wasmer/pull/2296) Add support for the bulk memory proposal in compiler Singlepass and compiler LLVM.
- [#2208](https://github.com/wasmerio/wasmer/pull/2208) Add a new CHANGELOG.md specific to our C API to make it easier for users primarily consuming our C API to keep up to date with changes that affect them.
- [#2103](https://github.com/wasmerio/wasmer/pull/2103) Add middleware (incl. metering) in the C API.
- [#2003](https://github.com/wasmerio/wasmer/pull/2003) Wasmer works with musl, and is built, tested and packaged for musl.
Expand Down
82 changes: 82 additions & 0 deletions lib/compiler-llvm/src/translator/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9388,6 +9388,88 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
size.add_attribute(AttributeLoc::Function, self.intrinsics.readonly);
self.state.push1(size.try_as_basic_value().left().unwrap());
}
Operator::MemoryInit { segment, mem } => {
let (dest, src, len) = self.state.pop3()?;
let mem = self
.intrinsics
.i32_ty
.const_int(mem.into(), false)
.as_basic_value_enum();
let segment = self
.intrinsics
.i32_ty
.const_int(segment.into(), false)
.as_basic_value_enum();
self.builder.build_call(
self.intrinsics.memory_init,
&[vmctx.as_basic_value_enum(), mem, segment, dest, src, len],
"",
);
}
Operator::DataDrop { segment } => {
let segment = self
.intrinsics
.i32_ty
.const_int(segment.into(), false)
.as_basic_value_enum();
self.builder.build_call(
self.intrinsics.data_drop,
&[vmctx.as_basic_value_enum(), segment],
"",
);
}
Operator::MemoryCopy { src, dst } => {
// ignored until we support multiple memories
let _dst = dst;
let (memory_copy, src) = if let Some(local_memory_index) = self
.wasm_module
.local_memory_index(MemoryIndex::from_u32(src))
{
(self.intrinsics.memory_copy, local_memory_index.as_u32())
} else {
(self.intrinsics.imported_memory_copy, src)
};

let (dest_pos, src_pos, len) = self.state.pop3()?;
let src_index = self
.intrinsics
.i32_ty
.const_int(src.into(), false)
.as_basic_value_enum();
self.builder.build_call(
memory_copy,
&[
vmctx.as_basic_value_enum(),
src_index,
dest_pos,
src_pos,
len,
],
"",
);
}
Operator::MemoryFill { mem } => {
let (memory_fill, mem) = if let Some(local_memory_index) = self
.wasm_module
.local_memory_index(MemoryIndex::from_u32(mem))
{
(self.intrinsics.memory_fill, local_memory_index.as_u32())
} else {
(self.intrinsics.imported_memory_fill, mem)
};

let (dst, val, len) = self.state.pop3()?;
let mem_index = self
.intrinsics
.i32_ty
.const_int(mem.into(), false)
.as_basic_value_enum();
self.builder.build_call(
memory_fill,
&[vmctx.as_basic_value_enum(), mem_index, dst, val, len],
"",
);
}
/***************************
* Reference types.
* https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md
Expand Down
83 changes: 83 additions & 0 deletions lib/compiler-llvm/src/translator/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,15 @@ pub struct Intrinsics<'ctx> {
pub imported_table_set: FunctionValue<'ctx>,
pub table_grow: FunctionValue<'ctx>,
pub imported_table_grow: FunctionValue<'ctx>,
pub memory_init: FunctionValue<'ctx>,
pub data_drop: FunctionValue<'ctx>,
pub func_ref: FunctionValue<'ctx>,
pub elem_drop: FunctionValue<'ctx>,
pub memory_copy: FunctionValue<'ctx>,
pub imported_memory_copy: FunctionValue<'ctx>,
pub memory_fill: FunctionValue<'ctx>,
pub imported_memory_fill: FunctionValue<'ctx>,

pub throw_trap: FunctionValue<'ctx>,

// VM builtins.
Expand Down Expand Up @@ -594,6 +601,82 @@ impl<'ctx> Intrinsics<'ctx> {
),
None,
),
memory_init: module.add_function(
"wasmer_vm_memory32_init",
void_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
],
false,
),
None,
),
memory_copy: module.add_function(
"wasmer_vm_memory32_copy",
void_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
],
false,
),
None,
),
imported_memory_copy: module.add_function(
"wasmer_vm_imported_memory32_copy",
void_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
],
false,
),
None,
),
memory_fill: module.add_function(
"wasmer_vm_memory32_fill",
void_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
],
false,
),
None,
),
imported_memory_fill: module.add_function(
"wasmer_vm_imported_memory32_fill",
void_ty.fn_type(
&[
ctx_ptr_ty.as_basic_type_enum(),
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
i32_ty_basic,
],
false,
),
None,
),
data_drop: module.add_function(
"wasmer_vm_data_drop",
void_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false),
None,
),
func_ref: module.add_function(
"wasmer_vm_func_ref",
funcref_ty.fn_type(&[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic], false),
Expand Down
154 changes: 154 additions & 0 deletions lib/compiler-singlepass/src/codegen_x64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5679,6 +5679,160 @@ impl<'a> FuncGen<'a> {
self.assembler
.emit_mov(Size::S64, Location::GPR(GPR::RAX), ret);
}
Operator::MemoryInit { segment, mem } => {
let len = self.value_stack.pop().unwrap();
let src = self.value_stack.pop().unwrap();
let dst = self.value_stack.pop().unwrap();
self.machine.release_locations_only_regs(&[len, src, dst]);

self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets
.vmctx_builtin_function(VMBuiltinFunctionIndex::get_memory_init_index())
as i32,
),
Location::GPR(GPR::RAX),
);

// TODO: should this be 3?
self.machine.release_locations_only_osr_state(1);

self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, memory_index, segment_index, dst, src, len]
[
Location::Imm32(mem),
Location::Imm32(segment),
dst,
src,
len,
]
.iter()
.cloned(),
)?;
self.machine
.release_locations_only_stack(&mut self.assembler, &[dst, src, len]);
}
Operator::DataDrop { segment } => {
self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets
.vmctx_builtin_function(VMBuiltinFunctionIndex::get_data_drop_index())
as i32,
),
Location::GPR(GPR::RAX),
);

self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, segment_index]
iter::once(Location::Imm32(segment)),
)?;
}
Operator::MemoryCopy { src, dst } => {
// ignore until we support multiple memories
let _dst = dst;
let len = self.value_stack.pop().unwrap();
let src_pos = self.value_stack.pop().unwrap();
let dst_pos = self.value_stack.pop().unwrap();
self.machine
.release_locations_only_regs(&[len, src_pos, dst_pos]);

let memory_index = MemoryIndex::new(src as usize);
let (memory_copy_index, memory_index) =
if self.module.local_memory_index(memory_index).is_some() {
(
VMBuiltinFunctionIndex::get_memory_copy_index(),
memory_index,
)
} else {
(
VMBuiltinFunctionIndex::get_imported_memory_copy_index(),
memory_index,
)
};

self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets.vmctx_builtin_function(memory_copy_index) as i32,
),
Location::GPR(GPR::RAX),
);

// TODO: should this be 3?
self.machine.release_locations_only_osr_state(1);

self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, memory_index, dst, src, len]
[
Location::Imm32(memory_index.index() as u32),
dst_pos,
src_pos,
len,
]
.iter()
.cloned(),
)?;
self.machine
.release_locations_only_stack(&mut self.assembler, &[dst_pos, src_pos, len]);
}
Operator::MemoryFill { mem } => {
let len = self.value_stack.pop().unwrap();
let val = self.value_stack.pop().unwrap();
let dst = self.value_stack.pop().unwrap();
self.machine.release_locations_only_regs(&[len, val, dst]);

let memory_index = MemoryIndex::new(mem as usize);
let (memory_fill_index, memory_index) =
if self.module.local_memory_index(memory_index).is_some() {
(
VMBuiltinFunctionIndex::get_memory_fill_index(),
memory_index,
)
} else {
(
VMBuiltinFunctionIndex::get_imported_memory_fill_index(),
memory_index,
)
};

self.assembler.emit_mov(
Size::S64,
Location::Memory(
Machine::get_vmctx_reg(),
self.vmoffsets.vmctx_builtin_function(memory_fill_index) as i32,
),
Location::GPR(GPR::RAX),
);

// TODO: should this be 3?
self.machine.release_locations_only_osr_state(1);

self.emit_call_sysv(
|this| {
this.assembler.emit_call_register(GPR::RAX);
},
// [vmctx, memory_index, dst, src, len]
[Location::Imm32(memory_index.index() as u32), dst, val, len]
.iter()
.cloned(),
)?;
self.machine
.release_locations_only_stack(&mut self.assembler, &[dst, val, len]);
}
Operator::MemoryGrow { mem, mem_byte: _ } => {
let memory_index = MemoryIndex::new(mem as usize);
let param_pages = self.value_stack.pop().unwrap();
Expand Down
10 changes: 0 additions & 10 deletions tests/ignores.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,6 @@ cranelift::spec::simd::simd_store32_lane
cranelift::spec::simd::simd_store64_lane
cranelift::spec::simd::simd_store8_lane

# bulk memory
llvm::spec::bulk
llvm::spec::memory_copy
llvm::spec::memory_fill
llvm::spec::memory_init
# new simd
llvm::spec::simd::simd_align
llvm::spec::simd::simd_conversions
Expand Down Expand Up @@ -174,8 +169,3 @@ llvm::spec::simd::simd_store32_lane
llvm::spec::simd::simd_store64_lane
llvm::spec::simd::simd_store8_lane

# bulk memory
singlepass::spec::bulk
singlepass::spec::memory_copy
singlepass::spec::memory_fill
singlepass::spec::memory_init

0 comments on commit 77fa434

Please sign in to comment.