[dev.regabi] cmd/compile: clean up Name and Func uses

Now that we have specific types for ONAME and ODCLFUNC nodes
(*Name and *Func), use them throughout the compiler to be more
precise about what data is being operated on.

This is a somewhat large CL, but once you start applying the types
in a few places, you end up needing to apply them to many other
places to keep everything type-checking. A lot of code also melts
away as types are added.

Passes buildall w/ toolstash -cmp.

Change-Id: I21dd9b945d701c470332bac5394fca744a5b232d
Reviewed-on: https://go-review.googlesource.com/c/go/+/274097
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-11-28 07:31:18 -05:00
parent c4bd0b7474
commit e84b27bec5
34 changed files with 627 additions and 633 deletions

View file

@ -22,6 +22,12 @@ package main_test
var knownFormats = map[string]string{ var knownFormats = map[string]string{
"*bytes.Buffer %s": "", "*bytes.Buffer %s": "",
"*cmd/compile/internal/gc.EscLocation %v": "", "*cmd/compile/internal/gc.EscLocation %v": "",
"*cmd/compile/internal/ir.Func %+v": "",
"*cmd/compile/internal/ir.Func %L": "",
"*cmd/compile/internal/ir.Func %v": "",
"*cmd/compile/internal/ir.Name %#v": "",
"*cmd/compile/internal/ir.Name %+v": "",
"*cmd/compile/internal/ir.Name %L": "",
"*cmd/compile/internal/ir.Name %v": "", "*cmd/compile/internal/ir.Name %v": "",
"*cmd/compile/internal/ir.node %v": "", "*cmd/compile/internal/ir.node %v": "",
"*cmd/compile/internal/ssa.Block %s": "", "*cmd/compile/internal/ssa.Block %s": "",
@ -54,6 +60,7 @@ var knownFormats = map[string]string{
"*math/big.Float %f": "", "*math/big.Float %f": "",
"*math/big.Int %s": "", "*math/big.Int %s": "",
"[16]byte %x": "", "[16]byte %x": "",
"[]*cmd/compile/internal/ir.Name %v": "",
"[]*cmd/compile/internal/ssa.Block %v": "", "[]*cmd/compile/internal/ssa.Block %v": "",
"[]*cmd/compile/internal/ssa.Value %v": "", "[]*cmd/compile/internal/ssa.Value %v": "",
"[][]string %q": "", "[][]string %q": "",
@ -77,7 +84,6 @@ var knownFormats = map[string]string{
"cmd/compile/internal/ir.Class %d": "", "cmd/compile/internal/ir.Class %d": "",
"cmd/compile/internal/ir.Class %v": "", "cmd/compile/internal/ir.Class %v": "",
"cmd/compile/internal/ir.FmtMode %d": "", "cmd/compile/internal/ir.FmtMode %d": "",
"cmd/compile/internal/ir.Node %#v": "",
"cmd/compile/internal/ir.Node %+S": "", "cmd/compile/internal/ir.Node %+S": "",
"cmd/compile/internal/ir.Node %+v": "", "cmd/compile/internal/ir.Node %+v": "",
"cmd/compile/internal/ir.Node %L": "", "cmd/compile/internal/ir.Node %L": "",

View file

@ -382,8 +382,8 @@ func genhash(t *types.Type) *obj.LSym {
funcbody() funcbody()
fn.Func().SetDupok(true) fn.SetDupok(true)
fn = typecheck(fn, ctxStmt) typecheckFunc(fn)
Curfn = fn Curfn = fn
typecheckslice(fn.Body().Slice(), ctxStmt) typecheckslice(fn.Body().Slice(), ctxStmt)
@ -393,7 +393,7 @@ func genhash(t *types.Type) *obj.LSym {
testdclstack() testdclstack()
} }
fn.Func().SetNilCheckDisabled(true) fn.SetNilCheckDisabled(true)
xtop = append(xtop, fn) xtop = append(xtop, fn)
// Build closure. It doesn't close over any variables, so // Build closure. It doesn't close over any variables, so
@ -761,8 +761,8 @@ func geneq(t *types.Type) *obj.LSym {
funcbody() funcbody()
fn.Func().SetDupok(true) fn.SetDupok(true)
fn = typecheck(fn, ctxStmt) typecheckFunc(fn)
Curfn = fn Curfn = fn
typecheckslice(fn.Body().Slice(), ctxStmt) typecheckslice(fn.Body().Slice(), ctxStmt)
@ -776,7 +776,7 @@ func geneq(t *types.Type) *obj.LSym {
// We are comparing a struct or an array, // We are comparing a struct or an array,
// neither of which can be nil, and our comparisons // neither of which can be nil, and our comparisons
// are shallow. // are shallow.
fn.Func().SetNilCheckDisabled(true) fn.SetNilCheckDisabled(true)
xtop = append(xtop, fn) xtop = append(xtop, fn)
// Generate a closure which points at the function we just generated. // Generate a closure which points at the function we just generated.

View file

@ -16,7 +16,7 @@ type exporter struct {
// markObject visits a reachable object. // markObject visits a reachable object.
func (p *exporter) markObject(n ir.Node) { func (p *exporter) markObject(n ir.Node) {
if n.Op() == ir.ONAME && n.Class() == ir.PFUNC { if n.Op() == ir.ONAME && n.Class() == ir.PFUNC {
inlFlood(n) inlFlood(n.(*ir.Name))
} }
p.markType(n.Type()) p.markType(n.Type())

View file

@ -17,28 +17,27 @@ func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node {
xtype := p.typeExpr(expr.Type) xtype := p.typeExpr(expr.Type)
ntype := p.typeExpr(expr.Type) ntype := p.typeExpr(expr.Type)
dcl := p.nod(expr, ir.ODCLFUNC, nil, nil) fn := ir.NewFunc(p.pos(expr))
fn := dcl.Func()
fn.SetIsHiddenClosure(Curfn != nil) fn.SetIsHiddenClosure(Curfn != nil)
fn.Nname = newfuncnamel(p.pos(expr), ir.BlankNode.Sym(), fn) // filled in by typecheckclosure fn.Nname = newFuncNameAt(p.pos(expr), ir.BlankNode.Sym(), fn) // filled in by typecheckclosure
fn.Nname.Name().Ntype = xtype fn.Nname.Ntype = xtype
fn.Nname.Name().Defn = dcl fn.Nname.Defn = fn
clo := p.nod(expr, ir.OCLOSURE, nil, nil) clo := p.nod(expr, ir.OCLOSURE, nil, nil)
clo.SetFunc(fn) clo.SetFunc(fn)
fn.ClosureType = ntype fn.ClosureType = ntype
fn.OClosure = clo fn.OClosure = clo
p.funcBody(dcl, expr.Body) p.funcBody(fn, expr.Body)
// closure-specific variables are hanging off the // closure-specific variables are hanging off the
// ordinary ones in the symbol table; see oldname. // ordinary ones in the symbol table; see oldname.
// unhook them. // unhook them.
// make the list of pointers for the closure call. // make the list of pointers for the closure call.
for _, v := range fn.ClosureVars.Slice() { for _, v := range fn.ClosureVars {
// Unlink from v1; see comment in syntax.go type Param for these fields. // Unlink from v1; see comment in syntax.go type Param for these fields.
v1 := v.Name().Defn v1 := v.Defn
v1.Name().Innermost = v.Name().Outer v1.Name().Innermost = v.Outer
// If the closure usage of v is not dense, // If the closure usage of v is not dense,
// we need to make it dense; now that we're out // we need to make it dense; now that we're out
@ -68,7 +67,7 @@ func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node {
// obtains f3's v, creating it if necessary (as it is in the example). // obtains f3's v, creating it if necessary (as it is in the example).
// //
// capturevars will decide whether to use v directly or &v. // capturevars will decide whether to use v directly or &v.
v.Name().Outer = oldname(v.Sym()).(*ir.Name) v.Outer = oldname(v.Sym()).(*ir.Name)
} }
return clo return clo
@ -80,26 +79,25 @@ func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node {
// separate pass from type-checking. // separate pass from type-checking.
func typecheckclosure(clo ir.Node, top int) { func typecheckclosure(clo ir.Node, top int) {
fn := clo.Func() fn := clo.Func()
dcl := fn.Decl
// Set current associated iota value, so iota can be used inside // Set current associated iota value, so iota can be used inside
// function in ConstSpec, see issue #22344 // function in ConstSpec, see issue #22344
if x := getIotaValue(); x >= 0 { if x := getIotaValue(); x >= 0 {
dcl.SetIota(x) fn.SetIota(x)
} }
fn.ClosureType = typecheck(fn.ClosureType, ctxType) fn.ClosureType = typecheck(fn.ClosureType, ctxType)
clo.SetType(fn.ClosureType.Type()) clo.SetType(fn.ClosureType.Type())
fn.ClosureCalled = top&ctxCallee != 0 fn.SetClosureCalled(top&ctxCallee != 0)
// Do not typecheck dcl twice, otherwise, we will end up pushing // Do not typecheck fn twice, otherwise, we will end up pushing
// dcl to xtop multiple times, causing initLSym called twice. // fn to xtop multiple times, causing initLSym called twice.
// See #30709 // See #30709
if dcl.Typecheck() == 1 { if fn.Typecheck() == 1 {
return return
} }
for _, ln := range fn.ClosureVars.Slice() { for _, ln := range fn.ClosureVars {
n := ln.Name().Defn n := ln.Defn
if !n.Name().Captured() { if !n.Name().Captured() {
n.Name().SetCaptured(true) n.Name().SetCaptured(true)
if n.Name().Decldepth == 0 { if n.Name().Decldepth == 0 {
@ -116,7 +114,7 @@ func typecheckclosure(clo ir.Node, top int) {
fn.Nname.SetSym(closurename(Curfn)) fn.Nname.SetSym(closurename(Curfn))
setNodeNameFunc(fn.Nname) setNodeNameFunc(fn.Nname)
dcl = typecheck(dcl, ctxStmt) typecheckFunc(fn)
// Type check the body now, but only if we're inside a function. // Type check the body now, but only if we're inside a function.
// At top level (in a variable initialization: curfn==nil) we're not // At top level (in a variable initialization: curfn==nil) we're not
@ -124,29 +122,29 @@ func typecheckclosure(clo ir.Node, top int) {
// underlying closure function we create is added to xtop. // underlying closure function we create is added to xtop.
if Curfn != nil && clo.Type() != nil { if Curfn != nil && clo.Type() != nil {
oldfn := Curfn oldfn := Curfn
Curfn = dcl Curfn = fn
olddd := decldepth olddd := decldepth
decldepth = 1 decldepth = 1
typecheckslice(dcl.Body().Slice(), ctxStmt) typecheckslice(fn.Body().Slice(), ctxStmt)
decldepth = olddd decldepth = olddd
Curfn = oldfn Curfn = oldfn
} }
xtop = append(xtop, dcl) xtop = append(xtop, fn)
} }
// globClosgen is like Func.Closgen, but for the global scope. // globClosgen is like Func.Closgen, but for the global scope.
var globClosgen int var globClosgen int32
// closurename generates a new unique name for a closure within // closurename generates a new unique name for a closure within
// outerfunc. // outerfunc.
func closurename(outerfunc ir.Node) *types.Sym { func closurename(outerfunc *ir.Func) *types.Sym {
outer := "glob." outer := "glob."
prefix := "func" prefix := "func"
gen := &globClosgen gen := &globClosgen
if outerfunc != nil { if outerfunc != nil {
if outerfunc.Func().OClosure != nil { if outerfunc.OClosure != nil {
prefix = "" prefix = ""
} }
@ -155,8 +153,8 @@ func closurename(outerfunc ir.Node) *types.Sym {
// There may be multiple functions named "_". In those // There may be multiple functions named "_". In those
// cases, we can't use their individual Closgens as it // cases, we can't use their individual Closgens as it
// would lead to name clashes. // would lead to name clashes.
if !ir.IsBlank(outerfunc.Func().Nname) { if !ir.IsBlank(outerfunc.Nname) {
gen = &outerfunc.Func().Closgen gen = &outerfunc.Closgen
} }
} }
@ -172,11 +170,10 @@ var capturevarscomplete bool
// by value or by reference. // by value or by reference.
// We use value capturing for values <= 128 bytes that are never reassigned // We use value capturing for values <= 128 bytes that are never reassigned
// after capturing (effectively constant). // after capturing (effectively constant).
func capturevars(dcl ir.Node) { func capturevars(fn *ir.Func) {
lno := base.Pos lno := base.Pos
base.Pos = dcl.Pos() base.Pos = fn.Pos()
fn := dcl.Func() cvars := fn.ClosureVars
cvars := fn.ClosureVars.Slice()
out := cvars[:0] out := cvars[:0]
for _, v := range cvars { for _, v := range cvars {
if v.Type() == nil { if v.Type() == nil {
@ -195,12 +192,12 @@ func capturevars(dcl ir.Node) {
dowidth(v.Type()) dowidth(v.Type())
var outer ir.Node var outer ir.Node
outer = v.Name().Outer outer = v.Outer
outermost := v.Name().Defn outermost := v.Defn
// out parameters will be assigned to implicitly upon return. // out parameters will be assigned to implicitly upon return.
if outermost.Class() != ir.PPARAMOUT && !outermost.Name().Addrtaken() && !outermost.Name().Assigned() && v.Type().Width <= 128 { if outermost.Class() != ir.PPARAMOUT && !outermost.Name().Addrtaken() && !outermost.Name().Assigned() && v.Type().Width <= 128 {
v.Name().SetByval(true) v.SetByval(true)
} else { } else {
outermost.Name().SetAddrtaken(true) outermost.Name().SetAddrtaken(true)
outer = ir.Nod(ir.OADDR, outer, nil) outer = ir.Nod(ir.OADDR, outer, nil)
@ -208,11 +205,11 @@ func capturevars(dcl ir.Node) {
if base.Flag.LowerM > 1 { if base.Flag.LowerM > 1 {
var name *types.Sym var name *types.Sym
if v.Name().Curfn != nil && v.Name().Curfn.Func().Nname != nil { if v.Curfn != nil && v.Curfn.Nname != nil {
name = v.Name().Curfn.Func().Nname.Sym() name = v.Curfn.Sym()
} }
how := "ref" how := "ref"
if v.Name().Byval() { if v.Byval() {
how = "value" how = "value"
} }
base.WarnfAt(v.Pos(), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym(), outermost.Name().Addrtaken(), outermost.Name().Assigned(), int32(v.Type().Width)) base.WarnfAt(v.Pos(), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym(), outermost.Name().Addrtaken(), outermost.Name().Assigned(), int32(v.Type().Width))
@ -222,18 +219,17 @@ func capturevars(dcl ir.Node) {
fn.ClosureEnter.Append(outer) fn.ClosureEnter.Append(outer)
} }
fn.ClosureVars.Set(out) fn.ClosureVars = out
base.Pos = lno base.Pos = lno
} }
// transformclosure is called in a separate phase after escape analysis. // transformclosure is called in a separate phase after escape analysis.
// It transform closure bodies to properly reference captured variables. // It transform closure bodies to properly reference captured variables.
func transformclosure(dcl ir.Node) { func transformclosure(fn *ir.Func) {
lno := base.Pos lno := base.Pos
base.Pos = dcl.Pos() base.Pos = fn.Pos()
fn := dcl.Func()
if fn.ClosureCalled { if fn.ClosureCalled() {
// If the closure is directly called, we transform it to a plain function call // If the closure is directly called, we transform it to a plain function call
// with variables passed as args. This avoids allocation of a closure object. // with variables passed as args. This avoids allocation of a closure object.
// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE) // Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
@ -254,16 +250,16 @@ func transformclosure(dcl ir.Node) {
// We are going to insert captured variables before input args. // We are going to insert captured variables before input args.
var params []*types.Field var params []*types.Field
var decls []ir.Node var decls []*ir.Name
for _, v := range fn.ClosureVars.Slice() { for _, v := range fn.ClosureVars {
if !v.Name().Byval() { if !v.Byval() {
// If v of type T is captured by reference, // If v of type T is captured by reference,
// we introduce function param &v *T // we introduce function param &v *T
// and v remains PAUTOHEAP with &v heapaddr // and v remains PAUTOHEAP with &v heapaddr
// (accesses will implicitly deref &v). // (accesses will implicitly deref &v).
addr := NewName(lookup("&" + v.Sym().Name)) addr := NewName(lookup("&" + v.Sym().Name))
addr.SetType(types.NewPtr(v.Type())) addr.SetType(types.NewPtr(v.Type()))
v.Name().Heapaddr = addr v.Heapaddr = addr
v = addr v = addr
} }
@ -282,24 +278,24 @@ func transformclosure(dcl ir.Node) {
} }
dowidth(f.Type()) dowidth(f.Type())
dcl.SetType(f.Type()) // update type of ODCLFUNC fn.SetType(f.Type()) // update type of ODCLFUNC
} else { } else {
// The closure is not called, so it is going to stay as closure. // The closure is not called, so it is going to stay as closure.
var body []ir.Node var body []ir.Node
offset := int64(Widthptr) offset := int64(Widthptr)
for _, v := range fn.ClosureVars.Slice() { for _, v := range fn.ClosureVars {
// cv refers to the field inside of closure OSTRUCTLIT. // cv refers to the field inside of closure OSTRUCTLIT.
cv := ir.Nod(ir.OCLOSUREVAR, nil, nil) cv := ir.Nod(ir.OCLOSUREVAR, nil, nil)
cv.SetType(v.Type()) cv.SetType(v.Type())
if !v.Name().Byval() { if !v.Byval() {
cv.SetType(types.NewPtr(v.Type())) cv.SetType(types.NewPtr(v.Type()))
} }
offset = Rnd(offset, int64(cv.Type().Align)) offset = Rnd(offset, int64(cv.Type().Align))
cv.SetOffset(offset) cv.SetOffset(offset)
offset += cv.Type().Width offset += cv.Type().Width
if v.Name().Byval() && v.Type().Width <= int64(2*Widthptr) { if v.Byval() && v.Type().Width <= int64(2*Widthptr) {
// If it is a small variable captured by value, downgrade it to PAUTO. // If it is a small variable captured by value, downgrade it to PAUTO.
v.SetClass(ir.PAUTO) v.SetClass(ir.PAUTO)
fn.Dcl = append(fn.Dcl, v) fn.Dcl = append(fn.Dcl, v)
@ -310,11 +306,11 @@ func transformclosure(dcl ir.Node) {
addr := NewName(lookup("&" + v.Sym().Name)) addr := NewName(lookup("&" + v.Sym().Name))
addr.SetType(types.NewPtr(v.Type())) addr.SetType(types.NewPtr(v.Type()))
addr.SetClass(ir.PAUTO) addr.SetClass(ir.PAUTO)
addr.Name().SetUsed(true) addr.SetUsed(true)
addr.Name().Curfn = dcl addr.Curfn = fn
fn.Dcl = append(fn.Dcl, addr) fn.Dcl = append(fn.Dcl, addr)
v.Name().Heapaddr = addr v.Heapaddr = addr
if v.Name().Byval() { if v.Byval() {
cv = ir.Nod(ir.OADDR, cv, nil) cv = ir.Nod(ir.OADDR, cv, nil)
} }
body = append(body, ir.Nod(ir.OAS, addr, cv)) body = append(body, ir.Nod(ir.OAS, addr, cv))
@ -334,7 +330,7 @@ func transformclosure(dcl ir.Node) {
// hasemptycvars reports whether closure clo has an // hasemptycvars reports whether closure clo has an
// empty list of captured vars. // empty list of captured vars.
func hasemptycvars(clo ir.Node) bool { func hasemptycvars(clo ir.Node) bool {
return clo.Func().ClosureVars.Len() == 0 return len(clo.Func().ClosureVars) == 0
} }
// closuredebugruntimecheck applies boilerplate checks for debug flags // closuredebugruntimecheck applies boilerplate checks for debug flags
@ -372,9 +368,9 @@ func closureType(clo ir.Node) *types.Type {
fields := []ir.Node{ fields := []ir.Node{
namedfield(".F", types.Types[types.TUINTPTR]), namedfield(".F", types.Types[types.TUINTPTR]),
} }
for _, v := range clo.Func().ClosureVars.Slice() { for _, v := range clo.Func().ClosureVars {
typ := v.Type() typ := v.Type()
if !v.Name().Byval() { if !v.Byval() {
typ = types.NewPtr(typ) typ = types.NewPtr(typ)
} }
fields = append(fields, symfield(v.Sym(), typ)) fields = append(fields, symfield(v.Sym(), typ))
@ -430,23 +426,24 @@ func typecheckpartialcall(dot ir.Node, sym *types.Sym) {
} }
// Create top-level function. // Create top-level function.
dcl := makepartialcall(dot, dot.Type(), sym) fn := makepartialcall(dot, dot.Type(), sym)
dcl.Func().SetWrapper(true) fn.SetWrapper(true)
dot.SetOp(ir.OCALLPART) dot.SetOp(ir.OCALLPART)
dot.SetRight(NewName(sym)) dot.SetRight(NewName(sym))
dot.SetType(dcl.Type()) dot.SetType(fn.Type())
dot.SetFunc(dcl.Func()) dot.SetFunc(fn)
dot.SetOpt(nil) // clear types.Field from ODOTMETH dot.SetOpt(nil) // clear types.Field from ODOTMETH
} }
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed // makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
// for partial calls. // for partial calls.
func makepartialcall(dot ir.Node, t0 *types.Type, meth *types.Sym) ir.Node { func makepartialcall(dot ir.Node, t0 *types.Type, meth *types.Sym) *ir.Func {
rcvrtype := dot.Left().Type() rcvrtype := dot.Left().Type()
sym := methodSymSuffix(rcvrtype, meth, "-fm") sym := methodSymSuffix(rcvrtype, meth, "-fm")
if sym.Uniq() { if sym.Uniq() {
return ir.AsNode(sym.Def) return ir.AsNode(sym.Def).(*ir.Func)
} }
sym.SetUniq(true) sym.SetUniq(true)
@ -469,8 +466,7 @@ func makepartialcall(dot ir.Node, t0 *types.Type, meth *types.Sym) ir.Node {
tfn.PtrList().Set(structargs(t0.Params(), true)) tfn.PtrList().Set(structargs(t0.Params(), true))
tfn.PtrRlist().Set(structargs(t0.Results(), false)) tfn.PtrRlist().Set(structargs(t0.Results(), false))
dcl := dclfunc(sym, tfn) fn := dclfunc(sym, tfn)
fn := dcl.Func()
fn.SetDupok(true) fn.SetDupok(true)
fn.SetNeedctxt(true) fn.SetNeedctxt(true)
@ -484,7 +480,7 @@ func makepartialcall(dot ir.Node, t0 *types.Type, meth *types.Sym) ir.Node {
ptr := NewName(lookup(".this")) ptr := NewName(lookup(".this"))
declare(ptr, ir.PAUTO) declare(ptr, ir.PAUTO)
ptr.Name().SetUsed(true) ptr.SetUsed(true)
var body []ir.Node var body []ir.Node
if rcvrtype.IsPtr() || rcvrtype.IsInterface() { if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
ptr.SetType(rcvrtype) ptr.SetType(rcvrtype)
@ -504,20 +500,20 @@ func makepartialcall(dot ir.Node, t0 *types.Type, meth *types.Sym) ir.Node {
} }
body = append(body, call) body = append(body, call)
dcl.PtrBody().Set(body) fn.PtrBody().Set(body)
funcbody() funcbody()
dcl = typecheck(dcl, ctxStmt) typecheckFunc(fn)
// Need to typecheck the body of the just-generated wrapper. // Need to typecheck the body of the just-generated wrapper.
// typecheckslice() requires that Curfn is set when processing an ORETURN. // typecheckslice() requires that Curfn is set when processing an ORETURN.
Curfn = dcl Curfn = fn
typecheckslice(dcl.Body().Slice(), ctxStmt) typecheckslice(fn.Body().Slice(), ctxStmt)
sym.Def = dcl sym.Def = fn
xtop = append(xtop, dcl) xtop = append(xtop, fn)
Curfn = savecurfn Curfn = savecurfn
base.Pos = saveLineNo base.Pos = saveLineNo
return dcl return fn
} }
// partialCallType returns the struct type used to hold all the information // partialCallType returns the struct type used to hold all the information

View file

@ -58,7 +58,7 @@ var declare_typegen int
// declare records that Node n declares symbol n.Sym in the specified // declare records that Node n declares symbol n.Sym in the specified
// declaration context. // declaration context.
func declare(n ir.Node, ctxt ir.Class) { func declare(n *ir.Name, ctxt ir.Class) {
if ir.IsBlank(n) { if ir.IsBlank(n) {
return return
} }
@ -85,7 +85,7 @@ func declare(n ir.Node, ctxt ir.Class) {
base.Fatalf("automatic outside function") base.Fatalf("automatic outside function")
} }
if Curfn != nil && ctxt != ir.PFUNC { if Curfn != nil && ctxt != ir.PFUNC {
Curfn.Func().Dcl = append(Curfn.Func().Dcl, n) Curfn.Dcl = append(Curfn.Dcl, n)
} }
if n.Op() == ir.OTYPE { if n.Op() == ir.OTYPE {
declare_typegen++ declare_typegen++
@ -122,7 +122,7 @@ func declare(n ir.Node, ctxt ir.Class) {
autoexport(n, ctxt) autoexport(n, ctxt)
} }
func addvar(n ir.Node, t *types.Type, ctxt ir.Class) { func addvar(n *ir.Name, t *types.Type, ctxt ir.Class) {
if n == nil || n.Sym() == nil || (n.Op() != ir.ONAME && n.Op() != ir.ONONAME) || t == nil { if n == nil || n.Sym() == nil || (n.Op() != ir.ONAME && n.Op() != ir.ONONAME) || t == nil {
base.Fatalf("addvar: n=%v t=%v nil", n, t) base.Fatalf("addvar: n=%v t=%v nil", n, t)
} }
@ -144,10 +144,11 @@ func variter(vl []ir.Node, t ir.Node, el []ir.Node) []ir.Node {
as2.PtrList().Set(vl) as2.PtrList().Set(vl)
as2.PtrRlist().Set1(e) as2.PtrRlist().Set1(e)
for _, v := range vl { for _, v := range vl {
v := v.(*ir.Name)
v.SetOp(ir.ONAME) v.SetOp(ir.ONAME)
declare(v, dclcontext) declare(v, dclcontext)
v.Name().Ntype = t v.Ntype = t
v.Name().Defn = as2 v.Defn = as2
if Curfn != nil { if Curfn != nil {
init = append(init, ir.Nod(ir.ODCL, v, nil)) init = append(init, ir.Nod(ir.ODCL, v, nil))
} }
@ -158,6 +159,7 @@ func variter(vl []ir.Node, t ir.Node, el []ir.Node) []ir.Node {
nel := len(el) nel := len(el)
for _, v := range vl { for _, v := range vl {
v := v.(*ir.Name)
var e ir.Node var e ir.Node
if doexpr { if doexpr {
if len(el) == 0 { if len(el) == 0 {
@ -170,7 +172,7 @@ func variter(vl []ir.Node, t ir.Node, el []ir.Node) []ir.Node {
v.SetOp(ir.ONAME) v.SetOp(ir.ONAME)
declare(v, dclcontext) declare(v, dclcontext)
v.Name().Ntype = t v.Ntype = t
if e != nil || Curfn != nil || ir.IsBlank(v) { if e != nil || Curfn != nil || ir.IsBlank(v) {
if Curfn != nil { if Curfn != nil {
@ -179,7 +181,7 @@ func variter(vl []ir.Node, t ir.Node, el []ir.Node) []ir.Node {
e = ir.Nod(ir.OAS, v, e) e = ir.Nod(ir.OAS, v, e)
init = append(init, e) init = append(init, e)
if e.Right() != nil { if e.Right() != nil {
v.Name().Defn = e v.Defn = e
} }
} }
} }
@ -200,10 +202,10 @@ func newnoname(s *types.Sym) ir.Node {
return n return n
} }
// newfuncnamel generates a new name node for a function or method. // newFuncNameAt generates a new name node for a function or method.
func newfuncnamel(pos src.XPos, s *types.Sym, fn *ir.Func) ir.Node { func newFuncNameAt(pos src.XPos, s *types.Sym, fn *ir.Func) *ir.Name {
if fn.Nname != nil { if fn.Nname != nil {
base.Fatalf("newfuncnamel - already have name") base.Fatalf("newFuncName - already have name")
} }
n := ir.NewNameAt(pos, s) n := ir.NewNameAt(pos, s)
n.SetFunc(fn) n.SetFunc(fn)
@ -271,20 +273,20 @@ func oldname(s *types.Sym) ir.Node {
// the := it looks like a reference to the outer x so we'll // the := it looks like a reference to the outer x so we'll
// make x a closure variable unnecessarily. // make x a closure variable unnecessarily.
c := n.Name().Innermost c := n.Name().Innermost
if c == nil || c.Name().Curfn != Curfn { if c == nil || c.Curfn != Curfn {
// Do not have a closure var for the active closure yet; make one. // Do not have a closure var for the active closure yet; make one.
c = NewName(s) c = NewName(s)
c.SetClass(ir.PAUTOHEAP) c.SetClass(ir.PAUTOHEAP)
c.Name().SetIsClosureVar(true) c.SetIsClosureVar(true)
c.SetIsDDD(n.IsDDD()) c.SetIsDDD(n.IsDDD())
c.Name().Defn = n c.Defn = n
// Link into list of active closure variables. // Link into list of active closure variables.
// Popped from list in func funcLit. // Popped from list in func funcLit.
c.Name().Outer = n.Name().Innermost c.Outer = n.Name().Innermost
n.Name().Innermost = c n.Name().Innermost = c
Curfn.Func().ClosureVars.Append(c) Curfn.ClosureVars = append(Curfn.ClosureVars, c)
} }
// return ref to closure var, not original // return ref to closure var, not original
@ -349,7 +351,7 @@ func colasdefn(left []ir.Node, defn ir.Node) {
} }
nnew++ nnew++
n = NewName(n.Sym()) n := NewName(n.Sym())
declare(n, dclcontext) declare(n, dclcontext)
n.Name().Defn = defn n.Name().Defn = defn
defn.PtrInit().Append(ir.Nod(ir.ODCL, n, nil)) defn.PtrInit().Append(ir.Nod(ir.ODCL, n, nil))
@ -377,18 +379,18 @@ func ifacedcl(n ir.Node) {
// and declare the arguments. // and declare the arguments.
// called in extern-declaration context // called in extern-declaration context
// returns in auto-declaration context. // returns in auto-declaration context.
func funchdr(n ir.Node) { func funchdr(fn *ir.Func) {
// change the declaration context from extern to auto // change the declaration context from extern to auto
funcStack = append(funcStack, funcStackEnt{Curfn, dclcontext}) funcStack = append(funcStack, funcStackEnt{Curfn, dclcontext})
Curfn = n Curfn = fn
dclcontext = ir.PAUTO dclcontext = ir.PAUTO
types.Markdcl() types.Markdcl()
if n.Func().Nname != nil && n.Func().Nname.Name().Ntype != nil { if fn.Nname != nil && fn.Nname.Ntype != nil {
funcargs(n.Func().Nname.Name().Ntype) funcargs(fn.Nname.Ntype)
} else { } else {
funcargs2(n.Type()) funcargs2(fn.Type())
} }
} }
@ -450,10 +452,11 @@ func funcarg(n ir.Node, ctxt ir.Class) {
return return
} }
n.SetRight(ir.NewNameAt(n.Pos(), n.Sym())) name := ir.NewNameAt(n.Pos(), n.Sym())
n.Right().Name().Ntype = n.Left() n.SetRight(name)
n.Right().SetIsDDD(n.IsDDD()) name.Ntype = n.Left()
declare(n.Right(), ctxt) name.SetIsDDD(n.IsDDD())
declare(name, ctxt)
vargen++ vargen++
n.Right().Name().Vargen = int32(vargen) n.Right().Name().Vargen = int32(vargen)
@ -492,7 +495,7 @@ func funcarg2(f *types.Field, ctxt ir.Class) {
var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext
type funcStackEnt struct { type funcStackEnt struct {
curfn ir.Node curfn *ir.Func
dclcontext ir.Class dclcontext ir.Class
} }
@ -937,18 +940,18 @@ func setNodeNameFunc(n ir.Node) {
n.Sym().SetFunc(true) n.Sym().SetFunc(true)
} }
func dclfunc(sym *types.Sym, tfn ir.Node) ir.Node { func dclfunc(sym *types.Sym, tfn ir.Node) *ir.Func {
if tfn.Op() != ir.OTFUNC { if tfn.Op() != ir.OTFUNC {
base.Fatalf("expected OTFUNC node, got %v", tfn) base.Fatalf("expected OTFUNC node, got %v", tfn)
} }
fn := ir.Nod(ir.ODCLFUNC, nil, nil) fn := ir.NewFunc(base.Pos)
fn.Func().Nname = newfuncnamel(base.Pos, sym, fn.Func()) fn.Nname = newFuncNameAt(base.Pos, sym, fn)
fn.Func().Nname.Name().Defn = fn fn.Nname.Defn = fn
fn.Func().Nname.Name().Ntype = tfn fn.Nname.Ntype = tfn
setNodeNameFunc(fn.Func().Nname) setNodeNameFunc(fn.Nname)
funchdr(fn) funchdr(fn)
fn.Func().Nname.Name().Ntype = typecheck(fn.Func().Nname.Name().Ntype, ctxType) fn.Nname.Ntype = typecheck(fn.Nname.Ntype, ctxType)
return fn return fn
} }
@ -959,11 +962,11 @@ type nowritebarrierrecChecker struct {
extraCalls map[ir.Node][]nowritebarrierrecCall extraCalls map[ir.Node][]nowritebarrierrecCall
// curfn is the current function during AST walks. // curfn is the current function during AST walks.
curfn ir.Node curfn *ir.Func
} }
type nowritebarrierrecCall struct { type nowritebarrierrecCall struct {
target ir.Node // ODCLFUNC of caller or callee target *ir.Func // caller or callee
lineno src.XPos // line of call lineno src.XPos // line of call
} }
@ -983,7 +986,7 @@ func newNowritebarrierrecChecker() *nowritebarrierrecChecker {
if n.Op() != ir.ODCLFUNC { if n.Op() != ir.ODCLFUNC {
continue continue
} }
c.curfn = n c.curfn = n.(*ir.Func)
ir.Inspect(n, c.findExtraCalls) ir.Inspect(n, c.findExtraCalls)
} }
c.curfn = nil c.curfn = nil
@ -1002,13 +1005,13 @@ func (c *nowritebarrierrecChecker) findExtraCalls(n ir.Node) bool {
return true return true
} }
var callee ir.Node var callee *ir.Func
arg := n.List().First() arg := n.List().First()
switch arg.Op() { switch arg.Op() {
case ir.ONAME: case ir.ONAME:
callee = arg.Name().Defn callee = arg.Name().Defn.(*ir.Func)
case ir.OCLOSURE: case ir.OCLOSURE:
callee = arg.Func().Decl callee = arg.Func()
default: default:
base.Fatalf("expected ONAME or OCLOSURE node, got %+v", arg) base.Fatalf("expected ONAME or OCLOSURE node, got %+v", arg)
} }
@ -1027,13 +1030,8 @@ func (c *nowritebarrierrecChecker) findExtraCalls(n ir.Node) bool {
// because that's all we know after we start SSA. // because that's all we know after we start SSA.
// //
// This can be called concurrently for different from Nodes. // This can be called concurrently for different from Nodes.
func (c *nowritebarrierrecChecker) recordCall(from ir.Node, to *obj.LSym, pos src.XPos) { func (c *nowritebarrierrecChecker) recordCall(fn *ir.Func, to *obj.LSym, pos src.XPos) {
if from.Op() != ir.ODCLFUNC { // We record this information on the *Func so this is concurrent-safe.
base.Fatalf("expected ODCLFUNC, got %v", from)
}
// We record this information on the *Func so this is
// concurrent-safe.
fn := from.Func()
if fn.NWBRCalls == nil { if fn.NWBRCalls == nil {
fn.NWBRCalls = new([]ir.SymAndPos) fn.NWBRCalls = new([]ir.SymAndPos)
} }
@ -1045,7 +1043,7 @@ func (c *nowritebarrierrecChecker) check() {
// capture all calls created by lowering, but this means we // capture all calls created by lowering, but this means we
// only get to see the obj.LSyms of calls. symToFunc lets us // only get to see the obj.LSyms of calls. symToFunc lets us
// get back to the ODCLFUNCs. // get back to the ODCLFUNCs.
symToFunc := make(map[*obj.LSym]ir.Node) symToFunc := make(map[*obj.LSym]*ir.Func)
// funcs records the back-edges of the BFS call graph walk. It // funcs records the back-edges of the BFS call graph walk. It
// maps from the ODCLFUNC of each function that must not have // maps from the ODCLFUNC of each function that must not have
// write barriers to the call that inhibits them. Functions // write barriers to the call that inhibits them. Functions
@ -1060,24 +1058,25 @@ func (c *nowritebarrierrecChecker) check() {
if n.Op() != ir.ODCLFUNC { if n.Op() != ir.ODCLFUNC {
continue continue
} }
fn := n.(*ir.Func)
symToFunc[n.Func().LSym] = n symToFunc[fn.LSym] = fn
// Make nowritebarrierrec functions BFS roots. // Make nowritebarrierrec functions BFS roots.
if n.Func().Pragma&ir.Nowritebarrierrec != 0 { if fn.Pragma&ir.Nowritebarrierrec != 0 {
funcs[n] = nowritebarrierrecCall{} funcs[fn] = nowritebarrierrecCall{}
q.PushRight(n) q.PushRight(fn)
} }
// Check go:nowritebarrier functions. // Check go:nowritebarrier functions.
if n.Func().Pragma&ir.Nowritebarrier != 0 && n.Func().WBPos.IsKnown() { if fn.Pragma&ir.Nowritebarrier != 0 && fn.WBPos.IsKnown() {
base.ErrorfAt(n.Func().WBPos, "write barrier prohibited") base.ErrorfAt(fn.WBPos, "write barrier prohibited")
} }
} }
// Perform a BFS of the call graph from all // Perform a BFS of the call graph from all
// go:nowritebarrierrec functions. // go:nowritebarrierrec functions.
enqueue := func(src, target ir.Node, pos src.XPos) { enqueue := func(src, target *ir.Func, pos src.XPos) {
if target.Func().Pragma&ir.Yeswritebarrierrec != 0 { if target.Pragma&ir.Yeswritebarrierrec != 0 {
// Don't flow into this function. // Don't flow into this function.
return return
} }
@ -1091,17 +1090,17 @@ func (c *nowritebarrierrecChecker) check() {
q.PushRight(target) q.PushRight(target)
} }
for !q.Empty() { for !q.Empty() {
fn := q.PopLeft() fn := q.PopLeft().(*ir.Func)
// Check fn. // Check fn.
if fn.Func().WBPos.IsKnown() { if fn.WBPos.IsKnown() {
var err bytes.Buffer var err bytes.Buffer
call := funcs[fn] call := funcs[fn]
for call.target != nil { for call.target != nil {
fmt.Fprintf(&err, "\n\t%v: called by %v", base.FmtPos(call.lineno), call.target.Func().Nname) fmt.Fprintf(&err, "\n\t%v: called by %v", base.FmtPos(call.lineno), call.target.Nname)
call = funcs[call.target] call = funcs[call.target]
} }
base.ErrorfAt(fn.Func().WBPos, "write barrier prohibited by caller; %v%s", fn.Func().Nname, err.String()) base.ErrorfAt(fn.WBPos, "write barrier prohibited by caller; %v%s", fn.Nname, err.String())
continue continue
} }
@ -1109,10 +1108,10 @@ func (c *nowritebarrierrecChecker) check() {
for _, callee := range c.extraCalls[fn] { for _, callee := range c.extraCalls[fn] {
enqueue(fn, callee.target, callee.lineno) enqueue(fn, callee.target, callee.lineno)
} }
if fn.Func().NWBRCalls == nil { if fn.NWBRCalls == nil {
continue continue
} }
for _, callee := range *fn.Func().NWBRCalls { for _, callee := range *fn.NWBRCalls {
target := symToFunc[callee.Sym] target := symToFunc[callee.Sym]
if target != nil { if target != nil {
enqueue(fn, target, callee.Pos) enqueue(fn, target, callee.Pos)

View file

@ -6,6 +6,7 @@ package gc
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/internal/dwarf" "cmd/internal/dwarf"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
@ -211,6 +212,7 @@ func genAbstractFunc(fn *obj.LSym) {
base.Ctxt.Diag("failed to locate precursor fn for %v", fn) base.Ctxt.Diag("failed to locate precursor fn for %v", fn)
return return
} }
_ = ifn.(*ir.Func)
if base.Debug.DwarfInl != 0 { if base.Debug.DwarfInl != 0 {
base.Ctxt.Logf("DwarfAbstractFunc(%v)\n", fn.Name) base.Ctxt.Logf("DwarfAbstractFunc(%v)\n", fn.Name)
} }

View file

@ -87,7 +87,7 @@ type Escape struct {
allLocs []*EscLocation allLocs []*EscLocation
labels map[*types.Sym]labelState // known labels labels map[*types.Sym]labelState // known labels
curfn ir.Node curfn *ir.Func
// loopDepth counts the current loop nesting depth within // loopDepth counts the current loop nesting depth within
// curfn. It increments within each "for" loop and at each // curfn. It increments within each "for" loop and at each
@ -103,7 +103,7 @@ type Escape struct {
// variable. // variable.
type EscLocation struct { type EscLocation struct {
n ir.Node // represented variable or expression, if any n ir.Node // represented variable or expression, if any
curfn ir.Node // enclosing function curfn *ir.Func // enclosing function
edges []EscEdge // incoming edges edges []EscEdge // incoming edges
loopDepth int // loopDepth at declaration loopDepth int // loopDepth at declaration
@ -180,7 +180,7 @@ func escFmt(n ir.Node, short bool) string {
// escapeFuncs performs escape analysis on a minimal batch of // escapeFuncs performs escape analysis on a minimal batch of
// functions. // functions.
func escapeFuncs(fns []ir.Node, recursive bool) { func escapeFuncs(fns []*ir.Func, recursive bool) {
for _, fn := range fns { for _, fn := range fns {
if fn.Op() != ir.ODCLFUNC { if fn.Op() != ir.ODCLFUNC {
base.Fatalf("unexpected node: %v", fn) base.Fatalf("unexpected node: %v", fn)
@ -203,8 +203,8 @@ func escapeFuncs(fns []ir.Node, recursive bool) {
e.finish(fns) e.finish(fns)
} }
func (e *Escape) initFunc(fn ir.Node) { func (e *Escape) initFunc(fn *ir.Func) {
if fn.Op() != ir.ODCLFUNC || fn.Esc() != EscFuncUnknown { if fn.Esc() != EscFuncUnknown {
base.Fatalf("unexpected node: %v", fn) base.Fatalf("unexpected node: %v", fn)
} }
fn.SetEsc(EscFuncPlanned) fn.SetEsc(EscFuncPlanned)
@ -216,14 +216,14 @@ func (e *Escape) initFunc(fn ir.Node) {
e.loopDepth = 1 e.loopDepth = 1
// Allocate locations for local variables. // Allocate locations for local variables.
for _, dcl := range fn.Func().Dcl { for _, dcl := range fn.Dcl {
if dcl.Op() == ir.ONAME { if dcl.Op() == ir.ONAME {
e.newLoc(dcl, false) e.newLoc(dcl, false)
} }
} }
} }
func (e *Escape) walkFunc(fn ir.Node) { func (e *Escape) walkFunc(fn *ir.Func) {
fn.SetEsc(EscFuncStarted) fn.SetEsc(EscFuncStarted)
// Identify labels that mark the head of an unstructured loop. // Identify labels that mark the head of an unstructured loop.
@ -589,7 +589,8 @@ func (e *Escape) exprSkipInit(k EscHole, n ir.Node) {
for i := m.Type.NumResults(); i > 0; i-- { for i := m.Type.NumResults(); i > 0; i-- {
ks = append(ks, e.heapHole()) ks = append(ks, e.heapHole())
} }
paramK := e.tagHole(ks, ir.AsNode(m.Nname), m.Type.Recv()) name, _ := m.Nname.(*ir.Name)
paramK := e.tagHole(ks, name, m.Type.Recv())
e.expr(e.teeHole(paramK, closureK), n.Left()) e.expr(e.teeHole(paramK, closureK), n.Left())
@ -633,17 +634,13 @@ func (e *Escape) exprSkipInit(k EscHole, n ir.Node) {
k = e.spill(k, n) k = e.spill(k, n)
// Link addresses of captured variables to closure. // Link addresses of captured variables to closure.
for _, v := range n.Func().ClosureVars.Slice() { for _, v := range n.Func().ClosureVars {
if v.Op() == ir.OXXX { // unnamed out argument; see dcl.go:/^funcargs
continue
}
k := k k := k
if !v.Name().Byval() { if !v.Byval() {
k = k.addr(v, "reference") k = k.addr(v, "reference")
} }
e.expr(k.note(n, "captured by a closure"), v.Name().Defn) e.expr(k.note(n, "captured by a closure"), v.Defn)
} }
case ir.ORUNES2STR, ir.OBYTES2STR, ir.OSTR2RUNES, ir.OSTR2BYTES, ir.ORUNESTR: case ir.ORUNES2STR, ir.OBYTES2STR, ir.OSTR2RUNES, ir.OSTR2BYTES, ir.ORUNESTR:
@ -813,12 +810,12 @@ func (e *Escape) call(ks []EscHole, call, where ir.Node) {
fixVariadicCall(call) fixVariadicCall(call)
// Pick out the function callee, if statically known. // Pick out the function callee, if statically known.
var fn ir.Node var fn *ir.Name
switch call.Op() { switch call.Op() {
case ir.OCALLFUNC: case ir.OCALLFUNC:
switch v := staticValue(call.Left()); { switch v := staticValue(call.Left()); {
case v.Op() == ir.ONAME && v.Class() == ir.PFUNC: case v.Op() == ir.ONAME && v.Class() == ir.PFUNC:
fn = v fn = v.(*ir.Name)
case v.Op() == ir.OCLOSURE: case v.Op() == ir.OCLOSURE:
fn = v.Func().Nname fn = v.Func().Nname
} }
@ -902,7 +899,7 @@ func (e *Escape) call(ks []EscHole, call, where ir.Node) {
// ks should contain the holes representing where the function // ks should contain the holes representing where the function
// callee's results flows. fn is the statically-known callee function, // callee's results flows. fn is the statically-known callee function,
// if any. // if any.
func (e *Escape) tagHole(ks []EscHole, fn ir.Node, param *types.Field) EscHole { func (e *Escape) tagHole(ks []EscHole, fn *ir.Name, param *types.Field) EscHole {
// If this is a dynamic call, we can't rely on param.Note. // If this is a dynamic call, we can't rely on param.Note.
if fn == nil { if fn == nil {
return e.heapHole() return e.heapHole()
@ -943,9 +940,9 @@ func (e *Escape) tagHole(ks []EscHole, fn ir.Node, param *types.Field) EscHole {
// fn has not yet been analyzed, so its parameters and results // fn has not yet been analyzed, so its parameters and results
// should be incorporated directly into the flow graph instead of // should be incorporated directly into the flow graph instead of
// relying on its escape analysis tagging. // relying on its escape analysis tagging.
func (e *Escape) inMutualBatch(fn ir.Node) bool { func (e *Escape) inMutualBatch(fn *ir.Name) bool {
if fn.Name().Defn != nil && fn.Name().Defn.Esc() < EscFuncTagged { if fn.Defn != nil && fn.Defn.Esc() < EscFuncTagged {
if fn.Name().Defn.Esc() == EscFuncUnknown { if fn.Defn.Esc() == EscFuncUnknown {
base.Fatalf("graph inconsistency") base.Fatalf("graph inconsistency")
} }
return true return true
@ -1368,7 +1365,7 @@ func (e *Escape) outlives(l, other *EscLocation) bool {
// //
// var u int // okay to stack allocate // var u int // okay to stack allocate
// *(func() *int { return &u }()) = 42 // *(func() *int { return &u }()) = 42
if containsClosure(other.curfn, l.curfn) && l.curfn.Func().ClosureCalled { if containsClosure(other.curfn, l.curfn) && l.curfn.ClosureCalled() {
return false return false
} }
@ -1402,11 +1399,7 @@ func (e *Escape) outlives(l, other *EscLocation) bool {
} }
// containsClosure reports whether c is a closure contained within f. // containsClosure reports whether c is a closure contained within f.
func containsClosure(f, c ir.Node) bool { func containsClosure(f, c *ir.Func) bool {
if f.Op() != ir.ODCLFUNC || c.Op() != ir.ODCLFUNC {
base.Fatalf("bad containsClosure: %v, %v", f, c)
}
// Common case. // Common case.
if f == c { if f == c {
return false return false
@ -1414,8 +1407,8 @@ func containsClosure(f, c ir.Node) bool {
// Closures within function Foo are named like "Foo.funcN..." // Closures within function Foo are named like "Foo.funcN..."
// TODO(mdempsky): Better way to recognize this. // TODO(mdempsky): Better way to recognize this.
fn := f.Func().Nname.Sym().Name fn := f.Sym().Name
cn := c.Func().Nname.Sym().Name cn := c.Sym().Name
return len(cn) > len(fn) && cn[:len(fn)] == fn && cn[len(fn)] == '.' return len(cn) > len(fn) && cn[:len(fn)] == fn && cn[len(fn)] == '.'
} }
@ -1437,7 +1430,7 @@ func (l *EscLocation) leakTo(sink *EscLocation, derefs int) {
l.paramEsc.AddHeap(derefs) l.paramEsc.AddHeap(derefs)
} }
func (e *Escape) finish(fns []ir.Node) { func (e *Escape) finish(fns []*ir.Func) {
// Record parameter tags for package export data. // Record parameter tags for package export data.
for _, fn := range fns { for _, fn := range fns {
fn.SetEsc(EscFuncTagged) fn.SetEsc(EscFuncTagged)
@ -1614,12 +1607,12 @@ const (
EscNever // By construction will not escape. EscNever // By construction will not escape.
) )
// funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way. // funcSym returns fn.Nname.Sym if no nils are encountered along the way.
func funcSym(fn ir.Node) *types.Sym { func funcSym(fn *ir.Func) *types.Sym {
if fn == nil || fn.Func().Nname == nil { if fn == nil || fn.Nname == nil {
return nil return nil
} }
return fn.Func().Nname.Sym() return fn.Sym()
} }
// Mark labels that have no backjumps to them as not increasing e.loopdepth. // Mark labels that have no backjumps to them as not increasing e.loopdepth.
@ -1798,6 +1791,7 @@ func addrescapes(n ir.Node) {
// Nothing to do. // Nothing to do.
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
if n == nodfp { if n == nodfp {
break break
} }
@ -1832,10 +1826,6 @@ func addrescapes(n ir.Node) {
// heap in f, not in the inner closure. Flip over to f before calling moveToHeap. // heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
oldfn := Curfn oldfn := Curfn
Curfn = n.Name().Curfn Curfn = n.Name().Curfn
if Curfn.Op() == ir.OCLOSURE {
Curfn = Curfn.Func().Decl
panic("can't happen")
}
ln := base.Pos ln := base.Pos
base.Pos = Curfn.Pos() base.Pos = Curfn.Pos()
moveToHeap(n) moveToHeap(n)
@ -1855,7 +1845,7 @@ func addrescapes(n ir.Node) {
} }
// moveToHeap records the parameter or local variable n as moved to the heap. // moveToHeap records the parameter or local variable n as moved to the heap.
func moveToHeap(n ir.Node) { func moveToHeap(n *ir.Name) {
if base.Flag.LowerR != 0 { if base.Flag.LowerR != 0 {
ir.Dump("MOVE", n) ir.Dump("MOVE", n)
} }
@ -1877,7 +1867,7 @@ func moveToHeap(n ir.Node) {
// Unset AutoTemp to persist the &foo variable name through SSA to // Unset AutoTemp to persist the &foo variable name through SSA to
// liveness analysis. // liveness analysis.
// TODO(mdempsky/drchase): Cleaner solution? // TODO(mdempsky/drchase): Cleaner solution?
heapaddr.Name().SetAutoTemp(false) heapaddr.SetAutoTemp(false)
// Parameters have a local stack copy used at function start/end // Parameters have a local stack copy used at function start/end
// in addition to the copy in the heap that may live longer than // in addition to the copy in the heap that may live longer than
@ -1895,14 +1885,14 @@ func moveToHeap(n ir.Node) {
stackcopy.SetType(n.Type()) stackcopy.SetType(n.Type())
stackcopy.SetOffset(n.Offset()) stackcopy.SetOffset(n.Offset())
stackcopy.SetClass(n.Class()) stackcopy.SetClass(n.Class())
stackcopy.Name().Heapaddr = heapaddr stackcopy.Heapaddr = heapaddr
if n.Class() == ir.PPARAMOUT { if n.Class() == ir.PPARAMOUT {
// Make sure the pointer to the heap copy is kept live throughout the function. // Make sure the pointer to the heap copy is kept live throughout the function.
// The function could panic at any point, and then a defer could recover. // The function could panic at any point, and then a defer could recover.
// Thus, we need the pointer to the heap copy always available so the // Thus, we need the pointer to the heap copy always available so the
// post-deferreturn code can copy the return value back to the stack. // post-deferreturn code can copy the return value back to the stack.
// See issue 16095. // See issue 16095.
heapaddr.Name().SetIsOutputParamHeapAddr(true) heapaddr.SetIsOutputParamHeapAddr(true)
} }
n.Name().Stackcopy = stackcopy n.Name().Stackcopy = stackcopy
@ -1910,9 +1900,9 @@ func moveToHeap(n ir.Node) {
// liveness and other analyses use the underlying stack slot // liveness and other analyses use the underlying stack slot
// and not the now-pseudo-variable n. // and not the now-pseudo-variable n.
found := false found := false
for i, d := range Curfn.Func().Dcl { for i, d := range Curfn.Dcl {
if d == n { if d == n {
Curfn.Func().Dcl[i] = stackcopy Curfn.Dcl[i] = stackcopy
found = true found = true
break break
} }
@ -1925,7 +1915,7 @@ func moveToHeap(n ir.Node) {
if !found { if !found {
base.Fatalf("cannot find %v in local variable list", n) base.Fatalf("cannot find %v in local variable list", n)
} }
Curfn.Func().Dcl = append(Curfn.Func().Dcl, n) Curfn.Dcl = append(Curfn.Dcl, n)
} }
// Modify n in place so that uses of n now mean indirection of the heapaddr. // Modify n in place so that uses of n now mean indirection of the heapaddr.

View file

@ -161,8 +161,12 @@ func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
if n == nil { if n == nil {
return return
} }
name := n.(*ir.Name)
n.SetFunc(new(ir.Func)) fn := ir.NewFunc(pos)
fn.SetType(t)
name.SetFunc(fn)
fn.Nname = name
if base.Flag.E != 0 { if base.Flag.E != 0 {
fmt.Printf("import func %v%S\n", s, t) fmt.Printf("import func %v%S\n", s, t)

View file

@ -52,7 +52,7 @@ func autotmpname(n int) string {
} }
// make a new Node off the books // make a new Node off the books
func tempAt(pos src.XPos, curfn ir.Node, t *types.Type) *ir.Name { func tempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
if curfn == nil { if curfn == nil {
base.Fatalf("no curfn for tempAt") base.Fatalf("no curfn for tempAt")
} }
@ -65,7 +65,7 @@ func tempAt(pos src.XPos, curfn ir.Node, t *types.Type) *ir.Name {
} }
s := &types.Sym{ s := &types.Sym{
Name: autotmpname(len(curfn.Func().Dcl)), Name: autotmpname(len(curfn.Dcl)),
Pkg: ir.LocalPkg, Pkg: ir.LocalPkg,
} }
n := ir.NewNameAt(pos, s) n := ir.NewNameAt(pos, s)
@ -73,10 +73,10 @@ func tempAt(pos src.XPos, curfn ir.Node, t *types.Type) *ir.Name {
n.SetType(t) n.SetType(t)
n.SetClass(ir.PAUTO) n.SetClass(ir.PAUTO)
n.SetEsc(EscNever) n.SetEsc(EscNever)
n.Name().Curfn = curfn n.Curfn = curfn
n.Name().SetUsed(true) n.SetUsed(true)
n.Name().SetAutoTemp(true) n.SetAutoTemp(true)
curfn.Func().Dcl = append(curfn.Func().Dcl, n) curfn.Dcl = append(curfn.Dcl, n)
dowidth(t) dowidth(t)

View file

@ -132,7 +132,7 @@ var xtop []ir.Node
var exportlist []ir.Node var exportlist []ir.Node
var importlist []ir.Node // imported functions and methods with inlinable bodies var importlist []*ir.Func // imported functions and methods with inlinable bodies
var ( var (
funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym) funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
@ -141,7 +141,7 @@ var (
var dclcontext ir.Class // PEXTERN/PAUTO var dclcontext ir.Class // PEXTERN/PAUTO
var Curfn ir.Node var Curfn *ir.Func
var Widthptr int var Widthptr int
@ -156,7 +156,7 @@ var instrumenting bool
// Whether we are tracking lexical scopes for DWARF. // Whether we are tracking lexical scopes for DWARF.
var trackScopes bool var trackScopes bool
var nodfp ir.Node var nodfp *ir.Name
var autogeneratedPos src.XPos var autogeneratedPos src.XPos

View file

@ -47,7 +47,7 @@ type Progs struct {
next *obj.Prog // next Prog next *obj.Prog // next Prog
pc int64 // virtual PC; count of Progs pc int64 // virtual PC; count of Progs
pos src.XPos // position to use for new Progs pos src.XPos // position to use for new Progs
curfn ir.Node // fn these Progs are for curfn *ir.Func // fn these Progs are for
progcache []obj.Prog // local progcache progcache []obj.Prog // local progcache
cacheidx int // first free element of progcache cacheidx int // first free element of progcache
@ -57,7 +57,7 @@ type Progs struct {
// newProgs returns a new Progs for fn. // newProgs returns a new Progs for fn.
// worker indicates which of the backend workers will use the Progs. // worker indicates which of the backend workers will use the Progs.
func newProgs(fn ir.Node, worker int) *Progs { func newProgs(fn *ir.Func, worker int) *Progs {
pp := new(Progs) pp := new(Progs)
if base.Ctxt.CanReuseProgs() { if base.Ctxt.CanReuseProgs() {
sz := len(sharedProgArray) / base.Flag.LowerC sz := len(sharedProgArray) / base.Flag.LowerC
@ -174,17 +174,17 @@ func (pp *Progs) Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16
return q return q
} }
func (pp *Progs) settext(fn ir.Node) { func (pp *Progs) settext(fn *ir.Func) {
if pp.Text != nil { if pp.Text != nil {
base.Fatalf("Progs.settext called twice") base.Fatalf("Progs.settext called twice")
} }
ptxt := pp.Prog(obj.ATEXT) ptxt := pp.Prog(obj.ATEXT)
pp.Text = ptxt pp.Text = ptxt
fn.Func().LSym.Func().Text = ptxt fn.LSym.Func().Text = ptxt
ptxt.From.Type = obj.TYPE_MEM ptxt.From.Type = obj.TYPE_MEM
ptxt.From.Name = obj.NAME_EXTERN ptxt.From.Name = obj.NAME_EXTERN
ptxt.From.Sym = fn.Func().LSym ptxt.From.Sym = fn.LSym
} }
// initLSym defines f's obj.LSym and initializes it based on the // initLSym defines f's obj.LSym and initializes it based on the
@ -281,7 +281,7 @@ func initLSym(f *ir.Func, hasBody bool) {
// See test/recover.go for test cases and src/reflect/value.go // See test/recover.go for test cases and src/reflect/value.go
// for the actual functions being considered. // for the actual functions being considered.
if base.Ctxt.Pkgpath == "reflect" { if base.Ctxt.Pkgpath == "reflect" {
switch f.Nname.Sym().Name { switch f.Sym().Name {
case "callReflect", "callMethod": case "callReflect", "callMethod":
flag |= obj.WRAPPER flag |= obj.WRAPPER
} }

View file

@ -429,6 +429,7 @@ func (p *iexporter) doDecl(n ir.Node) {
switch n.Op() { switch n.Op() {
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
switch n.Class() { switch n.Class() {
case ir.PEXTERN: case ir.PEXTERN:
// Variable. // Variable.
@ -515,7 +516,7 @@ func (w *exportWriter) tag(tag byte) {
w.data.WriteByte(tag) w.data.WriteByte(tag)
} }
func (p *iexporter) doInline(f ir.Node) { func (p *iexporter) doInline(f *ir.Name) {
w := p.newWriter() w := p.newWriter()
w.setPkg(fnpkg(f), false) w.setPkg(fnpkg(f), false)
@ -960,7 +961,7 @@ func (w *exportWriter) varExt(n ir.Node) {
w.symIdx(n.Sym()) w.symIdx(n.Sym())
} }
func (w *exportWriter) funcExt(n ir.Node) { func (w *exportWriter) funcExt(n *ir.Name) {
w.linkname(n.Sym()) w.linkname(n.Sym())
w.symIdx(n.Sym()) w.symIdx(n.Sym())
@ -979,14 +980,7 @@ func (w *exportWriter) funcExt(n ir.Node) {
} }
// Endlineno for inlined function. // Endlineno for inlined function.
if n.Name().Defn != nil {
w.pos(n.Name().Defn.Func().Endlineno)
} else {
// When the exported node was defined externally,
// e.g. io exports atomic.(*Value).Load or bytes exports errors.New.
// Keep it as we don't distinguish this case in iimport.go.
w.pos(n.Func().Endlineno) w.pos(n.Func().Endlineno)
}
} else { } else {
w.uint64(0) w.uint64(0)
} }
@ -994,7 +988,7 @@ func (w *exportWriter) funcExt(n ir.Node) {
func (w *exportWriter) methExt(m *types.Field) { func (w *exportWriter) methExt(m *types.Field) {
w.bool(m.Nointerface()) w.bool(m.Nointerface())
w.funcExt(ir.AsNode(m.Nname)) w.funcExt(ir.AsNode(m.Nname).(*ir.Name))
} }
func (w *exportWriter) linkname(s *types.Sym) { func (w *exportWriter) linkname(s *types.Sym) {

View file

@ -41,7 +41,7 @@ var (
inlineImporter = map[*types.Sym]iimporterAndOffset{} inlineImporter = map[*types.Sym]iimporterAndOffset{}
) )
func expandDecl(n ir.Node) { func expandDecl(n *ir.Name) {
if n.Op() != ir.ONONAME { if n.Op() != ir.ONONAME {
return return
} }
@ -55,12 +55,12 @@ func expandDecl(n ir.Node) {
r.doDecl(n) r.doDecl(n)
} }
func expandInline(fn ir.Node) { func expandInline(fn *ir.Func) {
if fn.Func().Inl.Body != nil { if fn.Inl.Body != nil {
return return
} }
r := importReaderFor(fn, inlineImporter) r := importReaderFor(fn.Nname, inlineImporter)
if r == nil { if r == nil {
base.Fatalf("missing import reader for %v", fn) base.Fatalf("missing import reader for %v", fn)
} }
@ -68,7 +68,7 @@ func expandInline(fn ir.Node) {
r.doInline(fn) r.doInline(fn)
} }
func importReaderFor(n ir.Node, importers map[*types.Sym]iimporterAndOffset) *importReader { func importReaderFor(n *ir.Name, importers map[*types.Sym]iimporterAndOffset) *importReader {
x, ok := importers[n.Sym()] x, ok := importers[n.Sym()]
if !ok { if !ok {
return nil return nil
@ -331,7 +331,9 @@ func (r *importReader) doDecl(n ir.Node) {
recv := r.param() recv := r.param()
mtyp := r.signature(recv) mtyp := r.signature(recv)
m := newfuncnamel(mpos, methodSym(recv.Type, msym), new(ir.Func)) fn := ir.NewFunc(mpos)
fn.SetType(mtyp)
m := newFuncNameAt(mpos, methodSym(recv.Type, msym), fn)
m.SetType(mtyp) m.SetType(mtyp)
m.SetClass(ir.PFUNC) m.SetClass(ir.PFUNC)
// methodSym already marked m.Sym as a function. // methodSym already marked m.Sym as a function.
@ -501,7 +503,7 @@ func (r *importReader) typ1() *types.Type {
// type. // type.
n := ir.AsNode(r.qualifiedIdent().PkgDef()) n := ir.AsNode(r.qualifiedIdent().PkgDef())
if n.Op() == ir.ONONAME { if n.Op() == ir.ONONAME {
expandDecl(n) expandDecl(n.(*ir.Name))
} }
if n.Op() != ir.OTYPE { if n.Op() != ir.OTYPE {
base.Fatalf("expected OTYPE, got %v: %v, %v", n.Op(), n.Sym(), n) base.Fatalf("expected OTYPE, got %v: %v, %v", n.Op(), n.Sym(), n)
@ -695,12 +697,12 @@ func (r *importReader) typeExt(t *types.Type) {
// so we can use index to reference the symbol. // so we can use index to reference the symbol.
var typeSymIdx = make(map[*types.Type][2]int64) var typeSymIdx = make(map[*types.Type][2]int64)
func (r *importReader) doInline(n ir.Node) { func (r *importReader) doInline(fn *ir.Func) {
if len(n.Func().Inl.Body) != 0 { if len(fn.Inl.Body) != 0 {
base.Fatalf("%v already has inline body", n) base.Fatalf("%v already has inline body", fn)
} }
funchdr(n) funchdr(fn)
body := r.stmtList() body := r.stmtList()
funcbody() funcbody()
if body == nil { if body == nil {
@ -712,15 +714,15 @@ func (r *importReader) doInline(n ir.Node) {
// functions). // functions).
body = []ir.Node{} body = []ir.Node{}
} }
n.Func().Inl.Body = body fn.Inl.Body = body
importlist = append(importlist, n) importlist = append(importlist, fn)
if base.Flag.E > 0 && base.Flag.LowerM > 2 { if base.Flag.E > 0 && base.Flag.LowerM > 2 {
if base.Flag.LowerM > 3 { if base.Flag.LowerM > 3 {
fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type(), ir.AsNodes(n.Func().Inl.Body)) fmt.Printf("inl body for %v %#v: %+v\n", fn, fn.Type(), ir.AsNodes(fn.Inl.Body))
} else { } else {
fmt.Printf("inl body for %v %#v: %v\n", n, n.Type(), ir.AsNodes(n.Func().Inl.Body)) fmt.Printf("inl body for %v %#v: %v\n", fn, fn.Type(), ir.AsNodes(fn.Inl.Body))
} }
} }
} }
@ -772,7 +774,7 @@ func (r *importReader) caseList(sw ir.Node) []ir.Node {
caseVar := ir.NewNameAt(cas.Pos(), r.ident()) caseVar := ir.NewNameAt(cas.Pos(), r.ident())
declare(caseVar, dclcontext) declare(caseVar, dclcontext)
cas.PtrRlist().Set1(caseVar) cas.PtrRlist().Set1(caseVar)
caseVar.Name().Defn = sw.Left() caseVar.Defn = sw.Left()
} }
cas.PtrBody().Set(r.stmtList()) cas.PtrBody().Set(r.stmtList())
cases[i] = cas cases[i] = cas

View file

@ -19,7 +19,7 @@ var renameinitgen int
// Function collecting autotmps generated during typechecking, // Function collecting autotmps generated during typechecking,
// to be included in the package-level init function. // to be included in the package-level init function.
var initTodo = ir.Nod(ir.ODCLFUNC, nil, nil) var initTodo = ir.NewFunc(base.Pos)
func renameinit() *types.Sym { func renameinit() *types.Sym {
s := lookupN("init.", renameinitgen) s := lookupN("init.", renameinitgen)
@ -49,23 +49,23 @@ func fninit(n []ir.Node) {
base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt
initializers := lookup("init") initializers := lookup("init")
fn := dclfunc(initializers, ir.Nod(ir.OTFUNC, nil, nil)) fn := dclfunc(initializers, ir.Nod(ir.OTFUNC, nil, nil))
for _, dcl := range initTodo.Func().Dcl { for _, dcl := range initTodo.Dcl {
dcl.Name().Curfn = fn dcl.Name().Curfn = fn
} }
fn.Func().Dcl = append(fn.Func().Dcl, initTodo.Func().Dcl...) fn.Dcl = append(fn.Dcl, initTodo.Dcl...)
initTodo.Func().Dcl = nil initTodo.Dcl = nil
fn.PtrBody().Set(nf) fn.PtrBody().Set(nf)
funcbody() funcbody()
fn = typecheck(fn, ctxStmt) typecheckFunc(fn)
Curfn = fn Curfn = fn
typecheckslice(nf, ctxStmt) typecheckslice(nf, ctxStmt)
Curfn = nil Curfn = nil
xtop = append(xtop, fn) xtop = append(xtop, fn)
fns = append(fns, initializers.Linksym()) fns = append(fns, initializers.Linksym())
} }
if initTodo.Func().Dcl != nil { if initTodo.Dcl != nil {
// We only generate temps using initTodo if there // We only generate temps using initTodo if there
// are package-scope initialization statements, so // are package-scope initialization statements, so
// something's weird if we get here. // something's weird if we get here.

View file

@ -284,11 +284,11 @@ func (d *initDeps) visit(n ir.Node) bool {
case ir.ONAME: case ir.ONAME:
switch n.Class() { switch n.Class() {
case ir.PEXTERN, ir.PFUNC: case ir.PEXTERN, ir.PFUNC:
d.foundDep(n) d.foundDep(n.(*ir.Name))
} }
case ir.OCLOSURE: case ir.OCLOSURE:
d.inspectList(n.Func().Decl.Body()) d.inspectList(n.Func().Body())
case ir.ODOTMETH, ir.OCALLPART: case ir.ODOTMETH, ir.OCALLPART:
d.foundDep(methodExprName(n)) d.foundDep(methodExprName(n))
@ -299,7 +299,7 @@ func (d *initDeps) visit(n ir.Node) bool {
// foundDep records that we've found a dependency on n by adding it to // foundDep records that we've found a dependency on n by adding it to
// seen. // seen.
func (d *initDeps) foundDep(n ir.Node) { func (d *initDeps) foundDep(n *ir.Name) {
// Can happen with method expressions involving interface // Can happen with method expressions involving interface
// types; e.g., fixedbugs/issue4495.go. // types; e.g., fixedbugs/issue4495.go.
if n == nil { if n == nil {
@ -308,7 +308,7 @@ func (d *initDeps) foundDep(n ir.Node) {
// Names without definitions aren't interesting as far as // Names without definitions aren't interesting as far as
// initialization ordering goes. // initialization ordering goes.
if n.Name().Defn == nil { if n.Defn == nil {
return return
} }
@ -317,7 +317,7 @@ func (d *initDeps) foundDep(n ir.Node) {
} }
d.seen.Add(n) d.seen.Add(n)
if d.transitive && n.Class() == ir.PFUNC { if d.transitive && n.Class() == ir.PFUNC {
d.inspectList(n.Name().Defn.Body()) d.inspectList(n.Defn.Body())
} }
} }

View file

@ -53,7 +53,7 @@ const (
// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
// the ->sym can be re-used in the local package, so peel it off the receiver's type. // the ->sym can be re-used in the local package, so peel it off the receiver's type.
func fnpkg(fn ir.Node) *types.Pkg { func fnpkg(fn *ir.Name) *types.Pkg {
if ir.IsMethod(fn) { if ir.IsMethod(fn) {
// method // method
rcvr := fn.Type().Recv().Type rcvr := fn.Type().Recv().Type
@ -73,8 +73,8 @@ func fnpkg(fn ir.Node) *types.Pkg {
// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck // Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
// because they're a copy of an already checked body. // because they're a copy of an already checked body.
func typecheckinl(fn ir.Node) { func typecheckinl(fn *ir.Func) {
lno := setlineno(fn) lno := setlineno(fn.Nname)
expandInline(fn) expandInline(fn)
@ -82,19 +82,19 @@ func typecheckinl(fn ir.Node) {
// their bodies may refer to unsafe as long as the package // their bodies may refer to unsafe as long as the package
// was marked safe during import (which was checked then). // was marked safe during import (which was checked then).
// the ->inl of a local function has been typechecked before caninl copied it. // the ->inl of a local function has been typechecked before caninl copied it.
pkg := fnpkg(fn) pkg := fnpkg(fn.Nname)
if pkg == ir.LocalPkg || pkg == nil { if pkg == ir.LocalPkg || pkg == nil {
return // typecheckinl on local function return // typecheckinl on local function
} }
if base.Flag.LowerM > 2 || base.Debug.Export != 0 { if base.Flag.LowerM > 2 || base.Debug.Export != 0 {
fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym(), fn, ir.AsNodes(fn.Func().Inl.Body)) fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym(), fn, ir.AsNodes(fn.Inl.Body))
} }
savefn := Curfn savefn := Curfn
Curfn = fn Curfn = fn
typecheckslice(fn.Func().Inl.Body, ctxStmt) typecheckslice(fn.Inl.Body, ctxStmt)
Curfn = savefn Curfn = savefn
// During expandInline (which imports fn.Func.Inl.Body), // During expandInline (which imports fn.Func.Inl.Body),
@ -102,8 +102,8 @@ func typecheckinl(fn ir.Node) {
// to fn.Func.Inl.Dcl for consistency with how local functions // to fn.Func.Inl.Dcl for consistency with how local functions
// behave. (Append because typecheckinl may be called multiple // behave. (Append because typecheckinl may be called multiple
// times.) // times.)
fn.Func().Inl.Dcl = append(fn.Func().Inl.Dcl, fn.Func().Dcl...) fn.Inl.Dcl = append(fn.Inl.Dcl, fn.Dcl...)
fn.Func().Dcl = nil fn.Dcl = nil
base.Pos = lno base.Pos = lno
} }
@ -111,11 +111,8 @@ func typecheckinl(fn ir.Node) {
// Caninl determines whether fn is inlineable. // Caninl determines whether fn is inlineable.
// If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy. // If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
// fn and ->nbody will already have been typechecked. // fn and ->nbody will already have been typechecked.
func caninl(fn ir.Node) { func caninl(fn *ir.Func) {
if fn.Op() != ir.ODCLFUNC { if fn.Nname == nil {
base.Fatalf("caninl %v", fn)
}
if fn.Func().Nname == nil {
base.Fatalf("caninl no nname %+v", fn) base.Fatalf("caninl no nname %+v", fn)
} }
@ -124,7 +121,7 @@ func caninl(fn ir.Node) {
defer func() { defer func() {
if reason != "" { if reason != "" {
if base.Flag.LowerM > 1 { if base.Flag.LowerM > 1 {
fmt.Printf("%v: cannot inline %v: %s\n", ir.Line(fn), fn.Func().Nname, reason) fmt.Printf("%v: cannot inline %v: %s\n", ir.Line(fn), fn.Nname, reason)
} }
if logopt.Enabled() { if logopt.Enabled() {
logopt.LogOpt(fn.Pos(), "cannotInlineFunction", "inline", ir.FuncName(fn), reason) logopt.LogOpt(fn.Pos(), "cannotInlineFunction", "inline", ir.FuncName(fn), reason)
@ -134,33 +131,33 @@ func caninl(fn ir.Node) {
} }
// If marked "go:noinline", don't inline // If marked "go:noinline", don't inline
if fn.Func().Pragma&ir.Noinline != 0 { if fn.Pragma&ir.Noinline != 0 {
reason = "marked go:noinline" reason = "marked go:noinline"
return return
} }
// If marked "go:norace" and -race compilation, don't inline. // If marked "go:norace" and -race compilation, don't inline.
if base.Flag.Race && fn.Func().Pragma&ir.Norace != 0 { if base.Flag.Race && fn.Pragma&ir.Norace != 0 {
reason = "marked go:norace with -race compilation" reason = "marked go:norace with -race compilation"
return return
} }
// If marked "go:nocheckptr" and -d checkptr compilation, don't inline. // If marked "go:nocheckptr" and -d checkptr compilation, don't inline.
if base.Debug.Checkptr != 0 && fn.Func().Pragma&ir.NoCheckPtr != 0 { if base.Debug.Checkptr != 0 && fn.Pragma&ir.NoCheckPtr != 0 {
reason = "marked go:nocheckptr" reason = "marked go:nocheckptr"
return return
} }
// If marked "go:cgo_unsafe_args", don't inline, since the // If marked "go:cgo_unsafe_args", don't inline, since the
// function makes assumptions about its argument frame layout. // function makes assumptions about its argument frame layout.
if fn.Func().Pragma&ir.CgoUnsafeArgs != 0 { if fn.Pragma&ir.CgoUnsafeArgs != 0 {
reason = "marked go:cgo_unsafe_args" reason = "marked go:cgo_unsafe_args"
return return
} }
// If marked as "go:uintptrescapes", don't inline, since the // If marked as "go:uintptrescapes", don't inline, since the
// escape information is lost during inlining. // escape information is lost during inlining.
if fn.Func().Pragma&ir.UintptrEscapes != 0 { if fn.Pragma&ir.UintptrEscapes != 0 {
reason = "marked as having an escaping uintptr argument" reason = "marked as having an escaping uintptr argument"
return return
} }
@ -169,7 +166,7 @@ func caninl(fn ir.Node) {
// granularity, so inlining yeswritebarrierrec functions can // granularity, so inlining yeswritebarrierrec functions can
// confuse it (#22342). As a workaround, disallow inlining // confuse it (#22342). As a workaround, disallow inlining
// them for now. // them for now.
if fn.Func().Pragma&ir.Yeswritebarrierrec != 0 { if fn.Pragma&ir.Yeswritebarrierrec != 0 {
reason = "marked go:yeswritebarrierrec" reason = "marked go:yeswritebarrierrec"
return return
} }
@ -184,7 +181,7 @@ func caninl(fn ir.Node) {
base.Fatalf("caninl on non-typechecked function %v", fn) base.Fatalf("caninl on non-typechecked function %v", fn)
} }
n := fn.Func().Nname n := fn.Nname
if n.Func().InlinabilityChecked() { if n.Func().InlinabilityChecked() {
return return
} }
@ -220,7 +217,7 @@ func caninl(fn ir.Node) {
n.Func().Inl = &ir.Inline{ n.Func().Inl = &ir.Inline{
Cost: inlineMaxBudget - visitor.budget, Cost: inlineMaxBudget - visitor.budget,
Dcl: inlcopylist(pruneUnusedAutos(n.Name().Defn.Func().Dcl, &visitor)), Dcl: pruneUnusedAutos(n.Defn.Func().Dcl, &visitor),
Body: inlcopylist(fn.Body().Slice()), Body: inlcopylist(fn.Body().Slice()),
} }
@ -236,36 +233,38 @@ func caninl(fn ir.Node) {
// inlFlood marks n's inline body for export and recursively ensures // inlFlood marks n's inline body for export and recursively ensures
// all called functions are marked too. // all called functions are marked too.
func inlFlood(n ir.Node) { func inlFlood(n *ir.Name) {
if n == nil { if n == nil {
return return
} }
if n.Op() != ir.ONAME || n.Class() != ir.PFUNC { if n.Op() != ir.ONAME || n.Class() != ir.PFUNC {
base.Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op(), n.Class()) base.Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op(), n.Class())
} }
if n.Func() == nil { fn := n.Func()
if fn == nil {
base.Fatalf("inlFlood: missing Func on %v", n) base.Fatalf("inlFlood: missing Func on %v", n)
} }
if n.Func().Inl == nil { if fn.Inl == nil {
return return
} }
if n.Func().ExportInline() { if fn.ExportInline() {
return return
} }
n.Func().SetExportInline(true) fn.SetExportInline(true)
typecheckinl(n) typecheckinl(fn)
// Recursively identify all referenced functions for // Recursively identify all referenced functions for
// reexport. We want to include even non-called functions, // reexport. We want to include even non-called functions,
// because after inlining they might be callable. // because after inlining they might be callable.
ir.InspectList(ir.AsNodes(n.Func().Inl.Body), func(n ir.Node) bool { ir.InspectList(ir.AsNodes(fn.Inl.Body), func(n ir.Node) bool {
switch n.Op() { switch n.Op() {
case ir.OMETHEXPR: case ir.OMETHEXPR, ir.ODOTMETH:
inlFlood(methodExprName(n)) inlFlood(methodExprName(n))
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
switch n.Class() { switch n.Class() {
case ir.PFUNC: case ir.PFUNC:
inlFlood(n) inlFlood(n)
@ -274,10 +273,6 @@ func inlFlood(n ir.Node) {
exportsym(n) exportsym(n)
} }
case ir.ODOTMETH:
fn := methodExprName(n)
inlFlood(fn)
case ir.OCALLPART: case ir.OCALLPART:
// Okay, because we don't yet inline indirect // Okay, because we don't yet inline indirect
// calls to method values. // calls to method values.
@ -342,8 +337,8 @@ func (v *hairyVisitor) visit(n ir.Node) bool {
break break
} }
if fn := inlCallee(n.Left()); fn != nil && fn.Func().Inl != nil { if fn := inlCallee(n.Left()); fn != nil && fn.Inl != nil {
v.budget -= fn.Func().Inl.Cost v.budget -= fn.Inl.Cost
break break
} }
@ -503,7 +498,7 @@ func countNodes(n ir.Node) int {
// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
// calls made to inlineable functions. This is the external entry point. // calls made to inlineable functions. This is the external entry point.
func inlcalls(fn ir.Node) { func inlcalls(fn *ir.Func) {
savefn := Curfn savefn := Curfn
Curfn = fn Curfn = fn
maxCost := int32(inlineMaxBudget) maxCost := int32(inlineMaxBudget)
@ -516,8 +511,8 @@ func inlcalls(fn ir.Node) {
// but allow inlining if there is a recursion cycle of many functions. // but allow inlining if there is a recursion cycle of many functions.
// Most likely, the inlining will stop before we even hit the beginning of // Most likely, the inlining will stop before we even hit the beginning of
// the cycle again, but the map catches the unusual case. // the cycle again, but the map catches the unusual case.
inlMap := make(map[ir.Node]bool) inlMap := make(map[*ir.Func]bool)
fn = inlnode(fn, maxCost, inlMap) fn = inlnode(fn, maxCost, inlMap).(*ir.Func)
if fn != Curfn { if fn != Curfn {
base.Fatalf("inlnode replaced curfn") base.Fatalf("inlnode replaced curfn")
} }
@ -558,7 +553,7 @@ func inlconv2list(n ir.Node) []ir.Node {
return s return s
} }
func inlnodelist(l ir.Nodes, maxCost int32, inlMap map[ir.Node]bool) { func inlnodelist(l ir.Nodes, maxCost int32, inlMap map[*ir.Func]bool) {
s := l.Slice() s := l.Slice()
for i := range s { for i := range s {
s[i] = inlnode(s[i], maxCost, inlMap) s[i] = inlnode(s[i], maxCost, inlMap)
@ -578,7 +573,7 @@ func inlnodelist(l ir.Nodes, maxCost int32, inlMap map[ir.Node]bool) {
// shorter and less complicated. // shorter and less complicated.
// The result of inlnode MUST be assigned back to n, e.g. // The result of inlnode MUST be assigned back to n, e.g.
// n.Left = inlnode(n.Left) // n.Left = inlnode(n.Left)
func inlnode(n ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node { func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
if n == nil { if n == nil {
return n return n
} }
@ -684,7 +679,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
if isIntrinsicCall(n) { if isIntrinsicCall(n) {
break break
} }
if fn := inlCallee(n.Left()); fn != nil && fn.Func().Inl != nil { if fn := inlCallee(n.Left()); fn != nil && fn.Inl != nil {
n = mkinlcall(n, fn, maxCost, inlMap) n = mkinlcall(n, fn, maxCost, inlMap)
} }
@ -698,7 +693,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
base.Fatalf("no function type for [%p] %+v\n", n.Left(), n.Left()) base.Fatalf("no function type for [%p] %+v\n", n.Left(), n.Left())
} }
n = mkinlcall(n, methodExprName(n.Left()), maxCost, inlMap) n = mkinlcall(n, methodExprName(n.Left()).Func(), maxCost, inlMap)
} }
base.Pos = lno base.Pos = lno
@ -707,7 +702,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
// inlCallee takes a function-typed expression and returns the underlying function ONAME // inlCallee takes a function-typed expression and returns the underlying function ONAME
// that it refers to if statically known. Otherwise, it returns nil. // that it refers to if statically known. Otherwise, it returns nil.
func inlCallee(fn ir.Node) ir.Node { func inlCallee(fn ir.Node) *ir.Func {
fn = staticValue(fn) fn = staticValue(fn)
switch { switch {
case fn.Op() == ir.OMETHEXPR: case fn.Op() == ir.OMETHEXPR:
@ -718,13 +713,13 @@ func inlCallee(fn ir.Node) ir.Node {
if n == nil || !types.Identical(n.Type().Recv().Type, fn.Left().Type()) { if n == nil || !types.Identical(n.Type().Recv().Type, fn.Left().Type()) {
return nil return nil
} }
return n return n.Func()
case fn.Op() == ir.ONAME && fn.Class() == ir.PFUNC: case fn.Op() == ir.ONAME && fn.Class() == ir.PFUNC:
return fn return fn.Func()
case fn.Op() == ir.OCLOSURE: case fn.Op() == ir.OCLOSURE:
c := fn.Func().Decl c := fn.Func()
caninl(c) caninl(c)
return c.Func().Nname return c
} }
return nil return nil
} }
@ -777,7 +772,7 @@ FindRHS:
base.Fatalf("RHS is nil: %v", defn) base.Fatalf("RHS is nil: %v", defn)
} }
unsafe, _ := reassigned(n) unsafe, _ := reassigned(n.(*ir.Name))
if unsafe { if unsafe {
return nil return nil
} }
@ -791,23 +786,15 @@ FindRHS:
// useful for -m output documenting the reason for inhibited optimizations. // useful for -m output documenting the reason for inhibited optimizations.
// NB: global variables are always considered to be re-assigned. // NB: global variables are always considered to be re-assigned.
// TODO: handle initial declaration not including an assignment and followed by a single assignment? // TODO: handle initial declaration not including an assignment and followed by a single assignment?
func reassigned(n ir.Node) (bool, ir.Node) { func reassigned(n *ir.Name) (bool, ir.Node) {
if n.Op() != ir.ONAME { if n.Op() != ir.ONAME {
base.Fatalf("reassigned %v", n) base.Fatalf("reassigned %v", n)
} }
// no way to reliably check for no-reassignment of globals, assume it can be // no way to reliably check for no-reassignment of globals, assume it can be
if n.Name().Curfn == nil { if n.Curfn == nil {
return true, nil return true, nil
} }
f := n.Name().Curfn f := n.Curfn
// There just might be a good reason for this although this can be pretty surprising:
// local variables inside a closure have Curfn pointing to the OCLOSURE node instead
// of the corresponding ODCLFUNC.
// We need to walk the function body to check for reassignments so we follow the
// linkage to the ODCLFUNC node as that is where body is held.
if f.Op() == ir.OCLOSURE {
f = f.Func().Decl
}
v := reassignVisitor{name: n} v := reassignVisitor{name: n}
a := v.visitList(f.Body()) a := v.visitList(f.Body())
return a != nil, a return a != nil, a
@ -863,13 +850,13 @@ func (v *reassignVisitor) visitList(l ir.Nodes) ir.Node {
return nil return nil
} }
func inlParam(t *types.Field, as ir.Node, inlvars map[ir.Node]ir.Node) ir.Node { func inlParam(t *types.Field, as ir.Node, inlvars map[*ir.Name]ir.Node) ir.Node {
n := ir.AsNode(t.Nname) n := ir.AsNode(t.Nname)
if n == nil || ir.IsBlank(n) { if n == nil || ir.IsBlank(n) {
return ir.BlankNode return ir.BlankNode
} }
inlvar := inlvars[n] inlvar := inlvars[n.(*ir.Name)]
if inlvar == nil { if inlvar == nil {
base.Fatalf("missing inlvar for %v", n) base.Fatalf("missing inlvar for %v", n)
} }
@ -887,25 +874,25 @@ var inlgen int
// parameters. // parameters.
// The result of mkinlcall MUST be assigned back to n, e.g. // The result of mkinlcall MUST be assigned back to n, e.g.
// n.Left = mkinlcall(n.Left, fn, isddd) // n.Left = mkinlcall(n.Left, fn, isddd)
func mkinlcall(n, fn ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node { func mkinlcall(n ir.Node, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
if fn.Func().Inl == nil { if fn.Inl == nil {
if logopt.Enabled() { if logopt.Enabled() {
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(Curfn), logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(Curfn),
fmt.Sprintf("%s cannot be inlined", ir.PkgFuncName(fn))) fmt.Sprintf("%s cannot be inlined", ir.PkgFuncName(fn)))
} }
return n return n
} }
if fn.Func().Inl.Cost > maxCost { if fn.Inl.Cost > maxCost {
// The inlined function body is too big. Typically we use this check to restrict // The inlined function body is too big. Typically we use this check to restrict
// inlining into very big functions. See issue 26546 and 17566. // inlining into very big functions. See issue 26546 and 17566.
if logopt.Enabled() { if logopt.Enabled() {
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(Curfn), logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(Curfn),
fmt.Sprintf("cost %d of %s exceeds max large caller cost %d", fn.Func().Inl.Cost, ir.PkgFuncName(fn), maxCost)) fmt.Sprintf("cost %d of %s exceeds max large caller cost %d", fn.Inl.Cost, ir.PkgFuncName(fn), maxCost))
} }
return n return n
} }
if fn == Curfn || fn.Name().Defn == Curfn { if fn == Curfn {
// Can't recursively inline a function into itself. // Can't recursively inline a function into itself.
if logopt.Enabled() { if logopt.Enabled() {
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(Curfn))) logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(Curfn)))
@ -939,7 +926,7 @@ func mkinlcall(n, fn ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
// We have a function node, and it has an inlineable body. // We have a function node, and it has an inlineable body.
if base.Flag.LowerM > 1 { if base.Flag.LowerM > 1 {
fmt.Printf("%v: inlining call to %v %#v { %#v }\n", ir.Line(n), fn.Sym(), fn.Type(), ir.AsNodes(fn.Func().Inl.Body)) fmt.Printf("%v: inlining call to %v %#v { %#v }\n", ir.Line(n), fn.Sym(), fn.Type(), ir.AsNodes(fn.Inl.Body))
} else if base.Flag.LowerM != 0 { } else if base.Flag.LowerM != 0 {
fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn) fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn)
} }
@ -969,29 +956,28 @@ func mkinlcall(n, fn ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
} }
// Make temp names to use instead of the originals. // Make temp names to use instead of the originals.
inlvars := make(map[ir.Node]ir.Node) inlvars := make(map[*ir.Name]ir.Node)
// record formals/locals for later post-processing // record formals/locals for later post-processing
var inlfvars []ir.Node var inlfvars []ir.Node
// Handle captured variables when inlining closures. // Handle captured variables when inlining closures.
if fn.Name().Defn != nil { if c := fn.OClosure; c != nil {
if c := fn.Name().Defn.Func().OClosure; c != nil { for _, v := range c.Func().ClosureVars {
for _, v := range c.Func().ClosureVars.Slice() {
if v.Op() == ir.OXXX { if v.Op() == ir.OXXX {
continue continue
} }
o := v.Name().Outer o := v.Outer
// make sure the outer param matches the inlining location // make sure the outer param matches the inlining location
// NB: if we enabled inlining of functions containing OCLOSURE or refined // NB: if we enabled inlining of functions containing OCLOSURE or refined
// the reassigned check via some sort of copy propagation this would most // the reassigned check via some sort of copy propagation this would most
// likely need to be changed to a loop to walk up to the correct Param // likely need to be changed to a loop to walk up to the correct Param
if o == nil || (o.Name().Curfn != Curfn && o.Name().Curfn.Func().OClosure != Curfn) { if o == nil || (o.Curfn != Curfn && o.Curfn.OClosure != Curfn) {
base.Fatalf("%v: unresolvable capture %v %v\n", ir.Line(n), fn, v) base.Fatalf("%v: unresolvable capture %v %v\n", ir.Line(n), fn, v)
} }
if v.Name().Byval() { if v.Byval() {
iv := typecheck(inlvar(v), ctxExpr) iv := typecheck(inlvar(v), ctxExpr)
ninit.Append(ir.Nod(ir.ODCL, iv, nil)) ninit.Append(ir.Nod(ir.ODCL, iv, nil))
ninit.Append(typecheck(ir.Nod(ir.OAS, iv, o), ctxStmt)) ninit.Append(typecheck(ir.Nod(ir.OAS, iv, o), ctxStmt))
@ -1010,9 +996,8 @@ func mkinlcall(n, fn ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
} }
} }
} }
}
for _, ln := range fn.Func().Inl.Dcl { for _, ln := range fn.Inl.Dcl {
if ln.Op() != ir.ONAME { if ln.Op() != ir.ONAME {
continue continue
} }
@ -1040,7 +1025,7 @@ func mkinlcall(n, fn ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
} }
nreturns := 0 nreturns := 0
ir.InspectList(ir.AsNodes(fn.Func().Inl.Body), func(n ir.Node) bool { ir.InspectList(ir.AsNodes(fn.Inl.Body), func(n ir.Node) bool {
if n != nil && n.Op() == ir.ORETURN { if n != nil && n.Op() == ir.ORETURN {
nreturns++ nreturns++
} }
@ -1057,6 +1042,7 @@ func mkinlcall(n, fn ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
for i, t := range fn.Type().Results().Fields().Slice() { for i, t := range fn.Type().Results().Fields().Slice() {
var m ir.Node var m ir.Node
if n := ir.AsNode(t.Nname); n != nil && !ir.IsBlank(n) && !strings.HasPrefix(n.Sym().Name, "~r") { if n := ir.AsNode(t.Nname); n != nil && !ir.IsBlank(n) && !strings.HasPrefix(n.Sym().Name, "~r") {
n := n.(*ir.Name)
m = inlvar(n) m = inlvar(n)
m = typecheck(m, ctxExpr) m = typecheck(m, ctxExpr)
inlvars[n] = m inlvars[n] = m
@ -1155,7 +1141,9 @@ func mkinlcall(n, fn ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
if b := base.Ctxt.PosTable.Pos(n.Pos()).Base(); b != nil { if b := base.Ctxt.PosTable.Pos(n.Pos()).Base(); b != nil {
parent = b.InliningIndex() parent = b.InliningIndex()
} }
newIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), fn.Sym().Linksym())
sym := fn.Sym().Linksym()
newIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym)
// Add an inline mark just before the inlined body. // Add an inline mark just before the inlined body.
// This mark is inline in the code so that it's a reasonable spot // This mark is inline in the code so that it's a reasonable spot
@ -1168,9 +1156,9 @@ func mkinlcall(n, fn ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
ninit.Append(inlMark) ninit.Append(inlMark)
if base.Flag.GenDwarfInl > 0 { if base.Flag.GenDwarfInl > 0 {
if !fn.Sym().Linksym().WasInlined() { if !sym.WasInlined() {
base.Ctxt.DwFixups.SetPrecursorFunc(fn.Sym().Linksym(), fn) base.Ctxt.DwFixups.SetPrecursorFunc(sym, fn)
fn.Sym().Linksym().Set(obj.AttrWasInlined, true) sym.Set(obj.AttrWasInlined, true)
} }
} }
@ -1183,7 +1171,7 @@ func mkinlcall(n, fn ir.Node, maxCost int32, inlMap map[ir.Node]bool) ir.Node {
newInlIndex: newIndex, newInlIndex: newIndex,
} }
body := subst.list(ir.AsNodes(fn.Func().Inl.Body)) body := subst.list(ir.AsNodes(fn.Inl.Body))
lab := nodSym(ir.OLABEL, nil, retlabel) lab := nodSym(ir.OLABEL, nil, retlabel)
body = append(body, lab) body = append(body, lab)
@ -1236,11 +1224,11 @@ func inlvar(var_ ir.Node) ir.Node {
n := NewName(var_.Sym()) n := NewName(var_.Sym())
n.SetType(var_.Type()) n.SetType(var_.Type())
n.SetClass(ir.PAUTO) n.SetClass(ir.PAUTO)
n.Name().SetUsed(true) n.SetUsed(true)
n.Name().Curfn = Curfn // the calling function, not the called one n.Curfn = Curfn // the calling function, not the called one
n.Name().SetAddrtaken(var_.Name().Addrtaken()) n.SetAddrtaken(var_.Name().Addrtaken())
Curfn.Func().Dcl = append(Curfn.Func().Dcl, n) Curfn.Dcl = append(Curfn.Dcl, n)
return n return n
} }
@ -1249,9 +1237,9 @@ func retvar(t *types.Field, i int) ir.Node {
n := NewName(lookupN("~R", i)) n := NewName(lookupN("~R", i))
n.SetType(t.Type) n.SetType(t.Type)
n.SetClass(ir.PAUTO) n.SetClass(ir.PAUTO)
n.Name().SetUsed(true) n.SetUsed(true)
n.Name().Curfn = Curfn // the calling function, not the called one n.Curfn = Curfn // the calling function, not the called one
Curfn.Func().Dcl = append(Curfn.Func().Dcl, n) Curfn.Dcl = append(Curfn.Dcl, n)
return n return n
} }
@ -1261,9 +1249,9 @@ func argvar(t *types.Type, i int) ir.Node {
n := NewName(lookupN("~arg", i)) n := NewName(lookupN("~arg", i))
n.SetType(t.Elem()) n.SetType(t.Elem())
n.SetClass(ir.PAUTO) n.SetClass(ir.PAUTO)
n.Name().SetUsed(true) n.SetUsed(true)
n.Name().Curfn = Curfn // the calling function, not the called one n.Curfn = Curfn // the calling function, not the called one
Curfn.Func().Dcl = append(Curfn.Func().Dcl, n) Curfn.Dcl = append(Curfn.Dcl, n)
return n return n
} }
@ -1280,7 +1268,7 @@ type inlsubst struct {
// "return" statement. // "return" statement.
delayretvars bool delayretvars bool
inlvars map[ir.Node]ir.Node inlvars map[*ir.Name]ir.Node
// bases maps from original PosBase to PosBase with an extra // bases maps from original PosBase to PosBase with an extra
// inlined call frame. // inlined call frame.
@ -1311,6 +1299,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
switch n.Op() { switch n.Op() {
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name)
if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
if base.Flag.LowerM > 2 { if base.Flag.LowerM > 2 {
fmt.Printf("substituting name %+v -> %+v\n", n, inlvar) fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
@ -1409,8 +1398,8 @@ func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
return base.Ctxt.PosTable.XPos(pos) return base.Ctxt.PosTable.XPos(pos)
} }
func pruneUnusedAutos(ll []ir.Node, vis *hairyVisitor) []ir.Node { func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
s := make([]ir.Node, 0, len(ll)) s := make([]*ir.Name, 0, len(ll))
for _, n := range ll { for _, n := range ll {
if n.Class() == ir.PAUTO { if n.Class() == ir.PAUTO {
if _, found := vis.usedLocals[n]; !found { if _, found := vis.usedLocals[n]; !found {
@ -1424,7 +1413,7 @@ func pruneUnusedAutos(ll []ir.Node, vis *hairyVisitor) []ir.Node {
// devirtualize replaces interface method calls within fn with direct // devirtualize replaces interface method calls within fn with direct
// concrete-type method calls where applicable. // concrete-type method calls where applicable.
func devirtualize(fn ir.Node) { func devirtualize(fn *ir.Func) {
Curfn = fn Curfn = fn
ir.InspectList(fn.Body(), func(n ir.Node) bool { ir.InspectList(fn.Body(), func(n ir.Node) bool {
if n.Op() == ir.OCALLINTER { if n.Op() == ir.OCALLINTER {

View file

@ -277,7 +277,7 @@ func Main(archInit func(*Arch)) {
for i := 0; i < len(xtop); i++ { for i := 0; i < len(xtop); i++ {
n := xtop[i] n := xtop[i]
if n.Op() == ir.ODCLFUNC { if n.Op() == ir.ODCLFUNC {
Curfn = n Curfn = n.(*ir.Func)
decldepth = 1 decldepth = 1
errorsBefore := base.Errors() errorsBefore := base.Errors()
typecheckslice(Curfn.Body().Slice(), ctxStmt) typecheckslice(Curfn.Body().Slice(), ctxStmt)
@ -307,8 +307,8 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "capturevars") timings.Start("fe", "capturevars")
for _, n := range xtop { for _, n := range xtop {
if n.Op() == ir.ODCLFUNC && n.Func().OClosure != nil { if n.Op() == ir.ODCLFUNC && n.Func().OClosure != nil {
Curfn = n Curfn = n.(*ir.Func)
capturevars(n) capturevars(Curfn)
} }
} }
capturevarscomplete = true capturevarscomplete = true
@ -321,7 +321,7 @@ func Main(archInit func(*Arch)) {
// Typecheck imported function bodies if Debug.l > 1, // Typecheck imported function bodies if Debug.l > 1,
// otherwise lazily when used or re-exported. // otherwise lazily when used or re-exported.
for _, n := range importlist { for _, n := range importlist {
if n.Func().Inl != nil { if n.Inl != nil {
typecheckinl(n) typecheckinl(n)
} }
} }
@ -330,7 +330,7 @@ func Main(archInit func(*Arch)) {
if base.Flag.LowerL != 0 { if base.Flag.LowerL != 0 {
// Find functions that can be inlined and clone them before walk expands them. // Find functions that can be inlined and clone them before walk expands them.
visitBottomUp(xtop, func(list []ir.Node, recursive bool) { visitBottomUp(xtop, func(list []*ir.Func, recursive bool) {
numfns := numNonClosures(list) numfns := numNonClosures(list)
for _, n := range list { for _, n := range list {
if !recursive || numfns > 1 { if !recursive || numfns > 1 {
@ -340,7 +340,7 @@ func Main(archInit func(*Arch)) {
caninl(n) caninl(n)
} else { } else {
if base.Flag.LowerM > 1 { if base.Flag.LowerM > 1 {
fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(n), n.Func().Nname) fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(n), n.Nname)
} }
} }
inlcalls(n) inlcalls(n)
@ -350,7 +350,7 @@ func Main(archInit func(*Arch)) {
for _, n := range xtop { for _, n := range xtop {
if n.Op() == ir.ODCLFUNC { if n.Op() == ir.ODCLFUNC {
devirtualize(n) devirtualize(n.(*ir.Func))
} }
} }
Curfn = nil Curfn = nil
@ -380,8 +380,8 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "xclosures") timings.Start("fe", "xclosures")
for _, n := range xtop { for _, n := range xtop {
if n.Op() == ir.ODCLFUNC && n.Func().OClosure != nil { if n.Op() == ir.ODCLFUNC && n.Func().OClosure != nil {
Curfn = n Curfn = n.(*ir.Func)
transformclosure(n) transformclosure(Curfn)
} }
} }
@ -403,7 +403,7 @@ func Main(archInit func(*Arch)) {
for i := 0; i < len(xtop); i++ { for i := 0; i < len(xtop); i++ {
n := xtop[i] n := xtop[i]
if n.Op() == ir.ODCLFUNC { if n.Op() == ir.ODCLFUNC {
funccompile(n) funccompile(n.(*ir.Func))
fcount++ fcount++
} }
} }
@ -481,10 +481,10 @@ func Main(archInit func(*Arch)) {
} }
// numNonClosures returns the number of functions in list which are not closures. // numNonClosures returns the number of functions in list which are not closures.
func numNonClosures(list []ir.Node) int { func numNonClosures(list []*ir.Func) int {
count := 0 count := 0
for _, n := range list { for _, fn := range list {
if n.Func().OClosure == nil { if fn.OClosure == nil {
count++ count++
} }
} }

View file

@ -152,7 +152,7 @@ type noder struct {
lastCloseScopePos syntax.Pos lastCloseScopePos syntax.Pos
} }
func (p *noder) funcBody(fn ir.Node, block *syntax.BlockStmt) { func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) {
oldScope := p.scope oldScope := p.scope
p.scope = 0 p.scope = 0
funchdr(fn) funchdr(fn)
@ -165,7 +165,7 @@ func (p *noder) funcBody(fn ir.Node, block *syntax.BlockStmt) {
fn.PtrBody().Set(body) fn.PtrBody().Set(body)
base.Pos = p.makeXPos(block.Rbrace) base.Pos = p.makeXPos(block.Rbrace)
fn.Func().Endlineno = base.Pos fn.Endlineno = base.Pos
} }
funcbody() funcbody()
@ -176,9 +176,9 @@ func (p *noder) openScope(pos syntax.Pos) {
types.Markdcl() types.Markdcl()
if trackScopes { if trackScopes {
Curfn.Func().Parents = append(Curfn.Func().Parents, p.scope) Curfn.Parents = append(Curfn.Parents, p.scope)
p.scopeVars = append(p.scopeVars, len(Curfn.Func().Dcl)) p.scopeVars = append(p.scopeVars, len(Curfn.Dcl))
p.scope = ir.ScopeID(len(Curfn.Func().Parents)) p.scope = ir.ScopeID(len(Curfn.Parents))
p.markScope(pos) p.markScope(pos)
} }
@ -191,29 +191,29 @@ func (p *noder) closeScope(pos syntax.Pos) {
if trackScopes { if trackScopes {
scopeVars := p.scopeVars[len(p.scopeVars)-1] scopeVars := p.scopeVars[len(p.scopeVars)-1]
p.scopeVars = p.scopeVars[:len(p.scopeVars)-1] p.scopeVars = p.scopeVars[:len(p.scopeVars)-1]
if scopeVars == len(Curfn.Func().Dcl) { if scopeVars == len(Curfn.Dcl) {
// no variables were declared in this scope, so we can retract it. // no variables were declared in this scope, so we can retract it.
if int(p.scope) != len(Curfn.Func().Parents) { if int(p.scope) != len(Curfn.Parents) {
base.Fatalf("scope tracking inconsistency, no variables declared but scopes were not retracted") base.Fatalf("scope tracking inconsistency, no variables declared but scopes were not retracted")
} }
p.scope = Curfn.Func().Parents[p.scope-1] p.scope = Curfn.Parents[p.scope-1]
Curfn.Func().Parents = Curfn.Func().Parents[:len(Curfn.Func().Parents)-1] Curfn.Parents = Curfn.Parents[:len(Curfn.Parents)-1]
nmarks := len(Curfn.Func().Marks) nmarks := len(Curfn.Marks)
Curfn.Func().Marks[nmarks-1].Scope = p.scope Curfn.Marks[nmarks-1].Scope = p.scope
prevScope := ir.ScopeID(0) prevScope := ir.ScopeID(0)
if nmarks >= 2 { if nmarks >= 2 {
prevScope = Curfn.Func().Marks[nmarks-2].Scope prevScope = Curfn.Marks[nmarks-2].Scope
} }
if Curfn.Func().Marks[nmarks-1].Scope == prevScope { if Curfn.Marks[nmarks-1].Scope == prevScope {
Curfn.Func().Marks = Curfn.Func().Marks[:nmarks-1] Curfn.Marks = Curfn.Marks[:nmarks-1]
} }
return return
} }
p.scope = Curfn.Func().Parents[p.scope-1] p.scope = Curfn.Parents[p.scope-1]
p.markScope(pos) p.markScope(pos)
} }
@ -221,10 +221,10 @@ func (p *noder) closeScope(pos syntax.Pos) {
func (p *noder) markScope(pos syntax.Pos) { func (p *noder) markScope(pos syntax.Pos) {
xpos := p.makeXPos(pos) xpos := p.makeXPos(pos)
if i := len(Curfn.Func().Marks); i > 0 && Curfn.Func().Marks[i-1].Pos == xpos { if i := len(Curfn.Marks); i > 0 && Curfn.Marks[i-1].Pos == xpos {
Curfn.Func().Marks[i-1].Scope = p.scope Curfn.Marks[i-1].Scope = p.scope
} else { } else {
Curfn.Func().Marks = append(Curfn.Func().Marks, ir.Mark{Pos: xpos, Scope: p.scope}) Curfn.Marks = append(Curfn.Marks, ir.Mark{Pos: xpos, Scope: p.scope})
} }
} }
@ -444,6 +444,7 @@ func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []ir.Node {
nn := make([]ir.Node, 0, len(names)) nn := make([]ir.Node, 0, len(names))
for i, n := range names { for i, n := range names {
n := n.(*ir.Name)
if i >= len(values) { if i >= len(values) {
base.Errorf("missing value in const declaration") base.Errorf("missing value in const declaration")
break break
@ -456,8 +457,8 @@ func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []ir.Node {
n.SetOp(ir.OLITERAL) n.SetOp(ir.OLITERAL)
declare(n, dclcontext) declare(n, dclcontext)
n.Name().Ntype = typ n.Ntype = typ
n.Name().Defn = v n.Defn = v
n.SetIota(cs.iota) n.SetIota(cs.iota)
nn = append(nn, p.nod(decl, ir.ODCLCONST, n, nil)) nn = append(nn, p.nod(decl, ir.ODCLCONST, n, nil))
@ -514,7 +515,7 @@ func (p *noder) declName(name *syntax.Name) *ir.Name {
func (p *noder) funcDecl(fun *syntax.FuncDecl) ir.Node { func (p *noder) funcDecl(fun *syntax.FuncDecl) ir.Node {
name := p.name(fun.Name) name := p.name(fun.Name)
t := p.signature(fun.Recv, fun.Type) t := p.signature(fun.Recv, fun.Type)
f := p.nod(fun, ir.ODCLFUNC, nil, nil) f := ir.NewFunc(p.pos(fun))
if fun.Recv == nil { if fun.Recv == nil {
if name.Name == "init" { if name.Name == "init" {
@ -530,16 +531,16 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) ir.Node {
} }
} }
} else { } else {
f.Func().Shortname = name f.Shortname = name
name = ir.BlankNode.Sym() // filled in by typecheckfunc name = ir.BlankNode.Sym() // filled in by typecheckfunc
} }
f.Func().Nname = newfuncnamel(p.pos(fun.Name), name, f.Func()) f.Nname = newFuncNameAt(p.pos(fun.Name), name, f)
f.Func().Nname.Name().Defn = f f.Nname.Defn = f
f.Func().Nname.Name().Ntype = t f.Nname.Ntype = t
if pragma, ok := fun.Pragma.(*Pragma); ok { if pragma, ok := fun.Pragma.(*Pragma); ok {
f.Func().Pragma = pragma.Flag & FuncPragmas f.Pragma = pragma.Flag & FuncPragmas
if pragma.Flag&ir.Systemstack != 0 && pragma.Flag&ir.Nosplit != 0 { if pragma.Flag&ir.Systemstack != 0 && pragma.Flag&ir.Nosplit != 0 {
base.ErrorfAt(f.Pos(), "go:nosplit and go:systemstack cannot be combined") base.ErrorfAt(f.Pos(), "go:nosplit and go:systemstack cannot be combined")
} }
@ -548,13 +549,13 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) ir.Node {
} }
if fun.Recv == nil { if fun.Recv == nil {
declare(f.Func().Nname, ir.PFUNC) declare(f.Nname, ir.PFUNC)
} }
p.funcBody(f, fun.Body) p.funcBody(f, fun.Body)
if fun.Body != nil { if fun.Body != nil {
if f.Func().Pragma&ir.Noescape != 0 { if f.Pragma&ir.Noescape != 0 {
base.ErrorfAt(f.Pos(), "can only use //go:noescape with external func implementations") base.ErrorfAt(f.Pos(), "can only use //go:noescape with external func implementations")
} }
} else { } else {
@ -1059,7 +1060,7 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node {
n := p.nod(stmt, ir.ORETURN, nil, nil) n := p.nod(stmt, ir.ORETURN, nil, nil)
n.PtrList().Set(results) n.PtrList().Set(results)
if n.List().Len() == 0 && Curfn != nil { if n.List().Len() == 0 && Curfn != nil {
for _, ln := range Curfn.Func().Dcl { for _, ln := range Curfn.Dcl {
if ln.Class() == ir.PPARAM { if ln.Class() == ir.PPARAM {
continue continue
} }
@ -1133,7 +1134,7 @@ func (p *noder) assignList(expr syntax.Expr, defn ir.Node, colas bool) []ir.Node
newOrErr = true newOrErr = true
n := NewName(sym) n := NewName(sym)
declare(n, dclcontext) declare(n, dclcontext)
n.Name().Defn = defn n.Defn = defn
defn.PtrInit().Append(ir.Nod(ir.ODCL, n, nil)) defn.PtrInit().Append(ir.Nod(ir.ODCL, n, nil))
res[i] = n res[i] = n
} }
@ -1240,7 +1241,7 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch ir.Node, rbrac
declare(nn, dclcontext) declare(nn, dclcontext)
n.PtrRlist().Set1(nn) n.PtrRlist().Set1(nn)
// keep track of the instances for reporting unused // keep track of the instances for reporting unused
nn.Name().Defn = tswitch nn.Defn = tswitch
} }
// Trim trailing empty statements. We omit them from // Trim trailing empty statements. We omit them from

View file

@ -143,7 +143,7 @@ func dumpdata() {
for i := xtops; i < len(xtop); i++ { for i := xtops; i < len(xtop); i++ {
n := xtop[i] n := xtop[i]
if n.Op() == ir.ODCLFUNC { if n.Op() == ir.ODCLFUNC {
funccompile(n) funccompile(n.(*ir.Func))
} }
} }
xtops = len(xtop) xtops = len(xtop)

View file

@ -51,9 +51,9 @@ type Order struct {
// Order rewrites fn.Nbody to apply the ordering constraints // Order rewrites fn.Nbody to apply the ordering constraints
// described in the comment at the top of the file. // described in the comment at the top of the file.
func order(fn ir.Node) { func order(fn *ir.Func) {
if base.Flag.W > 1 { if base.Flag.W > 1 {
s := fmt.Sprintf("\nbefore order %v", fn.Func().Nname.Sym()) s := fmt.Sprintf("\nbefore order %v", fn.Sym())
ir.DumpList(s, fn.Body()) ir.DumpList(s, fn.Body())
} }
@ -1258,7 +1258,7 @@ func (o *Order) expr(n, lhs ir.Node) ir.Node {
} }
case ir.OCLOSURE: case ir.OCLOSURE:
if n.Transient() && n.Func().ClosureVars.Len() > 0 { if n.Transient() && len(n.Func().ClosureVars) > 0 {
prealloc[n] = o.newTemp(closureType(n), false) prealloc[n] = o.newTemp(closureType(n), false)
} }

View file

@ -24,14 +24,14 @@ import (
// "Portable" code generation. // "Portable" code generation.
var ( var (
compilequeue []ir.Node // functions waiting to be compiled compilequeue []*ir.Func // functions waiting to be compiled
) )
func emitptrargsmap(fn ir.Node) { func emitptrargsmap(fn *ir.Func) {
if ir.FuncName(fn) == "_" || fn.Func().Nname.Sym().Linkname != "" { if ir.FuncName(fn) == "_" || fn.Sym().Linkname != "" {
return return
} }
lsym := base.Ctxt.Lookup(fn.Func().LSym.Name + ".args_stackmap") lsym := base.Ctxt.Lookup(fn.LSym.Name + ".args_stackmap")
nptr := int(fn.Type().ArgWidth() / int64(Widthptr)) nptr := int(fn.Type().ArgWidth() / int64(Widthptr))
bv := bvalloc(int32(nptr) * 2) bv := bvalloc(int32(nptr) * 2)
@ -68,7 +68,7 @@ func emitptrargsmap(fn ir.Node) {
// really means, in memory, things with pointers needing zeroing at // really means, in memory, things with pointers needing zeroing at
// the top of the stack and increasing in size. // the top of the stack and increasing in size.
// Non-autos sort on offset. // Non-autos sort on offset.
func cmpstackvarlt(a, b ir.Node) bool { func cmpstackvarlt(a, b *ir.Name) bool {
if (a.Class() == ir.PAUTO) != (b.Class() == ir.PAUTO) { if (a.Class() == ir.PAUTO) != (b.Class() == ir.PAUTO) {
return b.Class() == ir.PAUTO return b.Class() == ir.PAUTO
} }
@ -101,7 +101,7 @@ func cmpstackvarlt(a, b ir.Node) bool {
} }
// byStackvar implements sort.Interface for []*Node using cmpstackvarlt. // byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
type byStackVar []ir.Node type byStackVar []*ir.Name
func (s byStackVar) Len() int { return len(s) } func (s byStackVar) Len() int { return len(s) }
func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) } func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
@ -110,7 +110,7 @@ func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s *ssafn) AllocFrame(f *ssa.Func) { func (s *ssafn) AllocFrame(f *ssa.Func) {
s.stksize = 0 s.stksize = 0
s.stkptrsize = 0 s.stkptrsize = 0
fn := s.curfn.Func() fn := s.curfn
// Mark the PAUTO's unused. // Mark the PAUTO's unused.
for _, ln := range fn.Dcl { for _, ln := range fn.Dcl {
@ -193,9 +193,9 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg)) s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
} }
func funccompile(fn ir.Node) { func funccompile(fn *ir.Func) {
if Curfn != nil { if Curfn != nil {
base.Fatalf("funccompile %v inside %v", fn.Func().Nname.Sym(), Curfn.Func().Nname.Sym()) base.Fatalf("funccompile %v inside %v", fn.Sym(), Curfn.Sym())
} }
if fn.Type() == nil { if fn.Type() == nil {
@ -210,21 +210,19 @@ func funccompile(fn ir.Node) {
if fn.Body().Len() == 0 { if fn.Body().Len() == 0 {
// Initialize ABI wrappers if necessary. // Initialize ABI wrappers if necessary.
initLSym(fn.Func(), false) initLSym(fn, false)
emitptrargsmap(fn) emitptrargsmap(fn)
return return
} }
dclcontext = ir.PAUTO dclcontext = ir.PAUTO
Curfn = fn Curfn = fn
compile(fn) compile(fn)
Curfn = nil Curfn = nil
dclcontext = ir.PEXTERN dclcontext = ir.PEXTERN
} }
func compile(fn ir.Node) { func compile(fn *ir.Func) {
errorsBefore := base.Errors() errorsBefore := base.Errors()
order(fn) order(fn)
if base.Errors() > errorsBefore { if base.Errors() > errorsBefore {
@ -234,7 +232,7 @@ func compile(fn ir.Node) {
// Set up the function's LSym early to avoid data races with the assemblers. // Set up the function's LSym early to avoid data races with the assemblers.
// Do this before walk, as walk needs the LSym to set attributes/relocations // Do this before walk, as walk needs the LSym to set attributes/relocations
// (e.g. in markTypeUsedInInterface). // (e.g. in markTypeUsedInInterface).
initLSym(fn.Func(), true) initLSym(fn, true)
walk(fn) walk(fn)
if base.Errors() > errorsBefore { if base.Errors() > errorsBefore {
@ -259,15 +257,15 @@ func compile(fn ir.Node) {
// be types of stack objects. We need to do this here // be types of stack objects. We need to do this here
// because symbols must be allocated before the parallel // because symbols must be allocated before the parallel
// phase of the compiler. // phase of the compiler.
for _, n := range fn.Func().Dcl { for _, n := range fn.Dcl {
switch n.Class() { switch n.Class() {
case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO: case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO:
if livenessShouldTrack(n) && n.Name().Addrtaken() { if livenessShouldTrack(n) && n.Name().Addrtaken() {
dtypesym(n.Type()) dtypesym(n.Type())
// Also make sure we allocate a linker symbol // Also make sure we allocate a linker symbol
// for the stack object data, for the same reason. // for the stack object data, for the same reason.
if fn.Func().LSym.Func().StackObjects == nil { if fn.LSym.Func().StackObjects == nil {
fn.Func().LSym.Func().StackObjects = base.Ctxt.Lookup(fn.Func().LSym.Name + ".stkobj") fn.LSym.Func().StackObjects = base.Ctxt.Lookup(fn.LSym.Name + ".stkobj")
} }
} }
} }
@ -284,7 +282,7 @@ func compile(fn ir.Node) {
// If functions are not compiled immediately, // If functions are not compiled immediately,
// they are enqueued in compilequeue, // they are enqueued in compilequeue,
// which is drained by compileFunctions. // which is drained by compileFunctions.
func compilenow(fn ir.Node) bool { func compilenow(fn *ir.Func) bool {
// Issue 38068: if this function is a method AND an inline // Issue 38068: if this function is a method AND an inline
// candidate AND was not inlined (yet), put it onto the compile // candidate AND was not inlined (yet), put it onto the compile
// queue instead of compiling it immediately. This is in case we // queue instead of compiling it immediately. This is in case we
@ -299,8 +297,8 @@ func compilenow(fn ir.Node) bool {
// isInlinableButNotInlined returns true if 'fn' was marked as an // isInlinableButNotInlined returns true if 'fn' was marked as an
// inline candidate but then never inlined (presumably because we // inline candidate but then never inlined (presumably because we
// found no call sites). // found no call sites).
func isInlinableButNotInlined(fn ir.Node) bool { func isInlinableButNotInlined(fn *ir.Func) bool {
if fn.Func().Nname.Func().Inl == nil { if fn.Inl == nil {
return false return false
} }
if fn.Sym() == nil { if fn.Sym() == nil {
@ -315,7 +313,7 @@ const maxStackSize = 1 << 30
// uses it to generate a plist, // uses it to generate a plist,
// and flushes that plist to machine code. // and flushes that plist to machine code.
// worker indicates which of the backend workers is doing the processing. // worker indicates which of the backend workers is doing the processing.
func compileSSA(fn ir.Node, worker int) { func compileSSA(fn *ir.Func, worker int) {
f := buildssa(fn, worker) f := buildssa(fn, worker)
// Note: check arg size to fix issue 25507. // Note: check arg size to fix issue 25507.
if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type().ArgWidth() >= maxStackSize { if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type().ArgWidth() >= maxStackSize {
@ -343,7 +341,7 @@ func compileSSA(fn ir.Node, worker int) {
pp.Flush() // assemble, fill in boilerplate, etc. pp.Flush() // assemble, fill in boilerplate, etc.
// fieldtrack must be called after pp.Flush. See issue 20014. // fieldtrack must be called after pp.Flush. See issue 20014.
fieldtrack(pp.Text.From.Sym, fn.Func().FieldTrack) fieldtrack(pp.Text.From.Sym, fn.FieldTrack)
} }
func init() { func init() {
@ -360,7 +358,7 @@ func compileFunctions() {
sizeCalculationDisabled = true // not safe to calculate sizes concurrently sizeCalculationDisabled = true // not safe to calculate sizes concurrently
if race.Enabled { if race.Enabled {
// Randomize compilation order to try to shake out races. // Randomize compilation order to try to shake out races.
tmp := make([]ir.Node, len(compilequeue)) tmp := make([]*ir.Func, len(compilequeue))
perm := rand.Perm(len(compilequeue)) perm := rand.Perm(len(compilequeue))
for i, v := range perm { for i, v := range perm {
tmp[v] = compilequeue[i] tmp[v] = compilequeue[i]
@ -376,7 +374,7 @@ func compileFunctions() {
} }
var wg sync.WaitGroup var wg sync.WaitGroup
base.Ctxt.InParallel = true base.Ctxt.InParallel = true
c := make(chan ir.Node, base.Flag.LowerC) c := make(chan *ir.Func, base.Flag.LowerC)
for i := 0; i < base.Flag.LowerC; i++ { for i := 0; i < base.Flag.LowerC; i++ {
wg.Add(1) wg.Add(1)
go func(worker int) { go func(worker int) {
@ -398,9 +396,10 @@ func compileFunctions() {
} }
func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) { func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) {
fn := curfn.(ir.Node) fn := curfn.(*ir.Func)
if fn.Func().Nname != nil {
if expect := fn.Func().Nname.Sym().Linksym(); fnsym != expect { if fn.Nname != nil {
if expect := fn.Sym().Linksym(); fnsym != expect {
base.Fatalf("unexpected fnsym: %v != %v", fnsym, expect) base.Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
} }
} }
@ -430,12 +429,19 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
// //
// These two adjustments keep toolstash -cmp working for now. // These two adjustments keep toolstash -cmp working for now.
// Deciding the right answer is, as they say, future work. // Deciding the right answer is, as they say, future work.
isODCLFUNC := fn.Op() == ir.ODCLFUNC //
// We can tell the difference between the old ODCLFUNC and ONAME
// cases by looking at the infosym.Name. If it's empty, DebugInfo is
// being called from (*obj.Link).populateDWARF, which used to use
// the ODCLFUNC. If it's non-empty (the name will end in $abstract),
// DebugInfo is being called from (*obj.Link).DwarfAbstractFunc,
// which used to use the ONAME form.
isODCLFUNC := infosym.Name == ""
var apdecls []ir.Node var apdecls []ir.Node
// Populate decls for fn. // Populate decls for fn.
if isODCLFUNC { if isODCLFUNC {
for _, n := range fn.Func().Dcl { for _, n := range fn.Dcl {
if n.Op() != ir.ONAME { // might be OTYPE or OLITERAL if n.Op() != ir.ONAME { // might be OTYPE or OLITERAL
continue continue
} }
@ -457,7 +463,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
} }
} }
decls, dwarfVars := createDwarfVars(fnsym, isODCLFUNC, fn.Func(), apdecls) decls, dwarfVars := createDwarfVars(fnsym, isODCLFUNC, fn, apdecls)
// For each type referenced by the functions auto vars but not // For each type referenced by the functions auto vars but not
// already referenced by a dwarf var, attach an R_USETYPE relocation to // already referenced by a dwarf var, attach an R_USETYPE relocation to
@ -478,7 +484,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
var varScopes []ir.ScopeID var varScopes []ir.ScopeID
for _, decl := range decls { for _, decl := range decls {
pos := declPos(decl) pos := declPos(decl)
varScopes = append(varScopes, findScope(fn.Func().Marks, pos)) varScopes = append(varScopes, findScope(fn.Marks, pos))
} }
scopes := assembleScopes(fnsym, fn, dwarfVars, varScopes) scopes := assembleScopes(fnsym, fn, dwarfVars, varScopes)
@ -709,9 +715,9 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []ir.
// names of the variables may have been "versioned" to avoid conflicts // names of the variables may have been "versioned" to avoid conflicts
// with local vars; disregard this versioning when sorting. // with local vars; disregard this versioning when sorting.
func preInliningDcls(fnsym *obj.LSym) []ir.Node { func preInliningDcls(fnsym *obj.LSym) []ir.Node {
fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(ir.Node) fn := base.Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*ir.Func)
var rdcl []ir.Node var rdcl []ir.Node
for _, n := range fn.Func().Inl.Dcl { for _, n := range fn.Inl.Dcl {
c := n.Sym().Name[0] c := n.Sym().Name[0]
// Avoid reporting "_" parameters, since if there are more than // Avoid reporting "_" parameters, since if there are more than
// one, it can result in a collision later on, as in #23179. // one, it can result in a collision later on, as in #23179.

View file

@ -26,19 +26,19 @@ func typeWithPointers() *types.Type {
return t return t
} }
func markUsed(n ir.Node) ir.Node { func markUsed(n *ir.Name) *ir.Name {
n.Name().SetUsed(true) n.SetUsed(true)
return n return n
} }
func markNeedZero(n ir.Node) ir.Node { func markNeedZero(n *ir.Name) *ir.Name {
n.Name().SetNeedzero(true) n.SetNeedzero(true)
return n return n
} }
// Test all code paths for cmpstackvarlt. // Test all code paths for cmpstackvarlt.
func TestCmpstackvar(t *testing.T) { func TestCmpstackvar(t *testing.T) {
nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) ir.Node { nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
if s == nil { if s == nil {
s = &types.Sym{Name: "."} s = &types.Sym{Name: "."}
} }
@ -49,7 +49,7 @@ func TestCmpstackvar(t *testing.T) {
return n return n
} }
testdata := []struct { testdata := []struct {
a, b ir.Node a, b *ir.Name
lt bool lt bool
}{ }{
{ {
@ -156,14 +156,14 @@ func TestCmpstackvar(t *testing.T) {
} }
func TestStackvarSort(t *testing.T) { func TestStackvarSort(t *testing.T) {
nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) ir.Node { nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
n := NewName(s) n := NewName(s)
n.SetType(t) n.SetType(t)
n.SetOffset(xoffset) n.SetOffset(xoffset)
n.SetClass(cl) n.SetClass(cl)
return n return n
} }
inp := []ir.Node{ inp := []*ir.Name{
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC), nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO), nod(0, &types.Type{}, &types.Sym{}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC), nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
@ -178,7 +178,7 @@ func TestStackvarSort(t *testing.T) {
nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO), nod(0, &types.Type{}, &types.Sym{Name: "abc"}, ir.PAUTO),
nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO), nod(0, &types.Type{}, &types.Sym{Name: "xyz"}, ir.PAUTO),
} }
want := []ir.Node{ want := []*ir.Name{
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC), nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC), nod(0, &types.Type{}, &types.Sym{}, ir.PFUNC),
nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC), nod(10, &types.Type{}, &types.Sym{}, ir.PFUNC),

View file

@ -101,7 +101,7 @@ type BlockEffects struct {
// A collection of global state used by liveness analysis. // A collection of global state used by liveness analysis.
type Liveness struct { type Liveness struct {
fn ir.Node fn *ir.Func
f *ssa.Func f *ssa.Func
vars []ir.Node vars []ir.Node
idx map[ir.Node]int32 idx map[ir.Node]int32
@ -212,9 +212,9 @@ func livenessShouldTrack(n ir.Node) bool {
// getvariables returns the list of on-stack variables that we need to track // getvariables returns the list of on-stack variables that we need to track
// and a map for looking up indices by *Node. // and a map for looking up indices by *Node.
func getvariables(fn ir.Node) ([]ir.Node, map[ir.Node]int32) { func getvariables(fn *ir.Func) ([]ir.Node, map[ir.Node]int32) {
var vars []ir.Node var vars []ir.Node
for _, n := range fn.Func().Dcl { for _, n := range fn.Dcl {
if livenessShouldTrack(n) { if livenessShouldTrack(n) {
vars = append(vars, n) vars = append(vars, n)
} }
@ -356,7 +356,7 @@ type livenessFuncCache struct {
// Constructs a new liveness structure used to hold the global state of the // Constructs a new liveness structure used to hold the global state of the
// liveness computation. The cfg argument is a slice of *BasicBlocks and the // liveness computation. The cfg argument is a slice of *BasicBlocks and the
// vars argument is a slice of *Nodes. // vars argument is a slice of *Nodes.
func newliveness(fn ir.Node, f *ssa.Func, vars []ir.Node, idx map[ir.Node]int32, stkptrsize int64) *Liveness { func newliveness(fn *ir.Func, f *ssa.Func, vars []ir.Node, idx map[ir.Node]int32, stkptrsize int64) *Liveness {
lv := &Liveness{ lv := &Liveness{
fn: fn, fn: fn,
f: f, f: f,
@ -788,7 +788,7 @@ func (lv *Liveness) epilogue() {
// pointers to copy values back to the stack). // pointers to copy values back to the stack).
// TODO: if the output parameter is heap-allocated, then we // TODO: if the output parameter is heap-allocated, then we
// don't need to keep the stack copy live? // don't need to keep the stack copy live?
if lv.fn.Func().HasDefer() { if lv.fn.HasDefer() {
for i, n := range lv.vars { for i, n := range lv.vars {
if n.Class() == ir.PPARAMOUT { if n.Class() == ir.PPARAMOUT {
if n.Name().IsOutputParamHeapAddr() { if n.Name().IsOutputParamHeapAddr() {
@ -891,7 +891,7 @@ func (lv *Liveness) epilogue() {
if n.Class() == ir.PPARAM { if n.Class() == ir.PPARAM {
continue // ok continue // ok
} }
base.Fatalf("bad live variable at entry of %v: %L", lv.fn.Func().Nname, n) base.Fatalf("bad live variable at entry of %v: %L", lv.fn.Nname, n)
} }
// Record live variables. // Record live variables.
@ -904,7 +904,7 @@ func (lv *Liveness) epilogue() {
} }
// If we have an open-coded deferreturn call, make a liveness map for it. // If we have an open-coded deferreturn call, make a liveness map for it.
if lv.fn.Func().OpenCodedDeferDisallowed() { if lv.fn.OpenCodedDeferDisallowed() {
lv.livenessMap.deferreturn = LivenessDontCare lv.livenessMap.deferreturn = LivenessDontCare
} else { } else {
lv.livenessMap.deferreturn = LivenessIndex{ lv.livenessMap.deferreturn = LivenessIndex{
@ -922,7 +922,7 @@ func (lv *Liveness) epilogue() {
// input parameters. // input parameters.
for j, n := range lv.vars { for j, n := range lv.vars {
if n.Class() != ir.PPARAM && lv.stackMaps[0].Get(int32(j)) { if n.Class() != ir.PPARAM && lv.stackMaps[0].Get(int32(j)) {
lv.f.Fatalf("%v %L recorded as live on entry", lv.fn.Func().Nname, n) lv.f.Fatalf("%v %L recorded as live on entry", lv.fn.Nname, n)
} }
} }
} }
@ -980,7 +980,7 @@ func (lv *Liveness) showlive(v *ssa.Value, live bvec) {
return return
} }
pos := lv.fn.Func().Nname.Pos() pos := lv.fn.Nname.Pos()
if v != nil { if v != nil {
pos = v.Pos pos = v.Pos
} }
@ -1090,7 +1090,7 @@ func (lv *Liveness) printDebug() {
if b == lv.f.Entry { if b == lv.f.Entry {
live := lv.stackMaps[0] live := lv.stackMaps[0]
fmt.Printf("(%s) function entry\n", base.FmtPos(lv.fn.Func().Nname.Pos())) fmt.Printf("(%s) function entry\n", base.FmtPos(lv.fn.Nname.Pos()))
fmt.Printf("\tlive=") fmt.Printf("\tlive=")
printed = false printed = false
for j, n := range lv.vars { for j, n := range lv.vars {
@ -1266,7 +1266,7 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
} }
// Emit the live pointer map data structures // Emit the live pointer map data structures
ls := e.curfn.Func().LSym ls := e.curfn.LSym
fninfo := ls.Func() fninfo := ls.Func()
fninfo.GCArgs, fninfo.GCLocals = lv.emit() fninfo.GCArgs, fninfo.GCLocals = lv.emit()

View file

@ -60,13 +60,13 @@ func ispkgin(pkgs []string) bool {
return false return false
} }
func instrument(fn ir.Node) { func instrument(fn *ir.Func) {
if fn.Func().Pragma&ir.Norace != 0 { if fn.Pragma&ir.Norace != 0 {
return return
} }
if !base.Flag.Race || !ispkgin(norace_inst_pkgs) { if !base.Flag.Race || !ispkgin(norace_inst_pkgs) {
fn.Func().SetInstrumentBody(true) fn.SetInstrumentBody(true)
} }
if base.Flag.Race { if base.Flag.Race {
@ -74,8 +74,8 @@ func instrument(fn ir.Node) {
base.Pos = src.NoXPos base.Pos = src.NoXPos
if thearch.LinkArch.Arch.Family != sys.AMD64 { if thearch.LinkArch.Arch.Family != sys.AMD64 {
fn.Func().Enter.Prepend(mkcall("racefuncenterfp", nil, nil)) fn.Enter.Prepend(mkcall("racefuncenterfp", nil, nil))
fn.Func().Exit.Append(mkcall("racefuncexit", nil, nil)) fn.Exit.Append(mkcall("racefuncexit", nil, nil))
} else { } else {
// nodpc is the PC of the caller as extracted by // nodpc is the PC of the caller as extracted by
@ -83,12 +83,12 @@ func instrument(fn ir.Node) {
// This only works for amd64. This will not // This only works for amd64. This will not
// work on arm or others that might support // work on arm or others that might support
// race in the future. // race in the future.
nodpc := ir.Copy(nodfp) nodpc := ir.Copy(nodfp).(*ir.Name)
nodpc.SetType(types.Types[types.TUINTPTR]) nodpc.SetType(types.Types[types.TUINTPTR])
nodpc.SetOffset(int64(-Widthptr)) nodpc.SetOffset(int64(-Widthptr))
fn.Func().Dcl = append(fn.Func().Dcl, nodpc) fn.Dcl = append(fn.Dcl, nodpc)
fn.Func().Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc)) fn.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc))
fn.Func().Exit.Append(mkcall("racefuncexit", nil, nil)) fn.Exit.Append(mkcall("racefuncexit", nil, nil))
} }
base.Pos = lno base.Pos = lno
} }

View file

@ -593,7 +593,7 @@ func arrayClear(n, v1, v2, a ir.Node) bool {
var fn ir.Node var fn ir.Node
if a.Type().Elem().HasPointers() { if a.Type().Elem().HasPointers() {
// memclrHasPointers(hp, hn) // memclrHasPointers(hp, hn)
Curfn.Func().SetWBPos(stmt.Pos()) Curfn.SetWBPos(stmt.Pos())
fn = mkcall("memclrHasPointers", nil, nil, hp, hn) fn = mkcall("memclrHasPointers", nil, nil, hp, hn)
} else { } else {
// memclrNoHeapPointers(hp, hn) // memclrNoHeapPointers(hp, hn)

View file

@ -32,10 +32,10 @@ import "cmd/compile/internal/ir"
// when analyzing a set of mutually recursive functions. // when analyzing a set of mutually recursive functions.
type bottomUpVisitor struct { type bottomUpVisitor struct {
analyze func([]ir.Node, bool) analyze func([]*ir.Func, bool)
visitgen uint32 visitgen uint32
nodeID map[ir.Node]uint32 nodeID map[*ir.Func]uint32
stack []ir.Node stack []*ir.Func
} }
// visitBottomUp invokes analyze on the ODCLFUNC nodes listed in list. // visitBottomUp invokes analyze on the ODCLFUNC nodes listed in list.
@ -51,18 +51,18 @@ type bottomUpVisitor struct {
// If recursive is false, the list consists of only a single function and its closures. // If recursive is false, the list consists of only a single function and its closures.
// If recursive is true, the list may still contain only a single function, // If recursive is true, the list may still contain only a single function,
// if that function is itself recursive. // if that function is itself recursive.
func visitBottomUp(list []ir.Node, analyze func(list []ir.Node, recursive bool)) { func visitBottomUp(list []ir.Node, analyze func(list []*ir.Func, recursive bool)) {
var v bottomUpVisitor var v bottomUpVisitor
v.analyze = analyze v.analyze = analyze
v.nodeID = make(map[ir.Node]uint32) v.nodeID = make(map[*ir.Func]uint32)
for _, n := range list { for _, n := range list {
if n.Op() == ir.ODCLFUNC && !n.Func().IsHiddenClosure() { if n.Op() == ir.ODCLFUNC && !n.Func().IsHiddenClosure() {
v.visit(n) v.visit(n.(*ir.Func))
} }
} }
} }
func (v *bottomUpVisitor) visit(n ir.Node) uint32 { func (v *bottomUpVisitor) visit(n *ir.Func) uint32 {
if id := v.nodeID[n]; id > 0 { if id := v.nodeID[n]; id > 0 {
// already visited // already visited
return id return id
@ -80,41 +80,41 @@ func (v *bottomUpVisitor) visit(n ir.Node) uint32 {
case ir.ONAME: case ir.ONAME:
if n.Class() == ir.PFUNC { if n.Class() == ir.PFUNC {
if n != nil && n.Name().Defn != nil { if n != nil && n.Name().Defn != nil {
if m := v.visit(n.Name().Defn); m < min { if m := v.visit(n.Name().Defn.(*ir.Func)); m < min {
min = m min = m
} }
} }
} }
case ir.OMETHEXPR: case ir.OMETHEXPR:
fn := methodExprName(n) fn := methodExprName(n)
if fn != nil && fn.Name().Defn != nil { if fn != nil && fn.Defn != nil {
if m := v.visit(fn.Name().Defn); m < min { if m := v.visit(fn.Defn.(*ir.Func)); m < min {
min = m min = m
} }
} }
case ir.ODOTMETH: case ir.ODOTMETH:
fn := methodExprName(n) fn := methodExprName(n)
if fn != nil && fn.Op() == ir.ONAME && fn.Class() == ir.PFUNC && fn.Name().Defn != nil { if fn != nil && fn.Op() == ir.ONAME && fn.Class() == ir.PFUNC && fn.Defn != nil {
if m := v.visit(fn.Name().Defn); m < min { if m := v.visit(fn.Defn.(*ir.Func)); m < min {
min = m min = m
} }
} }
case ir.OCALLPART: case ir.OCALLPART:
fn := ir.AsNode(callpartMethod(n).Nname) fn := ir.AsNode(callpartMethod(n).Nname)
if fn != nil && fn.Op() == ir.ONAME && fn.Class() == ir.PFUNC && fn.Name().Defn != nil { if fn != nil && fn.Op() == ir.ONAME && fn.Class() == ir.PFUNC && fn.Name().Defn != nil {
if m := v.visit(fn.Name().Defn); m < min { if m := v.visit(fn.Name().Defn.(*ir.Func)); m < min {
min = m min = m
} }
} }
case ir.OCLOSURE: case ir.OCLOSURE:
if m := v.visit(n.Func().Decl); m < min { if m := v.visit(n.Func()); m < min {
min = m min = m
} }
} }
return true return true
}) })
if (min == id || min == id+1) && !n.Func().IsHiddenClosure() { if (min == id || min == id+1) && !n.IsHiddenClosure() {
// This node is the root of a strongly connected component. // This node is the root of a strongly connected component.
// The original min passed to visitcodelist was v.nodeID[n]+1. // The original min passed to visitcodelist was v.nodeID[n]+1.

View file

@ -40,7 +40,7 @@ const ssaDumpFile = "ssa.html"
const maxOpenDefers = 8 const maxOpenDefers = 8
// ssaDumpInlined holds all inlined functions when ssaDump contains a function name. // ssaDumpInlined holds all inlined functions when ssaDump contains a function name.
var ssaDumpInlined []ir.Node var ssaDumpInlined []*ir.Func
func initssaconfig() { func initssaconfig() {
types_ := ssa.NewTypes() types_ := ssa.NewTypes()
@ -242,8 +242,8 @@ func dvarint(x *obj.LSym, off int, v int64) int {
// - Size of the argument // - Size of the argument
// - Offset of where argument should be placed in the args frame when making call // - Offset of where argument should be placed in the args frame when making call
func (s *state) emitOpenDeferInfo() { func (s *state) emitOpenDeferInfo() {
x := base.Ctxt.Lookup(s.curfn.Func().LSym.Name + ".opendefer") x := base.Ctxt.Lookup(s.curfn.LSym.Name + ".opendefer")
s.curfn.Func().LSym.Func().OpenCodedDeferInfo = x s.curfn.LSym.Func().OpenCodedDeferInfo = x
off := 0 off := 0
// Compute maxargsize (max size of arguments for all defers) // Compute maxargsize (max size of arguments for all defers)
@ -289,7 +289,7 @@ func (s *state) emitOpenDeferInfo() {
// buildssa builds an SSA function for fn. // buildssa builds an SSA function for fn.
// worker indicates which of the backend workers is doing the processing. // worker indicates which of the backend workers is doing the processing.
func buildssa(fn ir.Node, worker int) *ssa.Func { func buildssa(fn *ir.Func, worker int) *ssa.Func {
name := ir.FuncName(fn) name := ir.FuncName(fn)
printssa := false printssa := false
if ssaDump != "" { // match either a simple name e.g. "(*Reader).Reset", or a package.name e.g. "compress/gzip.(*Reader).Reset" if ssaDump != "" { // match either a simple name e.g. "(*Reader).Reset", or a package.name e.g. "compress/gzip.(*Reader).Reset"
@ -298,9 +298,9 @@ func buildssa(fn ir.Node, worker int) *ssa.Func {
var astBuf *bytes.Buffer var astBuf *bytes.Buffer
if printssa { if printssa {
astBuf = &bytes.Buffer{} astBuf = &bytes.Buffer{}
ir.FDumpList(astBuf, "buildssa-enter", fn.Func().Enter) ir.FDumpList(astBuf, "buildssa-enter", fn.Enter)
ir.FDumpList(astBuf, "buildssa-body", fn.Body()) ir.FDumpList(astBuf, "buildssa-body", fn.Body())
ir.FDumpList(astBuf, "buildssa-exit", fn.Func().Exit) ir.FDumpList(astBuf, "buildssa-exit", fn.Exit)
if ssaDumpStdout { if ssaDumpStdout {
fmt.Println("generating SSA for", name) fmt.Println("generating SSA for", name)
fmt.Print(astBuf.String()) fmt.Print(astBuf.String())
@ -311,8 +311,8 @@ func buildssa(fn ir.Node, worker int) *ssa.Func {
s.pushLine(fn.Pos()) s.pushLine(fn.Pos())
defer s.popLine() defer s.popLine()
s.hasdefer = fn.Func().HasDefer() s.hasdefer = fn.HasDefer()
if fn.Func().Pragma&ir.CgoUnsafeArgs != 0 { if fn.Pragma&ir.CgoUnsafeArgs != 0 {
s.cgoUnsafeArgs = true s.cgoUnsafeArgs = true
} }
@ -331,7 +331,7 @@ func buildssa(fn ir.Node, worker int) *ssa.Func {
s.f.Name = name s.f.Name = name
s.f.DebugTest = s.f.DebugHashMatch("GOSSAHASH") s.f.DebugTest = s.f.DebugHashMatch("GOSSAHASH")
s.f.PrintOrHtmlSSA = printssa s.f.PrintOrHtmlSSA = printssa
if fn.Func().Pragma&ir.Nosplit != 0 { if fn.Pragma&ir.Nosplit != 0 {
s.f.NoSplit = true s.f.NoSplit = true
} }
s.panics = map[funcLine]*ssa.Block{} s.panics = map[funcLine]*ssa.Block{}
@ -359,7 +359,7 @@ func buildssa(fn ir.Node, worker int) *ssa.Func {
s.fwdVars = map[ir.Node]*ssa.Value{} s.fwdVars = map[ir.Node]*ssa.Value{}
s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem) s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem)
s.hasOpenDefers = base.Flag.N == 0 && s.hasdefer && !s.curfn.Func().OpenCodedDeferDisallowed() s.hasOpenDefers = base.Flag.N == 0 && s.hasdefer && !s.curfn.OpenCodedDeferDisallowed()
switch { switch {
case s.hasOpenDefers && (base.Ctxt.Flag_shared || base.Ctxt.Flag_dynlink) && thearch.LinkArch.Name == "386": case s.hasOpenDefers && (base.Ctxt.Flag_shared || base.Ctxt.Flag_dynlink) && thearch.LinkArch.Name == "386":
// Don't support open-coded defers for 386 ONLY when using shared // Don't support open-coded defers for 386 ONLY when using shared
@ -368,7 +368,7 @@ func buildssa(fn ir.Node, worker int) *ssa.Func {
// that we don't track correctly. // that we don't track correctly.
s.hasOpenDefers = false s.hasOpenDefers = false
} }
if s.hasOpenDefers && s.curfn.Func().Exit.Len() > 0 { if s.hasOpenDefers && s.curfn.Exit.Len() > 0 {
// Skip doing open defers if there is any extra exit code (likely // Skip doing open defers if there is any extra exit code (likely
// copying heap-allocated return values or race detection), since // copying heap-allocated return values or race detection), since
// we will not generate that code in the case of the extra // we will not generate that code in the case of the extra
@ -376,7 +376,7 @@ func buildssa(fn ir.Node, worker int) *ssa.Func {
s.hasOpenDefers = false s.hasOpenDefers = false
} }
if s.hasOpenDefers && if s.hasOpenDefers &&
s.curfn.Func().NumReturns*s.curfn.Func().NumDefers > 15 { s.curfn.NumReturns*s.curfn.NumDefers > 15 {
// Since we are generating defer calls at every exit for // Since we are generating defer calls at every exit for
// open-coded defers, skip doing open-coded defers if there are // open-coded defers, skip doing open-coded defers if there are
// too many returns (especially if there are multiple defers). // too many returns (especially if there are multiple defers).
@ -413,7 +413,7 @@ func buildssa(fn ir.Node, worker int) *ssa.Func {
s.decladdrs = map[ir.Node]*ssa.Value{} s.decladdrs = map[ir.Node]*ssa.Value{}
var args []ssa.Param var args []ssa.Param
var results []ssa.Param var results []ssa.Param
for _, n := range fn.Func().Dcl { for _, n := range fn.Dcl {
switch n.Class() { switch n.Class() {
case ir.PPARAM: case ir.PPARAM:
s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type()), n, s.sp, s.startmem) s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type()), n, s.sp, s.startmem)
@ -440,7 +440,7 @@ func buildssa(fn ir.Node, worker int) *ssa.Func {
} }
// Populate SSAable arguments. // Populate SSAable arguments.
for _, n := range fn.Func().Dcl { for _, n := range fn.Dcl {
if n.Class() == ir.PPARAM && s.canSSA(n) { if n.Class() == ir.PPARAM && s.canSSA(n) {
v := s.newValue0A(ssa.OpArg, n.Type(), n) v := s.newValue0A(ssa.OpArg, n.Type(), n)
s.vars[n] = v s.vars[n] = v
@ -449,12 +449,12 @@ func buildssa(fn ir.Node, worker int) *ssa.Func {
} }
// Convert the AST-based IR to the SSA-based IR // Convert the AST-based IR to the SSA-based IR
s.stmtList(fn.Func().Enter) s.stmtList(fn.Enter)
s.stmtList(fn.Body()) s.stmtList(fn.Body())
// fallthrough to exit // fallthrough to exit
if s.curBlock != nil { if s.curBlock != nil {
s.pushLine(fn.Func().Endlineno) s.pushLine(fn.Endlineno)
s.exit() s.exit()
s.popLine() s.popLine()
} }
@ -477,10 +477,10 @@ func buildssa(fn ir.Node, worker int) *ssa.Func {
return s.f return s.f
} }
func dumpSourcesColumn(writer *ssa.HTMLWriter, fn ir.Node) { func dumpSourcesColumn(writer *ssa.HTMLWriter, fn *ir.Func) {
// Read sources of target function fn. // Read sources of target function fn.
fname := base.Ctxt.PosTable.Pos(fn.Pos()).Filename() fname := base.Ctxt.PosTable.Pos(fn.Pos()).Filename()
targetFn, err := readFuncLines(fname, fn.Pos().Line(), fn.Func().Endlineno.Line()) targetFn, err := readFuncLines(fname, fn.Pos().Line(), fn.Endlineno.Line())
if err != nil { if err != nil {
writer.Logf("cannot read sources for function %v: %v", fn, err) writer.Logf("cannot read sources for function %v: %v", fn, err)
} }
@ -488,13 +488,7 @@ func dumpSourcesColumn(writer *ssa.HTMLWriter, fn ir.Node) {
// Read sources of inlined functions. // Read sources of inlined functions.
var inlFns []*ssa.FuncLines var inlFns []*ssa.FuncLines
for _, fi := range ssaDumpInlined { for _, fi := range ssaDumpInlined {
var elno src.XPos elno := fi.Endlineno
if fi.Name().Defn == nil {
// Endlineno is filled from exported data.
elno = fi.Func().Endlineno
} else {
elno = fi.Name().Defn.Func().Endlineno
}
fname := base.Ctxt.PosTable.Pos(fi.Pos()).Filename() fname := base.Ctxt.PosTable.Pos(fi.Pos()).Filename()
fnLines, err := readFuncLines(fname, fi.Pos().Line(), elno.Line()) fnLines, err := readFuncLines(fname, fi.Pos().Line(), elno.Line())
if err != nil { if err != nil {
@ -593,7 +587,7 @@ type state struct {
f *ssa.Func f *ssa.Func
// Node for function // Node for function
curfn ir.Node curfn *ir.Func
// labels in f // labels in f
labels map[string]*ssaLabel labels map[string]*ssaLabel
@ -972,7 +966,7 @@ func (s *state) newValueOrSfCall2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Valu
} }
func (s *state) instrument(t *types.Type, addr *ssa.Value, wr bool) { func (s *state) instrument(t *types.Type, addr *ssa.Value, wr bool) {
if !s.curfn.Func().InstrumentBody() { if !s.curfn.InstrumentBody() {
return return
} }
@ -1571,7 +1565,7 @@ func (s *state) exit() *ssa.Block {
// Run exit code. Typically, this code copies heap-allocated PPARAMOUT // Run exit code. Typically, this code copies heap-allocated PPARAMOUT
// variables back to the stack. // variables back to the stack.
s.stmtList(s.curfn.Func().Exit) s.stmtList(s.curfn.Exit)
// Store SSAable PPARAMOUT variables back to stack locations. // Store SSAable PPARAMOUT variables back to stack locations.
for _, n := range s.returns { for _, n := range s.returns {
@ -4296,7 +4290,7 @@ func (s *state) openDeferSave(n ir.Node, t *types.Type, val *ssa.Value) *ssa.Val
pos = n.Pos() pos = n.Pos()
} }
argTemp := tempAt(pos.WithNotStmt(), s.curfn, t) argTemp := tempAt(pos.WithNotStmt(), s.curfn, t)
argTemp.Name().SetOpenDeferSlot(true) argTemp.SetOpenDeferSlot(true)
var addrArgTemp *ssa.Value var addrArgTemp *ssa.Value
// Use OpVarLive to make sure stack slots for the args, etc. are not // Use OpVarLive to make sure stack slots for the args, etc. are not
// removed by dead-store elimination // removed by dead-store elimination
@ -4322,7 +4316,7 @@ func (s *state) openDeferSave(n ir.Node, t *types.Type, val *ssa.Value) *ssa.Val
// Therefore, we must make sure it is zeroed out in the entry // Therefore, we must make sure it is zeroed out in the entry
// block if it contains pointers, else GC may wrongly follow an // block if it contains pointers, else GC may wrongly follow an
// uninitialized pointer value. // uninitialized pointer value.
argTemp.Name().SetNeedzero(true) argTemp.SetNeedzero(true)
} }
if !canSSA { if !canSSA {
a := s.addr(n) a := s.addr(n)
@ -4790,7 +4784,7 @@ func (s *state) getMethodClosure(fn ir.Node) *ssa.Value {
// We get back an SSA value representing &sync.(*Mutex).Unlock·f. // We get back an SSA value representing &sync.(*Mutex).Unlock·f.
// We can then pass that to defer or go. // We can then pass that to defer or go.
n2 := ir.NewNameAt(fn.Pos(), fn.Sym()) n2 := ir.NewNameAt(fn.Pos(), fn.Sym())
n2.Name().Curfn = s.curfn n2.Curfn = s.curfn
n2.SetClass(ir.PFUNC) n2.SetClass(ir.PFUNC)
// n2.Sym already existed, so it's already marked as a function. // n2.Sym already existed, so it's already marked as a function.
n2.SetPos(fn.Pos()) n2.SetPos(fn.Pos())
@ -5023,7 +5017,7 @@ func (s *state) exprPtr(n ir.Node, bounded bool, lineno src.XPos) *ssa.Value {
// Used only for automatically inserted nil checks, // Used only for automatically inserted nil checks,
// not for user code like 'x != nil'. // not for user code like 'x != nil'.
func (s *state) nilCheck(ptr *ssa.Value) { func (s *state) nilCheck(ptr *ssa.Value) {
if base.Debug.DisableNil != 0 || s.curfn.Func().NilCheckDisabled() { if base.Debug.DisableNil != 0 || s.curfn.NilCheckDisabled() {
return return
} }
s.newValue2(ssa.OpNilCheck, types.TypeVoid, ptr, s.mem()) s.newValue2(ssa.OpNilCheck, types.TypeVoid, ptr, s.mem())
@ -6197,7 +6191,7 @@ func (s byXoffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func emitStackObjects(e *ssafn, pp *Progs) { func emitStackObjects(e *ssafn, pp *Progs) {
var vars []ir.Node var vars []ir.Node
for _, n := range e.curfn.Func().Dcl { for _, n := range e.curfn.Dcl {
if livenessShouldTrack(n) && n.Name().Addrtaken() { if livenessShouldTrack(n) && n.Name().Addrtaken() {
vars = append(vars, n) vars = append(vars, n)
} }
@ -6211,7 +6205,7 @@ func emitStackObjects(e *ssafn, pp *Progs) {
// Populate the stack object data. // Populate the stack object data.
// Format must match runtime/stack.go:stackObjectRecord. // Format must match runtime/stack.go:stackObjectRecord.
x := e.curfn.Func().LSym.Func().StackObjects x := e.curfn.LSym.Func().StackObjects
off := 0 off := 0
off = duintptr(x, off, uint64(len(vars))) off = duintptr(x, off, uint64(len(vars)))
for _, v := range vars { for _, v := range vars {
@ -6248,7 +6242,7 @@ func genssa(f *ssa.Func, pp *Progs) {
s.livenessMap = liveness(e, f, pp) s.livenessMap = liveness(e, f, pp)
emitStackObjects(e, pp) emitStackObjects(e, pp)
openDeferInfo := e.curfn.Func().LSym.Func().OpenCodedDeferInfo openDeferInfo := e.curfn.LSym.Func().OpenCodedDeferInfo
if openDeferInfo != nil { if openDeferInfo != nil {
// This function uses open-coded defers -- write out the funcdata // This function uses open-coded defers -- write out the funcdata
// info that we computed at the end of genssa. // info that we computed at the end of genssa.
@ -6453,7 +6447,7 @@ func genssa(f *ssa.Func, pp *Progs) {
// some of the inline marks. // some of the inline marks.
// Use this instruction instead. // Use this instruction instead.
p.Pos = p.Pos.WithIsStmt() // promote position to a statement p.Pos = p.Pos.WithIsStmt() // promote position to a statement
pp.curfn.Func().LSym.Func().AddInlMark(p, inlMarks[m]) pp.curfn.LSym.Func().AddInlMark(p, inlMarks[m])
// Make the inline mark a real nop, so it doesn't generate any code. // Make the inline mark a real nop, so it doesn't generate any code.
m.As = obj.ANOP m.As = obj.ANOP
m.Pos = src.NoXPos m.Pos = src.NoXPos
@ -6465,14 +6459,14 @@ func genssa(f *ssa.Func, pp *Progs) {
// Any unmatched inline marks now need to be added to the inlining tree (and will generate a nop instruction). // Any unmatched inline marks now need to be added to the inlining tree (and will generate a nop instruction).
for _, p := range inlMarkList { for _, p := range inlMarkList {
if p.As != obj.ANOP { if p.As != obj.ANOP {
pp.curfn.Func().LSym.Func().AddInlMark(p, inlMarks[p]) pp.curfn.LSym.Func().AddInlMark(p, inlMarks[p])
} }
} }
} }
if base.Ctxt.Flag_locationlists { if base.Ctxt.Flag_locationlists {
debugInfo := ssa.BuildFuncDebug(base.Ctxt, f, base.Debug.LocationLists > 1, stackOffset) debugInfo := ssa.BuildFuncDebug(base.Ctxt, f, base.Debug.LocationLists > 1, stackOffset)
e.curfn.Func().DebugInfo = debugInfo e.curfn.DebugInfo = debugInfo
bstart := s.bstart bstart := s.bstart
// Note that at this moment, Prog.Pc is a sequence number; it's // Note that at this moment, Prog.Pc is a sequence number; it's
// not a real PC until after assembly, so this mapping has to // not a real PC until after assembly, so this mapping has to
@ -6486,7 +6480,7 @@ func genssa(f *ssa.Func, pp *Progs) {
} }
return bstart[b].Pc return bstart[b].Pc
case ssa.BlockEnd.ID: case ssa.BlockEnd.ID:
return e.curfn.Func().LSym.Size return e.curfn.LSym.Size
default: default:
return valueToProgAfter[v].Pc return valueToProgAfter[v].Pc
} }
@ -6584,7 +6578,7 @@ func defframe(s *SSAGenState, e *ssafn) {
var state uint32 var state uint32
// Iterate through declarations. They are sorted in decreasing Xoffset order. // Iterate through declarations. They are sorted in decreasing Xoffset order.
for _, n := range e.curfn.Func().Dcl { for _, n := range e.curfn.Dcl {
if !n.Name().Needzero() { if !n.Name().Needzero() {
continue continue
} }
@ -6949,7 +6943,7 @@ func fieldIdx(n ir.Node) int {
// ssafn holds frontend information about a function that the backend is processing. // ssafn holds frontend information about a function that the backend is processing.
// It also exports a bunch of compiler services for the ssa backend. // It also exports a bunch of compiler services for the ssa backend.
type ssafn struct { type ssafn struct {
curfn ir.Node curfn *ir.Func
strings map[string]*obj.LSym // map from constant string to data symbols strings map[string]*obj.LSym // map from constant string to data symbols
scratchFpMem ir.Node // temp for floating point register / memory moves on some architectures scratchFpMem ir.Node // temp for floating point register / memory moves on some architectures
stksize int64 // stack size for current frame stksize int64 // stack size for current frame
@ -7072,8 +7066,8 @@ func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t
n.SetType(t) n.SetType(t)
n.SetClass(ir.PAUTO) n.SetClass(ir.PAUTO)
n.SetEsc(EscNever) n.SetEsc(EscNever)
n.Name().Curfn = e.curfn n.Curfn = e.curfn
e.curfn.Func().Dcl = append(e.curfn.Func().Dcl, n) e.curfn.Dcl = append(e.curfn.Dcl, n)
dowidth(t) dowidth(t)
return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset} return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset}
} }
@ -7136,7 +7130,7 @@ func (e *ssafn) Syslook(name string) *obj.LSym {
} }
func (e *ssafn) SetWBPos(pos src.XPos) { func (e *ssafn) SetWBPos(pos src.XPos) {
e.curfn.Func().SetWBPos(pos) e.curfn.SetWBPos(pos)
} }
func (e *ssafn) MyImportPath() string { func (e *ssafn) MyImportPath() string {

View file

@ -95,8 +95,8 @@ func autolabel(prefix string) *types.Sym {
if Curfn == nil { if Curfn == nil {
base.Fatalf("autolabel outside function") base.Fatalf("autolabel outside function")
} }
n := fn.Func().Label n := fn.Label
fn.Func().Label++ fn.Label++
return lookupN(prefix, int(n)) return lookupN(prefix, int(n))
} }
@ -138,7 +138,7 @@ func importdot(opkg *types.Pkg, pack *ir.PkgName) {
// newname returns a new ONAME Node associated with symbol s. // newname returns a new ONAME Node associated with symbol s.
func NewName(s *types.Sym) *ir.Name { func NewName(s *types.Sym) *ir.Name {
n := ir.NewNameAt(base.Pos, s) n := ir.NewNameAt(base.Pos, s)
n.Name().Curfn = Curfn n.Curfn = Curfn
return n return n
} }
@ -1165,7 +1165,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
tfn.PtrRlist().Set(structargs(method.Type.Results(), false)) tfn.PtrRlist().Set(structargs(method.Type.Results(), false))
fn := dclfunc(newnam, tfn) fn := dclfunc(newnam, tfn)
fn.Func().SetDupok(true) fn.SetDupok(true)
nthis := ir.AsNode(tfn.Type().Recv().Nname) nthis := ir.AsNode(tfn.Type().Recv().Nname)
@ -1201,7 +1201,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
fn.PtrBody().Append(as) fn.PtrBody().Append(as)
fn.PtrBody().Append(nodSym(ir.ORETJMP, nil, methodSym(methodrcvr, method.Sym))) fn.PtrBody().Append(nodSym(ir.ORETJMP, nil, methodSym(methodrcvr, method.Sym)))
} else { } else {
fn.Func().SetWrapper(true) // ignore frame for panic+recover matching fn.SetWrapper(true) // ignore frame for panic+recover matching
call := ir.Nod(ir.OCALL, dot, nil) call := ir.Nod(ir.OCALL, dot, nil)
call.PtrList().Set(paramNnames(tfn.Type())) call.PtrList().Set(paramNnames(tfn.Type()))
call.SetIsDDD(tfn.Type().IsVariadic()) call.SetIsDDD(tfn.Type().IsVariadic())
@ -1222,8 +1222,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
testdclstack() testdclstack()
} }
fn = typecheck(fn, ctxStmt) typecheckFunc(fn)
Curfn = fn Curfn = fn
typecheckslice(fn.Body().Slice(), ctxStmt) typecheckslice(fn.Body().Slice(), ctxStmt)
@ -1233,7 +1232,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym != nil { if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym != nil {
inlcalls(fn) inlcalls(fn)
} }
escapeFuncs([]ir.Node{fn}, false) escapeFuncs([]*ir.Func{fn}, false)
Curfn = nil Curfn = nil
xtop = append(xtop, fn) xtop = append(xtop, fn)

View file

@ -95,7 +95,7 @@ func resolve(n ir.Node) (res ir.Node) {
base.Fatalf("recursive inimport") base.Fatalf("recursive inimport")
} }
inimport = true inimport = true
expandDecl(n) expandDecl(n.(*ir.Name))
inimport = false inimport = false
return n return n
} }
@ -199,6 +199,13 @@ func cycleTrace(cycle []ir.Node) string {
var typecheck_tcstack []ir.Node var typecheck_tcstack []ir.Node
func typecheckFunc(fn *ir.Func) {
new := typecheck(fn, ctxStmt)
if new != fn {
base.Fatalf("typecheck changed func")
}
}
// typecheck type checks node n. // typecheck type checks node n.
// The result of typecheck MUST be assigned back to n, e.g. // The result of typecheck MUST be assigned back to n, e.g.
// n.Left = typecheck(n.Left, top) // n.Left = typecheck(n.Left, top)
@ -2069,7 +2076,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.ODCLFUNC: case ir.ODCLFUNC:
ok |= ctxStmt ok |= ctxStmt
typecheckfunc(n) typecheckfunc(n.(*ir.Func))
case ir.ODCLCONST: case ir.ODCLCONST:
ok |= ctxStmt ok |= ctxStmt
@ -3402,36 +3409,38 @@ out:
} }
// type check function definition // type check function definition
func typecheckfunc(n ir.Node) { // To be called by typecheck, not directly.
// (Call typecheckfn instead.)
func typecheckfunc(n *ir.Func) {
if enableTrace && base.Flag.LowerT { if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheckfunc", n)(nil) defer tracePrint("typecheckfunc", n)(nil)
} }
for _, ln := range n.Func().Dcl { for _, ln := range n.Dcl {
if ln.Op() == ir.ONAME && (ln.Class() == ir.PPARAM || ln.Class() == ir.PPARAMOUT) { if ln.Op() == ir.ONAME && (ln.Class() == ir.PPARAM || ln.Class() == ir.PPARAMOUT) {
ln.Name().Decldepth = 1 ln.Name().Decldepth = 1
} }
} }
n.Func().Nname = typecheck(n.Func().Nname, ctxExpr|ctxAssign) n.Nname = typecheck(n.Nname, ctxExpr|ctxAssign).(*ir.Name)
t := n.Func().Nname.Type() t := n.Nname.Type()
if t == nil { if t == nil {
return return
} }
n.SetType(t) n.SetType(t)
rcvr := t.Recv() rcvr := t.Recv()
if rcvr != nil && n.Func().Shortname != nil { if rcvr != nil && n.Shortname != nil {
m := addmethod(n, n.Func().Shortname, t, true, n.Func().Pragma&ir.Nointerface != 0) m := addmethod(n, n.Shortname, t, true, n.Pragma&ir.Nointerface != 0)
if m == nil { if m == nil {
return return
} }
n.Func().Nname.SetSym(methodSym(rcvr.Type, n.Func().Shortname)) n.Nname.SetSym(methodSym(rcvr.Type, n.Shortname))
declare(n.Func().Nname, ir.PFUNC) declare(n.Nname, ir.PFUNC)
} }
if base.Ctxt.Flag_dynlink && !inimport && n.Func().Nname != nil { if base.Ctxt.Flag_dynlink && !inimport && n.Nname != nil {
makefuncsym(n.Func().Nname.Sym()) makefuncsym(n.Sym())
} }
} }
@ -3861,22 +3870,19 @@ func isTermNode(n ir.Node) bool {
} }
// checkreturn makes sure that fn terminates appropriately. // checkreturn makes sure that fn terminates appropriately.
func checkreturn(fn ir.Node) { func checkreturn(fn *ir.Func) {
if fn.Type().NumResults() != 0 && fn.Body().Len() != 0 { if fn.Type().NumResults() != 0 && fn.Body().Len() != 0 {
var labels map[*types.Sym]ir.Node var labels map[*types.Sym]ir.Node
markbreaklist(&labels, fn.Body(), nil) markbreaklist(&labels, fn.Body(), nil)
if !isTermNodes(fn.Body()) { if !isTermNodes(fn.Body()) {
base.ErrorfAt(fn.Func().Endlineno, "missing return at end of function") base.ErrorfAt(fn.Endlineno, "missing return at end of function")
} }
} }
} }
func deadcode(fn ir.Node) { func deadcode(fn *ir.Func) {
deadcodeslice(fn.PtrBody()) deadcodeslice(fn.PtrBody())
deadcodefn(fn)
}
func deadcodefn(fn ir.Node) {
if fn.Body().Len() == 0 { if fn.Body().Len() == 0 {
return return
} }
@ -4014,21 +4020,15 @@ func curpkg() *types.Pkg {
// Initialization expressions for package-scope variables. // Initialization expressions for package-scope variables.
return ir.LocalPkg return ir.LocalPkg
} }
return fnpkg(fn.Nname)
// TODO(mdempsky): Standardize on either ODCLFUNC or ONAME for
// Curfn, rather than mixing them.
if fn.Op() == ir.ODCLFUNC {
fn = fn.Func().Nname
}
return fnpkg(fn)
} }
// MethodName returns the ONAME representing the method // MethodName returns the ONAME representing the method
// referenced by expression n, which must be a method selector, // referenced by expression n, which must be a method selector,
// method expression, or method value. // method expression, or method value.
func methodExprName(n ir.Node) ir.Node { func methodExprName(n ir.Node) *ir.Name {
return ir.AsNode(methodExprFunc(n).Nname) name, _ := ir.AsNode(methodExprFunc(n).Nname).(*ir.Name)
return name
} }
// MethodFunc is like MethodName, but returns the types.Field instead. // MethodFunc is like MethodName, but returns the types.Field instead.

View file

@ -22,33 +22,33 @@ import (
const tmpstringbufsize = 32 const tmpstringbufsize = 32
const zeroValSize = 1024 // must match value of runtime/map.go:maxZero const zeroValSize = 1024 // must match value of runtime/map.go:maxZero
func walk(fn ir.Node) { func walk(fn *ir.Func) {
Curfn = fn Curfn = fn
errorsBefore := base.Errors() errorsBefore := base.Errors()
if base.Flag.W != 0 { if base.Flag.W != 0 {
s := fmt.Sprintf("\nbefore walk %v", Curfn.Func().Nname.Sym()) s := fmt.Sprintf("\nbefore walk %v", Curfn.Sym())
ir.DumpList(s, Curfn.Body()) ir.DumpList(s, Curfn.Body())
} }
lno := base.Pos lno := base.Pos
// Final typecheck for any unused variables. // Final typecheck for any unused variables.
for i, ln := range fn.Func().Dcl { for i, ln := range fn.Dcl {
if ln.Op() == ir.ONAME && (ln.Class() == ir.PAUTO || ln.Class() == ir.PAUTOHEAP) { if ln.Op() == ir.ONAME && (ln.Class() == ir.PAUTO || ln.Class() == ir.PAUTOHEAP) {
ln = typecheck(ln, ctxExpr|ctxAssign) ln = typecheck(ln, ctxExpr|ctxAssign).(*ir.Name)
fn.Func().Dcl[i] = ln fn.Dcl[i] = ln
} }
} }
// Propagate the used flag for typeswitch variables up to the NONAME in its definition. // Propagate the used flag for typeswitch variables up to the NONAME in its definition.
for _, ln := range fn.Func().Dcl { for _, ln := range fn.Dcl {
if ln.Op() == ir.ONAME && (ln.Class() == ir.PAUTO || ln.Class() == ir.PAUTOHEAP) && ln.Name().Defn != nil && ln.Name().Defn.Op() == ir.OTYPESW && ln.Name().Used() { if ln.Op() == ir.ONAME && (ln.Class() == ir.PAUTO || ln.Class() == ir.PAUTOHEAP) && ln.Name().Defn != nil && ln.Name().Defn.Op() == ir.OTYPESW && ln.Name().Used() {
ln.Name().Defn.Left().Name().SetUsed(true) ln.Name().Defn.Left().Name().SetUsed(true)
} }
} }
for _, ln := range fn.Func().Dcl { for _, ln := range fn.Dcl {
if ln.Op() != ir.ONAME || (ln.Class() != ir.PAUTO && ln.Class() != ir.PAUTOHEAP) || ln.Sym().Name[0] == '&' || ln.Name().Used() { if ln.Op() != ir.ONAME || (ln.Class() != ir.PAUTO && ln.Class() != ir.PAUTOHEAP) || ln.Sym().Name[0] == '&' || ln.Name().Used() {
continue continue
} }
@ -69,15 +69,15 @@ func walk(fn ir.Node) {
} }
walkstmtlist(Curfn.Body().Slice()) walkstmtlist(Curfn.Body().Slice())
if base.Flag.W != 0 { if base.Flag.W != 0 {
s := fmt.Sprintf("after walk %v", Curfn.Func().Nname.Sym()) s := fmt.Sprintf("after walk %v", Curfn.Sym())
ir.DumpList(s, Curfn.Body()) ir.DumpList(s, Curfn.Body())
} }
zeroResults() zeroResults()
heapmoves() heapmoves()
if base.Flag.W != 0 && Curfn.Func().Enter.Len() > 0 { if base.Flag.W != 0 && Curfn.Enter.Len() > 0 {
s := fmt.Sprintf("enter %v", Curfn.Func().Nname.Sym()) s := fmt.Sprintf("enter %v", Curfn.Sym())
ir.DumpList(s, Curfn.Func().Enter) ir.DumpList(s, Curfn.Enter)
} }
} }
@ -87,8 +87,8 @@ func walkstmtlist(s []ir.Node) {
} }
} }
func paramoutheap(fn ir.Node) bool { func paramoutheap(fn *ir.Func) bool {
for _, ln := range fn.Func().Dcl { for _, ln := range fn.Dcl {
switch ln.Class() { switch ln.Class() {
case ir.PPARAMOUT: case ir.PPARAMOUT:
if isParamStackCopy(ln) || ln.Name().Addrtaken() { if isParamStackCopy(ln) || ln.Name().Addrtaken() {
@ -209,18 +209,18 @@ func walkstmt(n ir.Node) ir.Node {
base.Errorf("case statement out of place") base.Errorf("case statement out of place")
case ir.ODEFER: case ir.ODEFER:
Curfn.Func().SetHasDefer(true) Curfn.SetHasDefer(true)
Curfn.Func().NumDefers++ Curfn.NumDefers++
if Curfn.Func().NumDefers > maxOpenDefers { if Curfn.NumDefers > maxOpenDefers {
// Don't allow open-coded defers if there are more than // Don't allow open-coded defers if there are more than
// 8 defers in the function, since we use a single // 8 defers in the function, since we use a single
// byte to record active defers. // byte to record active defers.
Curfn.Func().SetOpenCodedDeferDisallowed(true) Curfn.SetOpenCodedDeferDisallowed(true)
} }
if n.Esc() != EscNever { if n.Esc() != EscNever {
// If n.Esc is not EscNever, then this defer occurs in a loop, // If n.Esc is not EscNever, then this defer occurs in a loop,
// so open-coded defers cannot be used in this function. // so open-coded defers cannot be used in this function.
Curfn.Func().SetOpenCodedDeferDisallowed(true) Curfn.SetOpenCodedDeferDisallowed(true)
} }
fallthrough fallthrough
case ir.OGO: case ir.OGO:
@ -270,7 +270,7 @@ func walkstmt(n ir.Node) ir.Node {
walkstmtlist(n.Rlist().Slice()) walkstmtlist(n.Rlist().Slice())
case ir.ORETURN: case ir.ORETURN:
Curfn.Func().NumReturns++ Curfn.NumReturns++
if n.List().Len() == 0 { if n.List().Len() == 0 {
break break
} }
@ -279,12 +279,13 @@ func walkstmt(n ir.Node) ir.Node {
// so that reorder3 can fix up conflicts // so that reorder3 can fix up conflicts
var rl []ir.Node var rl []ir.Node
for _, ln := range Curfn.Func().Dcl { for _, ln := range Curfn.Dcl {
cl := ln.Class() cl := ln.Class()
if cl == ir.PAUTO || cl == ir.PAUTOHEAP { if cl == ir.PAUTO || cl == ir.PAUTOHEAP {
break break
} }
if cl == ir.PPARAMOUT { if cl == ir.PPARAMOUT {
var ln ir.Node = ln
if isParamStackCopy(ln) { if isParamStackCopy(ln) {
ln = walkexpr(typecheck(ir.Nod(ir.ODEREF, ln.Name().Heapaddr, nil), ctxExpr), nil) ln = walkexpr(typecheck(ir.Nod(ir.ODEREF, ln.Name().Heapaddr, nil), ctxExpr), nil)
} }
@ -800,8 +801,8 @@ opswitch:
fromType := n.Left().Type() fromType := n.Left().Type()
toType := n.Type() toType := n.Type()
if !fromType.IsInterface() && !ir.IsBlank(Curfn.Func().Nname) { // skip unnamed functions (func _()) if !fromType.IsInterface() && !ir.IsBlank(Curfn.Nname) { // skip unnamed functions (func _())
markTypeUsedInInterface(fromType, Curfn.Func().LSym) markTypeUsedInInterface(fromType, Curfn.LSym)
} }
// typeword generates the type word of the interface value. // typeword generates the type word of the interface value.
@ -1625,7 +1626,7 @@ func markTypeUsedInInterface(t *types.Type, from *obj.LSym) {
func markUsedIfaceMethod(n ir.Node) { func markUsedIfaceMethod(n ir.Node) {
ityp := n.Left().Left().Type() ityp := n.Left().Left().Type()
tsym := typenamesym(ityp).Linksym() tsym := typenamesym(ityp).Linksym()
r := obj.Addrel(Curfn.Func().LSym) r := obj.Addrel(Curfn.LSym)
r.Sym = tsym r.Sym = tsym
// n.Left.Xoffset is the method index * Widthptr (the offset of code pointer // n.Left.Xoffset is the method index * Widthptr (the offset of code pointer
// in itab). // in itab).
@ -2448,7 +2449,7 @@ func zeroResults() {
v = v.Name().Stackcopy v = v.Name().Stackcopy
} }
// Zero the stack location containing f. // Zero the stack location containing f.
Curfn.Func().Enter.Append(ir.NodAt(Curfn.Pos(), ir.OAS, v, nil)) Curfn.Enter.Append(ir.NodAt(Curfn.Pos(), ir.OAS, v, nil))
} }
} }
@ -2478,9 +2479,9 @@ func heapmoves() {
nn := paramstoheap(Curfn.Type().Recvs()) nn := paramstoheap(Curfn.Type().Recvs())
nn = append(nn, paramstoheap(Curfn.Type().Params())...) nn = append(nn, paramstoheap(Curfn.Type().Params())...)
nn = append(nn, paramstoheap(Curfn.Type().Results())...) nn = append(nn, paramstoheap(Curfn.Type().Results())...)
Curfn.Func().Enter.Append(nn...) Curfn.Enter.Append(nn...)
base.Pos = Curfn.Func().Endlineno base.Pos = Curfn.Endlineno
Curfn.Func().Exit.Append(returnsfromheap(Curfn.Type().Results())...) Curfn.Exit.Append(returnsfromheap(Curfn.Type().Results())...)
base.Pos = lno base.Pos = lno
} }
@ -2781,7 +2782,7 @@ func appendslice(n ir.Node, init *ir.Nodes) ir.Node {
nptr2 := l2 nptr2 := l2
Curfn.Func().SetWBPos(n.Pos()) Curfn.SetWBPos(n.Pos())
// instantiate typedslicecopy(typ *type, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int // instantiate typedslicecopy(typ *type, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int
fn := syslook("typedslicecopy") fn := syslook("typedslicecopy")
@ -2966,7 +2967,7 @@ func extendslice(n ir.Node, init *ir.Nodes) ir.Node {
hasPointers := elemtype.HasPointers() hasPointers := elemtype.HasPointers()
if hasPointers { if hasPointers {
clrname = "memclrHasPointers" clrname = "memclrHasPointers"
Curfn.Func().SetWBPos(n.Pos()) Curfn.SetWBPos(n.Pos())
} }
var clr ir.Nodes var clr ir.Nodes
@ -3100,7 +3101,7 @@ func walkappend(n ir.Node, init *ir.Nodes, dst ir.Node) ir.Node {
// //
func copyany(n ir.Node, init *ir.Nodes, runtimecall bool) ir.Node { func copyany(n ir.Node, init *ir.Nodes, runtimecall bool) ir.Node {
if n.Left().Type().Elem().HasPointers() { if n.Left().Type().Elem().HasPointers() {
Curfn.Func().SetWBPos(n.Pos()) Curfn.SetWBPos(n.Pos())
fn := writebarrierfn("typedslicecopy", n.Left().Type().Elem(), n.Right().Type().Elem()) fn := writebarrierfn("typedslicecopy", n.Left().Type().Elem(), n.Right().Type().Elem())
n.SetLeft(cheapexpr(n.Left(), init)) n.SetLeft(cheapexpr(n.Left(), init))
ptrL, lenL := backingArrayPtrLen(n.Left()) ptrL, lenL := backingArrayPtrLen(n.Left())
@ -3714,9 +3715,9 @@ func usemethod(n ir.Node) {
// (including global variables such as numImports - was issue #19028). // (including global variables such as numImports - was issue #19028).
// Also need to check for reflect package itself (see Issue #38515). // Also need to check for reflect package itself (see Issue #38515).
if s := res0.Type.Sym; s != nil && s.Name == "Method" && isReflectPkg(s.Pkg) { if s := res0.Type.Sym; s != nil && s.Name == "Method" && isReflectPkg(s.Pkg) {
Curfn.Func().SetReflectMethod(true) Curfn.SetReflectMethod(true)
// The LSym is initialized at this point. We need to set the attribute on the LSym. // The LSym is initialized at this point. We need to set the attribute on the LSym.
Curfn.Func().LSym.Set(obj.AttrReflectMethod, true) Curfn.LSym.Set(obj.AttrReflectMethod, true)
} }
} }
@ -3765,10 +3766,10 @@ func usefield(n ir.Node) {
} }
sym := tracksym(outer, field) sym := tracksym(outer, field)
if Curfn.Func().FieldTrack == nil { if Curfn.FieldTrack == nil {
Curfn.Func().FieldTrack = make(map[*types.Sym]struct{}) Curfn.FieldTrack = make(map[*types.Sym]struct{})
} }
Curfn.Func().FieldTrack[sym] = struct{}{} Curfn.FieldTrack[sym] = struct{}{}
} }
func candiscardlist(l ir.Nodes) bool { func candiscardlist(l ir.Nodes) bool {
@ -3948,12 +3949,12 @@ func wrapCall(n ir.Node, init *ir.Nodes) ir.Node {
funcbody() funcbody()
fn = typecheck(fn, ctxStmt) typecheckFunc(fn)
typecheckslice(fn.Body().Slice(), ctxStmt) typecheckslice(fn.Body().Slice(), ctxStmt)
xtop = append(xtop, fn) xtop = append(xtop, fn)
call = ir.Nod(ir.OCALL, nil, nil) call = ir.Nod(ir.OCALL, nil, nil)
call.SetLeft(fn.Func().Nname) call.SetLeft(fn.Nname)
call.PtrList().Set(n.List().Slice()) call.PtrList().Set(n.List().Slice())
call = typecheck(call, ctxStmt) call = typecheck(call, ctxStmt)
call = walkexpr(call, init) call = walkexpr(call, init)
@ -4091,6 +4092,6 @@ func walkCheckPtrArithmetic(n ir.Node, init *ir.Nodes) ir.Node {
// checkPtr reports whether pointer checking should be enabled for // checkPtr reports whether pointer checking should be enabled for
// function fn at a given level. See debugHelpFooter for defined // function fn at a given level. See debugHelpFooter for defined
// levels. // levels.
func checkPtr(fn ir.Node, level int) bool { func checkPtr(fn *ir.Func, level int) bool {
return base.Debug.Checkptr >= level && fn.Func().Pragma&ir.NoCheckPtr == 0 return base.Debug.Checkptr >= level && fn.Pragma&ir.NoCheckPtr == 0
} }

View file

@ -1338,7 +1338,7 @@ func exprFmt(n Node, s fmt.State, prec int, mode FmtMode) {
mode.Fprintf(s, "%v { %v }", n.Type(), n.Body()) mode.Fprintf(s, "%v { %v }", n.Type(), n.Body())
return return
} }
mode.Fprintf(s, "%v { %v }", n.Type(), n.Func().Decl.Body()) mode.Fprintf(s, "%v { %v }", n.Type(), n.Func().Body())
case OCOMPLIT: case OCOMPLIT:
if mode == FErr { if mode == FErr {
@ -1638,7 +1638,7 @@ func nodeDumpFmt(n Node, s fmt.State, flag FmtFlag, mode FmtMode) {
} }
} }
if n.Op() == OCLOSURE && n.Func().Decl != nil && n.Func().Nname.Sym() != nil { if n.Op() == OCLOSURE && n.Func() != nil && n.Func().Nname.Sym() != nil {
mode.Fprintf(s, " fnName %v", n.Func().Nname.Sym()) mode.Fprintf(s, " fnName %v", n.Func().Nname.Sym())
} }
if n.Sym() != nil && n.Op() != ONAME { if n.Sym() != nil && n.Op() != ONAME {
@ -1656,15 +1656,15 @@ func nodeDumpFmt(n Node, s fmt.State, flag FmtFlag, mode FmtMode) {
if n.Right() != nil { if n.Right() != nil {
mode.Fprintf(s, "%v", n.Right()) mode.Fprintf(s, "%v", n.Right())
} }
if n.Op() == OCLOSURE && n.Func() != nil && n.Func().Decl != nil && n.Func().Decl.Body().Len() != 0 { if n.Op() == OCLOSURE && n.Func() != nil && n.Func().Body().Len() != 0 {
indent(s) indent(s)
// The function associated with a closure // The function associated with a closure
mode.Fprintf(s, "%v-clofunc%v", n.Op(), n.Func().Decl) mode.Fprintf(s, "%v-clofunc%v", n.Op(), n.Func())
} }
if n.Op() == ODCLFUNC && n.Func() != nil && n.Func().Dcl != nil && len(n.Func().Dcl) != 0 { if n.Op() == ODCLFUNC && n.Func() != nil && n.Func().Dcl != nil && len(n.Func().Dcl) != 0 {
indent(s) indent(s)
// The dcls for a func or closure // The dcls for a func or closure
mode.Fprintf(s, "%v-dcl%v", n.Op(), AsNodes(n.Func().Dcl)) mode.Fprintf(s, "%v-dcl%v", n.Op(), asNameNodes(n.Func().Dcl))
} }
if n.List().Len() != 0 { if n.List().Len() != 0 {
indent(s) indent(s)
@ -1683,6 +1683,16 @@ func nodeDumpFmt(n Node, s fmt.State, flag FmtFlag, mode FmtMode) {
} }
} }
// asNameNodes copies list to a new Nodes.
// It should only be called in debug formatting and other low-performance contexts.
func asNameNodes(list []*Name) Nodes {
var ns Nodes
for _, n := range list {
ns.Append(n)
}
return ns
}
// "%S" suppresses qualifying with package // "%S" suppresses qualifying with package
func symFormat(s *types.Sym, f fmt.State, verb rune, mode FmtMode) { func symFormat(s *types.Sym, f fmt.State, verb rune, mode FmtMode) {
switch verb { switch verb {

View file

@ -53,8 +53,7 @@ type Func struct {
body Nodes body Nodes
iota int64 iota int64
Nname Node // ONAME node Nname *Name // ONAME node
Decl Node // ODCLFUNC node
OClosure Node // OCLOSURE node OClosure Node // OCLOSURE node
Shortname *types.Sym Shortname *types.Sym
@ -65,12 +64,11 @@ type Func struct {
Exit Nodes Exit Nodes
// ONAME nodes for all params/locals for this func/closure, does NOT // ONAME nodes for all params/locals for this func/closure, does NOT
// include closurevars until transformclosure runs. // include closurevars until transformclosure runs.
Dcl []Node Dcl []*Name
ClosureEnter Nodes // list of ONAME nodes of captured variables ClosureEnter Nodes // list of ONAME nodes (or OADDR-of-ONAME nodes, for output parameters) of captured variables
ClosureType Node // closure representation type ClosureType Node // closure representation type
ClosureCalled bool // closure is only immediately called ClosureVars []*Name // closure params; each has closurevar set
ClosureVars Nodes // closure params; each has closurevar set
// Parents records the parent scope of each scope within a // Parents records the parent scope of each scope within a
// function. The root scope (0) has no parent, so the i'th // function. The root scope (0) has no parent, so the i'th
@ -80,17 +78,17 @@ type Func struct {
// Marks records scope boundary changes. // Marks records scope boundary changes.
Marks []Mark Marks []Mark
// Closgen tracks how many closures have been generated within
// this function. Used by closurename for creating unique
// function names.
Closgen int
FieldTrack map[*types.Sym]struct{} FieldTrack map[*types.Sym]struct{}
DebugInfo interface{} DebugInfo interface{}
LSym *obj.LSym LSym *obj.LSym
Inl *Inline Inl *Inline
// Closgen tracks how many closures have been generated within
// this function. Used by closurename for creating unique
// function names.
Closgen int32
Label int32 // largest auto-generated label in this function Label int32 // largest auto-generated label in this function
Endlineno src.XPos Endlineno src.XPos
@ -99,8 +97,8 @@ type Func struct {
Pragma PragmaFlag // go:xxx function annotations Pragma PragmaFlag // go:xxx function annotations
flags bitset16 flags bitset16
NumDefers int // number of defer calls in the function NumDefers int32 // number of defer calls in the function
NumReturns int // number of explicit returns in the function NumReturns int32 // number of explicit returns in the function
// nwbrCalls records the LSyms of functions called by this // nwbrCalls records the LSyms of functions called by this
// function for go:nowritebarrierrec analysis. Only filled in // function for go:nowritebarrierrec analysis. Only filled in
@ -112,7 +110,6 @@ func NewFunc(pos src.XPos) *Func {
f := new(Func) f := new(Func)
f.pos = pos f.pos = pos
f.op = ODCLFUNC f.op = ODCLFUNC
f.Decl = f
f.iota = -1 f.iota = -1
return f return f
} }
@ -141,7 +138,7 @@ type Inline struct {
Cost int32 // heuristic cost of inlining this function Cost int32 // heuristic cost of inlining this function
// Copies of Func.Dcl and Nbody for use during inlining. // Copies of Func.Dcl and Nbody for use during inlining.
Dcl []Node Dcl []*Name
Body []Node Body []Node
} }
@ -172,6 +169,7 @@ const (
funcExportInline // include inline body in export data funcExportInline // include inline body in export data
funcInstrumentBody // add race/msan instrumentation during SSA construction funcInstrumentBody // add race/msan instrumentation during SSA construction
funcOpenCodedDeferDisallowed // can't do open-coded defers funcOpenCodedDeferDisallowed // can't do open-coded defers
funcClosureCalled // closure is only immediately called
) )
type SymAndPos struct { type SymAndPos struct {
@ -190,6 +188,7 @@ func (f *Func) InlinabilityChecked() bool { return f.flags&funcInlinability
func (f *Func) ExportInline() bool { return f.flags&funcExportInline != 0 } func (f *Func) ExportInline() bool { return f.flags&funcExportInline != 0 }
func (f *Func) InstrumentBody() bool { return f.flags&funcInstrumentBody != 0 } func (f *Func) InstrumentBody() bool { return f.flags&funcInstrumentBody != 0 }
func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 } func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
func (f *Func) ClosureCalled() bool { return f.flags&funcClosureCalled != 0 }
func (f *Func) SetDupok(b bool) { f.flags.set(funcDupok, b) } func (f *Func) SetDupok(b bool) { f.flags.set(funcDupok, b) }
func (f *Func) SetWrapper(b bool) { f.flags.set(funcWrapper, b) } func (f *Func) SetWrapper(b bool) { f.flags.set(funcWrapper, b) }
@ -202,6 +201,7 @@ func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilit
func (f *Func) SetExportInline(b bool) { f.flags.set(funcExportInline, b) } func (f *Func) SetExportInline(b bool) { f.flags.set(funcExportInline, b) }
func (f *Func) SetInstrumentBody(b bool) { f.flags.set(funcInstrumentBody, b) } func (f *Func) SetInstrumentBody(b bool) { f.flags.set(funcInstrumentBody, b) }
func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) } func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
func (f *Func) SetClosureCalled(b bool) { f.flags.set(funcClosureCalled, b) }
func (f *Func) SetWBPos(pos src.XPos) { func (f *Func) SetWBPos(pos src.XPos) {
if base.Debug.WB != 0 { if base.Debug.WB != 0 {

View file

@ -32,9 +32,10 @@ type Name struct {
// For a local variable (not param) or extern, the initializing assignment (OAS or OAS2). // For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
// For a closure var, the ONAME node of the outer captured variable // For a closure var, the ONAME node of the outer captured variable
Defn Node Defn Node
// The ODCLFUNC node (for a static function/method or a closure) in which
// local variable or param is declared. // The function, method, or closure in which local variable or param is declared.
Curfn Node Curfn *Func
// Unique number for ONAME nodes within a function. Function outputs // Unique number for ONAME nodes within a function. Function outputs
// (results) are numbered starting at one, followed by function inputs // (results) are numbered starting at one, followed by function inputs
// (parameters), and then local variables. Vargen is used to distinguish // (parameters), and then local variables. Vargen is used to distinguish

View file

@ -20,8 +20,8 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms _32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms _64bit uintptr // size on 64bit platforms
}{ }{
{Func{}, 180, 320}, {Func{}, 172, 296},
{Name{}, 132, 232}, {Name{}, 128, 224},
{node{}, 84, 144}, {node{}, 84, 144},
} }