1
0
mirror of https://github.com/golang/go synced 2024-11-22 18:44:54 -07:00

[dev.regabi] cmd/compile: use OSELRECV2 for all <-c variants

OSELRECV2 can represent all possible receive clauses that can appear
in a select statement, and it simplifies later code, so use it instead.

Follow up CL will remove OSELRECV.

Passes buildall w/ toolstash -cmp.

Change-Id: Ibbdae45287ffd888acd8dc89ca8d99e454277cd1
Reviewed-on: https://go-review.googlesource.com/c/go/+/275458
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
Cuong Manh Le 2020-12-07 03:24:04 +07:00
parent 88e1415d08
commit 0328c3b660
3 changed files with 61 additions and 133 deletions

View File

@ -399,9 +399,6 @@ func (e *Escape) stmt(n ir.Node) {
e.stmt(cas.Left())
e.block(cas.Body())
}
case ir.OSELRECV:
n := n.(*ir.AssignStmt)
e.assign(n.Left(), n.Right(), "selrecv", n)
case ir.OSELRECV2:
n := n.(*ir.AssignListStmt)
e.assign(n.List().First(), n.Rlist().First(), "selrecv", n)

View File

@ -872,15 +872,14 @@ func (o *Order) stmt(n ir.Node) {
// give this away).
case ir.OSELECT:
t := o.markTemp()
for _, cas := range n.List().Slice() {
cas := cas.(*ir.CaseStmt)
r := cas.Left()
setlineno(cas)
for _, ncas := range n.List().Slice() {
ncas := ncas.(*ir.CaseStmt)
r := ncas.Left()
setlineno(ncas)
// Append any new body prologue to ninit.
// The next loop will insert ninit into nbody.
if cas.Init().Len() != 0 {
if ncas.Init().Len() != 0 {
base.Fatalf("order select ninit")
}
if r == nil {
@ -891,84 +890,48 @@ func (o *Order) stmt(n ir.Node) {
ir.Dump("select case", r)
base.Fatalf("unknown op in select %v", r.Op())
case ir.OSELRECV, ir.OSELRECV2:
var dst, ok ir.Node
var recv *ir.UnaryExpr
var def bool
if r.Op() == ir.OSELRECV {
// case x = <-c
// case <-c (dst is ir.BlankNode)
def, dst, ok, recv = r.Colas(), r.Left(), ir.BlankNode, r.Right().(*ir.UnaryExpr)
} else {
r := r.(*ir.AssignListStmt)
// case x, ok = <-c
def, dst, ok, recv = r.Colas(), r.List().First(), r.List().Second(), r.Rlist().First().(*ir.UnaryExpr)
}
// If this is case x := <-ch or case x, y := <-ch, the case has
// the ODCL nodes to declare x and y. We want to delay that
// declaration (and possible allocation) until inside the case body.
// Delete the ODCL nodes here and recreate them inside the body below.
if def {
init := r.Init().Slice()
if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).Left() == dst {
init = init[1:]
}
if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).Left() == ok {
init = init[1:]
}
r.PtrInit().Set(init)
}
if r.Init().Len() != 0 {
ir.DumpList("ninit", r.Init())
base.Fatalf("ninit on select recv")
}
case ir.OSELRECV2:
// case x, ok = <-c
recv := r.Rlist().First().(*ir.UnaryExpr)
recv.SetLeft(o.expr(recv.Left(), nil))
if recv.Left().Op() != ir.ONAME {
recv.SetLeft(o.copyExpr(recv.Left()))
}
r := r.(*ir.AssignListStmt)
init := r.PtrInit().Slice()
r.PtrInit().Set(nil)
// Introduce temporary for receive and move actual copy into case body.
// avoids problems with target being addressed, as usual.
// NOTE: If we wanted to be clever, we could arrange for just one
// temporary per distinct type, sharing the temp among all receives
// with that temp. Similarly one ok bool could be shared among all
// the x,ok receives. Not worth doing until there's a clear need.
if !ir.IsBlank(dst) {
// use channel element type for temporary to avoid conversions,
// such as in case interfacevalue = <-intchan.
// the conversion happens in the OAS instead.
if def {
dcl := ir.Nod(ir.ODCL, dst, nil)
cas.PtrInit().Append(typecheck(dcl, ctxStmt))
colas := r.Colas()
do := func(i int, t *types.Type) {
n := r.List().Index(i)
if ir.IsBlank(n) {
return
}
tmp := o.newTemp(recv.Left().Type().Elem(), recv.Left().Type().Elem().HasPointers())
as := ir.Nod(ir.OAS, dst, tmp)
cas.PtrInit().Append(typecheck(as, ctxStmt))
dst = tmp
}
if !ir.IsBlank(ok) {
if def {
dcl := ir.Nod(ir.ODCL, ok, nil)
cas.PtrInit().Append(typecheck(dcl, ctxStmt))
// If this is case x := <-ch or case x, y := <-ch, the case has
// the ODCL nodes to declare x and y. We want to delay that
// declaration (and possible allocation) until inside the case body.
// Delete the ODCL nodes here and recreate them inside the body below.
if colas {
if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).Left() == n {
init = init[1:]
}
dcl := ir.Nod(ir.ODCL, n, nil)
dcl = typecheck(dcl, ctxStmt)
ncas.PtrInit().Append(dcl)
}
tmp := o.newTemp(types.Types[types.TBOOL], false)
as := ir.Nod(ir.OAS, ok, conv(tmp, ok.Type()))
cas.PtrInit().Append(typecheck(as, ctxStmt))
ok = tmp
tmp := o.newTemp(t, t.HasPointers())
as := ir.Nod(ir.OAS, n, conv(tmp, n.Type()))
as = typecheck(as, ctxStmt)
ncas.PtrInit().Append(as)
r.PtrList().SetIndex(i, tmp)
}
if r.Op() == ir.OSELRECV {
r.SetLeft(dst)
} else {
r := r.(*ir.AssignListStmt)
r.List().SetIndex(0, dst)
r.List().SetIndex(1, ok)
do(0, recv.Left().Type().Elem())
do(1, types.Types[types.TBOOL])
if len(init) != 0 {
ir.DumpList("ninit", r.Init())
base.Fatalf("ninit on select recv")
}
orderBlock(cas.PtrInit(), o.free)
orderBlock(ncas.PtrInit(), o.free)
case ir.OSEND:
if r.Init().Len() != 0 {

View File

@ -32,6 +32,14 @@ func typecheckselect(sel *ir.SelectStmt) {
n := ncase.List().First()
ncase.SetLeft(n)
ncase.PtrList().Set(nil)
oselrecv2 := func(dst, recv ir.Node, colas bool) {
n := ir.NodAt(n.Pos(), ir.OSELRECV2, nil, nil)
n.PtrList().Set2(dst, ir.BlankNode)
n.PtrRlist().Set1(recv)
n.SetColas(colas)
n.SetTypecheck(1)
ncase.SetLeft(n)
}
switch n.Op() {
default:
pos := n.Pos()
@ -45,7 +53,7 @@ func typecheckselect(sel *ir.SelectStmt) {
base.ErrorfAt(pos, "select case must be receive, send or assign recv")
case ir.OAS:
// convert x = <-c into OSELRECV(x, <-c).
// convert x = <-c into x, _ = <-c
// remove implicit conversions; the eventual assignment
// will reintroduce them.
if r := n.Right(); r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
@ -57,10 +65,9 @@ func typecheckselect(sel *ir.SelectStmt) {
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
break
}
n.SetOp(ir.OSELRECV)
oselrecv2(n.Left(), n.Right(), n.Colas())
case ir.OAS2RECV:
// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
if n.Rlist().First().Op() != ir.ORECV {
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
break
@ -68,12 +75,8 @@ func typecheckselect(sel *ir.SelectStmt) {
n.SetOp(ir.OSELRECV2)
case ir.ORECV:
// convert <-c into OSELRECV(_, <-c)
as := ir.NewAssignStmt(n.Pos(), ir.BlankNode, n)
as.SetOp(ir.OSELRECV)
as.SetTypecheck(1)
n = as
ncase.SetLeft(n)
// convert <-c into _, _ = <-c
oselrecv2(ir.BlankNode, n, false)
case ir.OSEND:
break
@ -129,14 +132,6 @@ func walkselectcases(cases ir.Nodes) []ir.Node {
case ir.OSEND:
// already ok
case ir.OSELRECV:
r := n.(*ir.AssignStmt)
if ir.IsBlank(r.Left()) {
n = r.Right()
break
}
r.SetOp(ir.OAS)
case ir.OSELRECV2:
r := n.(*ir.AssignListStmt)
if ir.IsBlank(r.List().First()) && ir.IsBlank(r.List().Second()) {
@ -165,29 +160,11 @@ func walkselectcases(cases ir.Nodes) []ir.Node {
dflt = cas
continue
}
// Lower x, _ = <-c to x = <-c.
if sel := n; sel.Op() == ir.OSELRECV2 {
if ir.IsBlank(sel.List().Second()) {
as := ir.NewAssignStmt(sel.Pos(), sel.List().First(), sel.Rlist().First())
as.SetOp(ir.OSELRECV)
as.SetTypecheck(1)
n = as
cas.SetLeft(n)
}
}
switch n.Op() {
case ir.OSEND:
n.SetRight(nodAddr(n.Right()))
n.SetRight(typecheck(n.Right(), ctxExpr))
case ir.OSELRECV:
if !ir.IsBlank(n.Left()) {
n.SetLeft(nodAddr(n.Left()))
n.SetLeft(typecheck(n.Left(), ctxExpr))
}
case ir.OSELRECV2:
if !ir.IsBlank(n.List().First()) {
n.List().SetIndex(0, nodAddr(n.List().First()))
@ -217,26 +194,23 @@ func walkselectcases(cases ir.Nodes) []ir.Node {
ch := n.Left()
call = mkcall1(chanfn("selectnbsend", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), ch, n.Right())
case ir.OSELRECV:
// if selectnbrecv(&v, c) { body } else { default body }
recv := n.Right().(*ir.UnaryExpr)
ch := recv.Left()
elem := n.Left()
if ir.IsBlank(elem) {
elem = nodnil()
}
call = mkcall1(chanfn("selectnbrecv", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, ch)
case ir.OSELRECV2:
// if selectnbrecv2(&v, &received, c) { body } else { default body }
recv := n.Rlist().First().(*ir.UnaryExpr)
ch := recv.Left()
elem := n.List().First()
if ir.IsBlank(elem) {
elem = nodnil()
}
receivedp := typecheck(nodAddr(n.List().Second()), ctxExpr)
call = mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch)
if ir.IsBlank(n.List().Second()) {
// if selectnbrecv(&v, c) { body } else { default body }
call = mkcall1(chanfn("selectnbrecv", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, ch)
} else {
// TODO(cuonglm): make this use selectnbrecv()
// if selectnbrecv2(&v, &received, c) { body } else { default body }
receivedp := ir.Nod(ir.OADDR, n.List().Second(), nil)
receivedp = typecheck(receivedp, ctxExpr)
call = mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch)
}
}
r.SetLeft(typecheck(call, ctxExpr))
@ -292,12 +266,6 @@ func walkselectcases(cases ir.Nodes) []ir.Node {
nsends++
c = n.Left()
elem = n.Right()
case ir.OSELRECV:
nrecvs++
i = ncas - nrecvs
recv := n.Right().(*ir.UnaryExpr)
c = recv.Left()
elem = n.Left()
case ir.OSELRECV2:
nrecvs++
i = ncas - nrecvs
@ -355,7 +323,7 @@ func walkselectcases(cases ir.Nodes) []ir.Node {
r := ir.Nod(ir.OIF, cond, nil)
if n := cas.Left(); n != nil && n.Op() == ir.OSELRECV2 {
if n := cas.Left(); n != nil && n.Op() == ir.OSELRECV2 && !ir.IsBlank(n.List().Second()) {
x := ir.Nod(ir.OAS, n.List().Second(), recvOK)
r.PtrBody().Append(typecheck(x, ctxStmt))
}