github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/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 "md5.h" 12 #include "gg.h" 13 #include "opt.h" 14 #include "../../pkg/runtime/funcdata.h" 15 16 static void allocauto(Prog* p); 17 18 static Sym* 19 makefuncdatasym(char *namefmt, int64 funcdatakind) 20 { 21 Node nod; 22 Node *pnod; 23 Sym *sym; 24 static int32 nsym; 25 26 snprint(namebuf, sizeof(namebuf), namefmt, nsym++); 27 sym = lookup(namebuf); 28 pnod = newname(sym); 29 pnod->class = PEXTERN; 30 nodconst(&nod, types[TINT32], funcdatakind); 31 gins(AFUNCDATA, &nod, pnod); 32 return sym; 33 } 34 35 // gvardef inserts a VARDEF for n into the instruction stream. 36 // VARDEF is an annotation for the liveness analysis, marking a place 37 // where a complete initialization (definition) of a variable begins. 38 // Since the liveness analysis can see initialization of single-word 39 // variables quite easy, gvardef is usually only called for multi-word 40 // or 'fat' variables, those satisfying isfat(n->type). 41 // However, gvardef is also called when a non-fat variable is initialized 42 // via a block move; the only time this happens is when you have 43 // return f() 44 // for a function with multiple return values exactly matching the return 45 // types of the current function. 46 // 47 // A 'VARDEF x' annotation in the instruction stream tells the liveness 48 // analysis to behave as though the variable x is being initialized at that 49 // point in the instruction stream. The VARDEF must appear before the 50 // actual (multi-instruction) initialization, and it must also appear after 51 // any uses of the previous value, if any. For example, if compiling: 52 // 53 // x = x[1:] 54 // 55 // it is important to generate code like: 56 // 57 // base, len, cap = pieces of x[1:] 58 // VARDEF x 59 // x = {base, len, cap} 60 // 61 // If instead the generated code looked like: 62 // 63 // VARDEF x 64 // base, len, cap = pieces of x[1:] 65 // x = {base, len, cap} 66 // 67 // then the liveness analysis would decide the previous value of x was 68 // unnecessary even though it is about to be used by the x[1:] computation. 69 // Similarly, if the generated code looked like: 70 // 71 // base, len, cap = pieces of x[1:] 72 // x = {base, len, cap} 73 // VARDEF x 74 // 75 // then the liveness analysis will not preserve the new value of x, because 76 // the VARDEF appears to have "overwritten" it. 77 // 78 // VARDEF is a bit of a kludge to work around the fact that the instruction 79 // stream is working on single-word values but the liveness analysis 80 // wants to work on individual variables, which might be multi-word 81 // aggregates. It might make sense at some point to look into letting 82 // the liveness analysis work on single-word values as well, although 83 // there are complications around interface values, slices, and strings, 84 // all of which cannot be treated as individual words. 85 // 86 // VARKILL is the opposite of VARDEF: it marks a value as no longer needed, 87 // even if its address has been taken. That is, a VARKILL annotation asserts 88 // that its argument is certainly dead, for use when the liveness analysis 89 // would not otherwise be able to deduce that fact. 90 91 static void 92 gvardefx(Node *n, int as) 93 { 94 if(n == N) 95 fatal("gvardef nil"); 96 if(n->op != ONAME) { 97 yyerror("gvardef %#O; %N", n->op, n); 98 return; 99 } 100 switch(n->class) { 101 case PAUTO: 102 case PPARAM: 103 case PPARAMOUT: 104 gins(as, N, n); 105 } 106 } 107 108 void 109 gvardef(Node *n) 110 { 111 gvardefx(n, AVARDEF); 112 } 113 114 void 115 gvarkill(Node *n) 116 { 117 gvardefx(n, AVARKILL); 118 } 119 120 static void 121 removevardef(Prog *firstp) 122 { 123 Prog *p; 124 125 for(p = firstp; p != P; p = p->link) { 126 while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL)) 127 p->link = p->link->link; 128 if(p->to.type == D_BRANCH) 129 while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL)) 130 p->to.u.branch = p->to.u.branch->link; 131 } 132 } 133 134 static void 135 gcsymdup(Sym *s) 136 { 137 LSym *ls; 138 uint64 lo, hi; 139 140 ls = linksym(s); 141 if(ls->nr > 0) 142 fatal("cannot rosymdup %s with relocations", ls->name); 143 MD5 d; 144 md5reset(&d); 145 md5write(&d, ls->p, ls->np); 146 lo = md5sum(&d, &hi); 147 ls->name = smprint("gclocals·%016llux%016llux", lo, hi); 148 ls->dupok = 1; 149 } 150 151 void 152 compile(Node *fn) 153 { 154 Plist *pl; 155 Node nod1, *n; 156 Prog *ptxt, *p; 157 int32 lno; 158 Type *t; 159 Iter save; 160 vlong oldstksize; 161 NodeList *l; 162 Sym *gcargs; 163 Sym *gclocals; 164 165 if(newproc == N) { 166 newproc = sysfunc("newproc"); 167 deferproc = sysfunc("deferproc"); 168 deferreturn = sysfunc("deferreturn"); 169 panicindex = sysfunc("panicindex"); 170 panicslice = sysfunc("panicslice"); 171 throwreturn = sysfunc("throwreturn"); 172 } 173 174 lno = setlineno(fn); 175 176 if(fn->nbody == nil) { 177 if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) 178 yyerror("missing function body", fn); 179 goto ret; 180 } 181 182 saveerrors(); 183 184 // set up domain for labels 185 clearlabels(); 186 187 curfn = fn; 188 dowidth(curfn->type); 189 190 if(curfn->type->outnamed) { 191 // add clearing of the output parameters 192 t = structfirst(&save, getoutarg(curfn->type)); 193 while(t != T) { 194 if(t->nname != N) { 195 n = nod(OAS, t->nname, N); 196 typecheck(&n, Etop); 197 curfn->nbody = concat(list1(n), curfn->nbody); 198 } 199 t = structnext(&save); 200 } 201 } 202 203 order(curfn); 204 if(nerrors != 0) 205 goto ret; 206 207 hasdefer = 0; 208 walk(curfn); 209 if(nerrors != 0) 210 goto ret; 211 if(flag_race) 212 racewalk(curfn); 213 if(nerrors != 0) 214 goto ret; 215 216 continpc = P; 217 breakpc = P; 218 219 pl = newplist(); 220 pl->name = linksym(curfn->nname->sym); 221 222 setlineno(curfn); 223 224 nodconst(&nod1, types[TINT32], 0); 225 ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1); 226 if(fn->dupok) 227 ptxt->TEXTFLAG |= DUPOK; 228 if(fn->wrapper) 229 ptxt->TEXTFLAG |= WRAPPER; 230 if(fn->needctxt) 231 ptxt->TEXTFLAG |= NEEDCTXT; 232 233 // Clumsy but important. 234 // See test/recover.go for test cases and src/pkg/reflect/value.go 235 // for the actual functions being considered. 236 if(myimportpath != nil && strcmp(myimportpath, "reflect") == 0) { 237 if(strcmp(curfn->nname->sym->name, "callReflect") == 0 || strcmp(curfn->nname->sym->name, "callMethod") == 0) 238 ptxt->TEXTFLAG |= WRAPPER; 239 } 240 241 afunclit(&ptxt->from, curfn->nname); 242 243 ginit(); 244 245 gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps); 246 gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps); 247 248 for(t=curfn->paramfld; t; t=t->down) 249 gtrack(tracksym(t->type)); 250 251 for(l=fn->dcl; l; l=l->next) { 252 n = l->n; 253 if(n->op != ONAME) // might be OTYPE or OLITERAL 254 continue; 255 switch(n->class) { 256 case PAUTO: 257 case PPARAM: 258 case PPARAMOUT: 259 nodconst(&nod1, types[TUINTPTR], l->n->type->width); 260 p = gins(ATYPE, l->n, &nod1); 261 p->from.gotype = linksym(ngotype(l->n)); 262 break; 263 } 264 } 265 266 genlist(curfn->enter); 267 genlist(curfn->nbody); 268 gclean(); 269 checklabels(); 270 if(nerrors != 0) 271 goto ret; 272 if(curfn->endlineno) 273 lineno = curfn->endlineno; 274 275 if(curfn->type->outtuple != 0) 276 ginscall(throwreturn, 0); 277 278 ginit(); 279 // TODO: Determine when the final cgen_ret can be omitted. Perhaps always? 280 cgen_ret(nil); 281 if(hasdefer) { 282 // deferreturn pretends to have one uintptr argument. 283 // Reserve space for it so stack scanner is happy. 284 if(maxarg < widthptr) 285 maxarg = widthptr; 286 } 287 gclean(); 288 if(nerrors != 0) 289 goto ret; 290 291 pc->as = ARET; // overwrite AEND 292 pc->lineno = lineno; 293 294 fixjmp(ptxt); 295 if(!debug['N'] || debug['R'] || debug['P']) { 296 regopt(ptxt); 297 nilopt(ptxt); 298 } 299 expandchecks(ptxt); 300 301 oldstksize = stksize; 302 allocauto(ptxt); 303 304 if(0) 305 print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize); 306 USED(oldstksize); 307 308 setlineno(curfn); 309 if((int64)stksize+maxarg > (1ULL<<31)) { 310 yyerror("stack frame too large (>2GB)"); 311 goto ret; 312 } 313 314 // Emit garbage collection symbols. 315 liveness(curfn, ptxt, gcargs, gclocals); 316 gcsymdup(gcargs); 317 gcsymdup(gclocals); 318 319 defframe(ptxt); 320 321 if(0) 322 frame(0); 323 324 // Remove leftover instrumentation from the instruction stream. 325 removevardef(ptxt); 326 ret: 327 lineno = lno; 328 } 329 330 // Sort the list of stack variables. Autos after anything else, 331 // within autos, unused after used, within used, things with 332 // pointers first, zeroed things first, and then decreasing size. 333 // Because autos are laid out in decreasing addresses 334 // on the stack, pointers first, zeroed things first and decreasing size 335 // really means, in memory, things with pointers needing zeroing at 336 // the top of the stack and increasing in size. 337 // Non-autos sort on offset. 338 static int 339 cmpstackvar(Node *a, Node *b) 340 { 341 int ap, bp; 342 343 if (a->class != b->class) 344 return (a->class == PAUTO) ? +1 : -1; 345 if (a->class != PAUTO) { 346 if (a->xoffset < b->xoffset) 347 return -1; 348 if (a->xoffset > b->xoffset) 349 return +1; 350 return 0; 351 } 352 if ((a->used == 0) != (b->used == 0)) 353 return b->used - a->used; 354 355 ap = haspointers(a->type); 356 bp = haspointers(b->type); 357 if(ap != bp) 358 return bp - ap; 359 360 ap = a->needzero; 361 bp = b->needzero; 362 if(ap != bp) 363 return bp - ap; 364 365 if(a->type->width < b->type->width) 366 return +1; 367 if(a->type->width > b->type->width) 368 return -1; 369 370 return strcmp(a->sym->name, b->sym->name); 371 } 372 373 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. 374 static void 375 allocauto(Prog* ptxt) 376 { 377 NodeList *ll; 378 Node* n; 379 vlong w; 380 381 stksize = 0; 382 stkptrsize = 0; 383 384 if(curfn->dcl == nil) 385 return; 386 387 // Mark the PAUTO's unused. 388 for(ll=curfn->dcl; ll != nil; ll=ll->next) 389 if (ll->n->class == PAUTO) 390 ll->n->used = 0; 391 392 markautoused(ptxt); 393 394 listsort(&curfn->dcl, cmpstackvar); 395 396 // Unused autos are at the end, chop 'em off. 397 ll = curfn->dcl; 398 n = ll->n; 399 if (n->class == PAUTO && n->op == ONAME && !n->used) { 400 // No locals used at all 401 curfn->dcl = nil; 402 fixautoused(ptxt); 403 return; 404 } 405 406 for(ll = curfn->dcl; ll->next != nil; ll=ll->next) { 407 n = ll->next->n; 408 if (n->class == PAUTO && n->op == ONAME && !n->used) { 409 ll->next = nil; 410 curfn->dcl->end = ll; 411 break; 412 } 413 } 414 415 // Reassign stack offsets of the locals that are still there. 416 for(ll = curfn->dcl; ll != nil; ll=ll->next) { 417 n = ll->n; 418 if (n->class != PAUTO || n->op != ONAME) 419 continue; 420 421 dowidth(n->type); 422 w = n->type->width; 423 if(w >= MAXWIDTH || w < 0) 424 fatal("bad width"); 425 stksize += w; 426 stksize = rnd(stksize, n->type->align); 427 if(haspointers(n->type)) 428 stkptrsize = stksize; 429 if(thechar == '5') 430 stksize = rnd(stksize, widthptr); 431 if(stksize >= (1ULL<<31)) { 432 setlineno(curfn); 433 yyerror("stack frame too large (>2GB)"); 434 } 435 n->stkdelta = -stksize - n->xoffset; 436 } 437 stksize = rnd(stksize, widthreg); 438 stkptrsize = rnd(stkptrsize, widthreg); 439 440 fixautoused(ptxt); 441 442 // The debug information needs accurate offsets on the symbols. 443 for(ll = curfn->dcl; ll != nil; ll=ll->next) { 444 if (ll->n->class != PAUTO || ll->n->op != ONAME) 445 continue; 446 ll->n->xoffset += ll->n->stkdelta; 447 ll->n->stkdelta = 0; 448 } 449 } 450 451 static void movelargefn(Node*); 452 453 void 454 movelarge(NodeList *l) 455 { 456 for(; l; l=l->next) 457 if(l->n->op == ODCLFUNC) 458 movelargefn(l->n); 459 } 460 461 static void 462 movelargefn(Node *fn) 463 { 464 NodeList *l; 465 Node *n; 466 467 for(l=fn->dcl; l != nil; l=l->next) { 468 n = l->n; 469 if(n->class == PAUTO && n->type != T && n->type->width > MaxStackVarSize) 470 addrescapes(n); 471 } 472 } 473 474 void 475 cgen_checknil(Node *n) 476 { 477 Node reg; 478 479 if(disable_checknil) 480 return; 481 // Ideally we wouldn't see any integer types here, but we do. 482 if(n->type == T || (!isptr[n->type->etype] && !isint[n->type->etype] && n->type->etype != TUNSAFEPTR)) { 483 dump("checknil", n); 484 fatal("bad checknil"); 485 } 486 if((thechar == '5' && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) { 487 regalloc(®, types[tptr], n); 488 cgen(n, ®); 489 gins(ACHECKNIL, ®, N); 490 regfree(®); 491 return; 492 } 493 gins(ACHECKNIL, n, N); 494 }