Skip to content

Commit

Permalink
cmd/compile: extract inline related fields into separate Inline type
Browse files Browse the repository at this point in the history
Inl, Inldcl, and InlCost are only applicable to functions with bodies
that can be inlined, so pull them out into a separate Inline type to
make understanding them easier.

A side benefit is that we can check if a function can be inlined by
just checking if n.Func.Inl is non-nil, which simplifies handling of
empty function bodies.

While here, remove some unnecessary Curfn twiddling, and make imported
functions use Inl.Dcl instead of Func.Dcl for consistency for local
functions.

Passes toolstash-check.

Change-Id: Ifd4a80349d85d9e8e4484952b38ec4a63182e81f
Reviewed-on: https://go-review.googlesource.com/104756
Run-TryBot: Matthew Dempsky <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Robert Griesemer <[email protected]>
  • Loading branch information
mdempsky committed Apr 5, 2018
1 parent f2b5f75 commit 562a199
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 64 deletions.
6 changes: 3 additions & 3 deletions src/cmd/compile/internal/gc/bexport.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,11 @@ func export(out *bufio.Writer, trace bool) int {
// function has inlineable body:
// write index and body
if p.trace {
p.tracef("\n----\nfunc { %#v }\n", f.Inl)
p.tracef("\n----\nfunc { %#v }\n", asNodes(f.Inl.Body))
}
p.int(i)
p.int(int(f.InlCost))
p.stmtList(f.Inl)
p.int(int(f.Inl.Cost))
p.stmtList(asNodes(f.Inl.Body))
if p.trace {
p.tracef("\n")
}
Expand Down
22 changes: 8 additions & 14 deletions src/cmd/compile/internal/gc/bimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,28 +188,22 @@ func Import(imp *types.Pkg, in *bufio.Reader) {
// parameter renaming which doesn't matter if we don't have a body.

inlCost := p.int()
if f := p.funcList[i]; f != nil && f.Func.Inl.Len() == 0 {
if f := p.funcList[i]; f != nil && f.Func.Inl == nil {
// function not yet imported - read body and set it
funchdr(f)
body := p.stmtList()
if body == nil {
// Make sure empty body is not interpreted as
// no inlineable body (see also parser.fnbody)
// (not doing so can cause significant performance
// degradation due to unnecessary calls to empty
// functions).
body = []*Node{nod(OEMPTY, nil, nil)}
funcbody()
f.Func.Inl = &Inline{
Cost: int32(inlCost),
Body: body,
}
f.Func.Inl.Set(body)
f.Func.InlCost = int32(inlCost)
if Debug['E'] > 0 && Debug['m'] > 2 && f.Func.Inl.Len() != 0 {
if Debug['E'] > 0 && Debug['m'] > 2 {
if Debug['m'] > 3 {
fmt.Printf("inl body for %v: %+v\n", f, f.Func.Inl)
fmt.Printf("inl body for %v: %+v\n", f, asNodes(body))
} else {
fmt.Printf("inl body for %v: %v\n", f, f.Func.Inl)
fmt.Printf("inl body for %v: %v\n", f, asNodes(body))
}
}
funcbody()
} else {
// function already imported - read body but discard declarations
dclcontext = PDISCARD // throw away any declarations
Expand Down
66 changes: 31 additions & 35 deletions src/cmd/compile/internal/gc/inl.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,24 @@ func typecheckinl(fn *Node) {
}

if Debug['m'] > 2 || Debug_export != 0 {
fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, fn.Func.Inl)
fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, asNodes(fn.Func.Inl.Body))
}

save_safemode := safemode
safemode = false

savefn := Curfn
Curfn = fn
typecheckslice(fn.Func.Inl.Slice(), Etop)
typecheckslice(fn.Func.Inl.Body, Etop)
Curfn = savefn

// During typechecking, declarations are added to
// Curfn.Func.Dcl. Move them to Inl.Dcl for consistency with
// how local functions behave. (Append because typecheckinl
// may be called multiple times.)
fn.Func.Inl.Dcl = append(fn.Func.Inl.Dcl, fn.Func.Dcl...)
fn.Func.Dcl = nil

safemode = save_safemode

lineno = lno
Expand Down Expand Up @@ -155,26 +162,21 @@ func caninl(fn *Node) {
return
}

savefn := Curfn
Curfn = fn

n.Func.Inl.Set(fn.Nbody.Slice())
fn.Nbody.Set(inlcopylist(n.Func.Inl.Slice()))
inldcl := inlcopylist(n.Name.Defn.Func.Dcl)
n.Func.Inldcl.Set(inldcl)
n.Func.InlCost = maxBudget - visitor.budget
n.Func.Inl = &Inline{
Cost: maxBudget - visitor.budget,
Dcl: inlcopylist(n.Name.Defn.Func.Dcl),
Body: inlcopylist(fn.Nbody.Slice()),
}

// hack, TODO, check for better way to link method nodes back to the thing with the ->inl
// this is so export can find the body of a method
fn.Type.FuncType().Nname = asTypesNode(n)

if Debug['m'] > 1 {
fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, n.Func.Inl)
fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, asNodes(n.Func.Inl.Body))
} else if Debug['m'] != 0 {
fmt.Printf("%v: can inline %v\n", fn.Line(), n)
}

Curfn = savefn
}

// inlFlood marks n's inline body for export and recursively ensures
Expand All @@ -189,7 +191,7 @@ func inlFlood(n *Node) {
if n.Func == nil {
Fatalf("inlFlood: missing Func on %v", n)
}
if n.Func.Inl.Len() == 0 {
if n.Func.Inl == nil {
return
}

Expand All @@ -200,7 +202,7 @@ func inlFlood(n *Node) {

typecheckinl(n)

inspectList(n.Func.Inl, func(n *Node) bool {
inspectList(asNodes(n.Func.Inl.Body), func(n *Node) bool {
switch n.Op {
case ONAME:
// Mark any referenced global variables or
Expand Down Expand Up @@ -259,13 +261,13 @@ func (v *hairyVisitor) visit(n *Node) bool {
}
}

if fn := n.Left.Func; fn != nil && fn.Inl.Len() != 0 {
v.budget -= fn.InlCost
if fn := n.Left.Func; fn != nil && fn.Inl != nil {
v.budget -= fn.Inl.Cost
break
}
if n.Left.isMethodExpression() {
if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl.Len() != 0 {
v.budget -= d.Func.InlCost
if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl != nil {
v.budget -= d.Func.Inl.Cost
break
}
}
Expand Down Expand Up @@ -300,8 +302,8 @@ func (v *hairyVisitor) visit(n *Node) bool {
break
}
}
if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl.Len() != 0 {
v.budget -= inlfn.InlCost
if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl != nil {
v.budget -= inlfn.Inl.Cost
break
}
if Debug['l'] < 4 {
Expand Down Expand Up @@ -394,7 +396,7 @@ func inlcopy(n *Node) *Node {

m := n.copy()
if m.Func != nil {
m.Func.Inl.Set(nil)
Fatalf("unexpected Func: %v", m)
}
m.Left = inlcopy(n.Left)
m.Right = inlcopy(n.Right)
Expand Down Expand Up @@ -583,7 +585,7 @@ func inlnode(n *Node) *Node {
if Debug['m'] > 3 {
fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
}
if n.Left.Func != nil && n.Left.Func.Inl.Len() != 0 && !isIntrinsicCall(n) { // normal case
if n.Left.Func != nil && n.Left.Func.Inl != nil && !isIntrinsicCall(n) { // normal case
n = mkinlcall(n, n.Left)
} else if n.Left.isMethodExpression() && asNode(n.Left.Sym.Def) != nil {
n = mkinlcall(n, asNode(n.Left.Sym.Def))
Expand Down Expand Up @@ -647,7 +649,7 @@ func inlinableClosure(n *Node) *Node {
c := n.Func.Closure
caninl(c)
f := c.Func.Nname
if f == nil || f.Func.Inl.Len() == 0 {
if f == nil || f.Func.Inl == nil {
return nil
}
return f
Expand Down Expand Up @@ -772,7 +774,7 @@ var inlgen int
// The result of mkinlcall1 MUST be assigned back to n, e.g.
// n.Left = mkinlcall1(n.Left, fn, isddd)
func mkinlcall1(n, fn *Node) *Node {
if fn.Func.Inl.Len() == 0 {
if fn.Func.Inl == nil {
// No inlinable body.
return n
}
Expand All @@ -798,7 +800,7 @@ func mkinlcall1(n, fn *Node) *Node {

// We have a function node, and it has an inlineable body.
if Debug['m'] > 1 {
fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, fn.Func.Inl)
fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, asNodes(fn.Func.Inl.Body))
} else if Debug['m'] != 0 {
fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
}
Expand All @@ -814,12 +816,8 @@ func mkinlcall1(n, fn *Node) *Node {
// record formals/locals for later post-processing
var inlfvars []*Node

// Find declarations corresponding to inlineable body.
var dcl []*Node
// Handle captured variables when inlining closures.
if fn.Name.Defn != nil {
dcl = fn.Func.Inldcl.Slice() // local function

// handle captured variables when inlining closures
if c := fn.Name.Defn.Func.Closure; c != nil {
for _, v := range c.Func.Closure.Func.Cvars.Slice() {
if v.Op == OXXX {
Expand Down Expand Up @@ -854,11 +852,9 @@ func mkinlcall1(n, fn *Node) *Node {
}
}
}
} else {
dcl = fn.Func.Dcl // imported function
}

for _, ln := range dcl {
for _, ln := range fn.Func.Inl.Dcl {
if ln.Op != ONAME {
continue
}
Expand Down Expand Up @@ -1020,7 +1016,7 @@ func mkinlcall1(n, fn *Node) *Node {
newInlIndex: newIndex,
}

body := subst.list(fn.Func.Inl)
body := subst.list(asNodes(fn.Func.Inl.Body))

lab := nod(OLABEL, retlabel, nil)
body = append(body, lab)
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/gc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ func Main(archInit func(*Arch)) {
// Typecheck imported function bodies if debug['l'] > 1,
// otherwise lazily when used or re-exported.
for _, n := range importlist {
if n.Func.Inl.Len() != 0 {
if n.Func.Inl != nil {
saveerrors()
typecheckinl(n)
}
Expand Down
9 changes: 2 additions & 7 deletions src/cmd/compile/internal/gc/pgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,13 +570,8 @@ func createDwarfVars(fnsym *obj.LSym, fn *Func, automDecls []*Node) ([]*Node, []
// with local vars; disregard this versioning when sorting.
func preInliningDcls(fnsym *obj.LSym) []*Node {
fn := Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*Node)
var dcl, rdcl []*Node
if fn.Name.Defn != nil {
dcl = fn.Func.Inldcl.Slice() // local function
} else {
dcl = fn.Func.Dcl // imported function
}
for _, n := range dcl {
var rdcl []*Node
for _, n := range fn.Func.Inl.Dcl {
c := n.Sym.Name[0]
// Avoid reporting "_" parameters, since if there are more than
// one, it can result in a collision later on, as in #23179.
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/gc/sizeof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
{Func{}, 124, 224},
{Func{}, 116, 208},
{Name{}, 32, 56},
{Param{}, 24, 48},
{Node{}, 76, 128},
Expand Down
18 changes: 15 additions & 3 deletions src/cmd/compile/internal/gc/syntax.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,6 @@ type Func struct {
Exit Nodes
Cvars Nodes // closure params
Dcl []*Node // autodcl for this func/closure
Inldcl Nodes // copy of dcl for use in inlining

// Parents records the parent scope of each scope within a
// function. The root scope (0) has no parent, so the i'th
Expand All @@ -484,8 +483,7 @@ type Func struct {
Nname *Node
lsym *obj.LSym

Inl Nodes // copy of the body for use in inlining
InlCost int32
Inl *Inline

Label int32 // largest auto-generated label in this function

Expand All @@ -502,6 +500,15 @@ type Func struct {
nwbrCalls *[]nowritebarrierrecCallSym
}

// An Inline holds fields used for function bodies that can be inlined.
type Inline struct {
Cost int32 // heuristic cost of inlining this function

// Copies of Func.Dcl and Nbody for use during inlining.
Dcl []*Node
Body []*Node
}

// A Mark represents a scope boundary.
type Mark struct {
// Pos is the position of the token that marks the scope
Expand Down Expand Up @@ -737,6 +744,11 @@ const (
// a slice to save space.
type Nodes struct{ slice *[]*Node }

// asNodes returns a slice of *Node as a Nodes value.
func asNodes(s []*Node) Nodes {
return Nodes{&s}
}

// Slice returns the entries in Nodes as a slice.
// Changes to the slice entries (as in s[i] = n) will be reflected in
// the Nodes.
Expand Down

0 comments on commit 562a199

Please sign in to comment.