summaryrefslogtreecommitdiff
path: root/src/cmd/gc/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/select.c')
-rw-r--r--src/cmd/gc/select.c343
1 files changed, 0 insertions, 343 deletions
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
deleted file mode 100644
index 91d4ebfd5..000000000
--- a/src/cmd/gc/select.c
+++ /dev/null
@@ -1,343 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * select
- */
-
-#include "go.h"
-
-void
-typecheckselect(Node *sel)
-{
- Node *ncase, *n, *def;
- NodeList *l;
- int lno, count;
-
- def = nil;
- lno = setlineno(sel);
- count = 0;
- typechecklist(sel->ninit, Etop);
- for(l=sel->list; l; l=l->next) {
- count++;
- ncase = l->n;
- setlineno(ncase);
- if(ncase->op != OXCASE)
- fatal("typecheckselect %O", ncase->op);
-
- if(ncase->list == nil) {
- // default
- if(def != N)
- yyerror("multiple defaults in select (first at %L)", def->lineno);
- else
- def = ncase;
- } else if(ncase->list->next) {
- yyerror("select cases cannot be lists");
- } else {
- n = typecheck(&ncase->list->n, Etop);
- ncase->left = n;
- ncase->list = nil;
- setlineno(n);
- switch(n->op) {
- default:
- yyerror("select case must be receive, send or assign recv");
- break;
-
- case OAS:
- // convert x = <-c into OSELRECV(x, <-c).
- // remove implicit conversions; the eventual assignment
- // will reintroduce them.
- if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit)
- n->right = n->right->left;
-
- if(n->right->op != ORECV) {
- yyerror("select assignment must have receive on right hand side");
- break;
- }
- n->op = OSELRECV;
- break;
-
- case OAS2RECV:
- // convert x, ok = <-c into OSELRECV(x, <-c) with ntest=ok
- if(n->right->op != ORECV) {
- yyerror("select assignment must have receive on right hand side");
- break;
- }
- n->op = OSELRECV2;
- n->left = n->list->n;
- n->ntest = n->list->next->n;
- n->right = n->rlist->n;
- break;
-
- case ORECV:
- // convert <-c into OSELRECV(N, <-c)
- n = nod(OSELRECV, N, n);
- ncase->left = n;
- break;
-
- case OSEND:
- break;
- }
- }
- typechecklist(ncase->nbody, Etop);
- }
- sel->xoffset = count;
- lineno = lno;
-}
-
-void
-walkselect(Node *sel)
-{
- int lno, i;
- Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch;
- NodeList *l, *init;
-
- if(sel->list == nil && sel->xoffset != 0)
- fatal("double walkselect"); // already rewrote
-
- lno = setlineno(sel);
- i = count(sel->list);
-
- // optimization: zero-case select
- if(i == 0) {
- sel->nbody = list1(mkcall("block", nil, nil));
- goto out;
- }
-
- // optimization: one-case select: single op.
- if(i == 1) {
- cas = sel->list->n;
- l = cas->ninit;
- if(cas->left != N) { // not default:
- n = cas->left;
- l = concat(l, n->ninit);
- n->ninit = nil;
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- ch = cheapexpr(n->left, &l);
- n->left = ch;
- break;
-
- case OSELRECV:
- r = n->right;
- ch = cheapexpr(r->left, &l);
- r->left = ch;
-
- if(n->left == N)
- n = r;
- else {
- n = nod(OAS, n->left, r);
- typecheck(&n, Etop);
- }
- 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 = n->rlist;
- n = a;
- typecheck(&n, Etop);
- break;
- }
-
- // if ch == nil { block() }; n;
- a = nod(OIF, N, N);
- a->ntest = nod(OEQ, ch, nodnil());
- a->nbody = list1(mkcall("block", nil, &l));
- typecheck(&a, Etop);
- l = list(l, a);
- l = list(l, n);
- }
- l = concat(l, cas->nbody);
- sel->nbody = l;
- goto out;
- }
-
- // introduce temporary variables for OSELRECV where needed.
- // this rewrite is used by both the general code and the next optimization.
- for(l=sel->list; l; l=l->next) {
- cas = l->n;
- n = cas->left;
- if(n == N)
- continue;
- switch(n->op) {
- 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) {
- 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 = nod(OXXX, N, N);
- tempname(tmp, 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;
- }
- }
-
- if(n->left == N || isblank(n->left))
- 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) {
- n->left = nod(OADDR, n->left, N);
- n->left->etype = 1; // pointer does not escape
- typecheck(&n->left, Erv);
- } else {
- tmp = nod(OXXX, N, N);
- tempname(tmp, 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;
- }
- }
-
- // optimization: two-case select but one is default: single non-blocking op.
- if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) {
- if(sel->list->n->left == nil) {
- cas = sel->list->next->n;
- dflt = sel->list->n;
- } else {
- dflt = sel->list->next->n;
- cas = sel->list->n;
- }
-
- n = cas->left;
- r = nod(OIF, N, N);
- r->ninit = cas->ninit;
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- // if c != nil && selectnbsend(c, v) { body } else { default body }
- ch = cheapexpr(n->left, &r->ninit);
- r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
- mkcall1(chanfn("selectnbsend", 2, ch->type),
- types[TBOOL], &r->ninit, ch, n->right));
- break;
-
- case OSELRECV:
- // 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);
- r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
- mkcall1(chanfn("selectnbrecv", 2, ch->type),
- types[TBOOL], &r->ninit, n->left, ch));
- break;
-
- case OSELRECV2:
- // 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);
- r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
- mkcall1(chanfn("selectnbrecv2", 2, ch->type),
- types[TBOOL], &r->ninit, n->left, n->ntest, ch));
- break;
- }
- typecheck(&r->ntest, Erv);
- r->nbody = cas->nbody;
- r->nelse = concat(dflt->ninit, dflt->nbody);
- sel->nbody = list1(r);
- goto out;
- }
-
- init = sel->ninit;
- sel->ninit = nil;
-
- // generate sel-struct
- var = nod(OXXX, N, N);
- tempname(var, ptrto(types[TUINT8]));
- r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(sel->xoffset)));
- typecheck(&r, Etop);
- init = list(init, r);
-
- // register cases
- for(l=sel->list; l; l=l->next) {
- cas = l->n;
- n = cas->left;
- r = nod(OIF, N, N);
- r->nbody = cas->ninit;
- cas->ninit = nil;
- if(n != nil) {
- r->nbody = concat(r->nbody, n->ninit);
- n->ninit = nil;
- }
- if(n == nil) {
- // selectdefault(sel *byte);
- r->ntest = mkcall("selectdefault", types[TBOOL], &init, var);
- } else {
- switch(n->op) {
- default:
- fatal("select %O", n->op);
-
- case OSEND:
- // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
- r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
- &init, var, n->left, n->right);
- break;
-
- case OSELRECV:
- // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
- r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
- &init, var, n->right->left, n->left);
- break;
-
- case OSELRECV2:
- // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
- r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL],
- &init, var, n->right->left, n->left, n->ntest);
- break;
- }
- }
- r->nbody = concat(r->nbody, cas->nbody);
- r->nbody = list(r->nbody, nod(OBREAK, N, N));
- init = list(init, r);
- }
-
- // run the select
- init = list(init, mkcall("selectgo", T, nil, var));
- sel->nbody = init;
-
-out:
- sel->list = nil;
- walkstmtlist(sel->nbody);
- lineno = lno;
-}