diff --git a/crates/tests/tests/round_trip/return_call.wat b/crates/tests/tests/round_trip/return_call.wat new file mode 100644 index 00000000..3fa8baab --- /dev/null +++ b/crates/tests/tests/round_trip/return_call.wat @@ -0,0 +1,20 @@ +(module + (func $g (result i32) + i32.const 42 + return) + (func $f (result i32) + return_call $g) + (export "f" (func $f))) + +(; CHECK-ALL: + (module + (type (;0;) (func (result i32))) + (func $g (;0;) (type 0) (result i32) + i32.const 42 + return + ) + (func $f (;1;) (type 0) (result i32) + return_call $g + ) + (export "f" (func $f)) +;) diff --git a/crates/tests/tests/round_trip/return_call_indirect.wat b/crates/tests/tests/round_trip/return_call_indirect.wat new file mode 100644 index 00000000..89385323 --- /dev/null +++ b/crates/tests/tests/round_trip/return_call_indirect.wat @@ -0,0 +1,18 @@ +(module + (type (func (result i32))) + (table 1 funcref) + (func (export "a") (param i32) (result i32) + local.get 0 + return_call_indirect (type 0))) + +(; CHECK-ALL: + (module + (type (;0;) (func (result i32))) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 1) (param i32) (result i32) + local.get 0 + return_call_indirect (type 0) + ) + (table (;0;) 1 funcref) + (export "a" (func 0)) +;) diff --git a/src/ir/mod.rs b/src/ir/mod.rs index 595061f7..f60d2569 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -591,6 +591,20 @@ pub enum Instr { /// The destination table dst: TableId, }, + + /// `return_call` + ReturnCall { + /// The function being invoked. + func: FunctionId, + }, + + /// `return_call_indirect` + ReturnCallIndirect { + /// The type signature of the function we're calling + ty: TypeId, + /// The table which `func` below is indexing into + table: TableId, + }, } /// Argument in `V128Shuffle` of lane indices to select @@ -1215,7 +1229,12 @@ impl Instr { /// (`i32.add`, etc...). pub fn following_instructions_are_unreachable(&self) -> bool { match *self { - Instr::Unreachable(..) | Instr::Br(..) | Instr::BrTable(..) | Instr::Return(..) => true, + Instr::Unreachable(..) + | Instr::Br(..) + | Instr::BrTable(..) + | Instr::Return(..) + | Instr::ReturnCall(..) + | Instr::ReturnCallIndirect(..) => true, // No `_` arm to make sure that we properly update this function as // we add support for new instructions. diff --git a/src/module/config.rs b/src/module/config.rs index 42242f56..65b758c5 100644 --- a/src/module/config.rs +++ b/src/module/config.rs @@ -175,6 +175,7 @@ impl ModuleConfig { features.insert(WasmFeatures::REFERENCE_TYPES); features.insert(WasmFeatures::BULK_MEMORY); features.insert(WasmFeatures::SIMD); + features.insert(WasmFeatures::TAIL_CALL); // Enable supported active proposals. if !self.only_stable_features { // # Fully supported proposals. diff --git a/src/module/functions/local_function/emit.rs b/src/module/functions/local_function/emit.rs index 41447bc8..021138d1 100644 --- a/src/module/functions/local_function/emit.rs +++ b/src/module/functions/local_function/emit.rs @@ -845,6 +845,15 @@ impl<'instr> Visitor<'instr> for Emit<'_> { } } ElemDrop(e) => Instruction::ElemDrop(self.indices.get_element_index(e.elem)), + ReturnCall(e) => Instruction::ReturnCall(self.indices.get_func_index(e.func)), + ReturnCallIndirect(e) => { + let type_index = self.indices.get_type_index(e.ty); + let table_index = self.indices.get_table_index(e.table); + Instruction::ReturnCallIndirect { + type_index, + table_index, + } + } }); } } diff --git a/src/module/functions/local_function/mod.rs b/src/module/functions/local_function/mod.rs index bc8c327e..22891b88 100644 --- a/src/module/functions/local_function/mod.rs +++ b/src/module/functions/local_function/mod.rs @@ -1323,6 +1323,20 @@ fn append_instruction<'context>( ctx.alloc_instr(ElemDrop { elem }, loc); } + Operator::ReturnCall { function_index } => { + let func = ctx.indices.get_func(function_index).unwrap(); + ctx.alloc_instr(ReturnCall { func }, loc); + } + + Operator::ReturnCallIndirect { + type_index, + table_index, + } => { + let ty = ctx.indices.get_type(type_index).unwrap(); + let table = ctx.indices.get_table(table_index).unwrap(); + ctx.alloc_instr(ReturnCallIndirect { ty, table }, loc); + } + // List all unimplmented operators instead of have a catch-all arm. // So that future upgrades won't miss additions to this list that may be important to know. Operator::TryTable { try_table: _ } @@ -1333,11 +1347,6 @@ fn append_instruction<'context>( | Operator::Rethrow { relative_depth: _ } | Operator::Delegate { relative_depth: _ } | Operator::CatchAll - | Operator::ReturnCall { function_index: _ } - | Operator::ReturnCallIndirect { - type_index: _, - table_index: _, - } | Operator::RefEq | Operator::StructNew { struct_type_index: _,