]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: open code select{send,recv,default}
authorMatthew Dempsky <mdempsky@google.com>
Tue, 7 Mar 2017 22:26:27 +0000 (14:26 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Tue, 1 May 2018 03:17:44 +0000 (03:17 +0000)
Registration now looks like:

        var cases [4]runtime.scases
        var order [8]uint16
cases[0].kind = caseSend
cases[0].c = c1
cases[0].elem = &v1
if raceenabled || msanenabled {
selectsetpc(&cases[0])
}
cases[1].kind = caseRecv
cases[1].c = c2
cases[1].elem = &v2
if raceenabled || msanenabled {
selectsetpc(&cases[1])
}
...

Change-Id: Ib9bcf426a4797fe4bfd8152ca9e6e08e39a70b48
Reviewed-on: https://go-review.googlesource.com/37934
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
src/cmd/compile/internal/gc/builtin.go
src/cmd/compile/internal/gc/builtin/runtime.go
src/cmd/compile/internal/gc/select.go
src/cmd/compile/internal/gc/ssa.go
src/runtime/select.go
test/live.go

index fa8ed0aaf014971797a6b460802a8eb529349e84..47f0c38a00dce789bcbb26579739d5cf693babdd 100644 (file)
@@ -111,48 +111,46 @@ var runtimeDecls = [...]struct {
        {"selectnbsend", funcTag, 87},
        {"selectnbrecv", funcTag, 88},
        {"selectnbrecv2", funcTag, 90},
-       {"selectsend", funcTag, 91},
-       {"selectrecv", funcTag, 92},
-       {"selectdefault", funcTag, 55},
-       {"selectgo", funcTag, 93},
+       {"selectsetpc", funcTag, 55},
+       {"selectgo", funcTag, 91},
        {"block", funcTag, 5},
-       {"makeslice", funcTag, 95},
-       {"makeslice64", funcTag, 96},
-       {"growslice", funcTag, 97},
-       {"memmove", funcTag, 98},
-       {"memclrNoHeapPointers", funcTag, 99},
-       {"memclrHasPointers", funcTag, 99},
-       {"memequal", funcTag, 100},
-       {"memequal8", funcTag, 101},
-       {"memequal16", funcTag, 101},
-       {"memequal32", funcTag, 101},
-       {"memequal64", funcTag, 101},
-       {"memequal128", funcTag, 101},
-       {"int64div", funcTag, 102},
-       {"uint64div", funcTag, 103},
-       {"int64mod", funcTag, 102},
-       {"uint64mod", funcTag, 103},
-       {"float64toint64", funcTag, 104},
-       {"float64touint64", funcTag, 105},
-       {"float64touint32", funcTag, 106},
-       {"int64tofloat64", funcTag, 107},
-       {"uint64tofloat64", funcTag, 108},
-       {"uint32tofloat64", funcTag, 109},
-       {"complex128div", funcTag, 110},
-       {"racefuncenter", funcTag, 111},
+       {"makeslice", funcTag, 93},
+       {"makeslice64", funcTag, 94},
+       {"growslice", funcTag, 95},
+       {"memmove", funcTag, 96},
+       {"memclrNoHeapPointers", funcTag, 97},
+       {"memclrHasPointers", funcTag, 97},
+       {"memequal", funcTag, 98},
+       {"memequal8", funcTag, 99},
+       {"memequal16", funcTag, 99},
+       {"memequal32", funcTag, 99},
+       {"memequal64", funcTag, 99},
+       {"memequal128", funcTag, 99},
+       {"int64div", funcTag, 100},
+       {"uint64div", funcTag, 101},
+       {"int64mod", funcTag, 100},
+       {"uint64mod", funcTag, 101},
+       {"float64toint64", funcTag, 102},
+       {"float64touint64", funcTag, 103},
+       {"float64touint32", funcTag, 104},
+       {"int64tofloat64", funcTag, 105},
+       {"uint64tofloat64", funcTag, 106},
+       {"uint32tofloat64", funcTag, 107},
+       {"complex128div", funcTag, 108},
+       {"racefuncenter", funcTag, 109},
        {"racefuncexit", funcTag, 5},
-       {"raceread", funcTag, 111},
-       {"racewrite", funcTag, 111},
-       {"racereadrange", funcTag, 112},
-       {"racewriterange", funcTag, 112},
-       {"msanread", funcTag, 112},
-       {"msanwrite", funcTag, 112},
+       {"raceread", funcTag, 109},
+       {"racewrite", funcTag, 109},
+       {"racereadrange", funcTag, 110},
+       {"racewriterange", funcTag, 110},
+       {"msanread", funcTag, 110},
+       {"msanwrite", funcTag, 110},
        {"support_popcnt", varTag, 11},
        {"support_sse41", varTag, 11},
 }
 
 func runtimeTypes() []*types.Type {
-       var typs [113]*types.Type
+       var typs [111]*types.Type
        typs[0] = types.Bytetype
        typs[1] = types.NewPtr(typs[0])
        typs[2] = types.Types[TANY]
@@ -244,27 +242,25 @@ func runtimeTypes() []*types.Type {
        typs[88] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[77])}, []*Node{anonfield(typs[11])})
        typs[89] = types.NewPtr(typs[11])
        typs[90] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[89]), anonfield(typs[77])}, []*Node{anonfield(typs[11])})
-       typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[80]), anonfield(typs[3])}, nil)
-       typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[77]), anonfield(typs[3]), anonfield(typs[89])}, nil)
-       typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[32])})
-       typs[94] = types.NewSlice(typs[2])
-       typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[94])})
-       typs[96] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[94])})
-       typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[94]), anonfield(typs[32])}, []*Node{anonfield(typs[94])})
-       typs[98] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[48])}, nil)
-       typs[99] = functype(nil, []*Node{anonfield(typs[57]), anonfield(typs[48])}, nil)
-       typs[100] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[48])}, []*Node{anonfield(typs[11])})
-       typs[101] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
-       typs[102] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
-       typs[103] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])})
-       typs[104] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[15])})
-       typs[105] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[17])})
-       typs[106] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[59])})
-       typs[107] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])})
-       typs[108] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])})
-       typs[109] = functype(nil, []*Node{anonfield(typs[59])}, []*Node{anonfield(typs[13])})
-       typs[110] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
-       typs[111] = functype(nil, []*Node{anonfield(typs[48])}, nil)
-       typs[112] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[48])}, nil)
+       typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[32])})
+       typs[92] = types.NewSlice(typs[2])
+       typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[92])})
+       typs[94] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[92])})
+       typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[92]), anonfield(typs[32])}, []*Node{anonfield(typs[92])})
+       typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[48])}, nil)
+       typs[97] = functype(nil, []*Node{anonfield(typs[57]), anonfield(typs[48])}, nil)
+       typs[98] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[48])}, []*Node{anonfield(typs[11])})
+       typs[99] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
+       typs[100] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
+       typs[101] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])})
+       typs[102] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[15])})
+       typs[103] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[17])})
+       typs[104] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[59])})
+       typs[105] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])})
+       typs[106] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])})
+       typs[107] = functype(nil, []*Node{anonfield(typs[59])}, []*Node{anonfield(typs[13])})
+       typs[108] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
+       typs[109] = functype(nil, []*Node{anonfield(typs[48])}, nil)
+       typs[110] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[48])}, nil)
        return typs[:]
 }
index a4c8ce7ff996e8c1c3279cf811d05ad001af20b3..dc0a8b22222403d796237c1f628da1b1f72d92f9 100644 (file)
@@ -145,9 +145,7 @@ 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 selectsend(cas *byte, hchan chan<- any, elem *any)
-func selectrecv(cas *byte, hchan <-chan any, elem *any, received *bool)
-func selectdefault(cas *byte)
+func selectsetpc(cas *byte)
 func selectgo(cas0 *byte, order0 *byte, ncases int) int
 func block()
 
index 0cc286eebd60a65800eed2c763a1e02cbdb30d4c..6663ff6862fe2c3e9532dcd97956963f40e4ea7b 100644 (file)
@@ -192,9 +192,7 @@ func walkselectcases(cases *Nodes) []*Node {
                                n.List.SetFirst(typecheck(n.List.First(), Erv))
                        }
 
-                       if n.Left == nil {
-                               n.Left = nodnil()
-                       } else {
+                       if n.Left != nil {
                                n.Left = nod(OADDR, n.Left, nil)
                                n.Left = typecheck(n.Left, Erv)
                        }
@@ -231,14 +229,22 @@ func walkselectcases(cases *Nodes) []*Node {
                        r = nod(OIF, nil, nil)
                        r.Ninit.Set(cas.Ninit.Slice())
                        ch := n.Right.Left
-                       r.Left = mkcall1(chanfn("selectnbrecv", 2, ch.Type), types.Types[TBOOL], &r.Ninit, n.Left, ch)
+                       elem := n.Left
+                       if elem == nil {
+                               elem = nodnil()
+                       }
+                       r.Left = mkcall1(chanfn("selectnbrecv", 2, ch.Type), types.Types[TBOOL], &r.Ninit, elem, ch)
 
                case OSELRECV2:
                        // if c != nil && selectnbrecv2(&v, c) { body } else { default body }
                        r = nod(OIF, nil, nil)
                        r.Ninit.Set(cas.Ninit.Slice())
                        ch := n.Right.Left
-                       r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), types.Types[TBOOL], &r.Ninit, n.Left, n.List.First(), ch)
+                       elem := n.Left
+                       if elem == nil {
+                               elem = nodnil()
+                       }
+                       r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), types.Types[TBOOL], &r.Ninit, elem, n.List.First(), ch)
                }
 
                r.Left = typecheck(r.Left, Erv)
@@ -268,9 +274,17 @@ func walkselectcases(cases *Nodes) []*Node {
                init = append(init, cas.Ninit.Slice()...)
                cas.Ninit.Set(nil)
 
-               s := bytePtrToIndex(selv, int64(i))
+               // Keep in sync with runtime/select.go.
+               const (
+                       caseNil = iota
+                       caseRecv
+                       caseSend
+                       caseDefault
+               )
+
+               var c, elem, receivedp *Node
+               var kind int64 = caseDefault
 
-               var x *Node
                if n := cas.Left; n != nil {
                        init = append(init, n.Ninit.Slice()...)
 
@@ -278,21 +292,50 @@ func walkselectcases(cases *Nodes) []*Node {
                        default:
                                Fatalf("select %v", n.Op)
                        case OSEND:
-                               // selectsend(cas *byte, hchan *chan any, elem *any)
-                               x = mkcall1(chanfn("selectsend", 2, n.Left.Type), nil, nil, s, n.Left, n.Right)
+                               kind = caseSend
+                               c = n.Left
+                               elem = n.Right
                        case OSELRECV:
-                               // 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())
+                               kind = caseRecv
+                               c = n.Right.Left
+                               elem = n.Left
                        case OSELRECV2:
-                               // 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())
+                               kind = caseRecv
+                               c = n.Right.Left
+                               elem = n.Left
+                               receivedp = n.List.First()
                        }
-               } else {
-                       // selectdefault(cas *byte)
-                       x = mkcall("selectdefault", nil, nil, s)
                }
 
-               init = append(init, x)
+               setField := func(f string, val *Node) {
+                       r := nod(OAS, nodSym(ODOT, nod(OINDEX, selv, nodintconst(int64(i))), lookup(f)), val)
+                       r = typecheck(r, Etop)
+                       init = append(init, r)
+               }
+
+               setField("kind", nodintconst(kind))
+               if c != nil {
+                       c = nod(OCONVNOP, c, nil)
+                       c.Type = types.Types[TUNSAFEPTR]
+                       setField("c", c)
+               }
+               if elem != nil {
+                       elem = nod(OCONVNOP, elem, nil)
+                       elem.Type = types.Types[TUNSAFEPTR]
+                       setField("elem", elem)
+               }
+               if receivedp != nil {
+                       receivedp = nod(OCONVNOP, receivedp, nil)
+                       receivedp.Type = types.NewPtr(types.Types[TBOOL])
+                       setField("receivedp", receivedp)
+               }
+
+               // TODO(mdempsky): There should be a cleaner way to
+               // handle this.
+               if instrumenting {
+                       r = mkcall("selectsetpc", nil, nil, bytePtrToIndex(selv, int64(i)))
+                       init = append(init, r)
+               }
        }
 
        // run the select
@@ -337,11 +380,11 @@ var scase *types.Type
 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("c", types.Types[TUNSAFEPTR]),
+                       namedfield("elem", types.Types[TUNSAFEPTR]),
+                       namedfield("receivedp", types.NewPtr(types.Types[TBOOL])),
                        namedfield("kind", types.Types[TUINT16]),
-                       namedfield("receivedp", types.NewPtr(types.Types[TUINT8])),
+                       namedfield("pc", types.Types[TUINTPTR]),
                        namedfield("releasetime", types.Types[TUINT64]),
                })
                scase.SetNoalg(true)
index f473fa8218011e1925b211d32426483690eefcc1..7d2cd7e847ffd954653d969782a46d4901c19f96 100644 (file)
@@ -1681,7 +1681,7 @@ func (s *state) expr(n *Node) *ssa.Value {
                }
 
                // unsafe.Pointer <--> *T
-               if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
+               if to.Etype == TUNSAFEPTR && from.IsPtrShaped() || from.Etype == TUNSAFEPTR && to.IsPtrShaped() {
                        return v
                }
 
index 265f70ed9e4f8e48a0537ad773f220386c4713cd..6e6849c7d3bd82b02d7f78482a63085e1e30bfec 100644 (file)
@@ -12,8 +12,10 @@ import (
 
 const debugSelect = false
 
+// scase.kind values.
+// Known to compiler.
+// Changes here must also be made in src/cmd/compile/internal/gc/select.go's walkselect.
 const (
-       // scase.kind
        caseNil = iota
        caseRecv
        caseSend
@@ -24,11 +26,11 @@ const (
 // Known to compiler.
 // Changes here must also be made in src/cmd/internal/gc/select.go's scasetype.
 type scase struct {
-       elem        unsafe.Pointer // data element
        c           *hchan         // chan
-       pc          uintptr        // return pc (for race detector / msan)
+       elem        unsafe.Pointer // data element
+       receivedp   *bool          // pointer to received bool, if any
        kind        uint16
-       receivedp   *bool // pointer to received bool, if any
+       pc          uintptr // race pc (for race detector / msan)
        releasetime int64
 }
 
@@ -37,43 +39,8 @@ var (
        chanrecvpc = funcPC(chanrecv)
 )
 
-func selectsend(cas *scase, c *hchan, elem unsafe.Pointer) {
-       if c == nil {
-               return
-       }
-       cas.pc = getcallerpc()
-       cas.c = c
-       cas.kind = caseSend
-       cas.elem = elem
-
-       if debugSelect {
-               print("selectsend cas=", cas, " pc=", hex(cas.pc), " chan=", cas.c, "\n")
-       }
-}
-
-func selectrecv(cas *scase, c *hchan, elem unsafe.Pointer, received *bool) {
-       if c == nil {
-               return
-       }
-       cas.pc = getcallerpc()
-       cas.c = c
-       cas.kind = caseRecv
-       cas.elem = elem
-       cas.receivedp = received
-
-       if debugSelect {
-               print("selectrecv cas=", cas, " pc=", hex(cas.pc), " chan=", cas.c, "\n")
-       }
-}
-
-func selectdefault(cas *scase) {
+func selectsetpc(cas *scase) {
        cas.pc = getcallerpc()
-       cas.c = nil
-       cas.kind = caseDefault
-
-       if debugSelect {
-               print("selectdefault cas=", cas, " pc=", hex(cas.pc), "\n")
-       }
 }
 
 func sellock(scases []scase, lockorder []uint16) {
@@ -156,6 +123,15 @@ func selectgo(cas0 *scase, order0 *uint16, ncases int) int {
        pollorder := order1[:ncases:ncases]
        lockorder := order1[ncases:][:ncases:ncases]
 
+       // Replace send/receive cases involving nil channels with
+       // caseNil so logic below can assume non-nil channel.
+       for i := range scases {
+               cas := &scases[i]
+               if cas.c == nil && cas.kind != caseDefault {
+                       *cas = scase{}
+               }
+       }
+
        var t0 int64
        if blockprofilerate > 0 {
                t0 = cputicks()
@@ -556,11 +532,14 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
                rc := &cases[i]
                switch rc.dir {
                case selectDefault:
-                       selectdefault(&sel[i])
+                       sel[i] = scase{kind: caseDefault}
                case selectSend:
-                       selectsend(&sel[i], rc.ch, rc.val)
+                       sel[i] = scase{kind: caseSend, c: rc.ch, elem: rc.val}
                case selectRecv:
-                       selectrecv(&sel[i], rc.ch, rc.val, r)
+                       sel[i] = scase{kind: caseRecv, c: rc.ch, elem: rc.val, receivedp: r}
+               }
+               if raceenabled || msanenabled {
+                       selectsetpc(&sel[i])
                }
        }
 
index 43ef9bdad246a3129fb4eb8e4b821706a9508a0b..8de3cf7e8661735cf3b1c146dc11d384e1de1623 100644 (file)
@@ -164,9 +164,9 @@ var b bool
 // this used to have a spurious "live at entry to f11a: ~r0"
 func f11a() *int {
        select { // ERROR "live at call to selectgo: .autotmp_[0-9]+$"
-       case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$"
+       case <-c:
                return nil
-       case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$"
+       case <-c:
                return nil
        }
 }
@@ -179,9 +179,9 @@ func f11b() *int {
                // This used to have a spurious "live at call to printint: p".
                printint(1) // nothing live here!
                select {    // ERROR "live at call to selectgo: .autotmp_[0-9]+$"
-               case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$"
+               case <-c:
                        return nil
-               case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$"
+               case <-c:
                        return nil
                }
        }
@@ -199,8 +199,8 @@ func f11c() *int {
                // so we can get to the println, so p is not dead.
                printint(1) // ERROR "live at call to printint: p$"
                select {    // ERROR "live at call to selectgo: .autotmp_[0-9]+ p$"
-               case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+ p$"
-               case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+ p$"
+               case <-c:
+               case <-c:
                }
        }
        println(*p)
@@ -590,13 +590,13 @@ func f38(b bool) {
        // and therefore no output.
        if b {
                select { // ERROR "live at call to selectgo:( .autotmp_[0-9]+)+$"
-               case <-fc38(): // ERROR "live at call to selectrecv:( .autotmp_[0-9]+)+$"
+               case <-fc38():
                        printnl()
-               case fc38() <- *fi38(1): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "live at call to selectsend:( .autotmp_[0-9]+)+$"
+               case fc38() <- *fi38(1): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$"
                        printnl()
-               case *fi38(2) = <-fc38(): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "live at call to selectrecv:( .autotmp_[0-9]+)+$"
+               case *fi38(2) = <-fc38(): // ERROR "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$"
                        printnl()
-               case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38:( .autotmp_[0-9]+)+$" "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$" "live at call to selectrecv:( .autotmp_[0-9]+)+$"
+               case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38:( .autotmp_[0-9]+)+$" "live at call to fc38:( .autotmp_[0-9]+)+$" "live at call to fi38:( .autotmp_[0-9]+)+$"
                        printnl()
                }
                printnl()