diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 87244a6248..a33de438e2 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -234,39 +234,37 @@ func (b *Block) removePred(p *Block) { v.Args[i] = v.Args[n] v.Args[n] = nil // aid GC v.Args = v.Args[:n] - if n == 1 { - v.Op = OpCopy - // Note: this is trickier than it looks. Replacing - // a Phi with a Copy can in general cause problems because - // Phi and Copy don't have exactly the same semantics. - // Phi arguments always come from a predecessor block, - // whereas copies don't. This matters in loops like: - // 1: x = (Phi y) - // y = (Add x 1) - // goto 1 - // If we replace Phi->Copy, we get - // 1: x = (Copy y) - // y = (Add x 1) - // goto 1 - // (Phi y) refers to the *previous* value of y, whereas - // (Copy y) refers to the *current* value of y. - // The modified code has a cycle and the scheduler - // will barf on it. - // - // Fortunately, this situation can only happen for dead - // code loops. We know the code we're working with is - // not dead, so we're ok. - // Proof: If we have a potential bad cycle, we have a - // situation like this: - // x = (Phi z) - // y = (op1 x ...) - // z = (op2 y ...) - // Where opX are not Phi ops. But such a situation - // implies a cycle in the dominator graph. In the - // example, x.Block dominates y.Block, y.Block dominates - // z.Block, and z.Block dominates x.Block (treating - // "dominates" as reflexive). Cycles in the dominator - // graph can only happen in an unreachable cycle. - } + phielimValue(v) + // Note: this is trickier than it looks. Replacing + // a Phi with a Copy can in general cause problems because + // Phi and Copy don't have exactly the same semantics. + // Phi arguments always come from a predecessor block, + // whereas copies don't. This matters in loops like: + // 1: x = (Phi y) + // y = (Add x 1) + // goto 1 + // If we replace Phi->Copy, we get + // 1: x = (Copy y) + // y = (Add x 1) + // goto 1 + // (Phi y) refers to the *previous* value of y, whereas + // (Copy y) refers to the *current* value of y. + // The modified code has a cycle and the scheduler + // will barf on it. + // + // Fortunately, this situation can only happen for dead + // code loops. We know the code we're working with is + // not dead, so we're ok. + // Proof: If we have a potential bad cycle, we have a + // situation like this: + // x = (Phi z) + // y = (op1 x ...) + // z = (op2 y ...) + // Where opX are not Phi ops. But such a situation + // implies a cycle in the dominator graph. In the + // example, x.Block dominates y.Block, y.Block dominates + // z.Block, and z.Block dominates x.Block (treating + // "dominates" as reflexive). Cycles in the dominator + // graph can only happen in an unreachable cycle. } } diff --git a/src/cmd/compile/internal/ssa/phielim.go b/src/cmd/compile/internal/ssa/phielim.go index 20ce592030..d69449ee21 100644 --- a/src/cmd/compile/internal/ssa/phielim.go +++ b/src/cmd/compile/internal/ssa/phielim.go @@ -40,7 +40,11 @@ func phielimValue(v *Value) bool { // are not v itself, then the phi must remain. // Otherwise, we can replace it with a copy. var w *Value - for _, x := range v.Args { + for i, x := range v.Args { + if b := v.Block.Preds[i]; b.Kind == BlockFirst && b.Succs[1] == v.Block { + // This branch is never taken so we can just eliminate it. + continue + } if x == v { continue }