go/src/cmd/compile/internal/ir/func.go

433 lines
16 KiB
Go
Raw Normal View History

// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ir
import (
"cmd/compile/internal/base"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src"
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
"fmt"
)
// A Func corresponds to a single function in a Go program
// (and vice versa: each function is denoted by exactly one *Func).
//
// There are multiple nodes that represent a Func in the IR.
//
// The ONAME node (Func.Nname) is used for plain references to it.
// The ODCLFUNC node (the Func itself) is used for its declaration code.
// The OCLOSURE node (Func.OClosure) is used for a reference to a
// function literal.
//
// An imported function will have an ONAME node which points to a Func
// with an empty body.
// A declared function or method has an ODCLFUNC (the Func itself) and an ONAME.
// A function literal is represented directly by an OCLOSURE, but it also
// has an ODCLFUNC (and a matching ONAME) representing the compiled
// underlying form of the closure, which accesses the captured variables
// using a special data structure passed in a register.
//
// A method declaration is represented like functions, except f.Sym
// will be the qualified method name (e.g., "T.m").
//
// A method expression (T.M) is represented as an OMETHEXPR node,
// in which n.Left and n.Right point to the type and method, respectively.
// Each distinct mention of a method expression in the source code
// constructs a fresh node.
//
// A method value (t.M) is represented by ODOTMETH/ODOTINTER
// when it is called directly and by OMETHVALUE otherwise.
// These are like method expressions, except that for ODOTMETH/ODOTINTER,
// the method name is stored in Sym instead of Right.
// Each OMETHVALUE ends up being implemented as a new
// function, a bit like a closure, with its own ODCLFUNC.
// The OMETHVALUE uses n.Func to record the linkage to
// the generated ODCLFUNC, but there is no
// pointer from the Func back to the OMETHVALUE.
type Func struct {
miniNode
[dev.regabi] cmd/compile: remove Left, Right etc methods [generated] Now that the generic graph structure methods - Left, Right, and so on - have been removed from the Node interface, each implementation's uses can be replaced with direct field access, using more specific names, and the methods themselves can be deleted. Passes buildall w/ toolstash -cmp. [git-generate] cd src/cmd/compile/internal/ir rf ' mv Func.iota Func.Iota_ mv Name.fn Name.Func_ ' cd ../gc rf ' ex . ../ir { import "cmd/compile/internal/ir" import "cmd/compile/internal/types" var ns ir.Nodes var b bool var i64 int64 var n ir.Node var op ir.Op var sym *types.Sym var class ir.Class var decl *ir.Decl decl.Left() -> decl.X decl.SetLeft(n) -> decl.X = n var asl *ir.AssignListStmt asl.List() -> asl.Lhs asl.PtrList() -> &asl.Lhs asl.SetList(ns) -> asl.Lhs = ns asl.Rlist() -> asl.Rhs asl.PtrRlist() -> &asl.Rhs asl.SetRlist(ns) -> asl.Rhs = ns asl.Colas() -> asl.Def asl.SetColas(b) -> asl.Def = b var as *ir.AssignStmt as.Left() -> as.X as.SetLeft(n) -> as.X = n as.Right() -> as.Y as.SetRight(n) -> as.Y = n as.Colas() -> as.Def as.SetColas(b) -> as.Def = b var ao *ir.AssignOpStmt ao.Left() -> ao.X ao.SetLeft(n) -> ao.X = n ao.Right() -> ao.Y ao.SetRight(n) -> ao.Y = n ao.SubOp() -> ao.AsOp ao.SetSubOp(op) -> ao.AsOp = op ao.Implicit() -> ao.IncDec ao.SetImplicit(b) -> ao.IncDec = b var bl *ir.BlockStmt bl.List() -> bl.List_ bl.PtrList() -> &bl.List_ bl.SetList(ns) -> bl.List_ = ns var br *ir.BranchStmt br.Sym() -> br.Label br.SetSym(sym) -> br.Label = sym var cas *ir.CaseStmt cas.List() -> cas.List_ cas.PtrList() -> &cas.List_ cas.SetList(ns) -> cas.List_ = ns cas.Body() -> cas.Body_ cas.PtrBody() -> &cas.Body_ cas.SetBody(ns) -> cas.Body_ = ns cas.Rlist() -> cas.Vars cas.PtrRlist() -> &cas.Vars cas.SetRlist(ns) -> cas.Vars = ns cas.Left() -> cas.Comm cas.SetLeft(n) -> cas.Comm = n var fr *ir.ForStmt fr.Sym() -> fr.Label fr.SetSym(sym) -> fr.Label = sym fr.Left() -> fr.Cond fr.SetLeft(n) -> fr.Cond = n fr.Right() -> fr.Post fr.SetRight(n) -> fr.Post = n fr.Body() -> fr.Body_ fr.PtrBody() -> &fr.Body_ fr.SetBody(ns) -> fr.Body_ = ns fr.List() -> fr.Late fr.PtrList() -> &fr.Late fr.SetList(ns) -> fr.Late = ns fr.HasBreak() -> fr.HasBreak_ fr.SetHasBreak(b) -> fr.HasBreak_ = b var gs *ir.GoDeferStmt gs.Left() -> gs.Call gs.SetLeft(n) -> gs.Call = n var ifs *ir.IfStmt ifs.Left() -> ifs.Cond ifs.SetLeft(n) -> ifs.Cond = n ifs.Body() -> ifs.Body_ ifs.PtrBody() -> &ifs.Body_ ifs.SetBody(ns) -> ifs.Body_ = ns ifs.Rlist() -> ifs.Else ifs.PtrRlist() -> &ifs.Else ifs.SetRlist(ns) -> ifs.Else = ns ifs.Likely() -> ifs.Likely_ ifs.SetLikely(b) -> ifs.Likely_ = b var im *ir.InlineMarkStmt im.Offset() -> im.Index im.SetOffset(i64) -> im.Index = i64 var lab *ir.LabelStmt lab.Sym() -> lab.Label lab.SetSym(sym) -> lab.Label = sym var rng *ir.RangeStmt rng.Sym() -> rng.Label rng.SetSym(sym) -> rng.Label = sym rng.Right() -> rng.X rng.SetRight(n) -> rng.X = n rng.Body() -> rng.Body_ rng.PtrBody() -> &rng.Body_ rng.SetBody(ns) -> rng.Body_ = ns rng.List() -> rng.Vars rng.PtrList() -> &rng.Vars rng.SetList(ns) -> rng.Vars = ns rng.HasBreak() -> rng.HasBreak_ rng.SetHasBreak(b) -> rng.HasBreak_ = b rng.Colas() -> rng.Def rng.SetColas(b) -> rng.Def = b var ret *ir.ReturnStmt ret.List() -> ret.Results ret.PtrList() -> &ret.Results ret.SetList(ns) -> ret.Results = ns var sel *ir.SelectStmt sel.List() -> sel.Cases sel.PtrList() -> &sel.Cases sel.SetList(ns) -> sel.Cases = ns sel.Sym() -> sel.Label sel.SetSym(sym) -> sel.Label = sym sel.HasBreak() -> sel.HasBreak_ sel.SetHasBreak(b) -> sel.HasBreak_ = b sel.Body() -> sel.Compiled sel.PtrBody() -> &sel.Compiled sel.SetBody(ns) -> sel.Compiled = ns var send *ir.SendStmt send.Left() -> send.Chan send.SetLeft(n) -> send.Chan = n send.Right() -> send.Value send.SetRight(n) -> send.Value = n var sw *ir.SwitchStmt sw.Left() -> sw.Tag sw.SetLeft(n) -> sw.Tag = n sw.List() -> sw.Cases sw.PtrList() -> &sw.Cases sw.SetList(ns) -> sw.Cases = ns sw.Body() -> sw.Compiled sw.PtrBody() -> &sw.Compiled sw.SetBody(ns) -> sw.Compiled = ns sw.Sym() -> sw.Label sw.SetSym(sym) -> sw.Label = sym sw.HasBreak() -> sw.HasBreak_ sw.SetHasBreak(b) -> sw.HasBreak_ = b var tg *ir.TypeSwitchGuard tg.Left() -> tg.Tag tg.SetLeft(nil) -> tg.Tag = nil tg.SetLeft(n) -> tg.Tag = n.(*ir.Ident) tg.Right() -> tg.X tg.SetRight(n) -> tg.X = n var adds *ir.AddStringExpr adds.List() -> adds.List_ adds.PtrList() -> &adds.List_ adds.SetList(ns) -> adds.List_ = ns var addr *ir.AddrExpr addr.Left() -> addr.X addr.SetLeft(n) -> addr.X = n addr.Right() -> addr.Alloc addr.SetRight(n) -> addr.Alloc = n var bin *ir.BinaryExpr bin.Left() -> bin.X bin.SetLeft(n) -> bin.X = n bin.Right() -> bin.Y bin.SetRight(n) -> bin.Y = n var log *ir.LogicalExpr log.Left() -> log.X log.SetLeft(n) -> log.X = n log.Right() -> log.Y log.SetRight(n) -> log.Y = n var call *ir.CallExpr call.Left() -> call.X call.SetLeft(n) -> call.X = n call.List() -> call.Args call.PtrList() -> &call.Args call.SetList(ns) -> call.Args = ns call.Rlist() -> call.Rargs call.PtrRlist() -> &call.Rargs call.SetRlist(ns) -> call.Rargs = ns call.IsDDD() -> call.DDD call.SetIsDDD(b) -> call.DDD = b call.NoInline() -> call.NoInline_ call.SetNoInline(b) -> call.NoInline_ = b call.Body() -> call.Body_ call.PtrBody() -> &call.Body_ call.SetBody(ns) -> call.Body_ = ns var cp *ir.CallPartExpr cp.Func() -> cp.Func_ cp.Left() -> cp.X cp.SetLeft(n) -> cp.X = n cp.Sym() -> cp.Method.Sym var clo *ir.ClosureExpr clo.Func() -> clo.Func_ var cr *ir.ClosureReadExpr cr.Offset() -> cr.Offset_ var cl *ir.CompLitExpr cl.Right() -> cl.Ntype cl.SetRight(nil) -> cl.Ntype = nil cl.SetRight(n) -> cl.Ntype = ir.Node(n).(ir.Ntype) cl.List() -> cl.List_ cl.PtrList() -> &cl.List_ cl.SetList(ns) -> cl.List_ = ns var conv *ir.ConvExpr conv.Left() -> conv.X conv.SetLeft(n) -> conv.X = n var ix *ir.IndexExpr ix.Left() -> ix.X ix.SetLeft(n) -> ix.X = n ix.Right() -> ix.Index ix.SetRight(n) -> ix.Index = n ix.IndexMapLValue() -> ix.Assigned ix.SetIndexMapLValue(b) -> ix.Assigned = b var kv *ir.KeyExpr kv.Left() -> kv.Key kv.SetLeft(n) -> kv.Key = n kv.Right() -> kv.Value kv.SetRight(n) -> kv.Value = n var sk *ir.StructKeyExpr sk.Sym() -> sk.Field sk.SetSym(sym) -> sk.Field = sym sk.Left() -> sk.Value sk.SetLeft(n) -> sk.Value = n sk.Offset() -> sk.Offset_ sk.SetOffset(i64) -> sk.Offset_ = i64 var ic *ir.InlinedCallExpr ic.Body() -> ic.Body_ ic.PtrBody() -> &ic.Body_ ic.SetBody(ns) -> ic.Body_ = ns ic.Rlist() -> ic.ReturnVars ic.PtrRlist() -> &ic.ReturnVars ic.SetRlist(ns) -> ic.ReturnVars = ns var mak *ir.MakeExpr mak.Left() -> mak.Len mak.SetLeft(n) -> mak.Len = n mak.Right() -> mak.Cap mak.SetRight(n) -> mak.Cap = n var par *ir.ParenExpr par.Left() -> par.X par.SetLeft(n) -> par.X = n var res *ir.ResultExpr res.Offset() -> res.Offset_ res.SetOffset(i64) -> res.Offset_ = i64 var dot *ir.SelectorExpr dot.Left() -> dot.X dot.SetLeft(n) -> dot.X = n dot.Sym() -> dot.Sel dot.SetSym(sym) -> dot.Sel = sym dot.Offset() -> dot.Offset_ dot.SetOffset(i64) -> dot.Offset_ = i64 var sl *ir.SliceExpr sl.Left() -> sl.X sl.SetLeft(n) -> sl.X = n sl.List() -> sl.List_ sl.PtrList() -> &sl.List_ sl.SetList(ns) -> sl.List_ = ns var sh *ir.SliceHeaderExpr sh.Left() -> sh.Ptr sh.SetLeft(n) -> sh.Ptr = n sh.List() -> sh.LenCap_ sh.PtrList() -> &sh.LenCap_ sh.SetList(ns) -> sh.LenCap_ = ns var st *ir.StarExpr st.Left() -> st.X st.SetLeft(n) -> st.X = n var ta *ir.TypeAssertExpr ta.Left() -> ta.X ta.SetLeft(n) -> ta.X = n ta.Right() -> ta.Ntype ta.SetRight(n) -> ta.Ntype = n ta.List() -> ta.Itab ta.PtrList() -> &ta.Itab ta.SetList(ns) -> ta.Itab = ns var u *ir.UnaryExpr u.Left() -> u.X u.SetLeft(n) -> u.X = n var fn *ir.Func fn.Body() -> fn.Body_ fn.PtrBody() -> &fn.Body_ fn.SetBody(ns) -> fn.Body_ = ns fn.Iota() -> fn.Iota_ fn.SetIota(i64) -> fn.Iota_ = i64 fn.Func() -> fn var nam *ir.Name nam.SubOp() -> nam.BuiltinOp nam.SetSubOp(op) -> nam.BuiltinOp = op nam.Class() -> nam.Class_ nam.SetClass(class) -> nam.Class_ = class nam.Func() -> nam.Func_ nam.Offset() -> nam.Offset_ nam.SetOffset(i64) -> nam.Offset_ = i64 } ex . ../ir { import "cmd/compile/internal/ir" var n ir.Nodes (&n).Append -> n.Append (&n).AppendNodes -> n.AppendNodes (&n).MoveNodes -> n.MoveNodes (&n).Prepend -> n.Prepend (&n).Set -> n.Set (&n).Set1 -> n.Set1 (&n).Set2 -> n.Set2 (&n).Set3 -> n.Set3 var ntype ir.Ntype ir.Node(ntype).(ir.Ntype) -> ntype } ' cd ../ir rf ' rm \ Decl.Left Decl.SetLeft \ AssignListStmt.List AssignListStmt.PtrList AssignListStmt.SetList \ AssignListStmt.Rlist AssignListStmt.PtrRlist AssignListStmt.SetRlist \ AssignListStmt.Colas AssignListStmt.SetColas \ AssignStmt.Left AssignStmt.SetLeft \ AssignStmt.Right AssignStmt.SetRight \ AssignStmt.Colas AssignStmt.SetColas \ AssignOpStmt.Left AssignOpStmt.SetLeft \ AssignOpStmt.Right AssignOpStmt.SetRight \ AssignOpStmt.SubOp AssignOpStmt.SetSubOp \ AssignOpStmt.Implicit AssignOpStmt.SetImplicit \ BlockStmt.List BlockStmt.PtrList BlockStmt.SetList \ BranchStmt.SetSym \ CaseStmt.List CaseStmt.PtrList CaseStmt.SetList \ CaseStmt.Body CaseStmt.PtrBody CaseStmt.SetBody \ CaseStmt.Rlist CaseStmt.PtrRlist CaseStmt.SetRlist \ CaseStmt.Left CaseStmt.SetLeft \ ForStmt.Left ForStmt.SetLeft \ ForStmt.Right ForStmt.SetRight \ ForStmt.Body ForStmt.PtrBody ForStmt.SetBody \ ForStmt.List ForStmt.PtrList ForStmt.SetList \ ForStmt.HasBreak ForStmt.SetHasBreak \ ForStmt.Sym ForStmt.SetSym \ GoDeferStmt.Left GoDeferStmt.SetLeft \ IfStmt.Left IfStmt.SetLeft \ IfStmt.Body IfStmt.PtrBody IfStmt.SetBody \ IfStmt.Rlist IfStmt.PtrRlist IfStmt.SetRlist \ IfStmt.Likely IfStmt.SetLikely \ LabelStmt.SetSym \ RangeStmt.Right RangeStmt.SetRight \ RangeStmt.Body RangeStmt.PtrBody RangeStmt.SetBody \ RangeStmt.List RangeStmt.PtrList RangeStmt.SetList \ RangeStmt.HasBreak RangeStmt.SetHasBreak \ RangeStmt.Colas RangeStmt.SetColas \ RangeStmt.Sym RangeStmt.SetSym \ ReturnStmt.List ReturnStmt.PtrList ReturnStmt.SetList \ SelectStmt.List SelectStmt.PtrList SelectStmt.SetList \ SelectStmt.HasBreak SelectStmt.SetHasBreak \ SelectStmt.Body SelectStmt.PtrBody SelectStmt.SetBody \ SelectStmt.Sym SelectStmt.SetSym \ SendStmt.Left SendStmt.SetLeft \ SendStmt.Right SendStmt.SetRight \ SwitchStmt.Left SwitchStmt.SetLeft \ SwitchStmt.List SwitchStmt.PtrList SwitchStmt.SetList \ SwitchStmt.Body SwitchStmt.PtrBody SwitchStmt.SetBody \ SwitchStmt.HasBreak SwitchStmt.SetHasBreak \ SwitchStmt.Sym SwitchStmt.SetSym \ TypeSwitchGuard.Left TypeSwitchGuard.SetLeft \ TypeSwitchGuard.Right TypeSwitchGuard.SetRight \ AddStringExpr.List AddStringExpr.PtrList AddStringExpr.SetList \ AddrExpr.Left AddrExpr.SetLeft \ AddrExpr.Right AddrExpr.SetRight \ BinaryExpr.Left BinaryExpr.SetLeft \ BinaryExpr.Right BinaryExpr.SetRight \ LogicalExpr.Left LogicalExpr.SetLeft \ LogicalExpr.Right LogicalExpr.SetRight \ CallExpr.Left CallExpr.SetLeft \ CallExpr.List CallExpr.PtrList CallExpr.SetList \ CallExpr.Rlist CallExpr.PtrRlist CallExpr.SetRlist \ CallExpr.NoInline CallExpr.SetNoInline \ CallExpr.Body CallExpr.PtrBody CallExpr.SetBody \ CallExpr.IsDDD CallExpr.SetIsDDD \ CallPartExpr.Left CallPartExpr.SetLeft \ ClosureReadExpr.Offset \ ClosureReadExpr.Type \ # provided by miniExpr already CompLitExpr.Right CompLitExpr.SetRight \ CompLitExpr.List CompLitExpr.PtrList CompLitExpr.SetList \ ConvExpr.Left ConvExpr.SetLeft \ IndexExpr.Left IndexExpr.SetLeft \ IndexExpr.Right IndexExpr.SetRight \ IndexExpr.IndexMapLValue IndexExpr.SetIndexMapLValue \ KeyExpr.Left KeyExpr.SetLeft \ KeyExpr.Right KeyExpr.SetRight \ StructKeyExpr.Left StructKeyExpr.SetLeft \ StructKeyExpr.Offset StructKeyExpr.SetOffset \ StructKeyExpr.SetSym \ InlinedCallExpr.Body InlinedCallExpr.PtrBody InlinedCallExpr.SetBody \ InlinedCallExpr.Rlist InlinedCallExpr.PtrRlist InlinedCallExpr.SetRlist \ MakeExpr.Left MakeExpr.SetLeft \ MakeExpr.Right MakeExpr.SetRight \ MethodExpr.Left MethodExpr.SetLeft \ MethodExpr.Right MethodExpr.SetRight \ MethodExpr.Offset MethodExpr.SetOffset \ MethodExpr.Class MethodExpr.SetClass \ ParenExpr.Left ParenExpr.SetLeft \ ResultExpr.Offset ResultExpr.SetOffset \ ReturnStmt.IsDDD \ SelectorExpr.Left SelectorExpr.SetLeft \ SelectorExpr.Offset SelectorExpr.SetOffset \ SelectorExpr.SetSym \ SliceExpr.Left SliceExpr.SetLeft \ SliceExpr.List SliceExpr.PtrList SliceExpr.SetList \ SliceHeaderExpr.Left SliceHeaderExpr.SetLeft \ SliceHeaderExpr.List SliceHeaderExpr.PtrList SliceHeaderExpr.SetList \ StarExpr.Left StarExpr.SetLeft \ TypeAssertExpr.Left TypeAssertExpr.SetLeft \ TypeAssertExpr.Right TypeAssertExpr.SetRight \ TypeAssertExpr.List TypeAssertExpr.PtrList TypeAssertExpr.SetList \ UnaryExpr.Left UnaryExpr.SetLeft \ Func.Body Func.PtrBody Func.SetBody \ Func.Iota Func.SetIota \ CallPartExpr.Func ClosureExpr.Func Func.Func Name.Func \ mv BlockStmt.List_ BlockStmt.List mv CaseStmt.List_ CaseStmt.List mv CaseStmt.Body_ CaseStmt.Body mv ForStmt.Body_ ForStmt.Body mv ForStmt.HasBreak_ ForStmt.HasBreak mv Func.Iota_ Func.Iota mv IfStmt.Body_ IfStmt.Body mv IfStmt.Likely_ IfStmt.Likely mv RangeStmt.Body_ RangeStmt.Body mv RangeStmt.HasBreak_ RangeStmt.HasBreak mv SelectStmt.HasBreak_ SelectStmt.HasBreak mv SwitchStmt.HasBreak_ SwitchStmt.HasBreak mv AddStringExpr.List_ AddStringExpr.List mv CallExpr.NoInline_ CallExpr.NoInline mv CallExpr.Body_ CallExpr.Body # TODO what is this? mv CallExpr.DDD CallExpr.IsDDD mv ClosureReadExpr.Offset_ ClosureReadExpr.Offset mv CompLitExpr.List_ CompLitExpr.List mv StructKeyExpr.Offset_ StructKeyExpr.Offset mv InlinedCallExpr.Body_ InlinedCallExpr.Body mv ResultExpr.Offset_ ResultExpr.Offset mv SelectorExpr.Offset_ SelectorExpr.Offset mv SliceExpr.List_ SliceExpr.List mv SliceHeaderExpr.LenCap_ SliceHeaderExpr.LenCap mv Func.Body_ Func.Body mv CallPartExpr.Func_ CallPartExpr.Func mv ClosureExpr.Func_ ClosureExpr.Func mv Name.Func_ Name.Func ' Change-Id: Ia2ee59649674f83eb123e63fda7a7781cf91cc56 Reviewed-on: https://go-review.googlesource.com/c/go/+/277935 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>
2020-12-23 00:02:08 -05:00
Body Nodes
Nname *Name // ONAME node
OClosure *ClosureExpr // OCLOSURE node
// Extra entry code for the function. For example, allocate and initialize
// memory for escaping parameters.
Enter Nodes
Exit Nodes
// ONAME nodes for all params/locals for this func/closure, does NOT
// include closurevars until transforming closures during walk.
// Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs,
// with PPARAMs and PPARAMOUTs in order corresponding to the function signature.
// However, as anonymous or blank PPARAMs are not actually declared,
// they are omitted from Dcl.
// Anonymous and blank PPARAMOUTs are declared as ~rNN and ~bNN Names, respectively.
Dcl []*Name
// ClosureVars lists the free variables that are used within a
// function literal, but formally declared in an enclosing
// function. The variables in this slice are the closure function's
// own copy of the variables, which are used within its function
// body. They will also each have IsClosureVar set, and will have
// Byval set if they're captured by value.
ClosureVars []*Name
// Enclosed functions that need to be compiled.
// Populated during walk.
Closures []*Func
// Parents records the parent scope of each scope within a
// function. The root scope (0) has no parent, so the i'th
// scope's parent is stored at Parents[i-1].
Parents []ScopeID
// Marks records scope boundary changes.
Marks []Mark
FieldTrack map[*obj.LSym]struct{}
DebugInfo interface{}
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
LSym *obj.LSym // Linker object in this function's native ABI (Func.ABI)
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
Endlineno src.XPos
WBPos src.XPos // position of first write barrier; see SetWBPos
Pragma PragmaFlag // go:xxx function annotations
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
flags bitset16
// ABI is a function's "definition" ABI. This is the ABI that
// this function's generated code is expecting to be called by.
//
// For most functions, this will be obj.ABIInternal. It may be
// a different ABI for functions defined in assembly or ABI wrappers.
//
// This is included in the export data and tracked across packages.
ABI obj.ABI
// ABIRefs is the set of ABIs by which this function is referenced.
// For ABIs other than this function's definition ABI, the
// compiler generates ABI wrapper functions. This is only tracked
// within a package.
ABIRefs obj.ABISet
NumDefers int32 // number of defer calls in the function
NumReturns int32 // number of explicit returns in the function
// nwbrCalls records the LSyms of functions called by this
// function for go:nowritebarrierrec analysis. Only filled in
// if nowritebarrierrecCheck != nil.
NWBRCalls *[]SymAndPos
// For wrapper functions, WrappedFunc point to the original Func.
// Currently only used for go/defer wrappers.
WrappedFunc *Func
}
func NewFunc(pos src.XPos) *Func {
f := new(Func)
f.pos = pos
f.op = ODCLFUNC
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
// Most functions are ABIInternal. The importer or symabis
// pass may override this.
f.ABI = obj.ABIInternal
return f
}
func (f *Func) isStmt() {}
func (n *Func) copy() Node { panic(n.no("copy")) }
func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
func (n *Func) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) }
func (f *Func) Type() *types.Type { return f.Nname.Type() }
func (f *Func) Sym() *types.Sym { return f.Nname.Sym() }
func (f *Func) Linksym() *obj.LSym { return f.Nname.Linksym() }
func (f *Func) LinksymABI(abi obj.ABI) *obj.LSym { return f.Nname.LinksymABI(abi) }
// 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 Func.Body for use during inlining. Copies are
// needed because the function's dcl/body may be changed by later compiler
// transformations. These fields are also populated when a function from
// another package is imported.
Dcl []*Name
Body []Node
// CanDelayResults reports whether it's safe for the inliner to delay
// initializing the result parameters until immediately before the
// "return" statement.
CanDelayResults bool
}
// A Mark represents a scope boundary.
type Mark struct {
// Pos is the position of the token that marks the scope
// change.
Pos src.XPos
// Scope identifies the innermost scope to the right of Pos.
Scope ScopeID
}
// A ScopeID represents a lexical scope within a function.
type ScopeID int32
const (
funcDupok = 1 << iota // duplicate definitions ok
funcWrapper // hide frame from users (elide in tracebacks, don't count as a frame for recover())
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
funcABIWrapper // is an ABI wrapper (also set flagWrapper)
funcNeedctxt // function uses context register (has closure variables)
funcReflectMethod // function calls reflect.Type.Method or MethodByName
// true if closure inside a function; false if a simple function or a
// closure in a global variable initialization
funcIsHiddenClosure
funcIsDeadcodeClosure // true if closure is deadcode
funcHasDefer // contains a defer statement
funcNilCheckDisabled // disable nil checks when compiling this function
funcInlinabilityChecked // inliner has already determined whether the function is inlinable
funcExportInline // include inline body in export data
funcInstrumentBody // add race/msan/asan instrumentation during SSA construction
funcOpenCodedDeferDisallowed // can't do open-coded defers
funcClosureCalled // closure is only immediately called; used by escape analysis
funcPackageInit // compiler emitted .init func for package
)
type SymAndPos struct {
Sym *obj.LSym // LSym of callee
Pos src.XPos // line of call
}
func (f *Func) Dupok() bool { return f.flags&funcDupok != 0 }
func (f *Func) Wrapper() bool { return f.flags&funcWrapper != 0 }
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
func (f *Func) ABIWrapper() bool { return f.flags&funcABIWrapper != 0 }
func (f *Func) Needctxt() bool { return f.flags&funcNeedctxt != 0 }
func (f *Func) ReflectMethod() bool { return f.flags&funcReflectMethod != 0 }
func (f *Func) IsHiddenClosure() bool { return f.flags&funcIsHiddenClosure != 0 }
func (f *Func) IsDeadcodeClosure() bool { return f.flags&funcIsDeadcodeClosure != 0 }
func (f *Func) HasDefer() bool { return f.flags&funcHasDefer != 0 }
func (f *Func) NilCheckDisabled() bool { return f.flags&funcNilCheckDisabled != 0 }
func (f *Func) InlinabilityChecked() bool { return f.flags&funcInlinabilityChecked != 0 }
func (f *Func) ExportInline() bool { return f.flags&funcExportInline != 0 }
func (f *Func) InstrumentBody() bool { return f.flags&funcInstrumentBody != 0 }
func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
func (f *Func) ClosureCalled() bool { return f.flags&funcClosureCalled != 0 }
func (f *Func) IsPackageInit() bool { return f.flags&funcPackageInit != 0 }
func (f *Func) SetDupok(b bool) { f.flags.set(funcDupok, b) }
func (f *Func) SetWrapper(b bool) { f.flags.set(funcWrapper, b) }
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
func (f *Func) SetABIWrapper(b bool) { f.flags.set(funcABIWrapper, b) }
func (f *Func) SetNeedctxt(b bool) { f.flags.set(funcNeedctxt, b) }
func (f *Func) SetReflectMethod(b bool) { f.flags.set(funcReflectMethod, b) }
func (f *Func) SetIsHiddenClosure(b bool) { f.flags.set(funcIsHiddenClosure, b) }
func (f *Func) SetIsDeadcodeClosure(b bool) { f.flags.set(funcIsDeadcodeClosure, b) }
func (f *Func) SetHasDefer(b bool) { f.flags.set(funcHasDefer, b) }
func (f *Func) SetNilCheckDisabled(b bool) { f.flags.set(funcNilCheckDisabled, b) }
func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilityChecked, 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) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
func (f *Func) SetClosureCalled(b bool) { f.flags.set(funcClosureCalled, b) }
func (f *Func) SetIsPackageInit(b bool) { f.flags.set(funcPackageInit, b) }
func (f *Func) SetWBPos(pos src.XPos) {
if base.Debug.WB != 0 {
base.WarnfAt(pos, "write barrier")
}
if !f.WBPos.IsKnown() {
f.WBPos = pos
}
}
// FuncName returns the name (without the package) of the function n.
func FuncName(f *Func) string {
if f == nil || f.Nname == nil {
return "<nil>"
}
return f.Sym().Name
}
// PkgFuncName returns the name of the function referenced by n, with package prepended.
// This differs from the compiler's internal convention where local functions lack a package
// because the ultimate consumer of this is a human looking at an IDE; package is only empty
// if the compilation package is actually the empty string.
func PkgFuncName(f *Func) string {
if f == nil || f.Nname == nil {
return "<nil>"
}
s := f.Sym()
pkg := s.Pkg
return pkg.Path + "." + s.Name
}
[dev.regabi] cmd/compile: move helpers into package ir [generated] [git-generate] cd src/cmd/compile/internal/gc sed -i '' 's/TestBuiltin.*/& t.Skip("mkbuiltin needs fixing")/' builtin_test.go gofmt -w builtin_test.go rf ' # Inline a few little-used constructors to avoid bringing them. ex { import "cmd/compile/internal/base" import "cmd/compile/internal/ir" import "cmd/compile/internal/types" import "cmd/internal/src" var typ *types.Type var sym *types.Sym var str string symfield(sym, typ) -> ir.NewField(base.Pos, sym, nil, typ) anonfield(typ) -> ir.NewField(base.Pos, nil, nil, typ) namedfield(str, typ) -> ir.NewField(base.Pos, lookup(str), nil, typ) var cp *ir.CallPartExpr callpartMethod(cp) -> cp.Method var n ir.Node callpartMethod(n) -> n.(*ir.CallPartExpr).Method var ns []ir.Node liststmt(ns) -> ir.NewBlockStmt(src.NoXPos, ns) } rm symfield anonfield namedfield liststmt callpartMethod mv maxStackVarSize MaxStackVarSize mv maxImplicitStackVarSize MaxImplicitStackVarSize mv smallArrayBytes MaxSmallArraySize mv MaxStackVarSize cfg.go mv nodbool NewBool mv nodintconst NewInt mv nodstr NewString mv NewBool NewInt NewString const.go mv Mpprec ConstPrec mv bigFloatVal BigFloat mv doesoverflow ConstOverflow mv isGoConst IsConstNode mv smallintconst IsSmallIntConst mv isZero IsZero mv islvalue IsAssignable mv staticValue StaticValue mv samesafeexpr SameSafeExpr mv checkPtr ShouldCheckPtr mv isReflectHeaderDataField IsReflectHeaderDataField mv paramNnames ParamNames mv methodSym MethodSym mv methodSymSuffix MethodSymSuffix mv methodExprFunc MethodExprFunc mv methodExprName MethodExprName mv IsZero IsAssignable StaticValue staticValue1 reassigned \ IsIntrinsicCall \ SameSafeExpr ShouldCheckPtr IsReflectHeaderDataField \ ParamNames MethodSym MethodSymSuffix \ MethodExprName MethodExprFunc \ expr.go mv Curfn CurFunc mv funcsymname FuncSymName mv newFuncNameAt NewFuncNameAt mv setNodeNameFunc MarkFunc mv CurFunc FuncSymName NewFuncNameAt MarkFunc func.go mv isParamStackCopy IsParamStackCopy mv isParamHeapCopy IsParamHeapCopy mv nodfp RegFP mv IsParamStackCopy IsParamHeapCopy RegFP name.go mv hasUniquePos HasUniquePos mv setlineno SetPos mv initExpr InitExpr mv hasNamedResults HasNamedResults mv outervalue OuterValue mv HasNamedResults HasUniquePos SetPos InitExpr OuterValue EscNever node.go mv visitBottomUp VisitFuncsBottomUp # scc.go mv cfg.go \ NewBool NewInt NewString \ # parts of const.go ConstPrec BigFloat ConstOverflow IsConstNode IsSmallIntConst \ expr.go func.go name.go node.go scc.go \ cmd/compile/internal/ir ' Change-Id: I13402c5a2cedbf78d993a1eae2940718f23ac166 Reviewed-on: https://go-review.googlesource.com/c/go/+/279421 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>
2020-12-23 00:38:15 -05:00
var CurFunc *Func
// WithFunc invokes do with CurFunc and base.Pos set to curfn and
// curfn.Pos(), respectively, and then restores their previous values
// before returning.
func WithFunc(curfn *Func, do func()) {
oldfn, oldpos := CurFunc, base.Pos
defer func() { CurFunc, base.Pos = oldfn, oldpos }()
CurFunc, base.Pos = curfn, curfn.Pos()
do()
}
[dev.regabi] cmd/compile: move helpers into package ir [generated] [git-generate] cd src/cmd/compile/internal/gc sed -i '' 's/TestBuiltin.*/& t.Skip("mkbuiltin needs fixing")/' builtin_test.go gofmt -w builtin_test.go rf ' # Inline a few little-used constructors to avoid bringing them. ex { import "cmd/compile/internal/base" import "cmd/compile/internal/ir" import "cmd/compile/internal/types" import "cmd/internal/src" var typ *types.Type var sym *types.Sym var str string symfield(sym, typ) -> ir.NewField(base.Pos, sym, nil, typ) anonfield(typ) -> ir.NewField(base.Pos, nil, nil, typ) namedfield(str, typ) -> ir.NewField(base.Pos, lookup(str), nil, typ) var cp *ir.CallPartExpr callpartMethod(cp) -> cp.Method var n ir.Node callpartMethod(n) -> n.(*ir.CallPartExpr).Method var ns []ir.Node liststmt(ns) -> ir.NewBlockStmt(src.NoXPos, ns) } rm symfield anonfield namedfield liststmt callpartMethod mv maxStackVarSize MaxStackVarSize mv maxImplicitStackVarSize MaxImplicitStackVarSize mv smallArrayBytes MaxSmallArraySize mv MaxStackVarSize cfg.go mv nodbool NewBool mv nodintconst NewInt mv nodstr NewString mv NewBool NewInt NewString const.go mv Mpprec ConstPrec mv bigFloatVal BigFloat mv doesoverflow ConstOverflow mv isGoConst IsConstNode mv smallintconst IsSmallIntConst mv isZero IsZero mv islvalue IsAssignable mv staticValue StaticValue mv samesafeexpr SameSafeExpr mv checkPtr ShouldCheckPtr mv isReflectHeaderDataField IsReflectHeaderDataField mv paramNnames ParamNames mv methodSym MethodSym mv methodSymSuffix MethodSymSuffix mv methodExprFunc MethodExprFunc mv methodExprName MethodExprName mv IsZero IsAssignable StaticValue staticValue1 reassigned \ IsIntrinsicCall \ SameSafeExpr ShouldCheckPtr IsReflectHeaderDataField \ ParamNames MethodSym MethodSymSuffix \ MethodExprName MethodExprFunc \ expr.go mv Curfn CurFunc mv funcsymname FuncSymName mv newFuncNameAt NewFuncNameAt mv setNodeNameFunc MarkFunc mv CurFunc FuncSymName NewFuncNameAt MarkFunc func.go mv isParamStackCopy IsParamStackCopy mv isParamHeapCopy IsParamHeapCopy mv nodfp RegFP mv IsParamStackCopy IsParamHeapCopy RegFP name.go mv hasUniquePos HasUniquePos mv setlineno SetPos mv initExpr InitExpr mv hasNamedResults HasNamedResults mv outervalue OuterValue mv HasNamedResults HasUniquePos SetPos InitExpr OuterValue EscNever node.go mv visitBottomUp VisitFuncsBottomUp # scc.go mv cfg.go \ NewBool NewInt NewString \ # parts of const.go ConstPrec BigFloat ConstOverflow IsConstNode IsSmallIntConst \ expr.go func.go name.go node.go scc.go \ cmd/compile/internal/ir ' Change-Id: I13402c5a2cedbf78d993a1eae2940718f23ac166 Reviewed-on: https://go-review.googlesource.com/c/go/+/279421 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>
2020-12-23 00:38:15 -05:00
func FuncSymName(s *types.Sym) string {
return s.Name + "·f"
}
// MarkFunc marks a node as a function.
func MarkFunc(n *Name) {
if n.Op() != ONAME || n.Class != Pxxx {
base.FatalfAt(n.Pos(), "expected ONAME/Pxxx node, got %v (%v/%v)", n, n.Op(), n.Class)
[dev.regabi] cmd/compile: move helpers into package ir [generated] [git-generate] cd src/cmd/compile/internal/gc sed -i '' 's/TestBuiltin.*/& t.Skip("mkbuiltin needs fixing")/' builtin_test.go gofmt -w builtin_test.go rf ' # Inline a few little-used constructors to avoid bringing them. ex { import "cmd/compile/internal/base" import "cmd/compile/internal/ir" import "cmd/compile/internal/types" import "cmd/internal/src" var typ *types.Type var sym *types.Sym var str string symfield(sym, typ) -> ir.NewField(base.Pos, sym, nil, typ) anonfield(typ) -> ir.NewField(base.Pos, nil, nil, typ) namedfield(str, typ) -> ir.NewField(base.Pos, lookup(str), nil, typ) var cp *ir.CallPartExpr callpartMethod(cp) -> cp.Method var n ir.Node callpartMethod(n) -> n.(*ir.CallPartExpr).Method var ns []ir.Node liststmt(ns) -> ir.NewBlockStmt(src.NoXPos, ns) } rm symfield anonfield namedfield liststmt callpartMethod mv maxStackVarSize MaxStackVarSize mv maxImplicitStackVarSize MaxImplicitStackVarSize mv smallArrayBytes MaxSmallArraySize mv MaxStackVarSize cfg.go mv nodbool NewBool mv nodintconst NewInt mv nodstr NewString mv NewBool NewInt NewString const.go mv Mpprec ConstPrec mv bigFloatVal BigFloat mv doesoverflow ConstOverflow mv isGoConst IsConstNode mv smallintconst IsSmallIntConst mv isZero IsZero mv islvalue IsAssignable mv staticValue StaticValue mv samesafeexpr SameSafeExpr mv checkPtr ShouldCheckPtr mv isReflectHeaderDataField IsReflectHeaderDataField mv paramNnames ParamNames mv methodSym MethodSym mv methodSymSuffix MethodSymSuffix mv methodExprFunc MethodExprFunc mv methodExprName MethodExprName mv IsZero IsAssignable StaticValue staticValue1 reassigned \ IsIntrinsicCall \ SameSafeExpr ShouldCheckPtr IsReflectHeaderDataField \ ParamNames MethodSym MethodSymSuffix \ MethodExprName MethodExprFunc \ expr.go mv Curfn CurFunc mv funcsymname FuncSymName mv newFuncNameAt NewFuncNameAt mv setNodeNameFunc MarkFunc mv CurFunc FuncSymName NewFuncNameAt MarkFunc func.go mv isParamStackCopy IsParamStackCopy mv isParamHeapCopy IsParamHeapCopy mv nodfp RegFP mv IsParamStackCopy IsParamHeapCopy RegFP name.go mv hasUniquePos HasUniquePos mv setlineno SetPos mv initExpr InitExpr mv hasNamedResults HasNamedResults mv outervalue OuterValue mv HasNamedResults HasUniquePos SetPos InitExpr OuterValue EscNever node.go mv visitBottomUp VisitFuncsBottomUp # scc.go mv cfg.go \ NewBool NewInt NewString \ # parts of const.go ConstPrec BigFloat ConstOverflow IsConstNode IsSmallIntConst \ expr.go func.go name.go node.go scc.go \ cmd/compile/internal/ir ' Change-Id: I13402c5a2cedbf78d993a1eae2940718f23ac166 Reviewed-on: https://go-review.googlesource.com/c/go/+/279421 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>
2020-12-23 00:38:15 -05:00
}
n.Class = PFUNC
[dev.regabi] cmd/compile: move helpers into package ir [generated] [git-generate] cd src/cmd/compile/internal/gc sed -i '' 's/TestBuiltin.*/& t.Skip("mkbuiltin needs fixing")/' builtin_test.go gofmt -w builtin_test.go rf ' # Inline a few little-used constructors to avoid bringing them. ex { import "cmd/compile/internal/base" import "cmd/compile/internal/ir" import "cmd/compile/internal/types" import "cmd/internal/src" var typ *types.Type var sym *types.Sym var str string symfield(sym, typ) -> ir.NewField(base.Pos, sym, nil, typ) anonfield(typ) -> ir.NewField(base.Pos, nil, nil, typ) namedfield(str, typ) -> ir.NewField(base.Pos, lookup(str), nil, typ) var cp *ir.CallPartExpr callpartMethod(cp) -> cp.Method var n ir.Node callpartMethod(n) -> n.(*ir.CallPartExpr).Method var ns []ir.Node liststmt(ns) -> ir.NewBlockStmt(src.NoXPos, ns) } rm symfield anonfield namedfield liststmt callpartMethod mv maxStackVarSize MaxStackVarSize mv maxImplicitStackVarSize MaxImplicitStackVarSize mv smallArrayBytes MaxSmallArraySize mv MaxStackVarSize cfg.go mv nodbool NewBool mv nodintconst NewInt mv nodstr NewString mv NewBool NewInt NewString const.go mv Mpprec ConstPrec mv bigFloatVal BigFloat mv doesoverflow ConstOverflow mv isGoConst IsConstNode mv smallintconst IsSmallIntConst mv isZero IsZero mv islvalue IsAssignable mv staticValue StaticValue mv samesafeexpr SameSafeExpr mv checkPtr ShouldCheckPtr mv isReflectHeaderDataField IsReflectHeaderDataField mv paramNnames ParamNames mv methodSym MethodSym mv methodSymSuffix MethodSymSuffix mv methodExprFunc MethodExprFunc mv methodExprName MethodExprName mv IsZero IsAssignable StaticValue staticValue1 reassigned \ IsIntrinsicCall \ SameSafeExpr ShouldCheckPtr IsReflectHeaderDataField \ ParamNames MethodSym MethodSymSuffix \ MethodExprName MethodExprFunc \ expr.go mv Curfn CurFunc mv funcsymname FuncSymName mv newFuncNameAt NewFuncNameAt mv setNodeNameFunc MarkFunc mv CurFunc FuncSymName NewFuncNameAt MarkFunc func.go mv isParamStackCopy IsParamStackCopy mv isParamHeapCopy IsParamHeapCopy mv nodfp RegFP mv IsParamStackCopy IsParamHeapCopy RegFP name.go mv hasUniquePos HasUniquePos mv setlineno SetPos mv initExpr InitExpr mv hasNamedResults HasNamedResults mv outervalue OuterValue mv HasNamedResults HasUniquePos SetPos InitExpr OuterValue EscNever node.go mv visitBottomUp VisitFuncsBottomUp # scc.go mv cfg.go \ NewBool NewInt NewString \ # parts of const.go ConstPrec BigFloat ConstOverflow IsConstNode IsSmallIntConst \ expr.go func.go name.go node.go scc.go \ cmd/compile/internal/ir ' Change-Id: I13402c5a2cedbf78d993a1eae2940718f23ac166 Reviewed-on: https://go-review.googlesource.com/c/go/+/279421 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>
2020-12-23 00:38:15 -05:00
n.Sym().SetFunc(true)
}
[dev.regabi] cmd/compile: split out package walk [generated] [git-generate] cd src/cmd/compile/internal/gc rf ' # Late addition to package ir. mv closuredebugruntimecheck ClosureDebugRuntimeCheck mv hasemptycvars IsTrivialClosure mv ClosureDebugRuntimeCheck IsTrivialClosure func.go mv func.go cmd/compile/internal/ir # Late addition to package reflectdata. mv markTypeUsedInInterface MarkTypeUsedInInterface mv markUsedIfaceMethod MarkUsedIfaceMethod mv MarkTypeUsedInInterface MarkUsedIfaceMethod reflect.go mv reflect.go cmd/compile/internal/reflectdata # Late addition to package staticdata. mv litsym InitConst mv InitConst data.go mv data.go cmd/compile/internal/staticdata # Extract staticinit out of walk into its own package. mv InitEntry InitPlan InitSchedule InitSchedule.append InitSchedule.staticInit \ InitSchedule.tryStaticInit InitSchedule.staticcopy \ InitSchedule.staticassign InitSchedule.initplan InitSchedule.addvalue \ statuniqgen staticname stataddr anySideEffects getlit isvaluelit \ sched.go mv InitSchedule.initplans InitSchedule.Plans mv InitSchedule.inittemps InitSchedule.Temps mv InitSchedule.out InitSchedule.Out mv InitSchedule.staticInit InitSchedule.StaticInit mv InitSchedule.staticassign InitSchedule.StaticAssign mv InitSchedule Schedule mv InitPlan Plan mv InitEntry Entry mv anySideEffects AnySideEffects mv staticname StaticName mv stataddr StaticLoc mv sched.go cmd/compile/internal/staticinit # Export API and unexport non-API. mv transformclosure Closure mv walk Walk mv Order orderState mv swt.go switch.go mv racewalk.go race.go mv closure.go order.go range.go select.go switch.go race.go \ sinit.go subr.go walk.go \ cmd/compile/internal/walk ' : # Update format test. cd ../../ go install cmd/compile/... cmd/internal/archive go test -u || go test -u rm -rf ../../../pkg/darwin_amd64/cmd Change-Id: I11c7a45f74d4a9e963da15c080e1018caaa99c05 Reviewed-on: https://go-review.googlesource.com/c/go/+/279478 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-23 01:05:16 -05:00
// ClosureDebugRuntimeCheck applies boilerplate checks for debug flags
// and compiling runtime.
[dev.regabi] cmd/compile: split out package walk [generated] [git-generate] cd src/cmd/compile/internal/gc rf ' # Late addition to package ir. mv closuredebugruntimecheck ClosureDebugRuntimeCheck mv hasemptycvars IsTrivialClosure mv ClosureDebugRuntimeCheck IsTrivialClosure func.go mv func.go cmd/compile/internal/ir # Late addition to package reflectdata. mv markTypeUsedInInterface MarkTypeUsedInInterface mv markUsedIfaceMethod MarkUsedIfaceMethod mv MarkTypeUsedInInterface MarkUsedIfaceMethod reflect.go mv reflect.go cmd/compile/internal/reflectdata # Late addition to package staticdata. mv litsym InitConst mv InitConst data.go mv data.go cmd/compile/internal/staticdata # Extract staticinit out of walk into its own package. mv InitEntry InitPlan InitSchedule InitSchedule.append InitSchedule.staticInit \ InitSchedule.tryStaticInit InitSchedule.staticcopy \ InitSchedule.staticassign InitSchedule.initplan InitSchedule.addvalue \ statuniqgen staticname stataddr anySideEffects getlit isvaluelit \ sched.go mv InitSchedule.initplans InitSchedule.Plans mv InitSchedule.inittemps InitSchedule.Temps mv InitSchedule.out InitSchedule.Out mv InitSchedule.staticInit InitSchedule.StaticInit mv InitSchedule.staticassign InitSchedule.StaticAssign mv InitSchedule Schedule mv InitPlan Plan mv InitEntry Entry mv anySideEffects AnySideEffects mv staticname StaticName mv stataddr StaticLoc mv sched.go cmd/compile/internal/staticinit # Export API and unexport non-API. mv transformclosure Closure mv walk Walk mv Order orderState mv swt.go switch.go mv racewalk.go race.go mv closure.go order.go range.go select.go switch.go race.go \ sinit.go subr.go walk.go \ cmd/compile/internal/walk ' : # Update format test. cd ../../ go install cmd/compile/... cmd/internal/archive go test -u || go test -u rm -rf ../../../pkg/darwin_amd64/cmd Change-Id: I11c7a45f74d4a9e963da15c080e1018caaa99c05 Reviewed-on: https://go-review.googlesource.com/c/go/+/279478 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-23 01:05:16 -05:00
func ClosureDebugRuntimeCheck(clo *ClosureExpr) {
if base.Debug.Closure > 0 {
if clo.Esc() == EscHeap {
base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars)
} else {
base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars)
}
}
if base.Flag.CompilingRuntime && clo.Esc() == EscHeap && !clo.IsGoWrap {
base.ErrorfAt(clo.Pos(), "heap-allocated closure %s, not allowed in runtime", FuncName(clo.Func))
[dev.regabi] cmd/compile: split out package walk [generated] [git-generate] cd src/cmd/compile/internal/gc rf ' # Late addition to package ir. mv closuredebugruntimecheck ClosureDebugRuntimeCheck mv hasemptycvars IsTrivialClosure mv ClosureDebugRuntimeCheck IsTrivialClosure func.go mv func.go cmd/compile/internal/ir # Late addition to package reflectdata. mv markTypeUsedInInterface MarkTypeUsedInInterface mv markUsedIfaceMethod MarkUsedIfaceMethod mv MarkTypeUsedInInterface MarkUsedIfaceMethod reflect.go mv reflect.go cmd/compile/internal/reflectdata # Late addition to package staticdata. mv litsym InitConst mv InitConst data.go mv data.go cmd/compile/internal/staticdata # Extract staticinit out of walk into its own package. mv InitEntry InitPlan InitSchedule InitSchedule.append InitSchedule.staticInit \ InitSchedule.tryStaticInit InitSchedule.staticcopy \ InitSchedule.staticassign InitSchedule.initplan InitSchedule.addvalue \ statuniqgen staticname stataddr anySideEffects getlit isvaluelit \ sched.go mv InitSchedule.initplans InitSchedule.Plans mv InitSchedule.inittemps InitSchedule.Temps mv InitSchedule.out InitSchedule.Out mv InitSchedule.staticInit InitSchedule.StaticInit mv InitSchedule.staticassign InitSchedule.StaticAssign mv InitSchedule Schedule mv InitPlan Plan mv InitEntry Entry mv anySideEffects AnySideEffects mv staticname StaticName mv stataddr StaticLoc mv sched.go cmd/compile/internal/staticinit # Export API and unexport non-API. mv transformclosure Closure mv walk Walk mv Order orderState mv swt.go switch.go mv racewalk.go race.go mv closure.go order.go range.go select.go switch.go race.go \ sinit.go subr.go walk.go \ cmd/compile/internal/walk ' : # Update format test. cd ../../ go install cmd/compile/... cmd/internal/archive go test -u || go test -u rm -rf ../../../pkg/darwin_amd64/cmd Change-Id: I11c7a45f74d4a9e963da15c080e1018caaa99c05 Reviewed-on: https://go-review.googlesource.com/c/go/+/279478 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-23 01:05:16 -05:00
}
}
// IsTrivialClosure reports whether closure clo has an
// empty list of captured vars.
func IsTrivialClosure(clo *ClosureExpr) bool {
return len(clo.Func.ClosureVars) == 0
}
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
// globClosgen is like Func.Closgen, but for the global scope.
var globClosgen int32
// closureName generates a new unique name for a closure within outerfn.
func closureName(outerfn *Func) *types.Sym {
pkg := types.LocalPkg
outer := "glob."
prefix := "func"
gen := &globClosgen
if outerfn != nil {
if outerfn.OClosure != nil {
prefix = ""
}
pkg = outerfn.Sym().Pkg
outer = FuncName(outerfn)
// There may be multiple functions named "_". In those
// cases, we can't use their individual Closgens as it
// would lead to name clashes.
if !IsBlank(outerfn.Nname) {
gen = &outerfn.Closgen
}
}
*gen++
return pkg.Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
}
// NewClosureFunc creates a new Func to represent a function literal.
// If hidden is true, then the closure is marked hidden (i.e., as a
// function literal contained within another function, rather than a
// package-scope variable initialization expression).
func NewClosureFunc(pos src.XPos, hidden bool) *Func {
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
fn := NewFunc(pos)
fn.SetIsHiddenClosure(hidden)
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
fn.Nname = NewNameAt(pos, BlankNode.Sym())
fn.Nname.Func = fn
fn.Nname.Defn = fn
fn.OClosure = &ClosureExpr{Func: fn}
fn.OClosure.op = OCLOSURE
fn.OClosure.pos = pos
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
return fn
}
// NameClosure generates a unique for the given function literal,
// which must have appeared within outerfn.
func NameClosure(clo *ClosureExpr, outerfn *Func) {
fn := clo.Func
if fn.IsHiddenClosure() != (outerfn != nil) {
base.FatalfAt(clo.Pos(), "closure naming inconsistency: hidden %v, but outer %v", fn.IsHiddenClosure(), outerfn)
}
name := fn.Nname
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
if !IsBlank(name) {
base.FatalfAt(clo.Pos(), "closure already named: %v", name)
}
name.SetSym(closureName(outerfn))
MarkFunc(name)
}
// UseClosure checks that the given function literal has been setup
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
// correctly, and then returns it as an expression.
// It must be called after clo.Func.ClosureVars has been set.
func UseClosure(clo *ClosureExpr, pkg *Package) Node {
fn := clo.Func
name := fn.Nname
if IsBlank(name) {
base.FatalfAt(fn.Pos(), "unnamed closure func: %v", fn)
}
// Caution: clo.Typecheck() is still 0 when UseClosure is called by
// tcClosure.
if fn.Typecheck() != 1 || name.Typecheck() != 1 {
base.FatalfAt(fn.Pos(), "missed typecheck: %v", fn)
}
if clo.Type() == nil || name.Type() == nil {
base.FatalfAt(fn.Pos(), "missing types: %v", fn)
}
if !types.Identical(clo.Type(), name.Type()) {
base.FatalfAt(fn.Pos(), "mismatched types: %v", fn)
}
if base.Flag.W > 1 {
s := fmt.Sprintf("new closure func: %v", fn)
Dump(s, fn)
}
if pkg != nil {
pkg.Decls = append(pkg.Decls, fn)
}
if false && IsTrivialClosure(clo) {
// TODO(mdempsky): Investigate if we can/should optimize this
// case. walkClosure already handles it later, but it could be
// useful to recognize earlier (e.g., it might allow multiple
// inlined calls to a function to share a common trivial closure
// func, rather than cloning it for each inlined call).
}
return clo
}