aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/gc/select.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/gc/select.go')
-rw-r--r--src/cmd/compile/internal/gc/select.go326
1 files changed, 165 insertions, 161 deletions
diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
index 97e0424ce0..116b6f5b6e 100644
--- a/src/cmd/compile/internal/gc/select.go
+++ b/src/cmd/compile/internal/gc/select.go
@@ -4,152 +4,156 @@
package gc
-import "cmd/compile/internal/types"
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+)
// select
-func typecheckselect(sel *Node) {
- var def *Node
+func typecheckselect(sel ir.Node) {
+ var def ir.Node
lno := setlineno(sel)
- typecheckslice(sel.Ninit.Slice(), ctxStmt)
- for _, ncase := range sel.List.Slice() {
- if ncase.Op != OCASE {
+ typecheckslice(sel.Init().Slice(), ctxStmt)
+ for _, ncase := range sel.List().Slice() {
+ if ncase.Op() != ir.OCASE {
setlineno(ncase)
- Fatalf("typecheckselect %v", ncase.Op)
+ base.Fatalf("typecheckselect %v", ncase.Op())
}
- if ncase.List.Len() == 0 {
+ if ncase.List().Len() == 0 {
// default
if def != nil {
- yyerrorl(ncase.Pos, "multiple defaults in select (first at %v)", def.Line())
+ base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def))
} else {
def = ncase
}
- } else if ncase.List.Len() > 1 {
- yyerrorl(ncase.Pos, "select cases cannot be lists")
+ } else if ncase.List().Len() > 1 {
+ base.ErrorfAt(ncase.Pos(), "select cases cannot be lists")
} else {
- ncase.List.SetFirst(typecheck(ncase.List.First(), ctxStmt))
- n := ncase.List.First()
- ncase.Left = n
- ncase.List.Set(nil)
- switch n.Op {
+ ncase.List().SetFirst(typecheck(ncase.List().First(), ctxStmt))
+ n := ncase.List().First()
+ ncase.SetLeft(n)
+ ncase.PtrList().Set(nil)
+ switch n.Op() {
default:
- pos := n.Pos
- if n.Op == ONAME {
+ pos := n.Pos()
+ if n.Op() == ir.ONAME {
// We don't have the right position for ONAME nodes (see #15459 and
// others). Using ncase.Pos for now as it will provide the correct
// line number (assuming the expression follows the "case" keyword
// on the same line). This matches the approach before 1.10.
- pos = ncase.Pos
+ pos = ncase.Pos()
}
- yyerrorl(pos, "select case must be receive, send or assign recv")
+ base.ErrorfAt(pos, "select case must be receive, send or assign recv")
// convert x = <-c into OSELRECV(x, <-c).
// remove implicit conversions; the eventual assignment
// will reintroduce them.
- case OAS:
- if (n.Right.Op == OCONVNOP || n.Right.Op == OCONVIFACE) && n.Right.Implicit() {
- n.Right = n.Right.Left
+ case ir.OAS:
+ if (n.Right().Op() == ir.OCONVNOP || n.Right().Op() == ir.OCONVIFACE) && n.Right().Implicit() {
+ n.SetRight(n.Right().Left())
}
- if n.Right.Op != ORECV {
- yyerrorl(n.Pos, "select assignment must have receive on right hand side")
+ if n.Right().Op() != ir.ORECV {
+ base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
break
}
- n.Op = OSELRECV
+ n.SetOp(ir.OSELRECV)
// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
- case OAS2RECV:
- if n.Right.Op != ORECV {
- yyerrorl(n.Pos, "select assignment must have receive on right hand side")
+ case ir.OAS2RECV:
+ if n.Right().Op() != ir.ORECV {
+ base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
break
}
- n.Op = OSELRECV2
- n.Left = n.List.First()
- n.List.Set1(n.List.Second())
+ n.SetOp(ir.OSELRECV2)
+ n.SetLeft(n.List().First())
+ n.PtrList().Set1(n.List().Second())
// convert <-c into OSELRECV(N, <-c)
- case ORECV:
- n = nodl(n.Pos, OSELRECV, nil, n)
+ case ir.ORECV:
+ n = ir.NodAt(n.Pos(), ir.OSELRECV, nil, n)
n.SetTypecheck(1)
- ncase.Left = n
+ ncase.SetLeft(n)
- case OSEND:
+ case ir.OSEND:
break
}
}
- typecheckslice(ncase.Nbody.Slice(), ctxStmt)
+ typecheckslice(ncase.Body().Slice(), ctxStmt)
}
- lineno = lno
+ base.Pos = lno
}
-func walkselect(sel *Node) {
+func walkselect(sel ir.Node) {
lno := setlineno(sel)
- if sel.Nbody.Len() != 0 {
- Fatalf("double walkselect")
+ if sel.Body().Len() != 0 {
+ base.Fatalf("double walkselect")
}
- init := sel.Ninit.Slice()
- sel.Ninit.Set(nil)
+ init := sel.Init().Slice()
+ sel.PtrInit().Set(nil)
- init = append(init, walkselectcases(&sel.List)...)
- sel.List.Set(nil)
+ init = append(init, walkselectcases(sel.PtrList())...)
+ sel.PtrList().Set(nil)
- sel.Nbody.Set(init)
- walkstmtlist(sel.Nbody.Slice())
+ sel.PtrBody().Set(init)
+ walkstmtlist(sel.Body().Slice())
- lineno = lno
+ base.Pos = lno
}
-func walkselectcases(cases *Nodes) []*Node {
+func walkselectcases(cases *ir.Nodes) []ir.Node {
ncas := cases.Len()
- sellineno := lineno
+ sellineno := base.Pos
// optimization: zero-case select
if ncas == 0 {
- return []*Node{mkcall("block", nil, nil)}
+ return []ir.Node{mkcall("block", nil, nil)}
}
// optimization: one-case select: single op.
if ncas == 1 {
cas := cases.First()
setlineno(cas)
- l := cas.Ninit.Slice()
- if cas.Left != nil { // not default:
- n := cas.Left
- l = append(l, n.Ninit.Slice()...)
- n.Ninit.Set(nil)
- switch n.Op {
+ l := cas.Init().Slice()
+ if cas.Left() != nil { // not default:
+ n := cas.Left()
+ l = append(l, n.Init().Slice()...)
+ n.PtrInit().Set(nil)
+ switch n.Op() {
default:
- Fatalf("select %v", n.Op)
+ base.Fatalf("select %v", n.Op())
- case OSEND:
+ case ir.OSEND:
// already ok
- case OSELRECV, OSELRECV2:
- if n.Op == OSELRECV || n.List.Len() == 0 {
- if n.Left == nil {
- n = n.Right
+ case ir.OSELRECV, ir.OSELRECV2:
+ if n.Op() == ir.OSELRECV || n.List().Len() == 0 {
+ if n.Left() == nil {
+ n = n.Right()
} else {
- n.Op = OAS
+ n.SetOp(ir.OAS)
}
break
}
- if n.Left == nil {
- nblank = typecheck(nblank, ctxExpr|ctxAssign)
- n.Left = nblank
+ if n.Left() == nil {
+ ir.BlankNode = typecheck(ir.BlankNode, ctxExpr|ctxAssign)
+ n.SetLeft(ir.BlankNode)
}
- n.Op = OAS2
- n.List.Prepend(n.Left)
- n.Rlist.Set1(n.Right)
- n.Right = nil
- n.Left = nil
+ n.SetOp(ir.OAS2)
+ n.PtrList().Prepend(n.Left())
+ n.PtrRlist().Set1(n.Right())
+ n.SetRight(nil)
+ n.SetLeft(nil)
n.SetTypecheck(0)
n = typecheck(n, ctxStmt)
}
@@ -157,34 +161,34 @@ func walkselectcases(cases *Nodes) []*Node {
l = append(l, n)
}
- l = append(l, cas.Nbody.Slice()...)
- l = append(l, nod(OBREAK, nil, nil))
+ l = append(l, cas.Body().Slice()...)
+ l = append(l, ir.Nod(ir.OBREAK, nil, nil))
return l
}
// convert case value arguments to addresses.
// this rewrite is used by both the general code and the next optimization.
- var dflt *Node
+ var dflt ir.Node
for _, cas := range cases.Slice() {
setlineno(cas)
- n := cas.Left
+ n := cas.Left()
if n == nil {
dflt = cas
continue
}
- switch n.Op {
- case OSEND:
- n.Right = nod(OADDR, n.Right, nil)
- n.Right = typecheck(n.Right, ctxExpr)
-
- case OSELRECV, OSELRECV2:
- if n.Op == OSELRECV2 && n.List.Len() == 0 {
- n.Op = OSELRECV
+ switch n.Op() {
+ case ir.OSEND:
+ n.SetRight(ir.Nod(ir.OADDR, n.Right(), nil))
+ n.SetRight(typecheck(n.Right(), ctxExpr))
+
+ case ir.OSELRECV, ir.OSELRECV2:
+ if n.Op() == ir.OSELRECV2 && n.List().Len() == 0 {
+ n.SetOp(ir.OSELRECV)
}
- if n.Left != nil {
- n.Left = nod(OADDR, n.Left, nil)
- n.Left = typecheck(n.Left, ctxExpr)
+ if n.Left() != nil {
+ n.SetLeft(ir.Nod(ir.OADDR, n.Left(), nil))
+ n.SetLeft(typecheck(n.Left(), ctxExpr))
}
}
}
@@ -196,68 +200,68 @@ func walkselectcases(cases *Nodes) []*Node {
cas = cases.Second()
}
- n := cas.Left
+ n := cas.Left()
setlineno(n)
- r := nod(OIF, nil, nil)
- r.Ninit.Set(cas.Ninit.Slice())
- switch n.Op {
+ r := ir.Nod(ir.OIF, nil, nil)
+ r.PtrInit().Set(cas.Init().Slice())
+ switch n.Op() {
default:
- Fatalf("select %v", n.Op)
+ base.Fatalf("select %v", n.Op())
- case OSEND:
+ case ir.OSEND:
// if selectnbsend(c, v) { body } else { default body }
- ch := n.Left
- r.Left = mkcall1(chanfn("selectnbsend", 2, ch.Type), types.Types[TBOOL], &r.Ninit, ch, n.Right)
+ ch := n.Left()
+ r.SetLeft(mkcall1(chanfn("selectnbsend", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), ch, n.Right()))
- case OSELRECV:
+ case ir.OSELRECV:
// if selectnbrecv(&v, c) { body } else { default body }
- ch := n.Right.Left
- elem := n.Left
+ ch := n.Right().Left()
+ elem := n.Left()
if elem == nil {
elem = nodnil()
}
- r.Left = mkcall1(chanfn("selectnbrecv", 2, ch.Type), types.Types[TBOOL], &r.Ninit, elem, ch)
+ r.SetLeft(mkcall1(chanfn("selectnbrecv", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, ch))
- case OSELRECV2:
+ case ir.OSELRECV2:
// if selectnbrecv2(&v, &received, c) { body } else { default body }
- ch := n.Right.Left
- elem := n.Left
+ ch := n.Right().Left()
+ elem := n.Left()
if elem == nil {
elem = nodnil()
}
- receivedp := nod(OADDR, n.List.First(), nil)
+ receivedp := ir.Nod(ir.OADDR, n.List().First(), nil)
receivedp = typecheck(receivedp, ctxExpr)
- r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), types.Types[TBOOL], &r.Ninit, elem, receivedp, ch)
+ r.SetLeft(mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch))
}
- r.Left = typecheck(r.Left, ctxExpr)
- r.Nbody.Set(cas.Nbody.Slice())
- r.Rlist.Set(append(dflt.Ninit.Slice(), dflt.Nbody.Slice()...))
- return []*Node{r, nod(OBREAK, nil, nil)}
+ r.SetLeft(typecheck(r.Left(), ctxExpr))
+ r.PtrBody().Set(cas.Body().Slice())
+ r.PtrRlist().Set(append(dflt.Init().Slice(), dflt.Body().Slice()...))
+ return []ir.Node{r, ir.Nod(ir.OBREAK, nil, nil)}
}
if dflt != nil {
ncas--
}
- casorder := make([]*Node, ncas)
+ casorder := make([]ir.Node, ncas)
nsends, nrecvs := 0, 0
- var init []*Node
+ var init []ir.Node
// generate sel-struct
- lineno = sellineno
+ base.Pos = sellineno
selv := temp(types.NewArray(scasetype(), int64(ncas)))
- r := nod(OAS, selv, nil)
+ r := ir.Nod(ir.OAS, selv, nil)
r = typecheck(r, ctxStmt)
init = append(init, r)
// No initialization for order; runtime.selectgo is responsible for that.
- order := temp(types.NewArray(types.Types[TUINT16], 2*int64(ncas)))
+ order := temp(types.NewArray(types.Types[types.TUINT16], 2*int64(ncas)))
- var pc0, pcs *Node
- if flag_race {
- pcs = temp(types.NewArray(types.Types[TUINTPTR], int64(ncas)))
- pc0 = typecheck(nod(OADDR, nod(OINDEX, pcs, nodintconst(0)), nil), ctxExpr)
+ var pc0, pcs ir.Node
+ if base.Flag.Race {
+ pcs = temp(types.NewArray(types.Types[types.TUINTPTR], int64(ncas)))
+ pc0 = typecheck(ir.Nod(ir.OADDR, ir.Nod(ir.OINDEX, pcs, nodintconst(0)), nil), ctxExpr)
} else {
pc0 = nodnil()
}
@@ -266,109 +270,109 @@ func walkselectcases(cases *Nodes) []*Node {
for _, cas := range cases.Slice() {
setlineno(cas)
- init = append(init, cas.Ninit.Slice()...)
- cas.Ninit.Set(nil)
+ init = append(init, cas.Init().Slice()...)
+ cas.PtrInit().Set(nil)
- n := cas.Left
+ n := cas.Left()
if n == nil { // default:
continue
}
var i int
- var c, elem *Node
- switch n.Op {
+ var c, elem ir.Node
+ switch n.Op() {
default:
- Fatalf("select %v", n.Op)
- case OSEND:
+ base.Fatalf("select %v", n.Op())
+ case ir.OSEND:
i = nsends
nsends++
- c = n.Left
- elem = n.Right
- case OSELRECV, OSELRECV2:
+ c = n.Left()
+ elem = n.Right()
+ case ir.OSELRECV, ir.OSELRECV2:
nrecvs++
i = ncas - nrecvs
- c = n.Right.Left
- elem = n.Left
+ c = n.Right().Left()
+ elem = n.Left()
}
casorder[i] = cas
- setField := func(f string, val *Node) {
- r := nod(OAS, nodSym(ODOT, nod(OINDEX, selv, nodintconst(int64(i))), lookup(f)), val)
+ setField := func(f string, val ir.Node) {
+ r := ir.Nod(ir.OAS, nodSym(ir.ODOT, ir.Nod(ir.OINDEX, selv, nodintconst(int64(i))), lookup(f)), val)
r = typecheck(r, ctxStmt)
init = append(init, r)
}
- c = convnop(c, types.Types[TUNSAFEPTR])
+ c = convnop(c, types.Types[types.TUNSAFEPTR])
setField("c", c)
if elem != nil {
- elem = convnop(elem, types.Types[TUNSAFEPTR])
+ elem = convnop(elem, types.Types[types.TUNSAFEPTR])
setField("elem", elem)
}
// TODO(mdempsky): There should be a cleaner way to
// handle this.
- if flag_race {
- r = mkcall("selectsetpc", nil, nil, nod(OADDR, nod(OINDEX, pcs, nodintconst(int64(i))), nil))
+ if base.Flag.Race {
+ r = mkcall("selectsetpc", nil, nil, ir.Nod(ir.OADDR, ir.Nod(ir.OINDEX, pcs, nodintconst(int64(i))), nil))
init = append(init, r)
}
}
if nsends+nrecvs != ncas {
- Fatalf("walkselectcases: miscount: %v + %v != %v", nsends, nrecvs, ncas)
+ base.Fatalf("walkselectcases: miscount: %v + %v != %v", nsends, nrecvs, ncas)
}
// run the select
- lineno = sellineno
- chosen := temp(types.Types[TINT])
- recvOK := temp(types.Types[TBOOL])
- r = nod(OAS2, nil, nil)
- r.List.Set2(chosen, recvOK)
+ base.Pos = sellineno
+ chosen := temp(types.Types[types.TINT])
+ recvOK := temp(types.Types[types.TBOOL])
+ r = ir.Nod(ir.OAS2, nil, nil)
+ r.PtrList().Set2(chosen, recvOK)
fn := syslook("selectgo")
- r.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), pc0, nodintconst(int64(nsends)), nodintconst(int64(nrecvs)), nodbool(dflt == nil)))
+ r.PtrRlist().Set1(mkcall1(fn, fn.Type().Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), pc0, nodintconst(int64(nsends)), nodintconst(int64(nrecvs)), nodbool(dflt == nil)))
r = typecheck(r, ctxStmt)
init = append(init, r)
// selv and order are no longer alive after selectgo.
- init = append(init, nod(OVARKILL, selv, nil))
- init = append(init, nod(OVARKILL, order, nil))
- if flag_race {
- init = append(init, nod(OVARKILL, pcs, nil))
+ init = append(init, ir.Nod(ir.OVARKILL, selv, nil))
+ init = append(init, ir.Nod(ir.OVARKILL, order, nil))
+ if base.Flag.Race {
+ init = append(init, ir.Nod(ir.OVARKILL, pcs, nil))
}
// dispatch cases
- dispatch := func(cond, cas *Node) {
+ dispatch := func(cond, cas ir.Node) {
cond = typecheck(cond, ctxExpr)
cond = defaultlit(cond, nil)
- r := nod(OIF, cond, nil)
+ r := ir.Nod(ir.OIF, cond, nil)
- if n := cas.Left; n != nil && n.Op == OSELRECV2 {
- x := nod(OAS, n.List.First(), recvOK)
+ if n := cas.Left(); n != nil && n.Op() == ir.OSELRECV2 {
+ x := ir.Nod(ir.OAS, n.List().First(), recvOK)
x = typecheck(x, ctxStmt)
- r.Nbody.Append(x)
+ r.PtrBody().Append(x)
}
- r.Nbody.AppendNodes(&cas.Nbody)
- r.Nbody.Append(nod(OBREAK, nil, nil))
+ r.PtrBody().AppendNodes(cas.PtrBody())
+ r.PtrBody().Append(ir.Nod(ir.OBREAK, nil, nil))
init = append(init, r)
}
if dflt != nil {
setlineno(dflt)
- dispatch(nod(OLT, chosen, nodintconst(0)), dflt)
+ dispatch(ir.Nod(ir.OLT, chosen, nodintconst(0)), dflt)
}
for i, cas := range casorder {
setlineno(cas)
- dispatch(nod(OEQ, chosen, nodintconst(int64(i))), cas)
+ dispatch(ir.Nod(ir.OEQ, chosen, nodintconst(int64(i))), cas)
}
return init
}
// bytePtrToIndex returns a Node representing "(*byte)(&n[i])".
-func bytePtrToIndex(n *Node, i int64) *Node {
- s := nod(OADDR, nod(OINDEX, n, nodintconst(i)), nil)
- t := types.NewPtr(types.Types[TUINT8])
+func bytePtrToIndex(n ir.Node, i int64) ir.Node {
+ s := ir.Nod(ir.OADDR, ir.Nod(ir.OINDEX, n, nodintconst(i)), nil)
+ t := types.NewPtr(types.Types[types.TUINT8])
return convnop(s, t)
}
@@ -377,9 +381,9 @@ var scase *types.Type
// Keep in sync with src/runtime/select.go.
func scasetype() *types.Type {
if scase == nil {
- scase = tostruct([]*Node{
- namedfield("c", types.Types[TUNSAFEPTR]),
- namedfield("elem", types.Types[TUNSAFEPTR]),
+ scase = tostruct([]ir.Node{
+ namedfield("c", types.Types[types.TUNSAFEPTR]),
+ namedfield("elem", types.Types[types.TUNSAFEPTR]),
})
scase.SetNoalg(true)
}