mirror of
https://github.com/golang/go
synced 2024-11-22 14:34:45 -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:
parent
88e1415d08
commit
0328c3b660
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user