95
95
//! [previous attempt]: https://github.com/rust-lang/rust/pull/47954
96
96
//! [subsequent approach]: https://github.com/rust-lang/rust/pull/71003
97
97
98
- use crate :: dataflow:: { self , Analysis } ;
98
+ use crate :: dataflow:: impls:: { MaybeInitializedLocals , MaybeLiveLocals } ;
99
+ use crate :: dataflow:: Analysis ;
99
100
use crate :: {
100
101
transform:: { MirPass , MirSource } ,
101
102
util:: { dump_mir, PassWhere } ,
102
103
} ;
103
- use dataflow :: impls :: { MaybeInitializedLocals , MaybeLiveLocals } ;
104
+ use itertools :: Itertools ;
104
105
use rustc_data_structures:: unify:: { InPlaceUnificationTable , UnifyKey } ;
105
106
use rustc_index:: {
106
107
bit_set:: { BitMatrix , BitSet } ,
@@ -255,12 +256,14 @@ impl Replacements<'tcx> {
255
256
256
257
// We still return `Err` in any case, as `src` and `dest` do not need to be unified
257
258
// *again*.
259
+ trace ! ( "push({:?}): already unified" , candidate) ;
258
260
return Err ( ( ) ) ;
259
261
}
260
262
261
263
let entry = & mut self . map [ candidate. src ] ;
262
264
if entry. is_some ( ) {
263
265
// We're already replacing `src` with something else, so this candidate is out.
266
+ trace ! ( "push({:?}): src already has replacement" , candidate) ;
264
267
return Err ( ( ) ) ;
265
268
}
266
269
@@ -270,6 +273,7 @@ impl Replacements<'tcx> {
270
273
self . kill . insert ( candidate. src ) ;
271
274
self . kill . insert ( candidate. dest . local ) ;
272
275
276
+ trace ! ( "push({:?}): accepted" , candidate) ;
273
277
Ok ( ( ) )
274
278
}
275
279
@@ -521,7 +525,7 @@ impl Conflicts<'a> {
521
525
522
526
trace ! ( "record conflicts at {:?}" , loc) ;
523
527
524
- this. record_conflicts ( & mut live_and_init_locals[ statement_index] ) ;
528
+ this. record_dataflow_conflicts ( & mut live_and_init_locals[ statement_index] ) ;
525
529
}
526
530
527
531
init. seek_to_block_end ( block) ;
@@ -530,13 +534,13 @@ impl Conflicts<'a> {
530
534
conflicts. intersect ( live. get ( ) ) ;
531
535
trace ! ( "record conflicts at end of {:?}" , block) ;
532
536
533
- this. record_conflicts ( & mut conflicts) ;
537
+ this. record_dataflow_conflicts ( & mut conflicts) ;
534
538
}
535
539
536
540
this
537
541
}
538
542
539
- fn record_conflicts ( & mut self , new_conflicts : & mut BitSet < Local > ) {
543
+ fn record_dataflow_conflicts ( & mut self , new_conflicts : & mut BitSet < Local > ) {
540
544
// Remove all locals that are not candidates.
541
545
new_conflicts. intersect ( self . relevant_locals ) ;
542
546
@@ -545,6 +549,12 @@ impl Conflicts<'a> {
545
549
}
546
550
}
547
551
552
+ fn record_local_conflict ( & mut self , a : Local , b : Local , why : & str ) {
553
+ trace ! ( "conflict {:?} <-> {:?} due to {}" , a, b, why) ;
554
+ self . matrix . insert ( a, b) ;
555
+ self . matrix . insert ( b, a) ;
556
+ }
557
+
548
558
/// Records locals that must not overlap during the evaluation of `stmt`. These locals conflict
549
559
/// and must not be merged.
550
560
fn record_statement_conflicts ( & mut self , stmt : & Statement < ' _ > ) {
@@ -561,8 +571,11 @@ impl Conflicts<'a> {
561
571
if !in_place. is_indirect ( ) {
562
572
for out_place in & * asm. outputs {
563
573
if !out_place. is_indirect ( ) && !in_place. is_indirect ( ) {
564
- self . matrix . insert ( in_place. local , out_place. local ) ;
565
- self . matrix . insert ( out_place. local , in_place. local ) ;
574
+ self . record_local_conflict (
575
+ in_place. local ,
576
+ out_place. local ,
577
+ "aliasing llvm_asm! operands" ,
578
+ ) ;
566
579
}
567
580
}
568
581
}
@@ -585,16 +598,22 @@ impl Conflicts<'a> {
585
598
TerminatorKind :: DropAndReplace { location, value, target : _, unwind : _ } => {
586
599
if let Some ( place) = value. place ( ) {
587
600
if !place. is_indirect ( ) && !location. is_indirect ( ) {
588
- self . matrix . insert ( place. local , location. local ) ;
589
- self . matrix . insert ( location. local , place. local ) ;
601
+ self . record_local_conflict (
602
+ place. local ,
603
+ location. local ,
604
+ "DropAndReplace operand overlap" ,
605
+ ) ;
590
606
}
591
607
}
592
608
}
593
609
TerminatorKind :: Yield { value, resume : _, resume_arg, drop : _ } => {
594
610
if let Some ( place) = value. place ( ) {
595
611
if !place. is_indirect ( ) && !resume_arg. is_indirect ( ) {
596
- self . matrix . insert ( place. local , resume_arg. local ) ;
597
- self . matrix . insert ( resume_arg. local , place. local ) ;
612
+ self . record_local_conflict (
613
+ place. local ,
614
+ resume_arg. local ,
615
+ "Yield operand overlap" ,
616
+ ) ;
598
617
}
599
618
}
600
619
}
@@ -609,8 +628,11 @@ impl Conflicts<'a> {
609
628
for arg in args. iter ( ) . chain ( Some ( func) ) {
610
629
if let Some ( place) = arg. place ( ) {
611
630
if !place. is_indirect ( ) && !dest_place. is_indirect ( ) {
612
- self . matrix . insert ( dest_place. local , place. local ) ;
613
- self . matrix . insert ( place. local , dest_place. local ) ;
631
+ self . record_local_conflict (
632
+ dest_place. local ,
633
+ place. local ,
634
+ "call dest/arg overlap" ,
635
+ ) ;
614
636
}
615
637
}
616
638
}
@@ -639,8 +661,11 @@ impl Conflicts<'a> {
639
661
InlineAsmOperand :: In { reg : _, value } => {
640
662
if let Some ( p) = value. place ( ) {
641
663
if !p. is_indirect ( ) && !dest_place. is_indirect ( ) {
642
- self . matrix . insert ( p. local , dest_place. local ) ;
643
- self . matrix . insert ( dest_place. local , p. local ) ;
664
+ self . record_local_conflict (
665
+ p. local ,
666
+ dest_place. local ,
667
+ "asm! operand overlap" ,
668
+ ) ;
644
669
}
645
670
}
646
671
}
@@ -650,8 +675,11 @@ impl Conflicts<'a> {
650
675
place : Some ( place) ,
651
676
} => {
652
677
if !place. is_indirect ( ) && !dest_place. is_indirect ( ) {
653
- self . matrix . insert ( place. local , dest_place. local ) ;
654
- self . matrix . insert ( dest_place. local , place. local ) ;
678
+ self . record_local_conflict (
679
+ place. local ,
680
+ dest_place. local ,
681
+ "asm! operand overlap" ,
682
+ ) ;
655
683
}
656
684
}
657
685
InlineAsmOperand :: InOut {
@@ -662,15 +690,21 @@ impl Conflicts<'a> {
662
690
} => {
663
691
if let Some ( place) = in_value. place ( ) {
664
692
if !place. is_indirect ( ) && !dest_place. is_indirect ( ) {
665
- self . matrix . insert ( place. local , dest_place. local ) ;
666
- self . matrix . insert ( dest_place. local , place. local ) ;
693
+ self . record_local_conflict (
694
+ place. local ,
695
+ dest_place. local ,
696
+ "asm! operand overlap" ,
697
+ ) ;
667
698
}
668
699
}
669
700
670
701
if let Some ( place) = out_place {
671
702
if !place. is_indirect ( ) && !dest_place. is_indirect ( ) {
672
- self . matrix . insert ( place. local , dest_place. local ) ;
673
- self . matrix . insert ( dest_place. local , place. local ) ;
703
+ self . record_local_conflict (
704
+ place. local ,
705
+ dest_place. local ,
706
+ "asm! operand overlap" ,
707
+ ) ;
674
708
}
675
709
}
676
710
}
@@ -736,6 +770,10 @@ impl Conflicts<'a> {
736
770
// FIXME: This might be somewhat slow. Conflict graphs are undirected, maybe we can use
737
771
// something with union-find to speed this up?
738
772
773
+ trace ! ( "unify({:?}, {:?})" , a, b) ;
774
+ trace ! ( "{:?} conflicts: {:?}" , a, self . matrix. iter( a) . format( ", " ) ) ;
775
+ trace ! ( "{:?} conflicts: {:?}" , b, self . matrix. iter( b) . format( ", " ) ) ;
776
+
739
777
// Make all locals that conflict with `a` also conflict with `b`, and vice versa.
740
778
self . unify_cache . clear ( ) ;
741
779
for conflicts_with_a in self . matrix . iter ( a) {
0 commit comments