@@ -456,7 +456,7 @@ func (state *debugState) liveness() []*BlockDebug {
456
456
457
457
// Build the starting state for the block from the final
458
458
// state of its predecessors.
459
- startState , startValid := state .mergePredecessors (b , blockLocs )
459
+ startState , startValid := state .mergePredecessors (b , blockLocs , nil )
460
460
changed := false
461
461
if state .loggingEnabled {
462
462
state .logf ("Processing %v, initial state:\n %v" , b , state .stateString (state .currentState ))
@@ -518,9 +518,13 @@ func (state *debugState) liveness() []*BlockDebug {
518
518
}
519
519
520
520
// mergePredecessors takes the end state of each of b's predecessors and
521
- // intersects them to form the starting state for b. It returns that state in
522
- // the BlockDebug, and fills state.currentState with it.
523
- func (state * debugState ) mergePredecessors (b * Block , blockLocs []* BlockDebug ) ([]liveSlot , bool ) {
521
+ // intersects them to form the starting state for b. It puts that state in
522
+ // blockLocs, and fills state.currentState with it. If convenient, it returns
523
+ // a reused []liveSlot, true that represents the starting state.
524
+ // If previousBlock is non-nil, it registers changes vs. that block's end
525
+ // state in state.changedVars. Note that previousBlock will often not be a
526
+ // predecessor.
527
+ func (state * debugState ) mergePredecessors (b * Block , blockLocs []* BlockDebug , previousBlock * Block ) ([]liveSlot , bool ) {
524
528
// Filter out back branches.
525
529
var predsBuf [10 ]* Block
526
530
preds := predsBuf [:0 ]
@@ -538,31 +542,68 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([
538
542
state .logf ("Merging %v into %v\n " , preds2 , b )
539
543
}
540
544
545
+ // TODO all the calls to this are overkill; only need to do this for slots that are not present in the merge.
546
+ markChangedVars := func (slots []liveSlot ) {
547
+ for _ , live := range slots {
548
+ state .changedVars .add (ID (state .slotVars [live .slot ]))
549
+ }
550
+ }
551
+
541
552
if len (preds ) == 0 {
553
+ if previousBlock != nil {
554
+ // Mark everything in previous block as changed because it is not a predecessor.
555
+ markChangedVars (blockLocs [previousBlock .ID ].endState )
556
+ }
542
557
state .currentState .reset (nil )
543
558
return nil , true
544
559
}
545
560
546
561
p0 := blockLocs [preds [0 ].ID ].endState
547
562
if len (preds ) == 1 {
563
+ if previousBlock != nil && preds [0 ].ID != previousBlock .ID {
564
+ // Mark everything in previous block as changed because it is not a predecessor.
565
+ markChangedVars (blockLocs [previousBlock .ID ].endState )
566
+ }
548
567
state .currentState .reset (p0 )
549
568
return p0 , true
550
569
}
551
570
571
+ baseID := preds [0 ].ID
572
+ baseState := p0
573
+
574
+ // If previous block is not a predecessor, its location information changes at boundary with this block.
575
+ previousBlockIsNotPredecessor := previousBlock != nil // If it's nil, no info to change.
576
+
577
+ if previousBlock != nil {
578
+ // Try to use previousBlock as the base state
579
+ // if possible.
580
+ for _ , pred := range preds [1 :] {
581
+ if pred .ID == previousBlock .ID {
582
+ baseID = pred .ID
583
+ baseState = blockLocs [pred .ID ].endState
584
+ previousBlockIsNotPredecessor = false
585
+ break
586
+ }
587
+ }
588
+ }
589
+
552
590
if state .loggingEnabled {
553
- state .logf ("Starting %v with state from %v:\n %v" , b , preds [ 0 ] , state .blockEndStateString (blockLocs [preds [ 0 ]. ID ]))
591
+ state .logf ("Starting %v with state from b %v:\n %v" , b , baseID , state .blockEndStateString (blockLocs [baseID ]))
554
592
}
555
593
556
594
slotLocs := state .currentState .slots
557
- for _ , predSlot := range p0 {
595
+ for _ , predSlot := range baseState {
558
596
slotLocs [predSlot .slot ] = VarLoc {predSlot .Registers , predSlot .StackOffset }
559
597
state .liveCount [predSlot .slot ] = 1
560
598
}
561
- for i := 1 ; i < len (preds ); i ++ {
599
+ for _ , pred := range preds {
600
+ if pred .ID == baseID {
601
+ continue
602
+ }
562
603
if state .loggingEnabled {
563
- state .logf ("Merging in state from %v:\n %v" , preds [ i ] , state .blockEndStateString (blockLocs [preds [ i ] .ID ]))
604
+ state .logf ("Merging in state from %v:\n %v" , pred , state .blockEndStateString (blockLocs [pred .ID ]))
564
605
}
565
- for _ , predSlot := range blockLocs [preds [ i ] .ID ].endState {
606
+ for _ , predSlot := range blockLocs [pred .ID ].endState {
566
607
state .liveCount [predSlot .slot ]++
567
608
liveLoc := slotLocs [predSlot .slot ]
568
609
if ! liveLoc .onStack () || ! predSlot .onStack () || liveLoc .StackOffset != predSlot .StackOffset {
@@ -577,7 +618,7 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([
577
618
// final state, and reuse it if so. In principle it could match any,
578
619
// but it's probably not worth checking more than the first.
579
620
unchanged := true
580
- for _ , predSlot := range p0 {
621
+ for _ , predSlot := range baseState {
581
622
if state .liveCount [predSlot .slot ] != len (preds ) ||
582
623
slotLocs [predSlot .slot ].Registers != predSlot .Registers ||
583
624
slotLocs [predSlot .slot ].StackOffset != predSlot .StackOffset {
@@ -587,10 +628,14 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([
587
628
}
588
629
if unchanged {
589
630
if state .loggingEnabled {
590
- state .logf ("After merge, %v matches %v exactly.\n " , b , preds [ 0 ] )
631
+ state .logf ("After merge, %v matches b %v exactly.\n " , b , baseID )
591
632
}
592
- state .currentState .reset (p0 )
593
- return p0 , true
633
+ if previousBlockIsNotPredecessor {
634
+ // Mark everything in previous block as changed because it is not a predecessor.
635
+ markChangedVars (blockLocs [previousBlock .ID ].endState )
636
+ }
637
+ state .currentState .reset (baseState )
638
+ return baseState , true
594
639
}
595
640
596
641
for reg := range state .currentState .registers {
@@ -599,7 +644,7 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([
599
644
600
645
// A slot is live if it was seen in all predecessors, and they all had
601
646
// some storage in common.
602
- for _ , predSlot := range p0 {
647
+ for _ , predSlot := range baseState {
603
648
slotLoc := slotLocs [predSlot .slot ]
604
649
605
650
if state .liveCount [predSlot .slot ] != len (preds ) {
@@ -616,10 +661,15 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([
616
661
}
617
662
reg := uint8 (bits .TrailingZeros64 (mask ))
618
663
mask &^= 1 << reg
619
-
620
664
state .currentState .registers [reg ] = append (state .currentState .registers [reg ], predSlot .slot )
621
665
}
622
666
}
667
+
668
+ if previousBlockIsNotPredecessor {
669
+ // Mark everything in previous block as changed because it is not a predecessor.
670
+ markChangedVars (blockLocs [previousBlock .ID ].endState )
671
+
672
+ }
623
673
return nil , false
624
674
}
625
675
@@ -827,13 +877,19 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
827
877
// Run through the function in program text order, building up location
828
878
// lists as we go. The heavy lifting has mostly already been done.
829
879
880
+ var prevBlock * Block
830
881
for _ , b := range state .f .Blocks {
882
+ state .mergePredecessors (b , blockLocs , prevBlock )
883
+
884
+ // Handle any differences among predecessor blocks and previous block (perhaps not a predecessor)
885
+ for _ , varID := range state .changedVars .contents () {
886
+ state .updateVar (VarID (varID ), b , BlockStart )
887
+ }
888
+
831
889
if ! blockLocs [b .ID ].relevant {
832
890
continue
833
891
}
834
892
835
- state .mergePredecessors (b , blockLocs )
836
-
837
893
zeroWidthPending := false
838
894
apcChangedSize := 0 // size of changedVars for leading Args, Phi, ClosurePtr
839
895
// expect to see values in pattern (apc)* (zerowidth|real)*
@@ -881,6 +937,8 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
881
937
state .updateVar (VarID (varID ), b , BlockEnd )
882
938
}
883
939
}
940
+
941
+ prevBlock = b
884
942
}
885
943
886
944
if state .loggingEnabled {
0 commit comments