@@ -267,10 +267,11 @@ type state struct {
267
267
// symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
268
268
varsyms map [* Node ]interface {}
269
269
270
- // starting values. Memory, stack pointer, and globals pointer
270
+ // starting values. Memory, stack pointer, globals pointer, reusable dead value
271
271
startmem * ssa.Value
272
272
sp * ssa.Value
273
273
sb * ssa.Value
274
+ dead * ssa.Value
274
275
275
276
// line number stack. The current line number is top of stack
276
277
line []int32
@@ -279,8 +280,8 @@ type state struct {
279
280
// Used to deduplicate panic calls.
280
281
panics map [funcLine ]* ssa.Block
281
282
282
- // list of FwdRef values.
283
- fwdRefs []* ssa. Value
283
+ fwdRefs [] * ssa. Value // list of FwdRef values
284
+ reachable []bool // reachable[b.ID] is whether b.ID is reachable; used during fwdRef resolution
284
285
285
286
// list of PPARAMOUT (return) variables. Does not include PPARAM|PHEAP vars.
286
287
returns []* Node
@@ -3741,6 +3742,13 @@ func (s *state) mem() *ssa.Value {
3741
3742
return s .variable (& memVar , ssa .TypeMem )
3742
3743
}
3743
3744
3745
+ func (s * state ) deadval () * ssa.Value {
3746
+ if s .dead == nil {
3747
+ s .dead = s .entryNewValue0 (ssa .OpUnknown , nil ) // type doesn't matter
3748
+ }
3749
+ return s .dead
3750
+ }
3751
+
3744
3752
func (s * state ) linkForwardReferences () {
3745
3753
// Build SSA graph. Each variable on its first use in a basic block
3746
3754
// leaves a FwdRef in that block representing the incoming value
@@ -3753,11 +3761,19 @@ func (s *state) linkForwardReferences() {
3753
3761
// completely built. That way we can avoid the notion of "sealed"
3754
3762
// blocks.
3755
3763
// - Phi optimization is a separate pass (in ../ssa/phielim.go).
3764
+ s .reachable = ssa .ReachableBlocks (s .f )
3756
3765
for len (s .fwdRefs ) > 0 {
3757
3766
v := s .fwdRefs [len (s .fwdRefs )- 1 ]
3758
3767
s .fwdRefs = s .fwdRefs [:len (s .fwdRefs )- 1 ]
3759
- s .resolveFwdRef (v )
3768
+ if s .reachable [v .Block .ID ] {
3769
+ s .resolveFwdRef (v )
3770
+ } else {
3771
+ v .Op = ssa .OpUnknown
3772
+ v .Aux = nil
3773
+ v .AuxInt = 0
3774
+ }
3760
3775
}
3776
+ s .reachable = nil
3761
3777
}
3762
3778
3763
3779
// resolveFwdRef modifies v to be the variable's value at the start of its block.
@@ -3814,6 +3830,9 @@ func (s *state) resolveFwdRef(v *ssa.Value) {
3814
3830
if a == w {
3815
3831
continue // already have this witness
3816
3832
}
3833
+ if a .Op == ssa .OpUnknown {
3834
+ continue // dead value, ignore
3835
+ }
3817
3836
if w != nil {
3818
3837
// two witnesses, need a phi value
3819
3838
v .Op = ssa .OpPhi
@@ -3837,6 +3856,10 @@ func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int
3837
3856
return v
3838
3857
}
3839
3858
// The variable is not defined by b and we haven't looked it up yet.
3859
+ // If b is dead, don't bother, just return a (re-usable) placeholder.
3860
+ if ! s .reachable [b .ID ] {
3861
+ return s .deadval ()
3862
+ }
3840
3863
// If b has exactly one predecessor, loop to look it up there.
3841
3864
// Otherwise, give up and insert a new FwdRef and resolve it later.
3842
3865
if len (b .Preds ) != 1 {
0 commit comments