diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index b3c7544ad12..d8b0b0a5c1d 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -270,6 +270,7 @@ var passes = [...]pass{ {name: "checkLower", fn: checkLower, required: true}, {name: "late phielim", fn: phielim}, {name: "late copyelim", fn: copyelim}, + {name: "phi tighten", fn: phiTighten}, {name: "late deadcode", fn: deadcode}, {name: "critical", fn: critical, required: true}, // remove critical edges {name: "likelyadjust", fn: likelyadjust}, diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go index ecb43c101d2..2f7c30929d7 100644 --- a/src/cmd/compile/internal/ssa/tighten.go +++ b/src/cmd/compile/internal/ssa/tighten.go @@ -86,3 +86,26 @@ func tighten(f *Func) { } } } + +// phiTighten moves constants closer to phi users. +// This pass avoids having lots of constants live for lots of the program. +// See issue 16407. +func phiTighten(f *Func) { + for _, b := range f.Blocks { + for _, v := range b.Values { + if v.Op != OpPhi { + continue + } + for i, a := range v.Args { + if !a.rematerializeable() { + continue // not a constant we can move around + } + if a.Block == b.Preds[i].b { + continue // already in the right place + } + // Make a copy of a, put in predecessor block. + v.SetArg(i, a.copyInto(b.Preds[i].b)) + } + } + } +}