1414
1515use super :: { Env , LiveBundleIndex , SpillSet , SpillSlotIndex , VRegIndex } ;
1616use crate :: {
17- ion:: data_structures:: BlockparamOut , Function , Inst , OperandConstraint , OperandKind , PReg ,
17+ ion:: data_structures:: { BlockparamOut , CodeRange } ,
18+ Function , Inst , OperandConstraint , OperandKind , PReg , ProgPoint ,
1819} ;
1920use alloc:: format;
2021use smallvec:: smallvec;
@@ -58,6 +59,21 @@ impl<'a, F: Function> Env<'a, F> {
5859 }
5960 }
6061
62+ // If a bundle has a fixed-reg def then we need to be careful to not
63+ // extend the bundle to include another use in the same instruction.
64+ // This could result in a minimal bundle that is impossible to split.
65+ //
66+ // This can only happen with an early use and a late def, so we round
67+ // the start of each range containing a fixed def up to the start of
68+ // its instruction to detect overlaps.
69+ let adjust_range_start = |bundle_idx, range : CodeRange | {
70+ if self . bundles [ bundle_idx] . cached_fixed_def ( ) {
71+ ProgPoint :: before ( range. from . inst ( ) )
72+ } else {
73+ range. from
74+ }
75+ } ;
76+
6177 // Check for overlap in LiveRanges and for conflicting
6278 // requirements.
6379 let ranges_from = & self . bundles [ from] . ranges [ ..] ;
@@ -76,9 +92,11 @@ impl<'a, F: Function> Env<'a, F> {
7692 return false ;
7793 }
7894
79- if ranges_from[ idx_from] . range . from >= ranges_to[ idx_to] . range . to {
95+ if adjust_range_start ( from , ranges_from[ idx_from] . range ) >= ranges_to[ idx_to] . range . to {
8096 idx_to += 1 ;
81- } else if ranges_to[ idx_to] . range . from >= ranges_from[ idx_from] . range . to {
97+ } else if adjust_range_start ( to, ranges_to[ idx_to] . range )
98+ >= ranges_from[ idx_from] . range . to
99+ {
82100 idx_from += 1 ;
83101 } else {
84102 // Overlap -- cannot merge.
@@ -91,15 +109,6 @@ impl<'a, F: Function> Env<'a, F> {
91109 }
92110 }
93111
94- // Avoid merging if either side has a fixed-reg def: this can
95- // result in an impossible-to-solve allocation problem if
96- // there is a fixed-reg use in the same reg on the same
97- // instruction.
98- if self . bundles [ from] . cached_fixed_def ( ) || self . bundles [ to] . cached_fixed_def ( ) {
99- trace ! ( " -> one bundle has a fixed def; aborting merge" ) ;
100- return false ;
101- }
102-
103112 // Check for a requirements conflict.
104113 if self . bundles [ from] . cached_stack ( )
105114 || self . bundles [ from] . cached_fixed ( )
@@ -152,6 +161,9 @@ impl<'a, F: Function> Env<'a, F> {
152161 if self . bundles [ from] . cached_fixed ( ) {
153162 self . bundles [ to] . set_cached_fixed ( ) ;
154163 }
164+ if self . bundles [ from] . cached_fixed_def ( ) {
165+ self . bundles [ to] . set_cached_fixed_def ( ) ;
166+ }
155167
156168 return true ;
157169 }
@@ -218,6 +230,9 @@ impl<'a, F: Function> Env<'a, F> {
218230 if self . bundles [ from] . cached_fixed ( ) {
219231 self . bundles [ to] . set_cached_fixed ( ) ;
220232 }
233+ if self . bundles [ from] . cached_fixed_def ( ) {
234+ self . bundles [ to] . set_cached_fixed_def ( ) ;
235+ }
221236
222237 true
223238 }
0 commit comments