Implement all reference types instructions in compiler-llvm.

Remove spectest ignores for reference types tests on llvm.

Extend llvm ABIs to pass externref and funcref.

Expose all libcalls through the Libcalls enum.

Add support for all libcalls to llvm object_file.rs, even libcalls that we aren't using.

Add missing no_mangle to libcalls.
Change 'memory' to 'memory32' in libcalls in preparation for the memory64 proposal.
Remove 'local' from 'wasmer_local_memory_copy' in libcalls to fit naming convention.
Add mangling of externref and funcref for llvm-debug-dir.
Mark 'wasmer_func_ref' readonly.
This commit is contained in:
Nick Lewycky
2021-03-01 11:53:12 -08:00
parent 148aa41ec8
commit b14afa1342
11 changed files with 595 additions and 107 deletions

View File

@ -9344,6 +9344,192 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> {
size.add_attribute(AttributeLoc::Function, self.intrinsics.readonly);
self.state.push1(size.try_as_basic_value().left().unwrap());
}
/***************************
* Reference types.
* https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md
***************************/
Operator::RefNull { .. } => {
self.state.push1(self.intrinsics.funcref_ty.const_null());
}
Operator::RefIsNull => {
let value = self.state.pop1()?.into_pointer_value();
let is_null = self.builder.build_is_null(value, "");
let is_null = self
.builder
.build_int_z_extend(is_null, self.intrinsics.i32_ty, "");
self.state.push1(is_null);
}
Operator::RefFunc { function_index } => {
let index = self
.intrinsics
.i32_ty
.const_int(function_index.into(), false)
.as_basic_value_enum();
let value = self
.builder
.build_call(self.intrinsics.func_ref, &[self.ctx.basic(), index], "")
.try_as_basic_value()
.left()
.unwrap();
self.state.push1(value);
}
Operator::TableGet { table } => {
let table_index = self
.intrinsics
.i32_ty
.const_int(table.into(), false)
.as_basic_value_enum();
let elem = self.state.pop1()?;
let table_get = if let Some(_) = self
.wasm_module
.local_table_index(TableIndex::from_u32(table))
{
self.intrinsics.table_get
} else {
self.intrinsics.imported_table_get
};
let value = self
.builder
.build_call(table_get, &[self.ctx.basic(), table_index, elem], "")
.try_as_basic_value()
.left()
.unwrap();
self.state.push1(value);
}
Operator::TableSet { table } => {
let table_index = self
.intrinsics
.i32_ty
.const_int(table.into(), false)
.as_basic_value_enum();
let (elem, value) = self.state.pop2()?;
let table_set = if let Some(_) = self
.wasm_module
.local_table_index(TableIndex::from_u32(table))
{
self.intrinsics.table_set
} else {
self.intrinsics.imported_table_set
};
self.builder.build_call(
table_set,
&[self.ctx.basic(), table_index, elem, value],
"",
);
}
Operator::TableCopy {
dst_table,
src_table,
} => {
let (dst, src, len) = self.state.pop3()?;
let dst_table = self
.intrinsics
.i32_ty
.const_int(dst_table as u64, false)
.as_basic_value_enum();
let src_table = self
.intrinsics
.i32_ty
.const_int(src_table as u64, false)
.as_basic_value_enum();
self.builder.build_call(
self.intrinsics.table_copy,
&[self.ctx.basic(), dst_table, src_table, dst, src, len],
"",
);
}
Operator::TableInit { segment, table } => {
let (dst, src, len) = self.state.pop3()?;
let segment = self
.intrinsics
.i32_ty
.const_int(segment as u64, false)
.as_basic_value_enum();
let table = self
.intrinsics
.i32_ty
.const_int(table as u64, false)
.as_basic_value_enum();
self.builder.build_call(
self.intrinsics.table_init,
&[self.ctx.basic(), table, segment, dst, src, len],
"",
);
}
Operator::ElemDrop { segment } => {
let segment = self
.intrinsics
.i32_ty
.const_int(segment as u64, false)
.as_basic_value_enum();
self.builder.build_call(
self.intrinsics.elem_drop,
&[self.ctx.basic(), segment],
"",
);
}
Operator::TableFill { table } => {
let table = self
.intrinsics
.i32_ty
.const_int(table as u64, false)
.as_basic_value_enum();
let (start, elem, len) = self.state.pop3()?;
self.builder.build_call(
self.intrinsics.table_fill,
&[self.ctx.basic(), table, start, elem, len],
"",
);
}
Operator::TableGrow { table } => {
let (elem, delta) = self.state.pop2()?;
let (table_grow, table_index) = if let Some(local_table_index) = self
.wasm_module
.local_table_index(TableIndex::from_u32(table))
{
(self.intrinsics.table_grow, local_table_index.as_u32())
} else {
(self.intrinsics.imported_table_grow, table)
};
let table_index = self
.intrinsics
.i32_ty
.const_int(table_index as u64, false)
.as_basic_value_enum();
let size = self
.builder
.build_call(
table_grow,
&[self.ctx.basic(), elem, delta, table_index],
"",
)
.try_as_basic_value()
.left()
.unwrap();
self.state.push1(size);
}
Operator::TableSize { table } => {
let (table_size, table_index) = if let Some(local_table_index) = self
.wasm_module
.local_table_index(TableIndex::from_u32(table))
{
(self.intrinsics.table_size, local_table_index.as_u32())
} else {
(self.intrinsics.imported_table_size, table)
};
let table_index = self
.intrinsics
.i32_ty
.const_int(table_index as u64, false)
.as_basic_value_enum();
let size = self
.builder
.build_call(table_size, &[self.ctx.basic(), table_index], "")
.try_as_basic_value()
.left()
.unwrap();
self.state.push1(size);
}
_ => {
return Err(CompileError::Codegen(format!(
"Operator {:?} unimplemented",