github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/cmd/gc/pgen.c (about) 1 // Copyright 2011 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 // "Portable" code generation. 6 // Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h. 7 // Must code to the intersection of the three back ends. 8 9 #include <u.h> 10 #include <libc.h> 11 #include "gg.h" 12 #include "opt.h" 13 #include "../../pkg/runtime/funcdata.h" 14 15 enum { BitsPerPointer = 2 }; 16 17 static void allocauto(Prog* p); 18 static void dumpgcargs(Node*, Sym*); 19 static Bvec* dumpgclocals(Node*, Sym*); 20 21 void 22 compile(Node *fn) 23 { 24 Bvec *bv; 25 Plist *pl; 26 Node nod1, *n, *gcargsnod, *gclocalsnod; 27 Prog *ptxt, *p, *p1; 28 int32 lno; 29 Type *t; 30 Iter save; 31 vlong oldstksize; 32 NodeList *l; 33 Sym *gcargssym, *gclocalssym; 34 static int ngcargs, ngclocals; 35 36 if(newproc == N) { 37 newproc = sysfunc("newproc"); 38 deferproc = sysfunc("deferproc"); 39 deferreturn = sysfunc("deferreturn"); 40 panicindex = sysfunc("panicindex"); 41 panicslice = sysfunc("panicslice"); 42 throwreturn = sysfunc("throwreturn"); 43 } 44 45 lno = setlineno(fn); 46 47 if(fn->nbody == nil) { 48 if(pure_go || memcmp(fn->nname->sym->name, "init·", 6) == 0) 49 yyerror("missing function body", fn); 50 goto ret; 51 } 52 53 saveerrors(); 54 55 // set up domain for labels 56 clearlabels(); 57 58 curfn = fn; 59 dowidth(curfn->type); 60 61 if(curfn->type->outnamed) { 62 // add clearing of the output parameters 63 t = structfirst(&save, getoutarg(curfn->type)); 64 while(t != T) { 65 if(t->nname != N) { 66 n = nod(OAS, t->nname, N); 67 typecheck(&n, Etop); 68 curfn->nbody = concat(list1(n), curfn->nbody); 69 } 70 t = structnext(&save); 71 } 72 } 73 74 order(curfn); 75 if(nerrors != 0) 76 goto ret; 77 78 hasdefer = 0; 79 walk(curfn); 80 if(nerrors != 0) 81 goto ret; 82 if(flag_race) 83 racewalk(curfn); 84 if(nerrors != 0) 85 goto ret; 86 87 continpc = P; 88 breakpc = P; 89 90 pl = newplist(); 91 pl->name = curfn->nname; 92 93 setlineno(curfn); 94 95 nodconst(&nod1, types[TINT32], 0); 96 ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1); 97 if(fn->dupok) 98 ptxt->TEXTFLAG = DUPOK; 99 afunclit(&ptxt->from, curfn->nname); 100 101 ginit(); 102 103 snprint(namebuf, sizeof namebuf, "gcargs·%d", ngcargs++); 104 gcargssym = lookup(namebuf); 105 gcargsnod = newname(gcargssym); 106 gcargsnod->class = PEXTERN; 107 108 nodconst(&nod1, types[TINT32], FUNCDATA_GCArgs); 109 gins(AFUNCDATA, &nod1, gcargsnod); 110 111 snprint(namebuf, sizeof(namebuf), "gclocals·%d", ngclocals++); 112 gclocalssym = lookup(namebuf); 113 gclocalsnod = newname(gclocalssym); 114 gclocalsnod->class = PEXTERN; 115 116 nodconst(&nod1, types[TINT32], FUNCDATA_GCLocals); 117 gins(AFUNCDATA, &nod1, gclocalsnod); 118 119 for(t=curfn->paramfld; t; t=t->down) 120 gtrack(tracksym(t->type)); 121 122 for(l=fn->dcl; l; l=l->next) { 123 n = l->n; 124 if(n->op != ONAME) // might be OTYPE or OLITERAL 125 continue; 126 switch(n->class) { 127 case PAUTO: 128 case PPARAM: 129 case PPARAMOUT: 130 nodconst(&nod1, types[TUINTPTR], l->n->type->width); 131 p = gins(ATYPE, l->n, &nod1); 132 p->from.gotype = ngotype(l->n); 133 break; 134 } 135 } 136 137 genlist(curfn->enter); 138 139 retpc = nil; 140 if(hasdefer || curfn->exit) { 141 p1 = gjmp(nil); 142 retpc = gjmp(nil); 143 patch(p1, pc); 144 } 145 146 genlist(curfn->nbody); 147 gclean(); 148 checklabels(); 149 if(nerrors != 0) 150 goto ret; 151 if(curfn->endlineno) 152 lineno = curfn->endlineno; 153 154 if(curfn->type->outtuple != 0) 155 ginscall(throwreturn, 0); 156 157 if(retpc) 158 patch(retpc, pc); 159 ginit(); 160 if(hasdefer) 161 ginscall(deferreturn, 0); 162 if(curfn->exit) 163 genlist(curfn->exit); 164 gclean(); 165 if(nerrors != 0) 166 goto ret; 167 168 pc->as = ARET; // overwrite AEND 169 pc->lineno = lineno; 170 171 if(!debug['N'] || debug['R'] || debug['P']) { 172 regopt(ptxt); 173 } 174 expandchecks(ptxt); 175 176 oldstksize = stksize; 177 allocauto(ptxt); 178 179 if(0) 180 print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize); 181 182 setlineno(curfn); 183 if((int64)stksize+maxarg > (1ULL<<31)) { 184 yyerror("stack frame too large (>2GB)"); 185 goto ret; 186 } 187 188 // Emit garbage collection symbols. 189 dumpgcargs(fn, gcargssym); 190 bv = dumpgclocals(curfn, gclocalssym); 191 192 defframe(ptxt, bv); 193 free(bv); 194 195 if(0) 196 frame(0); 197 198 ret: 199 lineno = lno; 200 } 201 202 static void 203 walktype1(Type *t, vlong *xoffset, Bvec *bv) 204 { 205 vlong fieldoffset, i, o; 206 Type *t1; 207 208 if(t->align > 0 && (*xoffset % t->align) != 0) 209 fatal("walktype1: invalid initial alignment, %T", t); 210 211 switch(t->etype) { 212 case TINT8: 213 case TUINT8: 214 case TINT16: 215 case TUINT16: 216 case TINT32: 217 case TUINT32: 218 case TINT64: 219 case TUINT64: 220 case TINT: 221 case TUINT: 222 case TUINTPTR: 223 case TBOOL: 224 case TFLOAT32: 225 case TFLOAT64: 226 case TCOMPLEX64: 227 case TCOMPLEX128: 228 *xoffset += t->width; 229 break; 230 231 case TPTR32: 232 case TPTR64: 233 case TUNSAFEPTR: 234 case TFUNC: 235 case TCHAN: 236 case TMAP: 237 if(*xoffset % widthptr != 0) 238 fatal("walktype1: invalid alignment, %T", t); 239 bvset(bv, (*xoffset / widthptr) * BitsPerPointer); 240 *xoffset += t->width; 241 break; 242 243 case TSTRING: 244 // struct { byte *str; intgo len; } 245 if(*xoffset % widthptr != 0) 246 fatal("walktype1: invalid alignment, %T", t); 247 bvset(bv, (*xoffset / widthptr) * BitsPerPointer); 248 *xoffset += t->width; 249 break; 250 251 case TINTER: 252 // struct { Itab* tab; union { void* ptr, uintptr val } data; } 253 // or, when isnilinter(t)==true: 254 // struct { Type* type; union { void* ptr, uintptr val } data; } 255 if(*xoffset % widthptr != 0) 256 fatal("walktype1: invalid alignment, %T", t); 257 bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1); 258 if(isnilinter(t)) 259 bvset(bv, ((*xoffset / widthptr) * BitsPerPointer)); 260 *xoffset += t->width; 261 break; 262 263 case TARRAY: 264 // The value of t->bound is -1 for slices types and >0 for 265 // for fixed array types. All other values are invalid. 266 if(t->bound < -1) 267 fatal("walktype1: invalid bound, %T", t); 268 if(isslice(t)) { 269 // struct { byte* array; uintgo len; uintgo cap; } 270 if(*xoffset % widthptr != 0) 271 fatal("walktype1: invalid TARRAY alignment, %T", t); 272 bvset(bv, (*xoffset / widthptr) * BitsPerPointer); 273 *xoffset += t->width; 274 } else if(!haspointers(t->type)) 275 *xoffset += t->width; 276 else 277 for(i = 0; i < t->bound; ++i) 278 walktype1(t->type, xoffset, bv); 279 break; 280 281 case TSTRUCT: 282 o = 0; 283 for(t1 = t->type; t1 != T; t1 = t1->down) { 284 fieldoffset = t1->width; 285 *xoffset += fieldoffset - o; 286 walktype1(t1->type, xoffset, bv); 287 o = fieldoffset + t1->type->width; 288 } 289 *xoffset += t->width - o; 290 break; 291 292 default: 293 fatal("walktype1: unexpected type, %T", t); 294 } 295 } 296 297 static void 298 walktype(Type *type, Bvec *bv) 299 { 300 vlong xoffset; 301 302 // Start the walk at offset 0. The correct offset will be 303 // filled in by the first type encountered during the walk. 304 xoffset = 0; 305 walktype1(type, &xoffset, bv); 306 } 307 308 // Compute a bit vector to describes the pointer containing locations 309 // in the in and out argument list and dump the bitvector length and 310 // data to the provided symbol. 311 static void 312 dumpgcargs(Node *fn, Sym *sym) 313 { 314 Type *thistype, *inargtype, *outargtype; 315 Bvec *bv; 316 int32 i; 317 int off; 318 319 thistype = getthisx(fn->type); 320 inargtype = getinargx(fn->type); 321 outargtype = getoutargx(fn->type); 322 bv = bvalloc((fn->type->argwid / widthptr) * BitsPerPointer); 323 if(thistype != nil) 324 walktype(thistype, bv); 325 if(inargtype != nil) 326 walktype(inargtype, bv); 327 if(outargtype != nil) 328 walktype(outargtype, bv); 329 off = duint32(sym, 0, bv->n); 330 for(i = 0; i < bv->n; i += 32) 331 off = duint32(sym, off, bv->b[i/32]); 332 free(bv); 333 ggloblsym(sym, off, 0, 1); 334 } 335 336 // Compute a bit vector to describes the pointer containing locations 337 // in local variables and dumps the bitvector length and data out to 338 // the provided symbol. Returns the vector for use and freeing by caller. 339 static Bvec* 340 dumpgclocals(Node* fn, Sym *sym) 341 { 342 Bvec *bv; 343 NodeList *ll; 344 Node *node; 345 vlong xoffset; 346 int32 i; 347 int off; 348 349 bv = bvalloc((stkptrsize / widthptr) * BitsPerPointer); 350 for(ll = fn->dcl; ll != nil; ll = ll->next) { 351 node = ll->n; 352 if(node->class == PAUTO && node->op == ONAME) { 353 if(haspointers(node->type)) { 354 xoffset = node->xoffset + stkptrsize; 355 walktype1(node->type, &xoffset, bv); 356 } 357 } 358 } 359 off = duint32(sym, 0, bv->n); 360 for(i = 0; i < bv->n; i += 32) { 361 off = duint32(sym, off, bv->b[i/32]); 362 } 363 ggloblsym(sym, off, 0, 1); 364 return bv; 365 } 366 367 // Sort the list of stack variables. Autos after anything else, 368 // within autos, unused after used, within used, things with 369 // pointers first, zeroed things first, and then decreasing size. 370 // Because autos are laid out in decreasing addresses 371 // on the stack, pointers first, zeroed things first and decreasing size 372 // really means, in memory, things with pointers needing zeroing at 373 // the top of the stack and increasing in size. 374 // Non-autos sort on offset. 375 static int 376 cmpstackvar(Node *a, Node *b) 377 { 378 int ap, bp; 379 380 if (a->class != b->class) 381 return (a->class == PAUTO) ? +1 : -1; 382 if (a->class != PAUTO) { 383 if (a->xoffset < b->xoffset) 384 return -1; 385 if (a->xoffset > b->xoffset) 386 return +1; 387 return 0; 388 } 389 if ((a->used == 0) != (b->used == 0)) 390 return b->used - a->used; 391 392 ap = haspointers(a->type); 393 bp = haspointers(b->type); 394 if(ap != bp) 395 return bp - ap; 396 397 ap = a->needzero; 398 bp = b->needzero; 399 if(ap != bp) 400 return bp - ap; 401 402 if(a->type->width < b->type->width) 403 return +1; 404 if(a->type->width > b->type->width) 405 return -1; 406 return 0; 407 } 408 409 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. 410 static void 411 allocauto(Prog* ptxt) 412 { 413 NodeList *ll; 414 Node* n; 415 vlong w; 416 417 stksize = 0; 418 stkptrsize = 0; 419 stkzerosize = 0; 420 421 if(curfn->dcl == nil) 422 return; 423 424 // Mark the PAUTO's unused. 425 for(ll=curfn->dcl; ll != nil; ll=ll->next) 426 if (ll->n->class == PAUTO) 427 ll->n->used = 0; 428 429 markautoused(ptxt); 430 431 // TODO: Remove when liveness analysis sets needzero instead. 432 for(ll=curfn->dcl; ll != nil; ll=ll->next) 433 if (ll->n->class == PAUTO) 434 ll->n->needzero = 1; // ll->n->addrtaken; 435 436 listsort(&curfn->dcl, cmpstackvar); 437 438 // Unused autos are at the end, chop 'em off. 439 ll = curfn->dcl; 440 n = ll->n; 441 if (n->class == PAUTO && n->op == ONAME && !n->used) { 442 // No locals used at all 443 curfn->dcl = nil; 444 fixautoused(ptxt); 445 return; 446 } 447 448 for(ll = curfn->dcl; ll->next != nil; ll=ll->next) { 449 n = ll->next->n; 450 if (n->class == PAUTO && n->op == ONAME && !n->used) { 451 ll->next = nil; 452 curfn->dcl->end = ll; 453 break; 454 } 455 } 456 457 // Reassign stack offsets of the locals that are still there. 458 for(ll = curfn->dcl; ll != nil; ll=ll->next) { 459 n = ll->n; 460 if (n->class != PAUTO || n->op != ONAME) 461 continue; 462 463 dowidth(n->type); 464 w = n->type->width; 465 if(w >= MAXWIDTH || w < 0) 466 fatal("bad width"); 467 stksize += w; 468 stksize = rnd(stksize, n->type->align); 469 if(haspointers(n->type)) { 470 stkptrsize = stksize; 471 if(n->needzero) 472 stkzerosize = stksize; 473 } 474 if(thechar == '5') 475 stksize = rnd(stksize, widthptr); 476 if(stksize >= (1ULL<<31)) { 477 setlineno(curfn); 478 yyerror("stack frame too large (>2GB)"); 479 } 480 n->stkdelta = -stksize - n->xoffset; 481 } 482 stksize = rnd(stksize, widthptr); 483 stkptrsize = rnd(stkptrsize, widthptr); 484 stkzerosize = rnd(stkzerosize, widthptr); 485 486 fixautoused(ptxt); 487 488 // The debug information needs accurate offsets on the symbols. 489 for(ll = curfn->dcl; ll != nil; ll=ll->next) { 490 if (ll->n->class != PAUTO || ll->n->op != ONAME) 491 continue; 492 ll->n->xoffset += ll->n->stkdelta; 493 ll->n->stkdelta = 0; 494 } 495 } 496 497 static void movelargefn(Node*); 498 499 void 500 movelarge(NodeList *l) 501 { 502 for(; l; l=l->next) 503 if(l->n->op == ODCLFUNC) 504 movelargefn(l->n); 505 } 506 507 static void 508 movelargefn(Node *fn) 509 { 510 NodeList *l; 511 Node *n; 512 513 for(l=fn->dcl; l != nil; l=l->next) { 514 n = l->n; 515 if(n->class == PAUTO && n->type != T && n->type->width > MaxStackVarSize) 516 addrescapes(n); 517 } 518 } 519 520 void 521 cgen_checknil(Node *n) 522 { 523 Node reg; 524 525 if(disable_checknil) 526 return; 527 while(n->op == ODOT || (n->op == OINDEX && isfixedarray(n->left->type->type))) // NOTE: not ODOTPTR 528 n = n->left; 529 if((thechar == '5' && n->op != OREGISTER) || !n->addable) { 530 regalloc(®, types[tptr], n); 531 cgen(n, ®); 532 gins(ACHECKNIL, ®, N); 533 regfree(®); 534 return; 535 } 536 gins(ACHECKNIL, n, N); 537 }