mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] cmd/compile: use ir.EditChildren for inline rewriting
This CL rephrases the general inlining rewriter in terms of ir.EditChildren. It is the final part of the code that was processing arbitrary nodes using Left, SetLeft, and so on. After this CL, there should be none left except for the implementations of DoChildren and EditChildren, which fall next. Passes buildall w/ toolstash -cmp. Change-Id: I9c36053360cd040710716f0b39397a80114be713 Reviewed-on: https://go-review.googlesource.com/c/go/+/275373 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
b9df26d7a8
commit
d855b30fe4
4 changed files with 46 additions and 75 deletions
|
|
@ -803,6 +803,7 @@ func (e *Escape) call(ks []EscHole, call, where ir.Node) {
|
||||||
|
|
||||||
switch call.Op() {
|
switch call.Op() {
|
||||||
default:
|
default:
|
||||||
|
ir.Dump("esc", call)
|
||||||
base.Fatalf("unexpected call op: %v", call.Op())
|
base.Fatalf("unexpected call op: %v", call.Op())
|
||||||
|
|
||||||
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
|
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
|
||||||
|
|
|
||||||
|
|
@ -483,10 +483,11 @@ func inlcalls(fn *ir.Func) {
|
||||||
// Most likely, the inlining will stop before we even hit the beginning of
|
// Most likely, the inlining will stop before we even hit the beginning of
|
||||||
// the cycle again, but the map catches the unusual case.
|
// the cycle again, but the map catches the unusual case.
|
||||||
inlMap := make(map[*ir.Func]bool)
|
inlMap := make(map[*ir.Func]bool)
|
||||||
fn = inlnode(fn, maxCost, inlMap).(*ir.Func)
|
var edit func(ir.Node) ir.Node
|
||||||
if fn != Curfn {
|
edit = func(n ir.Node) ir.Node {
|
||||||
base.Fatalf("inlnode replaced curfn")
|
return inlnode(n, maxCost, inlMap, edit)
|
||||||
}
|
}
|
||||||
|
ir.EditChildren(fn, edit)
|
||||||
Curfn = savefn
|
Curfn = savefn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -521,13 +522,6 @@ func inlconv2list(n ir.Node) []ir.Node {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func inlnodelist(l ir.Nodes, maxCost int32, inlMap map[*ir.Func]bool) {
|
|
||||||
s := l.Slice()
|
|
||||||
for i := range s {
|
|
||||||
s[i] = inlnode(s[i], maxCost, inlMap)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// inlnode recurses over the tree to find inlineable calls, which will
|
// inlnode recurses over the tree to find inlineable calls, which will
|
||||||
// be turned into OINLCALLs by mkinlcall. When the recursion comes
|
// be turned into OINLCALLs by mkinlcall. When the recursion comes
|
||||||
// back up will examine left, right, list, rlist, ninit, ntest, nincr,
|
// back up will examine left, right, list, rlist, ninit, ntest, nincr,
|
||||||
|
|
@ -541,7 +535,7 @@ func inlnodelist(l ir.Nodes, maxCost int32, inlMap map[*ir.Func]bool) {
|
||||||
// shorter and less complicated.
|
// shorter and less complicated.
|
||||||
// The result of inlnode MUST be assigned back to n, e.g.
|
// The result of inlnode MUST be assigned back to n, e.g.
|
||||||
// n.Left = inlnode(n.Left)
|
// n.Left = inlnode(n.Left)
|
||||||
func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
|
func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.Node) ir.Node) ir.Node {
|
||||||
if n == nil {
|
if n == nil {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
@ -567,49 +561,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
|
||||||
|
|
||||||
lno := setlineno(n)
|
lno := setlineno(n)
|
||||||
|
|
||||||
inlnodelist(n.Init(), maxCost, inlMap)
|
ir.EditChildren(n, edit)
|
||||||
init := n.Init().Slice()
|
|
||||||
for i, n1 := range init {
|
|
||||||
if n1.Op() == ir.OINLCALL {
|
|
||||||
init[i] = inlconv2stmt(n1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n.SetLeft(inlnode(n.Left(), maxCost, inlMap))
|
|
||||||
if n.Left() != nil && n.Left().Op() == ir.OINLCALL {
|
|
||||||
n.SetLeft(inlconv2expr(n.Left()))
|
|
||||||
}
|
|
||||||
|
|
||||||
n.SetRight(inlnode(n.Right(), maxCost, inlMap))
|
|
||||||
if n.Right() != nil && n.Right().Op() == ir.OINLCALL {
|
|
||||||
if n.Op() == ir.OFOR || n.Op() == ir.OFORUNTIL {
|
|
||||||
n.SetRight(inlconv2stmt(n.Right()))
|
|
||||||
} else {
|
|
||||||
n.SetRight(inlconv2expr(n.Right()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inlnodelist(n.List(), maxCost, inlMap)
|
|
||||||
s := n.List().Slice()
|
|
||||||
convert := inlconv2expr
|
|
||||||
if n.Op() == ir.OBLOCK {
|
|
||||||
convert = inlconv2stmt
|
|
||||||
}
|
|
||||||
for i, n1 := range s {
|
|
||||||
if n1 != nil && n1.Op() == ir.OINLCALL {
|
|
||||||
s[i] = convert(n1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inlnodelist(n.Body(), maxCost, inlMap)
|
|
||||||
s = n.Body().Slice()
|
|
||||||
for i, n1 := range s {
|
|
||||||
if n1.Op() == ir.OINLCALL {
|
|
||||||
s[i] = inlconv2stmt(n1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inlnodelist(n.Rlist(), maxCost, inlMap)
|
|
||||||
|
|
||||||
if n.Op() == ir.OAS2FUNC && n.Rlist().First().Op() == ir.OINLCALL {
|
if n.Op() == ir.OAS2FUNC && n.Rlist().First().Op() == ir.OINLCALL {
|
||||||
n.PtrRlist().Set(inlconv2list(n.Rlist().First()))
|
n.PtrRlist().Set(inlconv2list(n.Rlist().First()))
|
||||||
|
|
@ -618,17 +570,6 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
|
||||||
n = typecheck(n, ctxStmt)
|
n = typecheck(n, ctxStmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
s = n.Rlist().Slice()
|
|
||||||
for i, n1 := range s {
|
|
||||||
if n1.Op() == ir.OINLCALL {
|
|
||||||
if n.Op() == ir.OIF {
|
|
||||||
s[i] = inlconv2stmt(n1)
|
|
||||||
} else {
|
|
||||||
s[i] = inlconv2expr(n1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// with all the branches out of the way, it is now time to
|
// with all the branches out of the way, it is now time to
|
||||||
// transmogrify this node itself unless inhibited by the
|
// transmogrify this node itself unless inhibited by the
|
||||||
// switch at the top of this function.
|
// switch at the top of this function.
|
||||||
|
|
@ -639,8 +580,10 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var call ir.Node
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
case ir.OCALLFUNC:
|
case ir.OCALLFUNC:
|
||||||
|
call = n
|
||||||
if base.Flag.LowerM > 3 {
|
if base.Flag.LowerM > 3 {
|
||||||
fmt.Printf("%v:call to func %+v\n", ir.Line(n), n.Left())
|
fmt.Printf("%v:call to func %+v\n", ir.Line(n), n.Left())
|
||||||
}
|
}
|
||||||
|
|
@ -648,10 +591,11 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if fn := inlCallee(n.Left()); fn != nil && fn.Inl != nil {
|
if fn := inlCallee(n.Left()); fn != nil && fn.Inl != nil {
|
||||||
n = mkinlcall(n, fn, maxCost, inlMap)
|
n = mkinlcall(n, fn, maxCost, inlMap, edit)
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OCALLMETH:
|
case ir.OCALLMETH:
|
||||||
|
call = n
|
||||||
if base.Flag.LowerM > 3 {
|
if base.Flag.LowerM > 3 {
|
||||||
fmt.Printf("%v:call to meth %L\n", ir.Line(n), n.Left().Right())
|
fmt.Printf("%v:call to meth %L\n", ir.Line(n), n.Left().Right())
|
||||||
}
|
}
|
||||||
|
|
@ -661,10 +605,25 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
|
||||||
base.Fatalf("no function type for [%p] %+v\n", n.Left(), n.Left())
|
base.Fatalf("no function type for [%p] %+v\n", n.Left(), n.Left())
|
||||||
}
|
}
|
||||||
|
|
||||||
n = mkinlcall(n, methodExprName(n.Left()).Func(), maxCost, inlMap)
|
n = mkinlcall(n, methodExprName(n.Left()).Func(), maxCost, inlMap, edit)
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Pos = lno
|
base.Pos = lno
|
||||||
|
|
||||||
|
if n.Op() == ir.OINLCALL {
|
||||||
|
switch call.(*ir.CallExpr).Use {
|
||||||
|
default:
|
||||||
|
ir.Dump("call", call)
|
||||||
|
base.Fatalf("call missing use")
|
||||||
|
case ir.CallUseExpr:
|
||||||
|
n = inlconv2expr(n)
|
||||||
|
case ir.CallUseStmt:
|
||||||
|
n = inlconv2stmt(n)
|
||||||
|
case ir.CallUseList:
|
||||||
|
// leave for caller to convert
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -805,7 +764,7 @@ var inlgen int
|
||||||
// parameters.
|
// parameters.
|
||||||
// The result of mkinlcall MUST be assigned back to n, e.g.
|
// The result of mkinlcall MUST be assigned back to n, e.g.
|
||||||
// n.Left = mkinlcall(n.Left, fn, isddd)
|
// n.Left = mkinlcall(n.Left, fn, isddd)
|
||||||
func mkinlcall(n ir.Node, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]bool) ir.Node {
|
func mkinlcall(n ir.Node, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.Node) ir.Node) ir.Node {
|
||||||
if fn.Inl == nil {
|
if fn.Inl == nil {
|
||||||
if logopt.Enabled() {
|
if logopt.Enabled() {
|
||||||
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(Curfn),
|
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(Curfn),
|
||||||
|
|
@ -1131,13 +1090,7 @@ func mkinlcall(n ir.Node, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]bool)
|
||||||
// instead we emit the things that the body needs
|
// instead we emit the things that the body needs
|
||||||
// and each use must redo the inlining.
|
// and each use must redo the inlining.
|
||||||
// luckily these are small.
|
// luckily these are small.
|
||||||
inlnodelist(call.Body(), maxCost, inlMap)
|
ir.EditChildren(call, edit)
|
||||||
s := call.Body().Slice()
|
|
||||||
for i, n1 := range s {
|
|
||||||
if n1.Op() == ir.OINLCALL {
|
|
||||||
s[i] = inlconv2stmt(n1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if base.Flag.LowerM > 2 {
|
if base.Flag.LowerM > 2 {
|
||||||
fmt.Printf("%v: After inlining %+v\n\n", ir.Line(call), call)
|
fmt.Printf("%v: After inlining %+v\n\n", ir.Line(call), call)
|
||||||
|
|
|
||||||
|
|
@ -1280,6 +1280,10 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
|
|
||||||
// call and call like
|
// call and call like
|
||||||
case ir.OCALL:
|
case ir.OCALL:
|
||||||
|
n.(*ir.CallExpr).Use = ir.CallUseExpr
|
||||||
|
if top == ctxStmt {
|
||||||
|
n.(*ir.CallExpr).Use = ir.CallUseStmt
|
||||||
|
}
|
||||||
typecheckslice(n.Init().Slice(), ctxStmt) // imported rewritten f(g()) calls (#30907)
|
typecheckslice(n.Init().Slice(), ctxStmt) // imported rewritten f(g()) calls (#30907)
|
||||||
n.SetLeft(typecheck(n.Left(), ctxExpr|ctxType|ctxCallee))
|
n.SetLeft(typecheck(n.Left(), ctxExpr|ctxType|ctxCallee))
|
||||||
if n.Left().Diag() {
|
if n.Left().Diag() {
|
||||||
|
|
@ -3294,6 +3298,7 @@ func typecheckas2(n ir.Node) {
|
||||||
if cr != cl {
|
if cr != cl {
|
||||||
goto mismatch
|
goto mismatch
|
||||||
}
|
}
|
||||||
|
r.(*ir.CallExpr).Use = ir.CallUseList
|
||||||
n.SetOp(ir.OAS2FUNC)
|
n.SetOp(ir.OAS2FUNC)
|
||||||
for i, l := range n.List().Slice() {
|
for i, l := range n.List().Slice() {
|
||||||
f := r.Type().Field(i)
|
f := r.Type().Field(i)
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,17 @@ func (n *BinaryExpr) SetOp(op Op) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A CallUse records how the result of the call is used:
|
||||||
|
type CallUse int
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ CallUse = iota
|
||||||
|
|
||||||
|
CallUseExpr // single expression result is used
|
||||||
|
CallUseList // list of results are used
|
||||||
|
CallUseStmt // results not used - call is a statement
|
||||||
|
)
|
||||||
|
|
||||||
// A CallExpr is a function call X(Args).
|
// A CallExpr is a function call X(Args).
|
||||||
type CallExpr struct {
|
type CallExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
|
|
@ -157,6 +168,7 @@ type CallExpr struct {
|
||||||
Rargs Nodes // TODO(rsc): Delete.
|
Rargs Nodes // TODO(rsc): Delete.
|
||||||
body Nodes // TODO(rsc): Delete.
|
body Nodes // TODO(rsc): Delete.
|
||||||
DDD bool
|
DDD bool
|
||||||
|
Use CallUse
|
||||||
noInline bool
|
noInline bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue