mirror of
https://github.com/golang/go
synced 2024-11-12 09:20:22 -07:00
exp/ssa: fixed bug (typo) in findPromotedField.
By appending to the wrong (always empty) list, only the last anonymous field was being considered for promotion. Also: - eliminated "function-local NamedTypes" TODO; nothing to do. - fixed Function.DumpTo: printing of anon receivers was "( T)", now "(T)"; extracted writeSignature into own function. - eliminated blockNames function; thanks to BasicBlock.String, "%s" of []*BasicBlock is fine. - extracted buildReferrers into own function. exp/ssa can now build its own transitive closure. R=gri CC=golang-dev https://golang.org/cl/7384054
This commit is contained in:
parent
0ba5f75513
commit
71c37e1c88
@ -33,8 +33,6 @@ package ssa
|
||||
// TODO(adonovan): fix the following:
|
||||
// - support f(g()) where g has multiple result parameters.
|
||||
// - concurrent SSA code generation of multiple packages.
|
||||
// - consider function-local NamedTypes.
|
||||
// They can have nonempty method-sets due to promotion. Test.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -265,6 +265,25 @@ func numberRegisters(f *Function) {
|
||||
}
|
||||
}
|
||||
|
||||
// buildReferrers populates the def/use information in all non-nil
|
||||
// Value.Referrers slice.
|
||||
// Precondition: all such slices are initially empty.
|
||||
func buildReferrers(f *Function) {
|
||||
var rands []*Value
|
||||
for _, b := range f.Blocks {
|
||||
for _, instr := range b.Instrs {
|
||||
rands = instr.Operands(rands[:0]) // recycle storage
|
||||
for _, rand := range rands {
|
||||
if r := *rand; r != nil {
|
||||
if ref := r.Referrers(); ref != nil {
|
||||
*ref = append(*ref, instr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finish() finalizes the function after SSA code generation of its body.
|
||||
func (f *Function) finish() {
|
||||
f.objects = nil
|
||||
@ -289,20 +308,7 @@ func (f *Function) finish() {
|
||||
|
||||
optimizeBlocks(f)
|
||||
|
||||
// Build immediate-use (referrers) graph.
|
||||
var rands []*Value
|
||||
for _, b := range f.Blocks {
|
||||
for _, instr := range b.Instrs {
|
||||
rands = instr.Operands(rands[:0]) // recycle storage
|
||||
for _, rand := range rands {
|
||||
if r := *rand; r != nil {
|
||||
if ref := r.Referrers(); ref != nil {
|
||||
*ref = append(*ref, instr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
buildReferrers(f)
|
||||
|
||||
if f.Prog.mode&NaiveForm == 0 {
|
||||
// For debugging pre-state of lifting pass:
|
||||
@ -460,6 +466,47 @@ func (f *Function) fullName(from *Package) string {
|
||||
return f.Name_
|
||||
}
|
||||
|
||||
// writeSignature writes to w the signature sig in declaration syntax.
|
||||
// Derived from types.Signature.String().
|
||||
//
|
||||
func writeSignature(w io.Writer, name string, sig *types.Signature, params []*Parameter) {
|
||||
io.WriteString(w, "func ")
|
||||
if sig.Recv != nil {
|
||||
io.WriteString(w, "(")
|
||||
if n := params[0].Name(); n != "" {
|
||||
io.WriteString(w, n)
|
||||
io.WriteString(w, " ")
|
||||
}
|
||||
io.WriteString(w, params[0].Type().String())
|
||||
io.WriteString(w, ") ")
|
||||
params = params[1:]
|
||||
}
|
||||
io.WriteString(w, name)
|
||||
io.WriteString(w, "(")
|
||||
for i, v := range params {
|
||||
if i > 0 {
|
||||
io.WriteString(w, ", ")
|
||||
}
|
||||
io.WriteString(w, v.Name())
|
||||
io.WriteString(w, " ")
|
||||
if sig.IsVariadic && i == len(params)-1 {
|
||||
io.WriteString(w, "...")
|
||||
}
|
||||
io.WriteString(w, v.Type().String())
|
||||
}
|
||||
io.WriteString(w, ")")
|
||||
if res := sig.Results; res != nil {
|
||||
io.WriteString(w, " ")
|
||||
var t types.Type
|
||||
if len(res) == 1 && res[0].Name == "" {
|
||||
t = res[0].Type
|
||||
} else {
|
||||
t = &types.Result{Values: res}
|
||||
}
|
||||
io.WriteString(w, t.String())
|
||||
}
|
||||
}
|
||||
|
||||
// DumpTo prints to w a human readable "disassembly" of the SSA code of
|
||||
// all basic blocks of function f.
|
||||
//
|
||||
@ -485,37 +532,7 @@ func (f *Function) DumpTo(w io.Writer) {
|
||||
}
|
||||
}
|
||||
|
||||
// Function Signature in declaration syntax; derived from types.Signature.String().
|
||||
io.WriteString(w, "func ")
|
||||
params := f.Params
|
||||
if f.Signature.Recv != nil {
|
||||
fmt.Fprintf(w, "(%s %s) ", params[0].Name(), params[0].Type())
|
||||
params = params[1:]
|
||||
}
|
||||
io.WriteString(w, f.Name())
|
||||
io.WriteString(w, "(")
|
||||
for i, v := range params {
|
||||
if i > 0 {
|
||||
io.WriteString(w, ", ")
|
||||
}
|
||||
io.WriteString(w, v.Name())
|
||||
io.WriteString(w, " ")
|
||||
if f.Signature.IsVariadic && i == len(params)-1 {
|
||||
io.WriteString(w, "...")
|
||||
}
|
||||
io.WriteString(w, v.Type().String())
|
||||
}
|
||||
io.WriteString(w, ")")
|
||||
if res := f.Signature.Results; res != nil {
|
||||
io.WriteString(w, " ")
|
||||
var t types.Type
|
||||
if len(res) == 1 && res[0].Name == "" {
|
||||
t = res[0].Type
|
||||
} else {
|
||||
t = &types.Result{Values: res}
|
||||
}
|
||||
io.WriteString(w, t.String())
|
||||
}
|
||||
writeSignature(w, f.Name(), f.Signature, f.Params)
|
||||
io.WriteString(w, ":\n")
|
||||
|
||||
if f.Blocks == nil {
|
||||
@ -530,7 +547,7 @@ func (f *Function) DumpTo(w io.Writer) {
|
||||
}
|
||||
fmt.Fprintf(w, ".%s:\t\t\t\t\t\t\t P:%d S:%d\n", b, len(b.Preds), len(b.Succs))
|
||||
if false { // CFG debugging
|
||||
fmt.Fprintf(w, "\t# CFG: %s --> %s --> %s\n", blockNames(b.Preds), b, blockNames(b.Succs))
|
||||
fmt.Fprintf(w, "\t# CFG: %s --> %s --> %s\n", b.Preds, b, b.Succs)
|
||||
}
|
||||
for _, instr := range b.Instrs {
|
||||
io.WriteString(w, "\t")
|
||||
|
@ -408,7 +408,7 @@ func findPromotedField(st *types.Struct, id Id) (*anonFieldPath, int) {
|
||||
var list, next []*anonFieldPath
|
||||
for i, f := range st.Fields {
|
||||
if f.IsAnonymous {
|
||||
list = append(next, &anonFieldPath{nil, i, f})
|
||||
list = append(list, &anonFieldPath{nil, i, f})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ package ssa
|
||||
// Currently it checks CFG invariants but little at the instruction level.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@ -41,20 +40,6 @@ func MustSanityCheck(fn *Function, reporter io.Writer) {
|
||||
}
|
||||
}
|
||||
|
||||
// blockNames returns the names of the specified blocks as a
|
||||
// human-readable string.
|
||||
//
|
||||
func blockNames(blocks []*BasicBlock) string {
|
||||
var buf bytes.Buffer
|
||||
for i, b := range blocks {
|
||||
if i > 0 {
|
||||
io.WriteString(&buf, ", ")
|
||||
}
|
||||
io.WriteString(&buf, b.String())
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (s *sanity) diagnostic(prefix, format string, args ...interface{}) {
|
||||
fmt.Fprintf(s.reporter, "%s: function %s", prefix, s.fn.FullName())
|
||||
if s.block != nil {
|
||||
@ -236,7 +221,7 @@ func (s *sanity) checkBlock(b *BasicBlock, index int) {
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
s.errorf("expected successor edge in predecessor %s; found only: %s", a, blockNames(a.Succs))
|
||||
s.errorf("expected successor edge in predecessor %s; found only: %s", a, a.Succs)
|
||||
}
|
||||
if a.Func != s.fn {
|
||||
s.errorf("predecessor %s belongs to different function %s", a, a.Func.FullName())
|
||||
@ -251,7 +236,7 @@ func (s *sanity) checkBlock(b *BasicBlock, index int) {
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
s.errorf("expected predecessor edge in successor %s; found only: %s", c, blockNames(c.Preds))
|
||||
s.errorf("expected predecessor edge in successor %s; found only: %s", c, c.Preds)
|
||||
}
|
||||
if c.Func != s.fn {
|
||||
s.errorf("successor %s belongs to different function %s", c, c.Func.FullName())
|
||||
|
Loading…
Reference in New Issue
Block a user