@@ -90,7 +90,11 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
90
90
} ;
91
91
92
92
for bb in body. basic_blocks . indices ( ) {
93
- finder. start_from_switch ( bb) ;
93
+ let old_len = finder. opportunities . len ( ) ;
94
+ // If we have any const-eval errors discard any opportunities found
95
+ if finder. start_from_switch ( bb) . is_none ( ) {
96
+ finder. opportunities . truncate ( old_len) ;
97
+ }
94
98
}
95
99
96
100
let opportunities = finder. opportunities ;
@@ -172,8 +176,21 @@ impl<'a> ConditionSet<'a> {
172
176
self . iter ( ) . filter ( move |c| c. matches ( value) )
173
177
}
174
178
175
- fn map ( self , arena : & ' a DroplessArena , f : impl Fn ( Condition ) -> Condition ) -> ConditionSet < ' a > {
176
- ConditionSet ( arena. alloc_from_iter ( self . iter ( ) . map ( f) ) )
179
+ fn map (
180
+ self ,
181
+ arena : & ' a DroplessArena ,
182
+ f : impl Fn ( Condition ) -> Option < Condition > ,
183
+ ) -> Option < ConditionSet < ' a > > {
184
+ let mut all_ok = true ;
185
+ let set = arena. alloc_from_iter ( self . iter ( ) . map_while ( |c| {
186
+ if let Some ( c) = f ( c) {
187
+ Some ( c)
188
+ } else {
189
+ all_ok = false ;
190
+ None
191
+ }
192
+ } ) ) ;
193
+ all_ok. then_some ( ConditionSet ( set) )
177
194
}
178
195
}
179
196
@@ -184,28 +201,28 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
184
201
185
202
/// Recursion entry point to find threading opportunities.
186
203
#[ instrument( level = "trace" , skip( self ) ) ]
187
- fn start_from_switch ( & mut self , bb : BasicBlock ) {
204
+ fn start_from_switch ( & mut self , bb : BasicBlock ) -> Option < ( ) > {
188
205
let bbdata = & self . body [ bb] ;
189
206
if bbdata. is_cleanup || self . loop_headers . contains ( bb) {
190
- return ;
207
+ return Some ( ( ) ) ;
191
208
}
192
- let Some ( ( discr, targets) ) = bbdata. terminator ( ) . kind . as_switch ( ) else { return } ;
193
- let Some ( discr) = discr. place ( ) else { return } ;
209
+ let Some ( ( discr, targets) ) = bbdata. terminator ( ) . kind . as_switch ( ) else { return Some ( ( ) ) } ;
210
+ let Some ( discr) = discr. place ( ) else { return Some ( ( ) ) } ;
194
211
debug ! ( ?discr, ?bb) ;
195
212
196
213
let discr_ty = discr. ty ( self . body , self . tcx ) . ty ;
197
214
let Ok ( discr_layout) = self . ecx . layout_of ( discr_ty) else {
198
- return ;
215
+ return Some ( ( ) ) ;
199
216
} ;
200
217
201
- let Some ( discr) = self . map . find ( discr. as_ref ( ) ) else { return } ;
218
+ let Some ( discr) = self . map . find ( discr. as_ref ( ) ) else { return Some ( ( ) ) } ;
202
219
debug ! ( ?discr) ;
203
220
204
221
let cost = CostChecker :: new ( self . tcx , self . typing_env , None , self . body ) ;
205
222
let mut state = State :: new_reachable ( ) ;
206
223
207
224
let conds = if let Some ( ( value, then, else_) ) = targets. as_static_if ( ) {
208
- let Some ( value) = ScalarInt :: try_from_uint ( value, discr_layout. size ) else { return } ;
225
+ let value = ScalarInt :: try_from_uint ( value, discr_layout. size ) ? ;
209
226
self . arena . alloc_from_iter ( [
210
227
Condition { value, polarity : Polarity :: Eq , target : then } ,
211
228
Condition { value, polarity : Polarity :: Ne , target : else_ } ,
@@ -219,7 +236,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
219
236
let conds = ConditionSet ( conds) ;
220
237
state. insert_value_idx ( discr, conds, & self . map ) ;
221
238
222
- self . find_opportunity ( bb, state, cost, 0 ) ;
239
+ self . find_opportunity ( bb, state, cost, 0 )
223
240
}
224
241
225
242
/// Recursively walk statements backwards from this bb's terminator to find threading
@@ -231,27 +248,27 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
231
248
mut state : State < ConditionSet < ' a > > ,
232
249
mut cost : CostChecker < ' _ , ' tcx > ,
233
250
depth : usize ,
234
- ) {
251
+ ) -> Option < ( ) > {
235
252
// Do not thread through loop headers.
236
253
if self . loop_headers . contains ( bb) {
237
- return ;
254
+ return Some ( ( ) ) ;
238
255
}
239
256
240
257
debug ! ( cost = ?cost. cost( ) ) ;
241
258
for ( statement_index, stmt) in
242
259
self . body . basic_blocks [ bb] . statements . iter ( ) . enumerate ( ) . rev ( )
243
260
{
244
261
if self . is_empty ( & state) {
245
- return ;
262
+ return Some ( ( ) ) ;
246
263
}
247
264
248
265
cost. visit_statement ( stmt, Location { block : bb, statement_index } ) ;
249
266
if cost. cost ( ) > MAX_COST {
250
- return ;
267
+ return Some ( ( ) ) ;
251
268
}
252
269
253
270
// Attempt to turn the `current_condition` on `lhs` into a condition on another place.
254
- self . process_statement ( bb, stmt, & mut state) ;
271
+ self . process_statement ( bb, stmt, & mut state) ? ;
255
272
256
273
// When a statement mutates a place, assignments to that place that happen
257
274
// above the mutation cannot fulfill a condition.
@@ -263,7 +280,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
263
280
}
264
281
265
282
if self . is_empty ( & state) || depth >= MAX_BACKTRACK {
266
- return ;
283
+ return Some ( ( ) ) ;
267
284
}
268
285
269
286
let last_non_rec = self . opportunities . len ( ) ;
@@ -276,9 +293,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
276
293
match term. kind {
277
294
TerminatorKind :: SwitchInt { ref discr, ref targets } => {
278
295
self . process_switch_int ( discr, targets, bb, & mut state) ;
279
- self . find_opportunity ( pred, state, cost, depth + 1 ) ;
296
+ self . find_opportunity ( pred, state, cost, depth + 1 ) ? ;
280
297
}
281
- _ => self . recurse_through_terminator ( pred, || state, & cost, depth) ,
298
+ _ => self . recurse_through_terminator ( pred, || state, & cost, depth) ? ,
282
299
}
283
300
} else if let & [ ref predecessors @ .., last_pred] = & predecessors[ ..] {
284
301
for & pred in predecessors {
@@ -303,12 +320,13 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
303
320
let first = & mut new_tos[ 0 ] ;
304
321
* first = ThreadingOpportunity { chain : vec ! [ bb] , target : first. target } ;
305
322
self . opportunities . truncate ( last_non_rec + 1 ) ;
306
- return ;
323
+ return Some ( ( ) ) ;
307
324
}
308
325
309
326
for op in self . opportunities [ last_non_rec..] . iter_mut ( ) {
310
327
op. chain . push ( bb) ;
311
328
}
329
+ Some ( ( ) )
312
330
}
313
331
314
332
/// Extract the mutated place from a statement.
@@ -422,23 +440,23 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
422
440
lhs : PlaceIndex ,
423
441
rhs : & Operand < ' tcx > ,
424
442
state : & mut State < ConditionSet < ' a > > ,
425
- ) {
443
+ ) -> Option < ( ) > {
426
444
match rhs {
427
445
// If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`.
428
446
Operand :: Constant ( constant) => {
429
- let Some ( constant) =
430
- self . ecx . eval_mir_constant ( & constant. const_ , constant. span , None ) . discard_err ( )
431
- else {
432
- return ;
433
- } ;
447
+ let constant = self
448
+ . ecx
449
+ . eval_mir_constant ( & constant. const_ , constant. span , None )
450
+ . discard_err ( ) ?;
434
451
self . process_constant ( bb, lhs, constant, state) ;
435
452
}
436
453
// Transfer the conditions on the copied rhs.
437
454
Operand :: Move ( rhs) | Operand :: Copy ( rhs) => {
438
- let Some ( rhs) = self . map . find ( rhs. as_ref ( ) ) else { return } ;
455
+ let Some ( rhs) = self . map . find ( rhs. as_ref ( ) ) else { return Some ( ( ) ) } ;
439
456
state. insert_place_idx ( rhs, lhs, & self . map ) ;
440
457
}
441
458
}
459
+ Some ( ( ) )
442
460
}
443
461
444
462
#[ instrument( level = "trace" , skip( self ) ) ]
@@ -448,22 +466,26 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
448
466
lhs_place : & Place < ' tcx > ,
449
467
rhs : & Rvalue < ' tcx > ,
450
468
state : & mut State < ConditionSet < ' a > > ,
451
- ) {
452
- let Some ( lhs) = self . map . find ( lhs_place. as_ref ( ) ) else { return } ;
469
+ ) -> Option < ( ) > {
470
+ let Some ( lhs) = self . map . find ( lhs_place. as_ref ( ) ) else {
471
+ return Some ( ( ) ) ;
472
+ } ;
453
473
match rhs {
454
- Rvalue :: Use ( operand) => self . process_operand ( bb, lhs, operand, state) ,
474
+ Rvalue :: Use ( operand) => self . process_operand ( bb, lhs, operand, state) ? ,
455
475
// Transfer the conditions on the copy rhs.
456
- Rvalue :: CopyForDeref ( rhs) => self . process_operand ( bb, lhs, & Operand :: Copy ( * rhs) , state) ,
476
+ Rvalue :: CopyForDeref ( rhs) => {
477
+ self . process_operand ( bb, lhs, & Operand :: Copy ( * rhs) , state) ?
478
+ }
457
479
Rvalue :: Discriminant ( rhs) => {
458
- let Some ( rhs) = self . map . find_discr ( rhs. as_ref ( ) ) else { return } ;
480
+ let Some ( rhs) = self . map . find_discr ( rhs. as_ref ( ) ) else { return Some ( ( ) ) } ;
459
481
state. insert_place_idx ( rhs, lhs, & self . map ) ;
460
482
}
461
483
// If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`.
462
484
Rvalue :: Aggregate ( box kind, operands) => {
463
485
let agg_ty = lhs_place. ty ( self . body , self . tcx ) . ty ;
464
486
let lhs = match kind {
465
487
// Do not support unions.
466
- AggregateKind :: Adt ( .., Some ( _) ) => return ,
488
+ AggregateKind :: Adt ( .., Some ( _) ) => return Some ( ( ) ) ,
467
489
AggregateKind :: Adt ( _, variant_index, ..) if agg_ty. is_enum ( ) => {
468
490
if let Some ( discr_target) = self . map . apply ( lhs, TrackElem :: Discriminant )
469
491
&& let Some ( discr_value) = self
@@ -476,31 +498,31 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
476
498
if let Some ( idx) = self . map . apply ( lhs, TrackElem :: Variant ( * variant_index) ) {
477
499
idx
478
500
} else {
479
- return ;
501
+ return Some ( ( ) ) ;
480
502
}
481
503
}
482
504
_ => lhs,
483
505
} ;
484
506
for ( field_index, operand) in operands. iter_enumerated ( ) {
485
507
if let Some ( field) = self . map . apply ( lhs, TrackElem :: Field ( field_index) ) {
486
- self . process_operand ( bb, field, operand, state) ;
508
+ self . process_operand ( bb, field, operand, state) ? ;
487
509
}
488
510
}
489
511
}
490
512
// Transfer the conditions on the copy rhs, after inverting the value of the condition.
491
513
Rvalue :: UnaryOp ( UnOp :: Not , Operand :: Move ( place) | Operand :: Copy ( place) ) => {
492
514
let layout = self . ecx . layout_of ( place. ty ( self . body , self . tcx ) . ty ) . unwrap ( ) ;
493
- let Some ( conditions) = state. try_get_idx ( lhs, & self . map ) else { return } ;
494
- let Some ( place) = self . map . find ( place. as_ref ( ) ) else { return } ;
515
+ let Some ( conditions) = state. try_get_idx ( lhs, & self . map ) else { return Some ( ( ) ) } ;
516
+ let Some ( place) = self . map . find ( place. as_ref ( ) ) else { return Some ( ( ) ) } ;
495
517
let conds = conditions. map ( self . arena , |mut cond| {
496
518
cond. value = self
497
519
. ecx
498
520
. unary_op ( UnOp :: Not , & ImmTy :: from_scalar_int ( cond. value , layout) )
499
- . unwrap ( )
521
+ . discard_err ( ) ?
500
522
. to_scalar_int ( )
501
- . unwrap ( ) ;
502
- cond
503
- } ) ;
523
+ . discard_err ( ) ? ;
524
+ Some ( cond)
525
+ } ) ? ;
504
526
state. insert_value_idx ( place, conds, & self . map ) ;
505
527
}
506
528
// We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`.
@@ -510,34 +532,34 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
510
532
box ( Operand :: Move ( place) | Operand :: Copy ( place) , Operand :: Constant ( value) )
511
533
| box ( Operand :: Constant ( value) , Operand :: Move ( place) | Operand :: Copy ( place) ) ,
512
534
) => {
513
- let Some ( conditions) = state. try_get_idx ( lhs, & self . map ) else { return } ;
514
- let Some ( place) = self . map . find ( place. as_ref ( ) ) else { return } ;
535
+ let Some ( conditions) = state. try_get_idx ( lhs, & self . map ) else { return Some ( ( ) ) } ;
536
+ let Some ( place) = self . map . find ( place. as_ref ( ) ) else { return Some ( ( ) ) } ;
515
537
let equals = match op {
516
538
BinOp :: Eq => ScalarInt :: TRUE ,
517
539
BinOp :: Ne => ScalarInt :: FALSE ,
518
- _ => return ,
540
+ _ => return Some ( ( ) ) ,
519
541
} ;
520
542
if value. const_ . ty ( ) . is_floating_point ( ) {
521
543
// Floating point equality does not follow bit-patterns.
522
544
// -0.0 and NaN both have special rules for equality,
523
545
// and therefore we cannot use integer comparisons for them.
524
546
// Avoid handling them, though this could be extended in the future.
525
- return ;
547
+ return Some ( ( ) ) ;
526
548
}
527
- let Some ( value) = value. const_ . try_eval_scalar_int ( self . tcx , self . typing_env )
528
- else {
529
- return ;
530
- } ;
531
- let conds = conditions. map ( self . arena , |c| Condition {
532
- value,
533
- polarity : if c. matches ( equals) { Polarity :: Eq } else { Polarity :: Ne } ,
534
- ..c
535
- } ) ;
549
+ let value = value. const_ . try_eval_scalar_int ( self . tcx , self . typing_env ) ?;
550
+ let conds = conditions. map ( self . arena , |c| {
551
+ Some ( Condition {
552
+ value,
553
+ polarity : if c. matches ( equals) { Polarity :: Eq } else { Polarity :: Ne } ,
554
+ ..c
555
+ } )
556
+ } ) ?;
536
557
state. insert_value_idx ( place, conds, & self . map ) ;
537
558
}
538
559
539
560
_ => { }
540
561
}
562
+ Some ( ( ) )
541
563
}
542
564
543
565
#[ instrument( level = "trace" , skip( self ) ) ]
@@ -546,7 +568,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
546
568
bb : BasicBlock ,
547
569
stmt : & Statement < ' tcx > ,
548
570
state : & mut State < ConditionSet < ' a > > ,
549
- ) {
571
+ ) -> Option < ( ) > {
550
572
let register_opportunity = |c : Condition | {
551
573
debug ! ( ?bb, ?c. target, "register" ) ;
552
574
self . opportunities . push ( ThreadingOpportunity { chain : vec ! [ bb] , target : c. target } )
@@ -559,30 +581,32 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
559
581
// If we expect `discriminant(place) ?= A`,
560
582
// we have an opportunity if `variant_index ?= A`.
561
583
StatementKind :: SetDiscriminant { box place, variant_index } => {
562
- let Some ( discr_target) = self . map . find_discr ( place. as_ref ( ) ) else { return } ;
584
+ let Some ( discr_target) = self . map . find_discr ( place. as_ref ( ) ) else {
585
+ return Some ( ( ) ) ;
586
+ } ;
563
587
let enum_ty = place. ty ( self . body , self . tcx ) . ty ;
564
588
// `SetDiscriminant` guarantees that the discriminant is now `variant_index`.
565
589
// Even if the discriminant write does nothing due to niches, it is UB to set the
566
590
// discriminant when the data does not encode the desired discriminant.
567
- let Some ( discr) =
568
- self . ecx . discriminant_for_variant ( enum_ty, * variant_index) . discard_err ( )
569
- else {
570
- return ;
571
- } ;
591
+ let discr =
592
+ self . ecx . discriminant_for_variant ( enum_ty, * variant_index) . discard_err ( ) ?;
572
593
self . process_immediate ( bb, discr_target, discr, state) ;
573
594
}
574
595
// If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`.
575
596
StatementKind :: Intrinsic ( box NonDivergingIntrinsic :: Assume (
576
597
Operand :: Copy ( place) | Operand :: Move ( place) ,
577
598
) ) => {
578
- let Some ( conditions) = state. try_get ( place. as_ref ( ) , & self . map ) else { return } ;
599
+ let Some ( conditions) = state. try_get ( place. as_ref ( ) , & self . map ) else {
600
+ return Some ( ( ) ) ;
601
+ } ;
579
602
conditions. iter_matches ( ScalarInt :: TRUE ) . for_each ( register_opportunity) ;
580
603
}
581
604
StatementKind :: Assign ( box ( lhs_place, rhs) ) => {
582
- self . process_assign ( bb, lhs_place, rhs, state) ;
605
+ self . process_assign ( bb, lhs_place, rhs, state) ? ;
583
606
}
584
607
_ => { }
585
608
}
609
+ Some ( ( ) )
586
610
}
587
611
588
612
#[ instrument( level = "trace" , skip( self , state, cost) ) ]
@@ -593,7 +617,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
593
617
state : impl FnOnce ( ) -> State < ConditionSet < ' a > > ,
594
618
cost : & CostChecker < ' _ , ' tcx > ,
595
619
depth : usize ,
596
- ) {
620
+ ) -> Option < ( ) > {
597
621
let term = self . body . basic_blocks [ bb] . terminator ( ) ;
598
622
let place_to_flood = match term. kind {
599
623
// We come from a target, so those are not possible.
@@ -608,9 +632,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
608
632
| TerminatorKind :: FalseUnwind { .. }
609
633
| TerminatorKind :: Yield { .. } => bug ! ( "{term:?} invalid" ) ,
610
634
// Cannot reason about inline asm.
611
- TerminatorKind :: InlineAsm { .. } => return ,
635
+ TerminatorKind :: InlineAsm { .. } => return Some ( ( ) ) ,
612
636
// `SwitchInt` is handled specially.
613
- TerminatorKind :: SwitchInt { .. } => return ,
637
+ TerminatorKind :: SwitchInt { .. } => return Some ( ( ) ) ,
614
638
// We can recurse, no thing particular to do.
615
639
TerminatorKind :: Goto { .. } => None ,
616
640
// Flood the overwritten place, and progress through.
@@ -625,7 +649,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
625
649
if let Some ( place_to_flood) = place_to_flood {
626
650
state. flood_with ( place_to_flood. as_ref ( ) , & self . map , ConditionSet :: BOTTOM ) ;
627
651
}
628
- self . find_opportunity ( bb, state, cost. clone ( ) , depth + 1 ) ;
652
+ self . find_opportunity ( bb, state, cost. clone ( ) , depth + 1 )
629
653
}
630
654
631
655
#[ instrument( level = "trace" , skip( self ) ) ]
0 commit comments