cranelift-wasm: Allow more customization of ref type representations
* Allow different Cranelift IR types to be used for different Wasm reference types. * Do not assume that all Wasm reference types are always a Cranelift IR reference type. For example, `funcref`s might not need GC in some implementations, and can therefore be represented with a pointer rather than a reference type.
This commit is contained in:
@@ -1039,12 +1039,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
Operator::F32Le | Operator::F64Le => {
|
Operator::F32Le | Operator::F64Le => {
|
||||||
translate_fcmp(FloatCC::LessThanOrEqual, builder, state)
|
translate_fcmp(FloatCC::LessThanOrEqual, builder, state)
|
||||||
}
|
}
|
||||||
Operator::RefNull { ty: _ } => state.push1(builder.ins().null(environ.reference_type())),
|
Operator::RefNull { ty } => state.push1(environ.translate_ref_null(builder.cursor(), *ty)?),
|
||||||
Operator::RefIsNull { ty: _ } => {
|
Operator::RefIsNull { ty: _ } => {
|
||||||
let arg = state.pop1();
|
let value = state.pop1();
|
||||||
let val = builder.ins().is_null(arg);
|
state.push1(environ.translate_ref_is_null(builder.cursor(), value)?);
|
||||||
let val_int = builder.ins().bint(I32, val);
|
|
||||||
state.push1(val_int);
|
|
||||||
}
|
}
|
||||||
Operator::RefFunc { function_index } => {
|
Operator::RefFunc { function_index } => {
|
||||||
state.push1(environ.translate_ref_func(builder.cursor(), *function_index)?);
|
state.push1(environ.translate_ref_func(builder.cursor(), *function_index)?);
|
||||||
|
|||||||
@@ -197,6 +197,14 @@ impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
|
|||||||
));
|
));
|
||||||
sig
|
sig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reference_type(&self) -> ir::Type {
|
||||||
|
match self.pointer_type() {
|
||||||
|
ir::types::I32 => ir::types::R32,
|
||||||
|
ir::types::I64 => ir::types::R64,
|
||||||
|
_ => panic!("unsupported pointer type"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'dummy_environment> TargetEnvironment for DummyFuncEnvironment<'dummy_environment> {
|
impl<'dummy_environment> TargetEnvironment for DummyFuncEnvironment<'dummy_environment> {
|
||||||
|
|||||||
@@ -133,10 +133,15 @@ pub trait TargetEnvironment {
|
|||||||
self.target_config().pointer_bytes()
|
self.target_config().pointer_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the Cranelift reference type to use for native references.
|
/// Get the Cranelift reference type to use for the given Wasm reference
|
||||||
|
/// type.
|
||||||
///
|
///
|
||||||
/// This returns `R64` for 64-bit architectures and `R32` for 32-bit architectures.
|
/// By default, this returns `R64` for 64-bit architectures and `R32` for
|
||||||
fn reference_type(&self) -> ir::Type {
|
/// 32-bit architectures. If you override this, then you should also
|
||||||
|
/// override `FuncEnvironment::{translate_ref_null, translate_ref_is_null}`
|
||||||
|
/// as well.
|
||||||
|
fn reference_type(&self, ty: WasmType) -> ir::Type {
|
||||||
|
let _ = ty;
|
||||||
match self.pointer_type() {
|
match self.pointer_type() {
|
||||||
ir::types::I32 => ir::types::R32,
|
ir::types::I32 => ir::types::R32,
|
||||||
ir::types::I64 => ir::types::R64,
|
ir::types::I64 => ir::types::R64,
|
||||||
@@ -419,6 +424,37 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||||||
/// Translate a `elem.drop` WebAssembly instruction.
|
/// Translate a `elem.drop` WebAssembly instruction.
|
||||||
fn translate_elem_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>;
|
fn translate_elem_drop(&mut self, pos: FuncCursor, seg_index: u32) -> WasmResult<()>;
|
||||||
|
|
||||||
|
/// Translate a `ref.null T` WebAssembly instruction.
|
||||||
|
///
|
||||||
|
/// By default, translates into a null reference type.
|
||||||
|
///
|
||||||
|
/// Override this if you don't use Cranelift reference types for all Wasm
|
||||||
|
/// reference types (e.g. you use a raw pointer for `funcref`s) or if the
|
||||||
|
/// null sentinel is not a null reference type pointer for your type. If you
|
||||||
|
/// override this method, then you should also override
|
||||||
|
/// `translate_ref_is_null` as well.
|
||||||
|
fn translate_ref_null(&mut self, mut pos: FuncCursor, ty: WasmType) -> WasmResult<ir::Value> {
|
||||||
|
let _ = ty;
|
||||||
|
Ok(pos.ins().null(self.reference_type(ty)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Translate a `ref.is_null` WebAssembly instruction.
|
||||||
|
///
|
||||||
|
/// By default, assumes that `value` is a Cranelift reference type, and that
|
||||||
|
/// a null Cranelift reference type is the null value for all Wasm reference
|
||||||
|
/// types.
|
||||||
|
///
|
||||||
|
/// If you override this method, you probably also want to override
|
||||||
|
/// `translate_ref_null` as well.
|
||||||
|
fn translate_ref_is_null(
|
||||||
|
&mut self,
|
||||||
|
mut pos: FuncCursor,
|
||||||
|
value: ir::Value,
|
||||||
|
) -> WasmResult<ir::Value> {
|
||||||
|
let is_null = pos.ins().is_null(value);
|
||||||
|
Ok(pos.ins().bint(ir::types::I32, is_null))
|
||||||
|
}
|
||||||
|
|
||||||
/// Translate a `ref.func` WebAssembly instruction.
|
/// Translate a `ref.func` WebAssembly instruction.
|
||||||
fn translate_ref_func(&mut self, pos: FuncCursor, func_index: u32) -> WasmResult<ir::Value>;
|
fn translate_ref_func(&mut self, pos: FuncCursor, func_index: u32) -> WasmResult<ir::Value>;
|
||||||
|
|
||||||
|
|||||||
@@ -196,8 +196,7 @@ fn declare_locals<FE: FuncEnvironment + ?Sized>(
|
|||||||
let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
|
let constant_handle = builder.func.dfg.constants.insert([0; 16].to_vec().into());
|
||||||
builder.ins().vconst(ir::types::I8X16, constant_handle)
|
builder.ins().vconst(ir::types::I8X16, constant_handle)
|
||||||
}
|
}
|
||||||
ExternRef => builder.ins().null(environ.reference_type()),
|
ExternRef | FuncRef => environ.translate_ref_null(builder.cursor(), wasm_type)?,
|
||||||
FuncRef => builder.ins().null(environ.reference_type()),
|
|
||||||
ty => return Err(wasm_unsupported!("unsupported local type {:?}", ty)),
|
ty => return Err(wasm_unsupported!("unsupported local type {:?}", ty)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ pub fn type_to_type<PE: TargetEnvironment + ?Sized>(
|
|||||||
wasmparser::Type::F32 => Ok(ir::types::F32),
|
wasmparser::Type::F32 => Ok(ir::types::F32),
|
||||||
wasmparser::Type::F64 => Ok(ir::types::F64),
|
wasmparser::Type::F64 => Ok(ir::types::F64),
|
||||||
wasmparser::Type::V128 => Ok(ir::types::I8X16),
|
wasmparser::Type::V128 => Ok(ir::types::I8X16),
|
||||||
wasmparser::Type::ExternRef | wasmparser::Type::FuncRef => Ok(environ.reference_type()),
|
wasmparser::Type::ExternRef | wasmparser::Type::FuncRef => Ok(environ.reference_type(ty)),
|
||||||
ty => Err(wasm_unsupported!("type_to_type: wasm type {:?}", ty)),
|
ty => Err(wasm_unsupported!("type_to_type: wasm type {:?}", ty)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ pub fn tabletype_to_type<PE: TargetEnvironment + ?Sized>(
|
|||||||
wasmparser::Type::F32 => Ok(Some(ir::types::F32)),
|
wasmparser::Type::F32 => Ok(Some(ir::types::F32)),
|
||||||
wasmparser::Type::F64 => Ok(Some(ir::types::F64)),
|
wasmparser::Type::F64 => Ok(Some(ir::types::F64)),
|
||||||
wasmparser::Type::V128 => Ok(Some(ir::types::I8X16)),
|
wasmparser::Type::V128 => Ok(Some(ir::types::I8X16)),
|
||||||
wasmparser::Type::ExternRef => Ok(Some(environ.reference_type())),
|
wasmparser::Type::ExternRef => Ok(Some(environ.reference_type(ty))),
|
||||||
wasmparser::Type::FuncRef => Ok(None),
|
wasmparser::Type::FuncRef => Ok(None),
|
||||||
ty => Err(wasm_unsupported!(
|
ty => Err(wasm_unsupported!(
|
||||||
"tabletype_to_type: table wasm type {:?}",
|
"tabletype_to_type: table wasm type {:?}",
|
||||||
@@ -216,7 +216,7 @@ pub fn block_with_params<PE: TargetEnvironment + ?Sized>(
|
|||||||
builder.append_block_param(block, ir::types::F64);
|
builder.append_block_param(block, ir::types::F64);
|
||||||
}
|
}
|
||||||
wasmparser::Type::ExternRef | wasmparser::Type::FuncRef => {
|
wasmparser::Type::ExternRef | wasmparser::Type::FuncRef => {
|
||||||
builder.append_block_param(block, environ.reference_type());
|
builder.append_block_param(block, environ.reference_type(*ty));
|
||||||
}
|
}
|
||||||
wasmparser::Type::V128 => {
|
wasmparser::Type::V128 => {
|
||||||
builder.append_block_param(block, ir::types::I8X16);
|
builder.append_block_param(block, ir::types::I8X16);
|
||||||
|
|||||||
Reference in New Issue
Block a user