@@ -47,6 +47,7 @@ use crate::{
4747 NegateCmpInstr ,
4848 TryIntoCmpBranchInstr as _,
4949 TryIntoCmpSelectInstr as _,
50+ UpdateBranchOffset as _,
5051 } ,
5152 utils:: { IntoShiftAmount , ToBits , WasmFloat , WasmInteger } ,
5253 WasmTranslator ,
@@ -55,8 +56,19 @@ use crate::{
5556 CompiledFuncEntity ,
5657 TranslationError ,
5758 } ,
58- ir,
59- ir:: { index, Address , BoundedSlotSpan , FixedSlotSpan , Offset16 , Op , Sign , Slot , SlotSpan } ,
59+ ir:: {
60+ self ,
61+ index,
62+ Address ,
63+ BoundedSlotSpan ,
64+ BranchOffset ,
65+ FixedSlotSpan ,
66+ Offset16 ,
67+ Op ,
68+ Sign ,
69+ Slot ,
70+ SlotSpan ,
71+ } ,
6072 module:: { FuncIdx , FuncTypeIdx , MemoryIdx , ModuleHeader , WasmiValueType } ,
6173 Engine ,
6274 Error ,
@@ -98,8 +110,6 @@ pub struct FuncTranslator {
98110 locals : LocalsRegistry ,
99111 /// Wasm layout to map stack slots to Wasmi registers.
100112 layout : StackLayout ,
101- /// Slots and pins labels and tracks their users.
102- labels : LabelRegistry ,
103113 /// Constructs and encodes function instructions.
104114 instrs : OpEncoder ,
105115 /// Temporary buffer for operands.
@@ -117,8 +127,6 @@ pub struct FuncTranslatorAllocations {
117127 locals : LocalsRegistry ,
118128 /// Wasm layout to map stack slots to Wasmi registers.
119129 layout : StackLayout ,
120- /// Slots and pins labels and tracks their users.
121- labels : LabelRegistry ,
122130 /// Constructs and encodes function instructions.
123131 instrs : OpEncoderAllocations ,
124132 /// Temporary buffer for operands.
@@ -132,7 +140,6 @@ impl Reset for FuncTranslatorAllocations {
132140 self . stack . reset ( ) ;
133141 self . locals . reset ( ) ;
134142 self . layout . reset ( ) ;
135- self . labels . reset ( ) ;
136143 self . instrs . reset ( ) ;
137144 self . operands . clear ( ) ;
138145 self . immediates . clear ( ) ;
@@ -173,7 +180,7 @@ impl WasmTranslator<'_> for FuncTranslator {
173180 let Some ( frame_size) = self . frame_size ( ) else {
174181 return Err ( Error :: from ( TranslationError :: AllocatedTooManySlots ) ) ;
175182 } ;
176- self . update_branch_offsets ( ) ?;
183+ self . instrs . update_branch_offsets ( ) ?;
177184 finalize ( CompiledFuncEntity :: new (
178185 frame_size,
179186 self . instrs . encoded_ops ( ) ,
@@ -190,7 +197,6 @@ impl ReusableAllocations for FuncTranslator {
190197 stack : self . stack . into_allocations ( ) ,
191198 locals : self . locals ,
192199 layout : self . layout ,
193- labels : self . labels ,
194200 instrs : self . instrs . into_allocations ( ) ,
195201 operands : self . operands ,
196202 immediates : self . immediates ,
@@ -215,7 +221,6 @@ impl FuncTranslator {
215221 stack,
216222 locals,
217223 layout,
218- labels,
219224 instrs,
220225 operands,
221226 immediates,
@@ -230,7 +235,6 @@ impl FuncTranslator {
230235 stack,
231236 locals,
232237 layout,
233- labels,
234238 instrs,
235239 operands,
236240 immediates,
@@ -244,7 +248,7 @@ impl FuncTranslator {
244248 fn init_func_body_block ( & mut self ) -> Result < ( ) , Error > {
245249 let func_ty = self . module . get_type_of_func ( self . func ) ;
246250 let block_ty = BlockType :: func_type ( func_ty) ;
247- let end_label = self . labels . new_label ( ) ;
251+ let end_label = self . instrs . new_label ( ) ;
248252 let consume_fuel = self . instrs . encode_consume_fuel ( ) ?;
249253 self . stack
250254 . push_func_block ( block_ty, end_label, consume_fuel) ?;
@@ -280,18 +284,6 @@ impl FuncTranslator {
280284 u16:: try_from ( frame_size) . ok ( )
281285 }
282286
283- /// Updates the branch offsets of all branch instructions inplace.
284- ///
285- /// # Panics
286- ///
287- /// If this is used before all branching labels have been pinned.
288- fn update_branch_offsets ( & mut self ) -> Result < ( ) , Error > {
289- for ( user, offset) in self . labels . resolved_users ( ) {
290- self . instrs . update_branch_offset ( user, offset?) ?;
291- }
292- Ok ( ( ) )
293- }
294-
295287 /// Returns the [`FuncType`] of the function that is currently translated.
296288 fn func_type ( & self ) -> FuncType {
297289 self . func_type_with ( FuncType :: clone)
@@ -704,7 +696,7 @@ impl FuncTranslator {
704696
705697 /// Pins the `label` to the next [`OpPos`].
706698 fn pin_label ( & mut self , label : LabelRef ) {
707- self . labels . pin_label ( label, self . instrs . next_pos ( ) ) ;
699+ self . instrs . pin_label ( label) ;
708700 }
709701
710702 /// Convert the [`Operand`] at `depth` into an [`Operand::Temp`] by copying if necessary.
@@ -783,12 +775,9 @@ impl FuncTranslator {
783775 fuel_costs : impl FnOnce ( & FuelCostsProvider ) -> u64 ,
784776 ) -> Result < ( ) , Error > {
785777 let consume_fuel_instr = self . stack . consume_fuel_instr ( ) ;
786- let expected_iidx = self . instrs . next_pos ( ) ;
787778 let result = self . layout . temp_to_slot ( self . stack . push_temp ( result_ty) ?) ?;
788- let actual_iidx = self
789- . instrs
779+ self . instrs
790780 . stage ( make_instr ( result) , consume_fuel_instr, fuel_costs) ?;
791- assert_eq ! ( expected_iidx, actual_iidx) ;
792781 Ok ( ( ) )
793782 }
794783
@@ -839,16 +828,15 @@ impl FuncTranslator {
839828 FuelCostsProvider :: base,
840829 ) ?;
841830 // Encode the `br_table` targets:
831+ let fuel_pos = self . stack . consume_fuel_instr ( ) ;
842832 let targets = & self . immediates [ ..] ;
843833 for target in targets {
844834 let Ok ( depth) = usize:: try_from ( u32:: from ( * target) ) else {
845835 panic ! ( "out of bounds `br_table` target does not fit `usize`: {target:?}" ) ;
846836 } ;
847837 let mut frame = self . stack . peek_control_mut ( depth) . control_frame ( ) ;
848- let _offset = self
849- . labels
850- . try_resolve_label ( frame. label ( ) , self . instrs . next_pos ( ) ) ?;
851- // self.instrs.push_param(Op::branch(offset)); // TODO: finish encoding impl
838+ self . instrs
839+ . encode_branch ( frame. label ( ) , Op :: branch, fuel_pos, 0 ) ?;
852840 frame. branch_to ( ) ;
853841 }
854842 Ok ( ( ) )
@@ -873,21 +861,23 @@ impl FuncTranslator {
873861 FuelCostsProvider :: base,
874862 ) ?;
875863 // Encode the `br_table` targets:
864+ let fuel_pos = self . stack . consume_fuel_instr ( ) ;
876865 let targets = & self . immediates [ ..] ;
877866 for target in targets {
878867 let Ok ( depth) = usize:: try_from ( u32:: from ( * target) ) else {
879868 panic ! ( "out of bounds `br_table` target does not fit `usize`: {target:?}" ) ;
880869 } ;
881870 let mut frame = self . stack . peek_control_mut ( depth) . control_frame ( ) ;
882- let Some ( _results ) = Self :: frame_results_impl ( & frame, & self . engine , & self . layout ) ?
871+ let Some ( results ) = Self :: frame_results_impl ( & frame, & self . engine , & self . layout ) ?
883872 else {
884873 panic ! ( "must have frame results since `br_table` requires to copy values" ) ;
885874 } ;
886- let _offset = self
887- . labels
888- . try_resolve_label ( frame. label ( ) , self . instrs . next_pos ( ) ) ?;
889- // self.instrs
890- // .push_param(Op::branch_table_target(results, offset)); // TODO: encode branch table targets properly
875+ self . instrs . encode_branch (
876+ frame. label ( ) ,
877+ |offset| ir:: BranchTableTarget :: new ( results, offset) ,
878+ fuel_pos,
879+ 0 ,
880+ ) ?;
891881 frame. branch_to ( ) ;
892882 }
893883 Ok ( ( ) )
@@ -1015,14 +1005,14 @@ impl FuncTranslator {
10151005 }
10161006 self . push_frame_results ( & frame) ?;
10171007 }
1018- self . labels . pin_label ( frame. label ( ) , self . instrs . next_pos ( ) ) ;
1008+ self . instrs . pin_label ( frame. label ( ) ) ;
10191009 self . reachable |= frame. is_branched_to ( ) ;
10201010 if self . reachable && self . stack . is_control_empty ( ) {
10211011 self . encode_return ( consume_fuel_instr) ?;
10221012 }
10231013 if frame. is_branched_to ( ) {
10241014 // No need to reset `last_instr` if there was no branch to the end of a Wasm `block`.
1025- self . instrs . try_encode_staged ( ) ;
1015+ self . instrs . try_encode_staged ( ) ? ;
10261016 }
10271017 Ok ( ( ) )
10281018 }
@@ -1053,18 +1043,14 @@ impl FuncTranslator {
10531043 if is_end_of_then_reachable && has_results {
10541044 let consume_fuel_instr = frame. consume_fuel_instr ( ) ;
10551045 self . copy_branch_params ( & frame, consume_fuel_instr) ?;
1056- let end_offset = self
1057- . labels
1058- . try_resolve_label ( frame. label ( ) , self . instrs . next_pos ( ) )
1059- . unwrap ( ) ;
1060- self . instrs . encode (
1061- Op :: branch ( end_offset) ,
1046+ self . instrs . encode_branch (
1047+ frame. label ( ) ,
1048+ Op :: branch,
10621049 consume_fuel_instr,
10631050 FuelCostsProvider :: base,
10641051 ) ?;
10651052 }
1066- self . labels
1067- . pin_label_if_unpinned ( else_label, self . instrs . next_pos ( ) ) ;
1053+ self . instrs . pin_label_if_unpinned ( else_label) ;
10681054 self . stack . push_else_operands ( & frame) ?;
10691055 if has_results {
10701056 // We haven't visited the `else` block and thus the `else`
@@ -1076,10 +1062,10 @@ impl FuncTranslator {
10761062 self . copy_branch_params ( & frame, consume_fuel_instr) ?;
10771063 }
10781064 self . push_frame_results ( & frame) ?;
1079- self . labels . pin_label ( frame. label ( ) , self . instrs . next_pos ( ) ) ;
1065+ self . instrs . pin_label ( frame. label ( ) ) ;
10801066 self . reachable = true ;
10811067 // Need to reset `last_instr` since end of `if` is a control flow boundary.
1082- self . instrs . try_encode_staged ( ) ;
1068+ self . instrs . try_encode_staged ( ) ? ;
10831069 Ok ( ( ) )
10841070 }
10851071
@@ -1108,10 +1094,10 @@ impl FuncTranslator {
11081094 self . copy_branch_params ( & frame, consume_fuel_instr) ?;
11091095 }
11101096 self . push_frame_results ( & frame) ?;
1111- self . labels . pin_label ( frame. label ( ) , self . instrs . next_pos ( ) ) ;
1097+ self . instrs . pin_label ( frame. label ( ) ) ;
11121098 self . reachable = reachable;
11131099 // Need to reset `last_instr` since end of `else` is a control flow boundary.
1114- self . instrs . try_encode_staged ( ) ;
1100+ self . instrs . try_encode_staged ( ) ? ;
11151101 Ok ( ( ) )
11161102 }
11171103
@@ -1128,12 +1114,12 @@ impl FuncTranslator {
11281114 }
11291115 self . push_frame_results ( & frame) ?;
11301116 }
1131- self . labels . pin_label ( frame. label ( ) , self . instrs . next_pos ( ) ) ;
1117+ self . instrs . pin_label ( frame. label ( ) ) ;
11321118 self . reachable = end_is_reachable || frame. is_branched_to ( ) ;
11331119 if frame. is_branched_to ( ) {
11341120 // No need to reset `last_instr` if there was no branch to the
11351121 // end of a Wasm `if` where only `then` or `else` is reachable.
1136- self . instrs . try_encode_staged ( ) ;
1122+ self . instrs . try_encode_staged ( ) ? ;
11371123 }
11381124 Ok ( ( ) )
11391125 }
@@ -1142,7 +1128,7 @@ impl FuncTranslator {
11421128 fn translate_end_unreachable ( & mut self , _frame : ControlFrameKind ) -> Result < ( ) , Error > {
11431129 debug_assert ! ( !self . stack. is_control_empty( ) ) ;
11441130 // We reset `last_instr` out of caution in case there is a control flow boundary.
1145- self . instrs . try_encode_staged ( ) ;
1131+ self . instrs . try_encode_staged ( ) ? ;
11461132 Ok ( ( ) )
11471133 }
11481134
@@ -1246,10 +1232,11 @@ impl FuncTranslator {
12461232
12471233 /// Encodes an unconditional Wasm `branch` instruction.
12481234 fn encode_br ( & mut self , label : LabelRef ) -> Result < Pos < Op > , Error > {
1249- let instr = self . instrs . next_pos ( ) ;
1250- let offset = self . labels . try_resolve_label ( label, instr) ?;
1251- let br_instr = self . push_instr ( Op :: branch ( offset) , FuelCostsProvider :: base) ?;
1252- Ok ( br_instr)
1235+ let fuel_pos = self . stack . consume_fuel_instr ( ) ;
1236+ let ( br_op, _) =
1237+ self . instrs
1238+ . encode_branch ( label, Op :: branch, fuel_pos, FuelCostsProvider :: base) ?;
1239+ Ok ( br_op)
12531240 }
12541241
12551242 /// Encodes a `i32.eqz`+`br_if` or `if` conditional branch instruction.
@@ -1291,13 +1278,16 @@ impl FuncTranslator {
12911278 }
12921279 }
12931280 } ;
1294- let instr = self . instrs . next_pos ( ) ;
1295- let offset = self . labels . try_resolve_label ( label, instr) ?;
1296- let instr = match branch_eqz {
1297- true => Op :: branch_i32_eq_si ( condition, 0 , offset) ,
1298- false => Op :: branch_i32_not_eq_si ( condition, 0 , offset) ,
1299- } ;
1300- self . push_instr ( instr, FuelCostsProvider :: base) ?;
1281+ let fuel_pos = self . stack . consume_fuel_instr ( ) ;
1282+ self . instrs . encode_branch (
1283+ label,
1284+ |offset| match branch_eqz {
1285+ true => Op :: branch_i32_eq_si ( condition, 0 , offset) ,
1286+ false => Op :: branch_i32_not_eq_si ( condition, 0 , offset) ,
1287+ } ,
1288+ fuel_pos,
1289+ FuelCostsProvider :: base,
1290+ ) ?;
13011291 Ok ( ( ) )
13021292 }
13031293
@@ -1343,11 +1333,17 @@ impl FuncTranslator {
13431333 }
13441334 } ,
13451335 } ;
1346- let offset = self . labels . try_resolve_label ( label , instr ) ? ;
1347- let Some ( fused_cmp_branch ) = cmp_op . try_into_cmp_branch_instr ( offset ) else {
1336+ let Some ( fused_cmp_branch ) = cmp_op . try_into_cmp_branch_instr ( BranchOffset :: uninit ( ) )
1337+ else {
13481338 return Ok ( false ) ;
13491339 } ;
1350- self . instrs . replace_staged ( fused_cmp_branch) ?;
1340+ let ( fuel_pos, _) = self . instrs . drop_staged ( ) ;
1341+ self . instrs . encode_branch (
1342+ label,
1343+ |offset| fused_cmp_branch. with_branch_offset ( offset) ,
1344+ fuel_pos,
1345+ FuelCostsProvider :: base,
1346+ ) ?;
13511347 Ok ( true )
13521348 }
13531349
0 commit comments