@@ -4,8 +4,7 @@ use rustc_abi::Variants;
44use rustc_data_structures:: fx:: FxHashSet ;
55use rustc_middle:: bug;
66use rustc_middle:: mir:: {
7- BasicBlock , BasicBlockData , BasicBlocks , Body , Local , Operand , Rvalue , StatementKind ,
8- TerminatorKind ,
7+ BasicBlockData , Body , Local , Operand , Rvalue , StatementKind , TerminatorKind ,
98} ;
109use rustc_middle:: ty:: layout:: TyAndLayout ;
1110use rustc_middle:: ty:: { Ty , TyCtxt } ;
@@ -125,43 +124,10 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
125124 unreachable_targets. push ( index) ;
126125 }
127126 }
128- let otherwise_is_empty_unreachable =
129- body. basic_blocks [ targets. otherwise ( ) ] . is_empty_unreachable ( ) ;
130- fn check_successors ( basic_blocks : & BasicBlocks < ' _ > , bb : BasicBlock ) -> bool {
131- // After resolving https://github.com/llvm/llvm-project/issues/78578,
132- // We can remove this check.
133- // The main issue here is that `early-tailduplication` causes compile time overhead
134- // and potential performance problems.
135- // Simply put, when encounter a switch (indirect branch) statement,
136- // `early-tailduplication` tries to duplicate the switch branch statement with BB
137- // into (each) predecessors. This makes CFG very complex.
138- // We can understand it as it transforms the following code
139- // ```rust
140- // match a { ... many cases };
141- // match b { ... many cases };
142- // ```
143- // into
144- // ```rust
145- // match a { ... many match b { goto BB cases } }
146- // ... BB cases
147- // ```
148- // Abandon this transformation when it is possible (the best effort)
149- // to encounter the problem.
150- let mut successors = basic_blocks[ bb] . terminator ( ) . successors ( ) ;
151- let Some ( first_successor) = successors. next ( ) else { return true } ;
152- if successors. next ( ) . is_some ( ) {
153- return true ;
154- }
155- if let TerminatorKind :: SwitchInt { .. } =
156- & basic_blocks[ first_successor] . terminator ( ) . kind
157- {
158- return false ;
159- } ;
160- true
161- }
127+
162128 // If and only if there is a variant that does not have a branch set, change the
163129 // current of otherwise as the variant branch and set otherwise to unreachable. It
164- // transforms following code
130+ // transforms the following code
165131 // ```rust
166132 // match c {
167133 // Ordering::Less => 1,
@@ -177,22 +143,16 @@ impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
177143 // Ordering::Greater => 3,
178144 // }
179145 // ```
180- let otherwise_is_last_variant = !otherwise_is_empty_unreachable
181- && allowed_variants. len ( ) == 1
182- // Despite the LLVM issue, we hope that small enum can still be transformed.
183- // This is valuable for both `a <= b` and `if let Some/Ok(v)`.
184- && ( targets. all_targets ( ) . len ( ) <= 3
185- || check_successors ( & body. basic_blocks , targets. otherwise ( ) ) ) ;
186- let replace_otherwise_to_unreachable = otherwise_is_last_variant
187- || ( !otherwise_is_empty_unreachable && allowed_variants. is_empty ( ) ) ;
188-
146+ let replace_otherwise_to_unreachable = allowed_variants. len ( ) <= 1
147+ && !body. basic_blocks [ targets. otherwise ( ) ] . is_empty_unreachable ( ) ;
189148 if unreachable_targets. is_empty ( ) && !replace_otherwise_to_unreachable {
190149 continue ;
191150 }
192151
193152 let unreachable_block = patch. unreachable_no_cleanup_block ( ) ;
194153 let mut targets = targets. clone ( ) ;
195154 if replace_otherwise_to_unreachable {
155+ let otherwise_is_last_variant = !allowed_variants. is_empty ( ) ;
196156 if otherwise_is_last_variant {
197157 // We have checked that `allowed_variants` has only one element.
198158 #[ allow( rustc:: potential_query_instability) ]
0 commit comments