@@ -17,8 +17,8 @@ use ir::{
1717 schedule:: { ScheduleContext , schedule_early, schedule_late} ,
1818 valgraph:: { DepValue , Node , ValGraph } ,
1919 valwalk:: {
20- CfgPreorderInfo , DefUseSuccs , GraphWalkInfo , dataflow_inputs, dataflow_preds ,
21- dataflow_succs, def_use_preds, raw_def_use_succs,
20+ CfgPreorderInfo , DefUseSuccs , GraphWalkInfo , dataflow_inputs, dataflow_outputs ,
21+ dataflow_preds , dataflow_succs, def_use_preds, raw_def_use_succs,
2222 } ,
2323} ;
2424use log:: trace;
@@ -419,9 +419,9 @@ impl PartialEq for ReadyNode {
419419struct BlockNodeData {
420420 /// The number of block-local predecessors of this node that have not yet been scheduled.
421421 unscheduled_preds : u32 ,
422- /// The number of deduplicated data inputs for which this node is the last use point in the
423- /// block .
424- last_use_count : u32 ,
422+ /// The number of live ranges forward execution of this instruction is expected to add. May be
423+ /// negative if the instruction terminates more live ranges than it creates .
424+ live_range_delta : i32 ,
425425 /// A deduplicated list of all data inputs to this node.
426426 unique_inputs : EntityList < DepValue > ,
427427}
@@ -479,7 +479,7 @@ impl<'a> BlockScheduler<'a> {
479479 let node_data = match self . block_node_data . entry ( node) {
480480 Entry :: Vacant ( entry) => entry. insert ( BlockNodeData {
481481 unscheduled_preds,
482- last_use_count : 0 ,
482+ live_range_delta : 0 ,
483483 unique_inputs : EntityList :: from_iter (
484484 dataflow_inputs ( self . graph , node) ,
485485 & mut self . unique_input_pool ,
@@ -498,15 +498,18 @@ impl<'a> BlockScheduler<'a> {
498498 }
499499 }
500500
501- // Now that all outstanding uses across the block have been counted, bump last use counts
502- // and enqueue nodes.
501+ // Now that all outstanding uses across the block have been counted, compute live range
502+ // deltas and enqueue nodes.
503503 for & node in nodes {
504504 let node_data = self . block_node_data . get_mut ( & node) . unwrap ( ) ;
505+
506+ node_data. live_range_delta = dataflow_outputs ( self . graph , node) . count ( ) as i32 ;
507+
505508 for & input in node_data. unique_inputs . as_slice ( & self . unique_input_pool ) {
506509 if self . block_value_data [ & input] . outstanding_uses == 1 {
507- // This node is the only use of the input in the block, bump its last use count
508- // now .
509- node_data. last_use_count + = 1 ;
510+ // This node is the only use of the input in the block, so it terminates the
511+ // input's live range .
512+ node_data. live_range_delta - = 1 ;
510513 }
511514 }
512515 self . enqueue_if_ready ( node) ;
@@ -527,9 +530,9 @@ impl<'a> BlockScheduler<'a> {
527530 }
528531
529532 trace ! (
530- " place: node {} [luc {}, cp {}]" ,
533+ " place: node {} [lrg delta {}, cp {}]" ,
531534 node. as_u32( ) ,
532- self . block_node_data[ & node] . last_use_count ,
535+ self . block_node_data[ & node] . live_range_delta ,
533536 self . node_cp_lengths[ node] ,
534537 ) ;
535538
@@ -574,8 +577,8 @@ impl<'a> BlockScheduler<'a> {
574577 debug_assert ! ( value_data. outstanding_uses > 0 ) ;
575578 value_data. outstanding_uses -= 1 ;
576579 if value_data. outstanding_uses == 1 {
577- // The remaining user of this value is now the last in the block, so bump its
578- // last use count and report it to the caller.
580+ // The remaining user of this value is now the last in the block, so adjust its live
581+ // range delta and report it to the caller.
579582
580583 // This search happens at most once per value during scheduling of the block (and
581584 // only walks edges leading into the block), so the total complexity here is still
@@ -593,7 +596,7 @@ impl<'a> BlockScheduler<'a> {
593596 self . block_node_data
594597 . get_mut ( & last_user)
595598 . unwrap ( )
596- . last_use_count + = 1 ;
599+ . live_range_delta - = 1 ;
597600 // Note: this node may be pushed multiple times if several of its inputs are
598601 // last users.
599602 updated_last_users. push ( last_user) ;
@@ -620,9 +623,14 @@ impl<'a> BlockScheduler<'a> {
620623 }
621624
622625 fn node_prio ( & self , node : Node ) -> u64 {
623- // Prefer last use count, and fall back to CP length when tied.
624- ( ( self . block_node_data [ & node] . last_use_count as u64 ) << 32 )
625- | self . node_cp_lengths [ node] as u64
626+ // We want lower `live_range_delta` values to have higher priority, so we need an unsigned
627+ // value that increases when `live_range_delta` decreases. Accomplish this by centering
628+ // `-live_range_delta` around the middle of the unsigned range.
629+ let biased_delta =
630+ ( 1u32 << 31 ) . wrapping_sub ( self . block_node_data [ & node] . live_range_delta as u32 ) ;
631+
632+ // Prefer reducing live ranges, and fall back to CP length when tied.
633+ ( ( biased_delta as u64 ) << 32 ) | self . node_cp_lengths [ node] as u64
626634 }
627635
628636 fn is_block_interior_node ( & self , node : Node ) -> bool {
0 commit comments