Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 1 | // Copyright 2009 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | /* |
| 6 | * select |
| 7 | */ |
| 8 | |
Russ Cox | 61f84a2 | 2011-08-25 16:25:10 -0400 | [diff] [blame] | 9 | #include <u.h> |
| 10 | #include <libc.h> |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 11 | #include "go.h" |
| 12 | |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 13 | static Type* selecttype(int32 size); |
| 14 | |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 15 | void |
| 16 | typecheckselect(Node *sel) |
| 17 | { |
| 18 | Node *ncase, *n, *def; |
| 19 | NodeList *l; |
| 20 | int lno, count; |
| 21 | |
| 22 | def = nil; |
| 23 | lno = setlineno(sel); |
| 24 | count = 0; |
| 25 | typechecklist(sel->ninit, Etop); |
| 26 | for(l=sel->list; l; l=l->next) { |
| 27 | count++; |
| 28 | ncase = l->n; |
| 29 | setlineno(ncase); |
| 30 | if(ncase->op != OXCASE) |
| 31 | fatal("typecheckselect %O", ncase->op); |
| 32 | |
| 33 | if(ncase->list == nil) { |
| 34 | // default |
| 35 | if(def != N) |
| 36 | yyerror("multiple defaults in select (first at %L)", def->lineno); |
| 37 | else |
| 38 | def = ncase; |
| 39 | } else if(ncase->list->next) { |
| 40 | yyerror("select cases cannot be lists"); |
| 41 | } else { |
| 42 | n = typecheck(&ncase->list->n, Etop); |
| 43 | ncase->left = n; |
| 44 | ncase->list = nil; |
| 45 | setlineno(n); |
| 46 | switch(n->op) { |
Russ Cox | 54b4037 | 2009-08-05 00:42:44 -0700 | [diff] [blame] | 47 | default: |
Russ Cox | 0db8d3d | 2010-10-20 16:38:25 -0400 | [diff] [blame] | 48 | yyerror("select case must be receive, send or assign recv"); |
Russ Cox | 54b4037 | 2009-08-05 00:42:44 -0700 | [diff] [blame] | 49 | break; |
| 50 | |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 51 | case OAS: |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 52 | // convert x = <-c into OSELRECV(x, <-c). |
| 53 | // remove implicit conversions; the eventual assignment |
| 54 | // will reintroduce them. |
Russ Cox | 0db8d3d | 2010-10-20 16:38:25 -0400 | [diff] [blame] | 55 | if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit) |
| 56 | n->right = n->right->left; |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 57 | |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 58 | if(n->right->op != ORECV) { |
| 59 | yyerror("select assignment must have receive on right hand side"); |
| 60 | break; |
| 61 | } |
| 62 | n->op = OSELRECV; |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 63 | break; |
| 64 | |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 65 | case OAS2RECV: |
Luuk van Dijk | 847b61b | 2011-08-24 19:07:08 +0200 | [diff] [blame] | 66 | // convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok |
Luuk van Dijk | e7f89fc | 2012-10-22 10:01:14 +0200 | [diff] [blame] | 67 | if(n->rlist->n->op != ORECV) { |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 68 | yyerror("select assignment must have receive on right hand side"); |
| 69 | break; |
| 70 | } |
| 71 | n->op = OSELRECV2; |
| 72 | n->left = n->list->n; |
| 73 | n->ntest = n->list->next->n; |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 74 | n->list = nil; |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 75 | n->right = n->rlist->n; |
Luuk van Dijk | e7f89fc | 2012-10-22 10:01:14 +0200 | [diff] [blame] | 76 | n->rlist = nil; |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 77 | break; |
| 78 | |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 79 | case ORECV: |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 80 | // convert <-c into OSELRECV(N, <-c) |
| 81 | n = nod(OSELRECV, N, n); |
Luuk van Dijk | 847b61b | 2011-08-24 19:07:08 +0200 | [diff] [blame] | 82 | n->typecheck = 1; |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 83 | ncase->left = n; |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 84 | break; |
| 85 | |
| 86 | case OSEND: |
| 87 | break; |
| 88 | } |
| 89 | } |
| 90 | typechecklist(ncase->nbody, Etop); |
| 91 | } |
| 92 | sel->xoffset = count; |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 93 | lineno = lno; |
| 94 | } |
| 95 | |
| 96 | void |
| 97 | walkselect(Node *sel) |
| 98 | { |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 99 | int lno, i; |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 100 | Node *n, *r, *a, *var, *selv, *cas, *dflt, *ch; |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 101 | NodeList *l, *init; |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 102 | |
| 103 | if(sel->list == nil && sel->xoffset != 0) |
| 104 | fatal("double walkselect"); // already rewrote |
| 105 | |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 106 | lno = setlineno(sel); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 107 | i = count(sel->list); |
| 108 | |
| 109 | // optimization: zero-case select |
| 110 | if(i == 0) { |
| 111 | sel->nbody = list1(mkcall("block", nil, nil)); |
| 112 | goto out; |
| 113 | } |
| 114 | |
| 115 | // optimization: one-case select: single op. |
Russ Cox | b700cb4 | 2014-04-01 13:31:38 -0400 | [diff] [blame] | 116 | // TODO(rsc): Reenable optimization once order.c can handle it. |
| 117 | // golang.org/issue/7672. |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 118 | if(i == 1) { |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 119 | cas = sel->list->n; |
Russ Cox | cce10da | 2011-07-26 00:52:17 -0400 | [diff] [blame] | 120 | setlineno(cas); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 121 | l = cas->ninit; |
| 122 | if(cas->left != N) { // not default: |
| 123 | n = cas->left; |
| 124 | l = concat(l, n->ninit); |
| 125 | n->ninit = nil; |
| 126 | switch(n->op) { |
| 127 | default: |
| 128 | fatal("select %O", n->op); |
| 129 | |
| 130 | case OSEND: |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 131 | // ok already |
| 132 | ch = n->left; |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 133 | break; |
| 134 | |
| 135 | case OSELRECV: |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 136 | ch = n->right->left; |
| 137 | Selrecv1: |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 138 | if(n->left == N) |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 139 | n = n->right; |
| 140 | else |
| 141 | n->op = OAS; |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 142 | break; |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 143 | |
| 144 | case OSELRECV2: |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 145 | ch = n->right->left; |
| 146 | if(n->ntest == N) |
| 147 | goto Selrecv1; |
| 148 | if(n->left == N) { |
| 149 | typecheck(&nblank, Erv | Easgn); |
| 150 | n->left = nblank; |
| 151 | } |
| 152 | n->op = OAS2; |
| 153 | n->list = list(list1(n->left), n->ntest); |
| 154 | n->rlist = list1(n->right); |
| 155 | n->right = N; |
| 156 | n->left = N; |
| 157 | n->ntest = N; |
| 158 | n->typecheck = 0; |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 159 | typecheck(&n, Etop); |
| 160 | break; |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 161 | } |
| 162 | |
| 163 | // if ch == nil { block() }; n; |
| 164 | a = nod(OIF, N, N); |
| 165 | a->ntest = nod(OEQ, ch, nodnil()); |
| 166 | a->nbody = list1(mkcall("block", nil, &l)); |
| 167 | typecheck(&a, Etop); |
| 168 | l = list(l, a); |
| 169 | l = list(l, n); |
| 170 | } |
| 171 | l = concat(l, cas->nbody); |
| 172 | sel->nbody = l; |
| 173 | goto out; |
| 174 | } |
| 175 | |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 176 | // convert case value arguments to addresses. |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 177 | // this rewrite is used by both the general code and the next optimization. |
| 178 | for(l=sel->list; l; l=l->next) { |
| 179 | cas = l->n; |
Russ Cox | cce10da | 2011-07-26 00:52:17 -0400 | [diff] [blame] | 180 | setlineno(cas); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 181 | n = cas->left; |
| 182 | if(n == N) |
| 183 | continue; |
| 184 | switch(n->op) { |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 185 | case OSEND: |
| 186 | n->right = nod(OADDR, n->right, N); |
| 187 | typecheck(&n->right, Erv); |
| 188 | break; |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 189 | case OSELRECV: |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 190 | case OSELRECV2: |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 191 | if(n->op == OSELRECV2 && n->ntest == N) |
| 192 | n->op = OSELRECV; |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 193 | if(n->op == OSELRECV2) { |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 194 | n->ntest = nod(OADDR, n->ntest, N); |
| 195 | typecheck(&n->ntest, Erv); |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 196 | } |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 197 | if(n->left == N) |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 198 | n->left = nodnil(); |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 199 | else { |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 200 | n->left = nod(OADDR, n->left, N); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 201 | typecheck(&n->left, Erv); |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 202 | } |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 203 | break; |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 204 | } |
| 205 | } |
| 206 | |
| 207 | // optimization: two-case select but one is default: single non-blocking op. |
| 208 | if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) { |
| 209 | if(sel->list->n->left == nil) { |
| 210 | cas = sel->list->next->n; |
| 211 | dflt = sel->list->n; |
| 212 | } else { |
| 213 | dflt = sel->list->next->n; |
| 214 | cas = sel->list->n; |
| 215 | } |
| 216 | |
| 217 | n = cas->left; |
Russ Cox | cce10da | 2011-07-26 00:52:17 -0400 | [diff] [blame] | 218 | setlineno(n); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 219 | r = nod(OIF, N, N); |
| 220 | r->ninit = cas->ninit; |
| 221 | switch(n->op) { |
| 222 | default: |
| 223 | fatal("select %O", n->op); |
| 224 | |
| 225 | case OSEND: |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 226 | // if selectnbsend(c, v) { body } else { default body } |
| 227 | ch = n->left; |
Russ Cox | 3770b0e | 2011-08-17 15:54:17 -0400 | [diff] [blame] | 228 | r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type), |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 229 | types[TBOOL], &r->ninit, typename(ch->type), ch, n->right); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 230 | break; |
| 231 | |
| 232 | case OSELRECV: |
| 233 | // if c != nil && selectnbrecv(&v, c) { body } else { default body } |
| 234 | r = nod(OIF, N, N); |
| 235 | r->ninit = cas->ninit; |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 236 | ch = n->right->left; |
Russ Cox | 3770b0e | 2011-08-17 15:54:17 -0400 | [diff] [blame] | 237 | r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type), |
| 238 | types[TBOOL], &r->ninit, typename(ch->type), n->left, ch); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 239 | break; |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 240 | |
| 241 | case OSELRECV2: |
| 242 | // if c != nil && selectnbrecv2(&v, c) { body } else { default body } |
| 243 | r = nod(OIF, N, N); |
| 244 | r->ninit = cas->ninit; |
Russ Cox | 96d90d0 | 2014-04-02 14:09:42 -0400 | [diff] [blame] | 245 | ch = n->right->left; |
Russ Cox | 3770b0e | 2011-08-17 15:54:17 -0400 | [diff] [blame] | 246 | r->ntest = mkcall1(chanfn("selectnbrecv2", 2, ch->type), |
| 247 | types[TBOOL], &r->ninit, typename(ch->type), n->left, n->ntest, ch); |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 248 | break; |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 249 | } |
| 250 | typecheck(&r->ntest, Erv); |
| 251 | r->nbody = cas->nbody; |
| 252 | r->nelse = concat(dflt->ninit, dflt->nbody); |
| 253 | sel->nbody = list1(r); |
| 254 | goto out; |
| 255 | } |
| 256 | |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 257 | init = sel->ninit; |
| 258 | sel->ninit = nil; |
| 259 | |
| 260 | // generate sel-struct |
Russ Cox | cce10da | 2011-07-26 00:52:17 -0400 | [diff] [blame] | 261 | setlineno(sel); |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 262 | selv = temp(selecttype(sel->xoffset)); |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 263 | r = nod(OAS, selv, N); |
| 264 | typecheck(&r, Etop); |
| 265 | init = list(init, r); |
| 266 | var = conv(conv(nod(OADDR, selv, N), types[TUNSAFEPTR]), ptrto(types[TUINT8])); |
| 267 | r = mkcall("newselect", T, nil, var, nodintconst(selv->type->width), nodintconst(sel->xoffset)); |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 268 | typecheck(&r, Etop); |
| 269 | init = list(init, r); |
| 270 | |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 271 | // register cases |
| 272 | for(l=sel->list; l; l=l->next) { |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 273 | cas = l->n; |
Russ Cox | cce10da | 2011-07-26 00:52:17 -0400 | [diff] [blame] | 274 | setlineno(cas); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 275 | n = cas->left; |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 276 | r = nod(OIF, N, N); |
Russ Cox | 1b3244e | 2012-12-22 16:46:01 -0500 | [diff] [blame] | 277 | r->ninit = cas->ninit; |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 278 | cas->ninit = nil; |
Russ Cox | 54b4037 | 2009-08-05 00:42:44 -0700 | [diff] [blame] | 279 | if(n != nil) { |
Russ Cox | 1b3244e | 2012-12-22 16:46:01 -0500 | [diff] [blame] | 280 | r->ninit = concat(r->ninit, n->ninit); |
Russ Cox | 54b4037 | 2009-08-05 00:42:44 -0700 | [diff] [blame] | 281 | n->ninit = nil; |
| 282 | } |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 283 | if(n == nil) { |
| 284 | // selectdefault(sel *byte); |
Russ Cox | 1b3244e | 2012-12-22 16:46:01 -0500 | [diff] [blame] | 285 | r->ntest = mkcall("selectdefault", types[TBOOL], &r->ninit, var); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 286 | } else { |
| 287 | switch(n->op) { |
| 288 | default: |
| 289 | fatal("select %O", n->op); |
| 290 | |
| 291 | case OSEND: |
Dmitriy Vyukov | 6b2ec06 | 2011-07-21 13:57:13 -0400 | [diff] [blame] | 292 | // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 293 | r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], |
Russ Cox | 1b3244e | 2012-12-22 16:46:01 -0500 | [diff] [blame] | 294 | &r->ninit, var, n->left, n->right); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 295 | break; |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 296 | |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 297 | case OSELRECV: |
| 298 | // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); |
| 299 | r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL], |
Russ Cox | 1b3244e | 2012-12-22 16:46:01 -0500 | [diff] [blame] | 300 | &r->ninit, var, n->right->left, n->left); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 301 | break; |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 302 | |
| 303 | case OSELRECV2: |
| 304 | // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool); |
| 305 | r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL], |
Russ Cox | 1b3244e | 2012-12-22 16:46:01 -0500 | [diff] [blame] | 306 | &r->ninit, var, n->right->left, n->left, n->ntest); |
Russ Cox | 8bf34e3 | 2011-03-11 14:47:26 -0500 | [diff] [blame] | 307 | break; |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 308 | } |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 309 | } |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 310 | // selv is no longer alive after use. |
| 311 | r->nbody = list(r->nbody, nod(OVARKILL, selv, N)); |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 312 | r->nbody = concat(r->nbody, cas->nbody); |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 313 | r->nbody = list(r->nbody, nod(OBREAK, N, N)); |
| 314 | init = list(init, r); |
| 315 | } |
| 316 | |
| 317 | // run the select |
Russ Cox | cce10da | 2011-07-26 00:52:17 -0400 | [diff] [blame] | 318 | setlineno(sel); |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 319 | init = list(init, mkcall("selectgo", T, nil, var)); |
| 320 | sel->nbody = init; |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 321 | |
Russ Cox | 5038792 | 2011-01-30 16:07:57 -0500 | [diff] [blame] | 322 | out: |
| 323 | sel->list = nil; |
| 324 | walkstmtlist(sel->nbody); |
Russ Cox | f7a867e | 2009-08-04 12:57:48 -0700 | [diff] [blame] | 325 | lineno = lno; |
| 326 | } |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 327 | |
Russ Cox | 220a6de | 2014-09-08 00:06:45 -0400 | [diff] [blame] | 328 | // Keep in sync with src/runtime/chan.h. |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 329 | static Type* |
| 330 | selecttype(int32 size) |
| 331 | { |
| 332 | Node *sel, *sudog, *scase, *arr; |
| 333 | |
| 334 | // TODO(dvyukov): it's possible to generate SudoG and Scase only once |
| 335 | // and then cache; and also cache Select per size. |
| 336 | sudog = nod(OTSTRUCT, N, N); |
| 337 | sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("g")), typenod(ptrto(types[TUINT8])))); |
| 338 | sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("selectdone")), typenod(ptrto(types[TUINT8])))); |
Keith Randall | 8eb8b40 | 2014-12-08 10:11:08 -0800 | [diff] [blame] | 339 | sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("next")), typenod(ptrto(types[TUINT8])))); |
Dmitriy Vyukov | ebac0e6 | 2014-08-25 20:12:26 +0400 | [diff] [blame] | 340 | sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("prev")), typenod(ptrto(types[TUINT8])))); |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 341 | sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8])))); |
| 342 | sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64]))); |
Dmitriy Vyukov | 684de04 | 2014-08-21 20:41:09 +0400 | [diff] [blame] | 343 | sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("nrelease")), typenod(types[TINT32]))); |
Keith Randall | 9a1e142 | 2014-08-24 12:31:03 +0400 | [diff] [blame] | 344 | sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("waitlink")), typenod(ptrto(types[TUINT8])))); |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 345 | typecheck(&sudog, Etype); |
| 346 | sudog->type->noalg = 1; |
| 347 | sudog->type->local = 1; |
| 348 | |
| 349 | scase = nod(OTSTRUCT, N, N); |
Keith Randall | 1d8fa7f | 2014-09-02 14:13:29 -0700 | [diff] [blame] | 350 | scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8])))); |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 351 | scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("chan")), typenod(ptrto(types[TUINT8])))); |
Dmitriy Vyukov | 88b78b4 | 2014-07-20 18:52:46 +0400 | [diff] [blame] | 352 | scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("pc")), typenod(types[TUINTPTR]))); |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 353 | scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("kind")), typenod(types[TUINT16]))); |
| 354 | scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("so")), typenod(types[TUINT16]))); |
| 355 | scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("receivedp")), typenod(ptrto(types[TUINT8])))); |
Keith Randall | 1d8fa7f | 2014-09-02 14:13:29 -0700 | [diff] [blame] | 356 | scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64]))); |
Dmitriy Vyukov | 40d7d5a | 2014-07-20 15:07:10 +0400 | [diff] [blame] | 357 | typecheck(&scase, Etype); |
| 358 | scase->type->noalg = 1; |
| 359 | scase->type->local = 1; |
| 360 | |
| 361 | sel = nod(OTSTRUCT, N, N); |
| 362 | sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("tcase")), typenod(types[TUINT16]))); |
| 363 | sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("ncase")), typenod(types[TUINT16]))); |
| 364 | sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorder")), typenod(ptrto(types[TUINT8])))); |
| 365 | sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorder")), typenod(ptrto(types[TUINT8])))); |
| 366 | arr = nod(OTARRAY, nodintconst(size), scase); |
| 367 | sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("scase")), arr)); |
| 368 | arr = nod(OTARRAY, nodintconst(size), typenod(ptrto(types[TUINT8]))); |
| 369 | sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorderarr")), arr)); |
| 370 | arr = nod(OTARRAY, nodintconst(size), typenod(types[TUINT16])); |
| 371 | sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorderarr")), arr)); |
| 372 | typecheck(&sel, Etype); |
| 373 | sel->type->noalg = 1; |
| 374 | sel->type->local = 1; |
| 375 | |
| 376 | return sel->type; |
| 377 | } |