@@ -950,33 +950,46 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
950
950
let loc = self . srcloc ( branch) ;
951
951
self . finish_ir_inst ( loc) ;
952
952
// Add block param outputs for current block.
953
- self . lower_branch_blockparam_args ( bindex) ;
953
+ match self . vcode . block_order ( ) . succ_indices ( bindex) . 1 {
954
+ & [ succ] => self . lower_branch_blockparam_args ( branch, 0 , succ) ,
955
+ succs => {
956
+ // If there are multiple edges, either the destination has
957
+ // multiple predecessors and there is a split critical edge
958
+ // block that can hold these block params, or it has one
959
+ // predecessor and doesn't need block params.
960
+ debug_assert ! ( succs
961
+ . iter( )
962
+ . zip( self . f. dfg. insts[ branch] . branch_destination( & self . f. dfg. jump_tables) )
963
+ . all( |( succ, block_call) | {
964
+ matches!(
965
+ self . vcode. block_order( ) . lowered_order( ) [ succ. index( ) ] ,
966
+ LoweredBlock :: CriticalEdge { .. }
967
+ ) || block_call. args_slice( & self . f. dfg. value_lists) . is_empty( )
968
+ } ) ) ;
969
+ let succs: SmallVec < [ BlockIndex ; 2 ] > = SmallVec :: from_slice ( succs) ;
970
+ for succ in succs {
971
+ self . vcode . add_succ ( succ, & [ ] ) ;
972
+ }
973
+ }
974
+ }
954
975
Ok ( ( ) )
955
976
}
956
977
957
- fn lower_branch_blockparam_args ( & mut self , block : BlockIndex ) {
958
- // TODO: why not make `block_order` public?
959
- for succ_idx in 0 ..self . vcode . block_order ( ) . succ_indices ( block) . 1 . len ( ) {
960
- // Avoid immutable borrow by explicitly indexing.
961
- let ( opt_inst, succs) = self . vcode . block_order ( ) . succ_indices ( block) ;
962
- let inst = opt_inst. expect ( "lower_branch_blockparam_args called on a critical edge!" ) ;
963
- let succ = succs[ succ_idx] ;
964
-
965
- // The use of `succ_idx` to index `branch_destination` is valid on the assumption that
966
- // the traversal order defined in `visit_block_succs` mirrors the order returned by
967
- // `branch_destination`. If that assumption is violated, the branch targets returned
968
- // here will not match the clif.
969
- let branches = self . f . dfg . insts [ inst] . branch_destination ( & self . f . dfg . jump_tables ) ;
970
- let branch_args = branches[ succ_idx] . args_slice ( & self . f . dfg . value_lists ) ;
971
-
972
- let mut branch_arg_vregs: SmallVec < [ Reg ; 16 ] > = smallvec ! [ ] ;
973
- for & arg in branch_args {
974
- let arg = self . f . dfg . resolve_aliases ( arg) ;
975
- let regs = self . put_value_in_regs ( arg) ;
976
- branch_arg_vregs. extend_from_slice ( regs. regs ( ) ) ;
977
- }
978
- self . vcode . add_succ ( succ, & branch_arg_vregs[ ..] ) ;
978
+ fn lower_branch_blockparam_args ( & mut self , inst : Inst , succ_idx : usize , succ : BlockIndex ) {
979
+ // The use of `succ_idx` to index `branch_destination` is valid on the assumption that
980
+ // the traversal order defined in `visit_block_succs` mirrors the order returned by
981
+ // `branch_destination`. If that assumption is violated, the branch targets returned
982
+ // here will not match the clif.
983
+ let branches = self . f . dfg . insts [ inst] . branch_destination ( & self . f . dfg . jump_tables ) ;
984
+ let branch_args = branches[ succ_idx] . args_slice ( & self . f . dfg . value_lists ) ;
985
+
986
+ let mut branch_arg_vregs: SmallVec < [ Reg ; 16 ] > = smallvec ! [ ] ;
987
+ for & arg in branch_args {
988
+ let arg = self . f . dfg . resolve_aliases ( arg) ;
989
+ let regs = self . put_value_in_regs ( arg) ;
990
+ branch_arg_vregs. extend_from_slice ( regs. regs ( ) ) ;
979
991
}
992
+ self . vcode . add_succ ( succ, & branch_arg_vregs[ ..] ) ;
980
993
}
981
994
982
995
fn collect_branches_and_targets (
@@ -1028,44 +1041,29 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
1028
1041
// `lower_clif_block()` for rationale).
1029
1042
1030
1043
// End branches.
1031
- if let Some ( bb) = lb. orig_block ( ) {
1032
- if let Some ( branch) = self . collect_branches_and_targets ( bindex, bb, & mut targets) {
1033
- self . lower_clif_branches ( backend, bindex, bb, branch, & targets) ?;
1034
- self . finish_ir_inst ( self . srcloc ( branch) ) ;
1035
- }
1036
- } else {
1037
- // If no orig block, this must be a pure edge block;
1038
- // get the successor and emit a jump. Add block params
1039
- // according to the one successor, and pass them
1040
- // through; note that the successor must have an
1041
- // original block.
1042
- let ( _, succs) = self . vcode . block_order ( ) . succ_indices ( bindex) ;
1043
- let succ = succs[ 0 ] ;
1044
-
1045
- let orig_succ = lowered_order[ succ. index ( ) ] ;
1046
- let orig_succ = orig_succ
1047
- . orig_block ( )
1048
- . expect ( "Edge block succ must be body block" ) ;
1049
-
1050
- let mut branch_arg_vregs: SmallVec < [ Reg ; 16 ] > = smallvec ! [ ] ;
1051
- for ty in self . f . dfg . block_param_types ( orig_succ) {
1052
- let regs = self . vregs . alloc ( ty) ?;
1053
- for & reg in regs. regs ( ) {
1054
- branch_arg_vregs. push ( reg) ;
1055
- let vreg = reg. to_virtual_reg ( ) . unwrap ( ) ;
1056
- self . vcode . add_block_param ( vreg) ;
1044
+ match lb {
1045
+ & LoweredBlock :: Orig { block : bb } => {
1046
+ if let Some ( branch) =
1047
+ self . collect_branches_and_targets ( bindex, bb, & mut targets)
1048
+ {
1049
+ self . lower_clif_branches ( backend, bindex, bb, branch, & targets) ?;
1050
+ self . finish_ir_inst ( self . srcloc ( branch) ) ;
1057
1051
}
1058
- }
1059
- self . vcode . add_succ ( succ, & branch_arg_vregs[ ..] ) ;
1060
1052
1061
- self . emit ( I :: gen_jump ( MachLabel :: from_block ( succ) ) ) ;
1062
- self . finish_ir_inst ( Default :: default ( ) ) ;
1063
- }
1064
-
1065
- // Original block body.
1066
- if let Some ( bb) = lb. orig_block ( ) {
1067
- self . lower_clif_block ( backend, bb, ctrl_plane) ?;
1068
- self . emit_value_label_markers_for_block_args ( bb) ;
1053
+ // Original block body.
1054
+ self . lower_clif_block ( backend, bb, ctrl_plane) ?;
1055
+ self . emit_value_label_markers_for_block_args ( bb) ;
1056
+ }
1057
+ & LoweredBlock :: CriticalEdge { pred, succ_idx, .. } => {
1058
+ // Emit a jump to the successor, placing the block params
1059
+ // that the predecessor was going to pass along here.
1060
+ let ( _, succs) = self . vcode . block_order ( ) . succ_indices ( bindex) ;
1061
+ let succ = succs[ 0 ] ;
1062
+ let branch = self . f . layout . last_inst ( pred) . unwrap ( ) ;
1063
+ self . lower_branch_blockparam_args ( branch, succ_idx as usize , succ) ;
1064
+ self . emit ( I :: gen_jump ( MachLabel :: from_block ( succ) ) ) ;
1065
+ self . finish_ir_inst ( Default :: default ( ) ) ;
1066
+ }
1069
1067
}
1070
1068
1071
1069
if bindex. index ( ) == 0 {
0 commit comments