github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/gc/order.c (about) 1 // Copyright 2012 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 // Rewrite tree to use separate statements to enforce 6 // order of evaluation. Makes walk easier, because it 7 // can (after this runs) reorder at will within an expression. 8 9 #include <u.h> 10 #include <libc.h> 11 #include "go.h" 12 13 static void orderstmt(Node*, NodeList**); 14 static void orderstmtlist(NodeList*, NodeList**); 15 static void orderblock(NodeList **l); 16 static void orderexpr(Node**, NodeList**); 17 static void orderexprlist(NodeList*, NodeList**); 18 19 void 20 order(Node *fn) 21 { 22 orderblock(&fn->nbody); 23 } 24 25 static void 26 orderstmtlist(NodeList *l, NodeList **out) 27 { 28 for(; l; l=l->next) 29 orderstmt(l->n, out); 30 } 31 32 // Order the block of statements *l onto a new list, 33 // and then replace *l with that list. 34 static void 35 orderblock(NodeList **l) 36 { 37 NodeList *out; 38 39 out = nil; 40 orderstmtlist(*l, &out); 41 *l = out; 42 } 43 44 // Order the side effects in *np and leave them as 45 // the init list of the final *np. 46 static void 47 orderexprinplace(Node **np) 48 { 49 Node *n; 50 NodeList *out; 51 52 n = *np; 53 out = nil; 54 orderexpr(&n, &out); 55 addinit(&n, out); 56 *np = n; 57 } 58 59 // Like orderblock, but applied to a single statement. 60 static void 61 orderstmtinplace(Node **np) 62 { 63 Node *n; 64 NodeList *out; 65 66 n = *np; 67 out = nil; 68 orderstmt(n, &out); 69 *np = liststmt(out); 70 } 71 72 // Move n's init list to *out. 73 static void 74 orderinit(Node *n, NodeList **out) 75 { 76 orderstmtlist(n->ninit, out); 77 n->ninit = nil; 78 } 79 80 // Is the list l actually just f() for a multi-value function? 81 static int 82 ismulticall(NodeList *l) 83 { 84 Node *n; 85 86 // one arg only 87 if(l == nil || l->next != nil) 88 return 0; 89 n = l->n; 90 91 // must be call 92 switch(n->op) { 93 default: 94 return 0; 95 case OCALLFUNC: 96 case OCALLMETH: 97 case OCALLINTER: 98 break; 99 } 100 101 // call must return multiple values 102 return n->left->type->outtuple > 1; 103 } 104 105 // n is a multi-value function call. Add t1, t2, .. = n to out 106 // and return the list t1, t2, ... 107 static NodeList* 108 copyret(Node *n, NodeList **out) 109 { 110 Type *t; 111 Node *tmp, *as; 112 NodeList *l1, *l2; 113 Iter tl; 114 115 if(n->type->etype != TSTRUCT || !n->type->funarg) 116 fatal("copyret %T %d", n->type, n->left->type->outtuple); 117 118 l1 = nil; 119 l2 = nil; 120 for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) { 121 tmp = temp(t->type); 122 l1 = list(l1, tmp); 123 l2 = list(l2, tmp); 124 } 125 126 as = nod(OAS2, N, N); 127 as->list = l1; 128 as->rlist = list1(n); 129 typecheck(&as, Etop); 130 orderstmt(as, out); 131 132 return l2; 133 } 134 135 static void 136 ordercallargs(NodeList **l, NodeList **out) 137 { 138 if(ismulticall(*l)) { 139 // return f() where f() is multiple values. 140 *l = copyret((*l)->n, out); 141 } else { 142 orderexprlist(*l, out); 143 } 144 } 145 146 static void 147 ordercall(Node *n, NodeList **out) 148 { 149 orderexpr(&n->left, out); 150 ordercallargs(&n->list, out); 151 } 152 153 static void 154 orderstmt(Node *n, NodeList **out) 155 { 156 int lno; 157 NodeList *l; 158 Node *r; 159 160 if(n == N) 161 return; 162 163 lno = setlineno(n); 164 165 orderinit(n, out); 166 167 switch(n->op) { 168 default: 169 fatal("orderstmt %O", n->op); 170 171 case OAS2: 172 case OAS2DOTTYPE: 173 case OAS2MAPR: 174 case OAS: 175 case OASOP: 176 case OCLOSE: 177 case OCOPY: 178 case ODELETE: 179 case OPANIC: 180 case OPRINT: 181 case OPRINTN: 182 case ORECOVER: 183 case ORECV: 184 case OSEND: 185 orderexpr(&n->left, out); 186 orderexpr(&n->right, out); 187 orderexprlist(n->list, out); 188 orderexprlist(n->rlist, out); 189 *out = list(*out, n); 190 break; 191 192 case OAS2FUNC: 193 // Special: avoid copy of func call n->rlist->n. 194 orderexprlist(n->list, out); 195 ordercall(n->rlist->n, out); 196 *out = list(*out, n); 197 break; 198 199 case OAS2RECV: 200 // Special: avoid copy of receive. 201 orderexprlist(n->list, out); 202 orderexpr(&n->rlist->n->left, out); // arg to recv 203 *out = list(*out, n); 204 break; 205 206 case OBLOCK: 207 case OEMPTY: 208 // Special: does not save n onto out. 209 orderstmtlist(n->list, out); 210 break; 211 212 case OBREAK: 213 case OCONTINUE: 214 case ODCL: 215 case ODCLCONST: 216 case ODCLTYPE: 217 case OFALL: 218 case_OFALL: 219 case OGOTO: 220 case OLABEL: 221 // Special: n->left is not an expression; save as is. 222 *out = list(*out, n); 223 break; 224 225 case OCALLFUNC: 226 case OCALLINTER: 227 case OCALLMETH: 228 // Special: handle call arguments. 229 ordercall(n, out); 230 *out = list(*out, n); 231 break; 232 233 case ODEFER: 234 case OPROC: 235 // Special: order arguments to inner call but not call itself. 236 ordercall(n->left, out); 237 *out = list(*out, n); 238 break; 239 240 case OFOR: 241 orderexprinplace(&n->ntest); 242 orderstmtinplace(&n->nincr); 243 orderblock(&n->nbody); 244 *out = list(*out, n); 245 break; 246 247 case OIF: 248 orderexprinplace(&n->ntest); 249 orderblock(&n->nbody); 250 orderblock(&n->nelse); 251 *out = list(*out, n); 252 break; 253 254 case ORANGE: 255 orderexpr(&n->right, out); 256 for(l=n->list; l; l=l->next) 257 orderexprinplace(&l->n); 258 orderblock(&n->nbody); 259 *out = list(*out, n); 260 break; 261 262 case ORETURN: 263 ordercallargs(&n->list, out); 264 *out = list(*out, n); 265 break; 266 267 case OSELECT: 268 for(l=n->list; l; l=l->next) { 269 if(l->n->op != OXCASE) 270 fatal("order select case %O", l->n->op); 271 r = l->n->left; 272 if(r == nil) 273 continue; 274 switch(r->op) { 275 case OSELRECV: 276 case OSELRECV2: 277 orderexprinplace(&r->left); 278 orderexprinplace(&r->ntest); 279 orderexpr(&r->right->left, &l->n->ninit); 280 break; 281 case OSEND: 282 orderexpr(&r->left, &l->n->ninit); 283 orderexpr(&r->right, &l->n->ninit); 284 break; 285 } 286 } 287 *out = list(*out, n); 288 break; 289 290 case OSWITCH: 291 orderexpr(&n->ntest, out); 292 for(l=n->list; l; l=l->next) { 293 if(l->n->op != OXCASE) 294 fatal("order switch case %O", l->n->op); 295 orderexpr(&l->n->left, &l->n->ninit); 296 } 297 *out = list(*out, n); 298 break; 299 300 case OXFALL: 301 yyerror("fallthrough statement out of place"); 302 n->op = OFALL; 303 goto case_OFALL; 304 } 305 306 lineno = lno; 307 } 308 309 static void 310 orderexprlist(NodeList *l, NodeList **out) 311 { 312 for(; l; l=l->next) 313 orderexpr(&l->n, out); 314 } 315 316 static void 317 orderexpr(Node **np, NodeList **out) 318 { 319 Node *n; 320 int lno; 321 322 n = *np; 323 if(n == N) 324 return; 325 326 lno = setlineno(n); 327 orderinit(n, out); 328 329 switch(n->op) { 330 default: 331 orderexpr(&n->left, out); 332 orderexpr(&n->right, out); 333 orderexprlist(n->list, out); 334 orderexprlist(n->rlist, out); 335 break; 336 337 case OANDAND: 338 case OOROR: 339 orderexpr(&n->left, out); 340 orderexprinplace(&n->right); 341 break; 342 343 case OCALLFUNC: 344 case OCALLMETH: 345 case OCALLINTER: 346 ordercall(n, out); 347 n = copyexpr(n, n->type, out); 348 break; 349 350 case ORECV: 351 n = copyexpr(n, n->type, out); 352 break; 353 } 354 355 lineno = lno; 356 357 *np = n; 358 }