mirror of
https://github.com/golang/go.git
synced 2026-04-03 09:49:56 +09:00
cmd/compile: keep blank nodes alive in b.loop
The current bloop pass implementation skips blank nodes silently. This CL makes it aware of that and keep them alive in temps. Fixes #77654. Change-Id: Iaffa5194ba1f0fe8d7c80a4c8e5c9a65a47bf534 Reviewed-on: https://go-review.googlesource.com/c/go/+/754920 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
@@ -216,11 +216,49 @@ func preserveCallArgs(curFn *ir.Func, call *ir.CallExpr) ir.Node {
|
||||
func preserveStmt(curFn *ir.Func, stmt ir.Node) ir.Node {
|
||||
switch n := stmt.(type) {
|
||||
case *ir.AssignStmt:
|
||||
// If the left hand side is blank, we need to assign it to a temp
|
||||
// so that it can be kept alive.
|
||||
if ir.IsBlank(n.X) {
|
||||
tmp := typecheck.TempAt(n.Pos(), curFn, n.Y.Type())
|
||||
n.X = tmp
|
||||
n.Def = true
|
||||
n.PtrInit().Append(typecheck.Stmt(ir.NewDecl(n.Pos(), ir.ODCL, tmp)))
|
||||
stmt = typecheck.AssignExpr(n)
|
||||
n = stmt.(*ir.AssignStmt)
|
||||
}
|
||||
return keepAliveAt(getKeepAliveNodes(n.Pos(), n.X), n)
|
||||
case *ir.AssignListStmt:
|
||||
var ns ir.Nodes
|
||||
for _, lhs := range n.Lhs {
|
||||
ns = append(ns, getKeepAliveNodes(n.Pos(), lhs)...)
|
||||
hasBlank := false
|
||||
for i, lhs := range n.Lhs {
|
||||
if ir.IsBlank(lhs) {
|
||||
// If the left hand side has blanks, we need to assign them to temps
|
||||
// so that they can be kept alive.
|
||||
var typ *types.Type
|
||||
// AssignListStmt can have tuple or a list of expressions on the right hand side.
|
||||
if len(n.Rhs) == 1 && n.Rhs[0].Type() != nil &&
|
||||
n.Rhs[0].Type().IsTuple() &&
|
||||
len(n.Lhs) == n.Rhs[0].Type().NumFields() {
|
||||
typ = n.Rhs[0].Type().Field(i).Type
|
||||
} else if len(n.Rhs) == len(n.Lhs) {
|
||||
typ = n.Rhs[i].Type()
|
||||
} else {
|
||||
// Unrecognized shapes, skip?
|
||||
base.WarnfAt(n.Pos(), "unrecognized shape for assign list stmt for blank assignment")
|
||||
continue
|
||||
}
|
||||
tmp := typecheck.TempAt(n.Pos(), curFn, typ)
|
||||
n.Lhs[i] = tmp
|
||||
n.PtrInit().Append(typecheck.Stmt(ir.NewDecl(n.Pos(), ir.ODCL, tmp)))
|
||||
hasBlank = true
|
||||
}
|
||||
ns = append(ns, getKeepAliveNodes(n.Pos(), n.Lhs[i])...)
|
||||
}
|
||||
if hasBlank {
|
||||
// blank nodes are rewritten to temps, we need to typecheck the node again.
|
||||
n.Def = true
|
||||
stmt = typecheck.AssignExpr(n)
|
||||
n = stmt.(*ir.AssignListStmt)
|
||||
}
|
||||
return keepAliveAt(ns, n)
|
||||
case *ir.AssignOpStmt:
|
||||
|
||||
@@ -15,6 +15,10 @@ func caninline(x int) int { // ERROR "can inline caninline"
|
||||
return x
|
||||
}
|
||||
|
||||
func caninlineMulti(x int) (int, int) { // ERROR "can inline caninlineMulti"
|
||||
return x, x
|
||||
}
|
||||
|
||||
var something int
|
||||
|
||||
func caninlineNoRet(x int) { // ERROR "can inline caninlineNoRet"
|
||||
@@ -56,6 +60,13 @@ func test(b *testing.B, localsink, cond int) { // ERROR ".*"
|
||||
caninline(1) // ERROR "inlining call to caninline" "function result will be kept alive"
|
||||
}
|
||||
|
||||
_ = caninline(1) // ERROR "inlining call to caninline" ".*autotmp.* will be kept alive"
|
||||
|
||||
// An assign list stmt with a single rhs expression returning multiple values via a tuple.
|
||||
_, _ = caninlineMulti(1) // ERROR "inlining call to caninlineMulti" ".*autotmp.* will be kept alive"
|
||||
// An assign list stmt with multiple rhs expressions.
|
||||
_, _ = caninline(1), caninline(2) // ERROR "inlining call to caninline" ".*autotmp.* will be kept alive"
|
||||
|
||||
receiver(argument) // ERROR inlining call to receiver" "function arg will be kept alive"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user