mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
steals idea from CL 312093 further investigation revealed additional duplicate slots (equivalent, but not equal), so delete those too. Rearranged Func.Names to be addresses of slots, create canonical addresses so that split slots (which use those addresses to refer to their parent, and split slots can be further split) will preserve "equivalent slots are equal". Removes duplicates, improves metrics for "args at entry". Change-Id: I5bbdcb50bd33655abcab3d27ad8cdce25499faaf Reviewed-on: https://go-review.googlesource.com/c/go/+/312292 Trust: David Chase <drchase@google.com> Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
159 lines
3.1 KiB
Go
159 lines
3.1 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package ssa
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
func printFunc(f *Func) {
|
|
f.Logf("%s", f)
|
|
}
|
|
|
|
func hashFunc(f *Func) []byte {
|
|
h := sha256.New()
|
|
p := stringFuncPrinter{w: h}
|
|
fprintFunc(p, f)
|
|
return h.Sum(nil)
|
|
}
|
|
|
|
func (f *Func) String() string {
|
|
var buf bytes.Buffer
|
|
p := stringFuncPrinter{w: &buf}
|
|
fprintFunc(p, f)
|
|
return buf.String()
|
|
}
|
|
|
|
type funcPrinter interface {
|
|
header(f *Func)
|
|
startBlock(b *Block, reachable bool)
|
|
endBlock(b *Block)
|
|
value(v *Value, live bool)
|
|
startDepCycle()
|
|
endDepCycle()
|
|
named(n LocalSlot, vals []*Value)
|
|
}
|
|
|
|
type stringFuncPrinter struct {
|
|
w io.Writer
|
|
}
|
|
|
|
func (p stringFuncPrinter) header(f *Func) {
|
|
fmt.Fprint(p.w, f.Name)
|
|
fmt.Fprint(p.w, " ")
|
|
fmt.Fprintln(p.w, f.Type)
|
|
}
|
|
|
|
func (p stringFuncPrinter) startBlock(b *Block, reachable bool) {
|
|
fmt.Fprintf(p.w, " b%d:", b.ID)
|
|
if len(b.Preds) > 0 {
|
|
io.WriteString(p.w, " <-")
|
|
for _, e := range b.Preds {
|
|
pred := e.b
|
|
fmt.Fprintf(p.w, " b%d", pred.ID)
|
|
}
|
|
}
|
|
if !reachable {
|
|
fmt.Fprint(p.w, " DEAD")
|
|
}
|
|
io.WriteString(p.w, "\n")
|
|
}
|
|
|
|
func (p stringFuncPrinter) endBlock(b *Block) {
|
|
fmt.Fprintln(p.w, " "+b.LongString())
|
|
}
|
|
|
|
func (p stringFuncPrinter) value(v *Value, live bool) {
|
|
fmt.Fprint(p.w, " ")
|
|
//fmt.Fprint(p.w, v.Block.Func.fe.Pos(v.Pos))
|
|
//fmt.Fprint(p.w, ": ")
|
|
fmt.Fprint(p.w, v.LongString())
|
|
if !live {
|
|
fmt.Fprint(p.w, " DEAD")
|
|
}
|
|
fmt.Fprintln(p.w)
|
|
}
|
|
|
|
func (p stringFuncPrinter) startDepCycle() {
|
|
fmt.Fprintln(p.w, "dependency cycle!")
|
|
}
|
|
|
|
func (p stringFuncPrinter) endDepCycle() {}
|
|
|
|
func (p stringFuncPrinter) named(n LocalSlot, vals []*Value) {
|
|
fmt.Fprintf(p.w, "name %s: %v\n", n, vals)
|
|
}
|
|
|
|
func fprintFunc(p funcPrinter, f *Func) {
|
|
reachable, live := findlive(f)
|
|
defer f.retDeadcodeLive(live)
|
|
p.header(f)
|
|
printed := make([]bool, f.NumValues())
|
|
for _, b := range f.Blocks {
|
|
p.startBlock(b, reachable[b.ID])
|
|
|
|
if f.scheduled {
|
|
// Order of Values has been decided - print in that order.
|
|
for _, v := range b.Values {
|
|
p.value(v, live[v.ID])
|
|
printed[v.ID] = true
|
|
}
|
|
p.endBlock(b)
|
|
continue
|
|
}
|
|
|
|
// print phis first since all value cycles contain a phi
|
|
n := 0
|
|
for _, v := range b.Values {
|
|
if v.Op != OpPhi {
|
|
continue
|
|
}
|
|
p.value(v, live[v.ID])
|
|
printed[v.ID] = true
|
|
n++
|
|
}
|
|
|
|
// print rest of values in dependency order
|
|
for n < len(b.Values) {
|
|
m := n
|
|
outer:
|
|
for _, v := range b.Values {
|
|
if printed[v.ID] {
|
|
continue
|
|
}
|
|
for _, w := range v.Args {
|
|
// w == nil shouldn't happen, but if it does,
|
|
// don't panic; we'll get a better diagnosis later.
|
|
if w != nil && w.Block == b && !printed[w.ID] {
|
|
continue outer
|
|
}
|
|
}
|
|
p.value(v, live[v.ID])
|
|
printed[v.ID] = true
|
|
n++
|
|
}
|
|
if m == n {
|
|
p.startDepCycle()
|
|
for _, v := range b.Values {
|
|
if printed[v.ID] {
|
|
continue
|
|
}
|
|
p.value(v, live[v.ID])
|
|
printed[v.ID] = true
|
|
n++
|
|
}
|
|
p.endDepCycle()
|
|
}
|
|
}
|
|
|
|
p.endBlock(b)
|
|
}
|
|
for _, name := range f.Names {
|
|
p.named(*name, f.NamedValues[*name])
|
|
}
|
|
}
|