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
@@ -535,7 +539,7 @@ impl Conflicts<'a> {
535
539
536
540
trace ! ( "record conflicts at {:?}" , loc) ;
537
541
538
- this. record_conflicts ( & mut live_and_init_locals[ statement_index] ) ;
542
+ this. record_dataflow_conflicts ( & mut live_and_init_locals[ statement_index] ) ;
539
543
}
540
544
541
545
init. seek_to_block_end ( block) ;
@@ -544,13 +548,13 @@ impl Conflicts<'a> {
544
548
conflicts. intersect ( live. get ( ) ) ;
545
549
trace ! ( "record conflicts at end of {:?}" , block) ;
546
550
547
- this. record_conflicts ( & mut conflicts) ;
551
+ this. record_dataflow_conflicts ( & mut conflicts) ;
548
552
}
549
553
550
554
this
551
555
}
552
556
553
- fn record_conflicts ( & mut self , new_conflicts : & mut BitSet < Local > ) {
557
+ fn record_dataflow_conflicts ( & mut self , new_conflicts : & mut BitSet < Local > ) {
554
558
// Remove all locals that are not candidates.
555
559
new_conflicts. intersect ( self . relevant_locals ) ;
556
560
@@ -559,6 +563,12 @@ impl Conflicts<'a> {
559
563
}
560
564
}
561
565
566
+ fn record_local_conflict ( & mut self , a : Local , b : Local , why : & str ) {
567
+ trace ! ( "conflict {:?} <-> {:?} due to {}" , a, b, why) ;
568
+ self . matrix . insert ( a, b) ;
569
+ self . matrix . insert ( b, a) ;
570
+ }
571
+
562
572
/// Records locals that must not overlap during the evaluation of `stmt`. These locals conflict
563
573
/// and must not be merged.
564
574
fn record_statement_conflicts ( & mut self , stmt : & Statement < ' _ > ) {
@@ -575,8 +585,11 @@ impl Conflicts<'a> {
575
585
if !in_place. is_indirect ( ) {
576
586
for out_place in & * asm. outputs {
577
587
if !out_place. is_indirect ( ) && !in_place. is_indirect ( ) {
578
- self . matrix . insert ( in_place. local , out_place. local ) ;
579
- self . matrix . insert ( out_place. local , in_place. local ) ;
588
+ self . record_local_conflict (
589
+ in_place. local ,
590
+ out_place. local ,
591
+ "aliasing llvm_asm! operands" ,
592
+ ) ;
580
593
}
581
594
}
582
595
}
@@ -599,16 +612,22 @@ impl Conflicts<'a> {
599
612
TerminatorKind :: DropAndReplace { location, value, target : _, unwind : _ } => {
600
613
if let Some ( place) = value. place ( ) {
601
614
if !place. is_indirect ( ) && !location. is_indirect ( ) {
602
- self . matrix . insert ( place. local , location. local ) ;
603
- self . matrix . insert ( location. local , place. local ) ;
615
+ self . record_local_conflict (
616
+ place. local ,
617
+ location. local ,
618
+ "DropAndReplace operand overlap" ,
619
+ ) ;
604
620
}
605
621
}
606
622
}
607
623
TerminatorKind :: Yield { value, resume : _, resume_arg, drop : _ } => {
608
624
if let Some ( place) = value. place ( ) {
609
625
if !place. is_indirect ( ) && !resume_arg. is_indirect ( ) {
610
- self . matrix . insert ( place. local , resume_arg. local ) ;
611
- self . matrix . insert ( resume_arg. local , place. local ) ;
626
+ self . record_local_conflict (
627
+ place. local ,
628
+ resume_arg. local ,
629
+ "Yield operand overlap" ,
630
+ ) ;
612
631
}
613
632
}
614
633
}
@@ -623,8 +642,11 @@ impl Conflicts<'a> {
623
642
for arg in args. iter ( ) . chain ( Some ( func) ) {
624
643
if let Some ( place) = arg. place ( ) {
625
644
if !place. is_indirect ( ) && !dest_place. is_indirect ( ) {
626
- self . matrix . insert ( dest_place. local , place. local ) ;
627
- self . matrix . insert ( place. local , dest_place. local ) ;
645
+ self . record_local_conflict (
646
+ dest_place. local ,
647
+ place. local ,
648
+ "call dest/arg overlap" ,
649
+ ) ;
628
650
}
629
651
}
630
652
}
@@ -653,8 +675,11 @@ impl Conflicts<'a> {
653
675
InlineAsmOperand :: In { reg : _, value } => {
654
676
if let Some ( p) = value. place ( ) {
655
677
if !p. is_indirect ( ) && !dest_place. is_indirect ( ) {
656
- self . matrix . insert ( p. local , dest_place. local ) ;
657
- self . matrix . insert ( dest_place. local , p. local ) ;
678
+ self . record_local_conflict (
679
+ p. local ,
680
+ dest_place. local ,
681
+ "asm! operand overlap" ,
682
+ ) ;
658
683
}
659
684
}
660
685
}
@@ -664,8 +689,11 @@ impl Conflicts<'a> {
664
689
place : Some ( place) ,
665
690
} => {
666
691
if !place. is_indirect ( ) && !dest_place. is_indirect ( ) {
667
- self . matrix . insert ( place. local , dest_place. local ) ;
668
- self . matrix . insert ( dest_place. local , place. local ) ;
692
+ self . record_local_conflict (
693
+ place. local ,
694
+ dest_place. local ,
695
+ "asm! operand overlap" ,
696
+ ) ;
669
697
}
670
698
}
671
699
InlineAsmOperand :: InOut {
@@ -676,15 +704,21 @@ impl Conflicts<'a> {
676
704
} => {
677
705
if let Some ( place) = in_value. place ( ) {
678
706
if !place. is_indirect ( ) && !dest_place. is_indirect ( ) {
679
- self . matrix . insert ( place. local , dest_place. local ) ;
680
- self . matrix . insert ( dest_place. local , place. local ) ;
707
+ self . record_local_conflict (
708
+ place. local ,
709
+ dest_place. local ,
710
+ "asm! operand overlap" ,
711
+ ) ;
681
712
}
682
713
}
683
714
684
715
if let Some ( place) = out_place {
685
716
if !place. is_indirect ( ) && !dest_place. is_indirect ( ) {
686
- self . matrix . insert ( place. local , dest_place. local ) ;
687
- self . matrix . insert ( dest_place. local , place. local ) ;
717
+ self . record_local_conflict (
718
+ place. local ,
719
+ dest_place. local ,
720
+ "asm! operand overlap" ,
721
+ ) ;
688
722
}
689
723
}
690
724
}
@@ -750,6 +784,10 @@ impl Conflicts<'a> {
750
784
// FIXME: This might be somewhat slow. Conflict graphs are undirected, maybe we can use
751
785
// something with union-find to speed this up?
752
786
787
+ trace ! ( "unify({:?}, {:?})" , a, b) ;
788
+ trace ! ( "{:?} conflicts: {:?}" , a, self . matrix. iter( a) . format( ", " ) ) ;
789
+ trace ! ( "{:?} conflicts: {:?}" , b, self . matrix. iter( b) . format( ", " ) ) ;
790
+
753
791
// Make all locals that conflict with `a` also conflict with `b`, and vice versa.
754
792
self . unify_cache . clear ( ) ;
755
793
for conflicts_with_a in self . matrix . iter ( a) {
0 commit comments