@@ -827,6 +827,17 @@ impl<'a, F: Function> Env<'a, F> {
827827 . iter ( )
828828 . enumerate ( )
829829 {
830+ if self
831+ . func
832+ . inst_operands ( inst)
833+ . iter ( )
834+ . find ( |op| op. vreg ( ) == * vreg && op. kind ( ) == OperandKind :: Def )
835+ . is_some ( )
836+ {
837+ // vreg is defined in this instruction, so it's dead already.
838+ // Can't move it.
839+ continue ;
840+ }
830841 let succ_params = self . func . block_params ( * succ) ;
831842 let succ_param_vreg = succ_params[ pos] ;
832843 if self . vreg_spillslots [ succ_param_vreg. vreg ( ) ] . is_invalid ( ) {
@@ -1061,6 +1072,41 @@ impl<'a, F: Function> Env<'a, F> {
10611072 Operand :: new ( op. vreg ( ) , reused_op. constraint ( ) , op. kind ( ) , op. pos ( ) ) ;
10621073 trace ! ( "allocating reuse op {op} as {new_reuse_op}" ) ;
10631074 self . process_operand_allocation ( inst, new_reuse_op, op_idx) ?;
1075+ } else if self . func . is_branch ( inst) {
1076+ // If the defined vreg is used as a branch arg and it has an
1077+ // any or stack constraint, define it into the block param spillslot
1078+ let mut param_spillslot = None ;
1079+ ' outer: for ( succ_idx, succ) in
1080+ self . func . block_succs ( block) . iter ( ) . cloned ( ) . enumerate ( )
1081+ {
1082+ for ( param_idx, branch_arg_vreg) in self
1083+ . func
1084+ . branch_blockparams ( block, inst, succ_idx)
1085+ . iter ( )
1086+ . cloned ( )
1087+ . enumerate ( )
1088+ {
1089+ if op. vreg ( ) == branch_arg_vreg {
1090+ if matches ! (
1091+ op. constraint( ) ,
1092+ OperandConstraint :: Any | OperandConstraint :: Stack
1093+ ) {
1094+ let block_param = self . func . block_params ( succ) [ param_idx] ;
1095+ param_spillslot = Some ( self . get_spillslot ( block_param) ) ;
1096+ }
1097+ break ' outer;
1098+ }
1099+ }
1100+ }
1101+ if let Some ( param_spillslot) = param_spillslot {
1102+ let spillslot = self . vreg_spillslots [ op. vreg ( ) . vreg ( ) ] ;
1103+ self . vreg_spillslots [ op. vreg ( ) . vreg ( ) ] = param_spillslot;
1104+ let op = Operand :: new ( op. vreg ( ) , OperandConstraint :: Stack , op. kind ( ) , op. pos ( ) ) ;
1105+ self . process_operand_allocation ( inst, op, op_idx) ?;
1106+ self . vreg_spillslots [ op. vreg ( ) . vreg ( ) ] = spillslot;
1107+ } else {
1108+ self . process_operand_allocation ( inst, op, op_idx) ?;
1109+ }
10641110 } else {
10651111 self . process_operand_allocation ( inst, op, op_idx) ?;
10661112 }
@@ -1159,13 +1205,10 @@ impl<'a, F: Function> Env<'a, F> {
11591205 // be none at this point.
11601206 continue ;
11611207 }
1162- if self . vreg_spillslots [ vreg. vreg ( ) ] . is_invalid ( ) {
1163- self . vreg_spillslots [ vreg. vreg ( ) ] = self . stack . allocstack ( vreg. class ( ) ) ;
1164- }
11651208 // The allocation where the vreg is expected to be before
11661209 // the first instruction.
11671210 let prev_alloc = self . vreg_allocs [ vreg. vreg ( ) ] ;
1168- let slot = Allocation :: stack ( self . vreg_spillslots [ vreg . vreg ( ) ] ) ;
1211+ let slot = Allocation :: stack ( self . get_spillslot ( vreg ) ) ;
11691212 self . vreg_to_live_inst_range [ vreg. vreg ( ) ] . 2 = slot;
11701213 self . vreg_to_live_inst_range [ vreg. vreg ( ) ] . 0 = ProgPoint :: before ( first_inst) ;
11711214 trace ! ( "{} is a block param. Freeing it" , vreg) ;
@@ -1260,6 +1303,67 @@ impl<'a, F: Function> Env<'a, F> {
12601303 InstPosition :: Before ,
12611304 ) ;
12621305 }
1306+ // Reset this, in case a fixed reg used by a branch arg defined on the branch
1307+ // is used as a scratch reg in the previous loop.
1308+ self . edits . scratch_regs = self . edits . dedicated_scratch_regs . clone ( ) ;
1309+
1310+ let get_succ_idx_of_pred = |pred, func : & F | {
1311+ for ( idx, pred_succ) in func. block_succs ( pred) . iter ( ) . enumerate ( ) {
1312+ if * pred_succ == block {
1313+ return idx;
1314+ }
1315+ }
1316+ unreachable ! (
1317+ "{:?} was not found in the successor list of its predecessor {:?}" ,
1318+ block, pred
1319+ ) ;
1320+ } ;
1321+ trace ! (
1322+ "Checking for predecessor branch args defined in the branch with fixed-reg constraint"
1323+ ) ;
1324+ for ( param_idx, block_param) in self . func . block_params ( block) . iter ( ) . cloned ( ) . enumerate ( ) {
1325+ // Block param is never used. Don't bother.
1326+ if self . vreg_spillslots [ block_param. vreg ( ) ] . is_invalid ( ) {
1327+ continue ;
1328+ }
1329+ for pred in self . func . block_preds ( block) . iter ( ) . cloned ( ) {
1330+ let pred_last_inst = self . func . block_insns ( pred) . last ( ) ;
1331+ let curr_block_succ_idx = get_succ_idx_of_pred ( pred, self . func ) ;
1332+ let branch_arg_for_param =
1333+ self . func
1334+ . branch_blockparams ( pred, pred_last_inst, curr_block_succ_idx) [ param_idx] ;
1335+ // If the branch arg is defined in the branch instruction, the move will have to be done
1336+ // here, instead of at the end of the predecessor block.
1337+ let move_from = self . func . inst_operands ( pred_last_inst)
1338+ . iter ( )
1339+ . find_map ( |op| if op. kind ( ) == OperandKind :: Def && op. vreg ( ) == branch_arg_for_param {
1340+ match op. constraint ( ) {
1341+ OperandConstraint :: FixedReg ( reg) => {
1342+ trace ! ( "Found one for branch arg {branch_arg_for_param} and param {block_param} in reg {reg}" ) ;
1343+ Some ( Allocation :: reg ( reg) )
1344+ } ,
1345+ // In these cases, the vreg is defined directly into the block param
1346+ // spillslot.
1347+ OperandConstraint :: Stack | OperandConstraint :: Any => None ,
1348+ constraint => panic ! ( "fastalloc does not support using any-reg or reuse constraints ({}) defined on a branch instruction as a branch arg on the same instruction" , constraint) ,
1349+ }
1350+ } else {
1351+ None
1352+ } ) ;
1353+ if let Some ( from) = move_from {
1354+ let to = Allocation :: stack ( self . vreg_spillslots [ block_param. vreg ( ) ] ) ;
1355+ trace ! ( "Inserting edit to move from {from} to {to}" ) ;
1356+ self . add_move (
1357+ first_inst,
1358+ from,
1359+ to,
1360+ block_param. class ( ) ,
1361+ InstPosition :: Before ,
1362+ ) ?;
1363+ }
1364+ break ;
1365+ }
1366+ }
12631367 if trace_enabled ! ( ) {
12641368 self . log_post_reload_at_begin_state ( block) ;
12651369 }
0 commit comments