diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/select.go')
-rw-r--r-- | src/cmd/compile/internal/gc/select.go | 326 |
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) } |