diff options
Diffstat (limited to 'src/cmd/gc/select.c')
-rw-r--r-- | src/cmd/gc/select.c | 116 |
1 files changed, 41 insertions, 75 deletions
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c index cd3de8c7b..58a120674 100644 --- a/src/cmd/gc/select.c +++ b/src/cmd/gc/select.c @@ -69,6 +69,7 @@ typecheckselect(Node *sel) n->op = OSELRECV2; n->left = n->list->n; n->ntest = n->list->next->n; + n->list = nil; n->right = n->rlist->n; n->rlist = nil; break; @@ -94,7 +95,7 @@ void walkselect(Node *sel) { int lno, i; - Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch; + Node *n, *r, *a, *var, *cas, *dflt, *ch; NodeList *l, *init; if(sel->list == nil && sel->xoffset != 0) @@ -110,6 +111,8 @@ walkselect(Node *sel) } // optimization: one-case select: single op. + // TODO(rsc): Reenable optimization once order.c can handle it. + // golang.org/issue/7672. if(i == 1) { cas = sel->list->n; setlineno(cas); @@ -123,32 +126,34 @@ walkselect(Node *sel) fatal("select %O", n->op); case OSEND: - ch = cheapexpr(n->left, &l); - n->left = ch; + // ok already + ch = n->left; break; case OSELRECV: - r = n->right; - ch = cheapexpr(r->left, &l); - r->left = ch; - + ch = n->right->left; + Selrecv1: if(n->left == N) - n = r; - else { - n = nod(OAS, n->left, r); - typecheck(&n, Etop); - } + n = n->right; + else + n->op = OAS; break; case OSELRECV2: - r = n->right; - ch = cheapexpr(r->left, &l); - r->left = ch; - - a = nod(OAS2, N, N); - a->list = n->list; - a->rlist = list1(n->right); - n = a; + ch = n->right->left; + if(n->ntest == N) + goto Selrecv1; + if(n->left == N) { + typecheck(&nblank, Erv | Easgn); + n->left = nblank; + } + n->op = OAS2; + n->list = list(list1(n->left), n->ntest); + n->rlist = list1(n->right); + n->right = N; + n->left = N; + n->ntest = N; + n->typecheck = 0; typecheck(&n, Etop); break; } @@ -166,7 +171,7 @@ walkselect(Node *sel) goto out; } - // introduce temporary variables for OSELRECV where needed. + // convert case value arguments to addresses. // this rewrite is used by both the general code and the next optimization. for(l=sel->list; l; l=l->next) { cas = l->n; @@ -175,58 +180,24 @@ walkselect(Node *sel) if(n == N) continue; switch(n->op) { + case OSEND: + n->right = nod(OADDR, n->right, N); + typecheck(&n->right, Erv); + break; case OSELRECV: case OSELRECV2: - ch = n->right->left; - - // If we can use the address of the target without - // violating addressability or order of operations, do so. - // Otherwise introduce a temporary. - // Also introduce a temporary for := variables that escape, - // so that we can delay the heap allocation until the case - // is selected. + if(n->op == OSELRECV2 && n->ntest == N) + n->op = OSELRECV; if(n->op == OSELRECV2) { - if(n->ntest == N || isblank(n->ntest)) - n->ntest = nodnil(); - else if(n->ntest->op == ONAME && - (!n->colas || (n->ntest->class&PHEAP) == 0) && - convertop(types[TBOOL], n->ntest->type, nil) == OCONVNOP) { - n->ntest = nod(OADDR, n->ntest, N); - n->ntest->etype = 1; // pointer does not escape - typecheck(&n->ntest, Erv); - } else { - tmp = temp(types[TBOOL]); - a = nod(OADDR, tmp, N); - a->etype = 1; // pointer does not escape - typecheck(&a, Erv); - r = nod(OAS, n->ntest, tmp); - typecheck(&r, Etop); - cas->nbody = concat(list1(r), cas->nbody); - n->ntest = a; - } + n->ntest = nod(OADDR, n->ntest, N); + typecheck(&n->ntest, Erv); } - - if(n->left == N || isblank(n->left)) + if(n->left == N) n->left = nodnil(); - else if(n->left->op == ONAME && - (!n->colas || (n->left->class&PHEAP) == 0) && - convertop(ch->type->type, n->left->type, nil) == OCONVNOP) { + else { n->left = nod(OADDR, n->left, N); - n->left->etype = 1; // pointer does not escape typecheck(&n->left, Erv); - } else { - tmp = temp(ch->type->type); - a = nod(OADDR, tmp, N); - a->etype = 1; // pointer does not escape - typecheck(&a, Erv); - r = nod(OAS, n->left, tmp); - typecheck(&r, Etop); - cas->nbody = concat(list1(r), cas->nbody); - n->left = a; - } - - cas->nbody = concat(n->ninit, cas->nbody); - n->ninit = nil; + } break; } } @@ -250,8 +221,8 @@ walkselect(Node *sel) fatal("select %O", n->op); case OSEND: - // if c != nil && selectnbsend(c, v) { body } else { default body } - ch = cheapexpr(n->left, &r->ninit); + // if selectnbsend(c, v) { body } else { default body } + ch = n->left; r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type), types[TBOOL], &r->ninit, typename(ch->type), ch, n->right); break; @@ -260,7 +231,7 @@ walkselect(Node *sel) // if c != nil && selectnbrecv(&v, c) { body } else { default body } r = nod(OIF, N, N); r->ninit = cas->ninit; - ch = cheapexpr(n->right->left, &r->ninit); + ch = n->right->left; r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type), types[TBOOL], &r->ninit, typename(ch->type), n->left, ch); break; @@ -269,7 +240,7 @@ walkselect(Node *sel) // if c != nil && selectnbrecv2(&v, c) { body } else { default body } r = nod(OIF, N, N); r->ninit = cas->ninit; - ch = cheapexpr(n->right->left, &r->ninit); + ch = n->right->left; r->ntest = mkcall1(chanfn("selectnbrecv2", 2, ch->type), types[TBOOL], &r->ninit, typename(ch->type), n->left, n->ntest, ch); break; @@ -313,11 +284,6 @@ walkselect(Node *sel) case OSEND: // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); - n->left = localexpr(safeexpr(n->left, &r->ninit), n->left->type, &r->ninit); - n->right = localexpr(n->right, n->left->type->type, &r->ninit); - n->right = nod(OADDR, n->right, N); - n->right->etype = 1; // pointer does not escape - typecheck(&n->right, Erv); r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], &r->ninit, var, n->left, n->right); break; |