Skip to content

Commit

Permalink
runtime: eliminate runtime.hselect
Browse files Browse the repository at this point in the history
Now the registration phase looks like:

    var cases [4]runtime.scases
    var order [8]uint16
    selectsend(&cases[0], c1, &v1)
    selectrecv(&cases[1], c2, &v2, nil)
    selectrecv(&cases[2], c3, &v3, &ok)
    selectdefault(&cases[3])
    chosen := selectgo(&cases[0], &order[0], 4)

Primarily, this is just preparation for having the compiler open-code
selectsend, selectrecv, and selectdefault.

As a minor benefit, order can now be layed out separately on the stack
in the pointer-free segment, so it won't take up space in the
function's stack pointer maps.

Change-Id: I5552ba594201efd31fcb40084da20b42ea569a45
Reviewed-on: https://go-review.googlesource.com/37933
Run-TryBot: Matthew Dempsky <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Austin Clements <[email protected]>
  • Loading branch information
mdempsky committed May 1, 2018
1 parent a4aa2e0 commit 3aa53b3
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 204 deletions.
114 changes: 56 additions & 58 deletions src/cmd/compile/internal/gc/builtin.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 4 additions & 5 deletions src/cmd/compile/internal/gc/builtin/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,10 @@ func selectnbsend(hchan chan<- any, elem *any) bool
func selectnbrecv(elem *any, hchan <-chan any) bool
func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool

func newselect(sel *byte, selsize int64, size int32)
func selectsend(sel *byte, hchan chan<- any, elem *any)
func selectrecv(sel *byte, hchan <-chan any, elem *any, received *bool)
func selectdefault(sel *byte)
func selectgo(sel *byte) int
func selectsend(cas *byte, hchan chan<- any, elem *any)
func selectrecv(cas *byte, hchan <-chan any, elem *any, received *bool)
func selectdefault(cas *byte)
func selectgo(cas0 *byte, order0 *byte, ncases int) int
func block()

func makeslice(typ *byte, len int, cap int) (ary []any)
Expand Down
1 change: 0 additions & 1 deletion src/cmd/compile/internal/gc/inl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ func TestIntendedInlining(t *testing.T) {
"releasem",
"round",
"roundupsize",
"selectsize",
"stringStructOf",
"subtract1",
"subtractb",
Expand Down
81 changes: 41 additions & 40 deletions src/cmd/compile/internal/gc/select.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,22 +251,25 @@ func walkselectcases(cases *Nodes) []*Node {

// generate sel-struct
lineno = sellineno
selv := temp(selecttype(int64(n)))
selv := temp(types.NewArray(scasetype(), int64(n)))
r := nod(OAS, selv, nil)
r = typecheck(r, Etop)
init = append(init, r)
var_ := conv(conv(nod(OADDR, selv, nil), types.Types[TUNSAFEPTR]), types.NewPtr(types.Types[TUINT8]))
r = mkcall("newselect", nil, nil, var_, nodintconst(selv.Type.Width), nodintconst(int64(n)))

order := temp(types.NewArray(types.Types[TUINT16], 2*int64(n)))
r = nod(OAS, order, nil)
r = typecheck(r, Etop)
init = append(init, r)

// register cases
for _, cas := range cases.Slice() {
for i, cas := range cases.Slice() {
setlineno(cas)

init = append(init, cas.Ninit.Slice()...)
cas.Ninit.Set(nil)

s := bytePtrToIndex(selv, int64(i))

var x *Node
if n := cas.Left; n != nil {
init = append(init, n.Ninit.Slice()...)
Expand All @@ -275,18 +278,18 @@ func walkselectcases(cases *Nodes) []*Node {
default:
Fatalf("select %v", n.Op)
case OSEND:
// selectsend(sel *byte, hchan *chan any, elem *any)
x = mkcall1(chanfn("selectsend", 2, n.Left.Type), nil, nil, var_, n.Left, n.Right)
// selectsend(cas *byte, hchan *chan any, elem *any)
x = mkcall1(chanfn("selectsend", 2, n.Left.Type), nil, nil, s, n.Left, n.Right)
case OSELRECV:
// selectrecv(sel *byte, hchan *chan any, elem *any, received *bool)
x = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), nil, nil, var_, n.Right.Left, n.Left, nodnil())
// selectrecv(cas *byte, hchan *chan any, elem *any, received *bool)
x = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), nil, nil, s, n.Right.Left, n.Left, nodnil())
case OSELRECV2:
// selectrecv(sel *byte, hchan *chan any, elem *any, received *bool)
x = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), nil, nil, var_, n.Right.Left, n.Left, n.List.First())
// selectrecv(cas *byte, hchan *chan any, elem *any, received *bool)
x = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), nil, nil, s, n.Right.Left, n.Left, n.List.First())
}
} else {
// selectdefault(sel *byte)
x = mkcall("selectdefault", nil, nil, var_)
// selectdefault(cas *byte)
x = mkcall("selectdefault", nil, nil, s)
}

init = append(init, x)
Expand All @@ -295,12 +298,13 @@ func walkselectcases(cases *Nodes) []*Node {
// run the select
lineno = sellineno
chosen := temp(types.Types[TINT])
r = nod(OAS, chosen, mkcall("selectgo", types.Types[TINT], nil, var_))
r = nod(OAS, chosen, mkcall("selectgo", types.Types[TINT], nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), nodintconst(int64(n))))
r = typecheck(r, Etop)
init = append(init, r)

// selv is no longer alive after selectgo.
// selv and order are no longer alive after selectgo.
init = append(init, nod(OVARKILL, selv, nil))
init = append(init, nod(OVARKILL, order, nil))

// dispatch cases
for i, cas := range cases.Slice() {
Expand All @@ -319,31 +323,28 @@ func walkselectcases(cases *Nodes) []*Node {
return init
}

// bytePtrToIndex returns a Node representing "(*byte)(&n[i])".
func bytePtrToIndex(n *Node, i int64) *Node {
s := nod(OCONVNOP, nod(OADDR, nod(OINDEX, n, nodintconst(i)), nil), nil)
s.Type = types.NewPtr(types.Types[TUINT8])
s = typecheck(s, Erv)
return s
}

var scase *types.Type

// Keep in sync with src/runtime/select.go.
func selecttype(size int64) *types.Type {
// TODO(dvyukov): it's possible to generate Scase only once
// and then cache; and also cache Select per size.

scase := tostruct([]*Node{
namedfield("elem", types.NewPtr(types.Types[TUINT8])),
namedfield("chan", types.NewPtr(types.Types[TUINT8])),
namedfield("pc", types.Types[TUINTPTR]),
namedfield("kind", types.Types[TUINT16]),
namedfield("receivedp", types.NewPtr(types.Types[TUINT8])),
namedfield("releasetime", types.Types[TUINT64]),
})
scase.SetNoalg(true)

sel := tostruct([]*Node{
namedfield("tcase", types.Types[TUINT16]),
namedfield("ncase", types.Types[TUINT16]),
namedfield("pollorder", types.NewPtr(types.Types[TUINT8])),
namedfield("lockorder", types.NewPtr(types.Types[TUINT8])),
namedfield("scase", types.NewArray(scase, size)),
namedfield("lockorderarr", types.NewArray(types.Types[TUINT16], size)),
namedfield("pollorderarr", types.NewArray(types.Types[TUINT16], size)),
})
sel.SetNoalg(true)

return sel
func scasetype() *types.Type {
if scase == nil {
scase = tostruct([]*Node{
namedfield("elem", types.NewPtr(types.Types[TUINT8])),
namedfield("chan", types.NewPtr(types.Types[TUINT8])),
namedfield("pc", types.Types[TUINTPTR]),
namedfield("kind", types.Types[TUINT16]),
namedfield("receivedp", types.NewPtr(types.Types[TUINT8])),
namedfield("releasetime", types.Types[TUINT64]),
})
scase.SetNoalg(true)
}
return scase
}
Loading

0 comments on commit 3aa53b3

Please sign in to comment.