github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/gc/popt.c (about) 1 // Derived from Inferno utils/6c/reg.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 // "Portable" optimizations. 32 // Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h. 33 // Must code to the intersection of the three back ends. 34 35 #include <u.h> 36 #include <libc.h> 37 #include "gg.h" 38 #include "opt.h" 39 40 // p is a call instruction. Does the call fail to return? 41 int 42 noreturn(Prog *p) 43 { 44 Sym *s; 45 int i; 46 static Sym* symlist[10]; 47 48 if(symlist[0] == S) { 49 symlist[0] = pkglookup("panicindex", runtimepkg); 50 symlist[1] = pkglookup("panicslice", runtimepkg); 51 symlist[2] = pkglookup("throwinit", runtimepkg); 52 symlist[3] = pkglookup("panic", runtimepkg); 53 symlist[4] = pkglookup("panicwrap", runtimepkg); 54 } 55 56 s = p->to.sym; 57 if(s == S) 58 return 0; 59 for(i=0; symlist[i]!=S; i++) 60 if(s == symlist[i]) 61 return 1; 62 return 0; 63 } 64 65 // JMP chasing and removal. 66 // 67 // The code generator depends on being able to write out jump 68 // instructions that it can jump to now but fill in later. 69 // the linker will resolve them nicely, but they make the code 70 // longer and more difficult to follow during debugging. 71 // Remove them. 72 73 /* what instruction does a JMP to p eventually land on? */ 74 static Prog* 75 chasejmp(Prog *p, int *jmploop) 76 { 77 int n; 78 79 n = 0; 80 while(p != P && p->as == AJMP && p->to.type == D_BRANCH) { 81 if(++n > 10) { 82 *jmploop = 1; 83 break; 84 } 85 p = p->to.u.branch; 86 } 87 return p; 88 } 89 90 /* 91 * reuse reg pointer for mark/sweep state. 92 * leave reg==nil at end because alive==nil. 93 */ 94 #define alive ((void*)0) 95 #define dead ((void*)1) 96 97 /* mark all code reachable from firstp as alive */ 98 static void 99 mark(Prog *firstp) 100 { 101 Prog *p; 102 103 for(p=firstp; p; p=p->link) { 104 if(p->opt != dead) 105 break; 106 p->opt = alive; 107 if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch) 108 mark(p->to.u.branch); 109 if(p->as == AJMP || p->as == ARET || p->as == AUNDEF) 110 break; 111 } 112 } 113 114 void 115 fixjmp(Prog *firstp) 116 { 117 int jmploop; 118 Prog *p, *last; 119 120 if(debug['R'] && debug['v']) 121 print("\nfixjmp\n"); 122 123 // pass 1: resolve jump to jump, mark all code as dead. 124 jmploop = 0; 125 for(p=firstp; p; p=p->link) { 126 if(debug['R'] && debug['v']) 127 print("%P\n", p); 128 if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) { 129 p->to.u.branch = chasejmp(p->to.u.branch, &jmploop); 130 if(debug['R'] && debug['v']) 131 print("->%P\n", p); 132 } 133 p->opt = dead; 134 } 135 if(debug['R'] && debug['v']) 136 print("\n"); 137 138 // pass 2: mark all reachable code alive 139 mark(firstp); 140 141 // pass 3: delete dead code (mostly JMPs). 142 last = nil; 143 for(p=firstp; p; p=p->link) { 144 if(p->opt == dead) { 145 if(p->link == P && p->as == ARET && last && last->as != ARET) { 146 // This is the final ARET, and the code so far doesn't have one. 147 // Let it stay. 148 } else { 149 if(debug['R'] && debug['v']) 150 print("del %P\n", p); 151 continue; 152 } 153 } 154 if(last) 155 last->link = p; 156 last = p; 157 } 158 last->link = P; 159 160 // pass 4: elide JMP to next instruction. 161 // only safe if there are no jumps to JMPs anymore. 162 if(!jmploop) { 163 last = nil; 164 for(p=firstp; p; p=p->link) { 165 if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) { 166 if(debug['R'] && debug['v']) 167 print("del %P\n", p); 168 continue; 169 } 170 if(last) 171 last->link = p; 172 last = p; 173 } 174 last->link = P; 175 } 176 177 if(debug['R'] && debug['v']) { 178 print("\n"); 179 for(p=firstp; p; p=p->link) 180 print("%P\n", p); 181 print("\n"); 182 } 183 } 184 185 #undef alive 186 #undef dead 187 188 // Control flow analysis. The Flow structures hold predecessor and successor 189 // information as well as basic loop analysis. 190 // 191 // graph = flowstart(firstp, sizeof(Flow)); 192 // ... use flow graph ... 193 // flowend(graph); // free graph 194 // 195 // Typical uses of the flow graph are to iterate over all the flow-relevant instructions: 196 // 197 // for(f = graph->start; f != nil; f = f->link) 198 // 199 // or, given an instruction f, to iterate over all the predecessors, which is 200 // f->p1 and this list: 201 // 202 // for(f2 = f->p2; f2 != nil; f2 = f2->p2link) 203 // 204 // Often the Flow struct is embedded as the first field inside a larger struct S. 205 // In that case casts are needed to convert Flow* to S* in many places but the 206 // idea is the same. Pass sizeof(S) instead of sizeof(Flow) to flowstart. 207 208 Graph* 209 flowstart(Prog *firstp, int size) 210 { 211 int nf; 212 Flow *f, *f1, *start, *last; 213 Graph *graph; 214 Prog *p; 215 ProgInfo info; 216 217 // Count and mark instructions to annotate. 218 nf = 0; 219 for(p = firstp; p != P; p = p->link) { 220 p->opt = nil; // should be already, but just in case 221 proginfo(&info, p); 222 if(info.flags & Skip) 223 continue; 224 p->opt = (void*)1; 225 nf++; 226 } 227 228 if(nf == 0) 229 return nil; 230 231 if(nf >= 20000) { 232 // fatal("%S is too big (%d instructions)", curfn->nname->sym, nf); 233 return nil; 234 } 235 236 // Allocate annotations and assign to instructions. 237 graph = calloc(sizeof *graph + size*nf, 1); 238 if(graph == nil) 239 fatal("out of memory"); 240 start = (Flow*)(graph+1); 241 last = nil; 242 f = start; 243 for(p = firstp; p != P; p = p->link) { 244 if(p->opt == nil) 245 continue; 246 p->opt = f; 247 f->prog = p; 248 if(last) 249 last->link = f; 250 last = f; 251 252 f = (Flow*)((uchar*)f + size); 253 } 254 255 // Fill in pred/succ information. 256 for(f = start; f != nil; f = f->link) { 257 p = f->prog; 258 proginfo(&info, p); 259 if(!(info.flags & Break)) { 260 f1 = f->link; 261 f->s1 = f1; 262 f1->p1 = f; 263 } 264 if(p->to.type == D_BRANCH) { 265 if(p->to.u.branch == P) 266 fatal("pnil %P", p); 267 f1 = p->to.u.branch->opt; 268 if(f1 == nil) 269 fatal("fnil %P / %P", p, p->to.u.branch); 270 if(f1 == f) { 271 //fatal("self loop %P", p); 272 continue; 273 } 274 f->s2 = f1; 275 f->p2link = f1->p2; 276 f1->p2 = f; 277 } 278 } 279 280 graph->start = start; 281 graph->num = nf; 282 return graph; 283 } 284 285 void 286 flowend(Graph *graph) 287 { 288 Flow *f; 289 290 for(f = graph->start; f != nil; f = f->link) 291 f->prog->opt = nil; 292 free(graph); 293 } 294 295 /* 296 * find looping structure 297 * 298 * 1) find reverse postordering 299 * 2) find approximate dominators, 300 * the actual dominators if the flow graph is reducible 301 * otherwise, dominators plus some other non-dominators. 302 * See Matthew S. Hecht and Jeffrey D. Ullman, 303 * "Analysis of a Simple Algorithm for Global Data Flow Problems", 304 * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts, 305 * Oct. 1-3, 1973, pp. 207-217. 306 * 3) find all nodes with a predecessor dominated by the current node. 307 * such a node is a loop head. 308 * recursively, all preds with a greater rpo number are in the loop 309 */ 310 static int32 311 postorder(Flow *r, Flow **rpo2r, int32 n) 312 { 313 Flow *r1; 314 315 r->rpo = 1; 316 r1 = r->s1; 317 if(r1 && !r1->rpo) 318 n = postorder(r1, rpo2r, n); 319 r1 = r->s2; 320 if(r1 && !r1->rpo) 321 n = postorder(r1, rpo2r, n); 322 rpo2r[n] = r; 323 n++; 324 return n; 325 } 326 327 static int32 328 rpolca(int32 *idom, int32 rpo1, int32 rpo2) 329 { 330 int32 t; 331 332 if(rpo1 == -1) 333 return rpo2; 334 while(rpo1 != rpo2){ 335 if(rpo1 > rpo2){ 336 t = rpo2; 337 rpo2 = rpo1; 338 rpo1 = t; 339 } 340 while(rpo1 < rpo2){ 341 t = idom[rpo2]; 342 if(t >= rpo2) 343 fatal("bad idom"); 344 rpo2 = t; 345 } 346 } 347 return rpo1; 348 } 349 350 static int 351 doms(int32 *idom, int32 r, int32 s) 352 { 353 while(s > r) 354 s = idom[s]; 355 return s == r; 356 } 357 358 static int 359 loophead(int32 *idom, Flow *r) 360 { 361 int32 src; 362 363 src = r->rpo; 364 if(r->p1 != nil && doms(idom, src, r->p1->rpo)) 365 return 1; 366 for(r = r->p2; r != nil; r = r->p2link) 367 if(doms(idom, src, r->rpo)) 368 return 1; 369 return 0; 370 } 371 372 static void 373 loopmark(Flow **rpo2r, int32 head, Flow *r) 374 { 375 if(r->rpo < head || r->active == head) 376 return; 377 r->active = head; 378 r->loop += LOOP; 379 if(r->p1 != nil) 380 loopmark(rpo2r, head, r->p1); 381 for(r = r->p2; r != nil; r = r->p2link) 382 loopmark(rpo2r, head, r); 383 } 384 385 void 386 flowrpo(Graph *g) 387 { 388 Flow *r1; 389 int32 i, d, me, nr, *idom; 390 Flow **rpo2r; 391 392 free(g->rpo); 393 g->rpo = calloc(g->num*sizeof g->rpo[0], 1); 394 idom = calloc(g->num*sizeof idom[0], 1); 395 if(g->rpo == nil || idom == nil) 396 fatal("out of memory"); 397 398 for(r1 = g->start; r1 != nil; r1 = r1->link) 399 r1->active = 0; 400 401 rpo2r = g->rpo; 402 d = postorder(g->start, rpo2r, 0); 403 nr = g->num; 404 if(d > nr) 405 fatal("too many reg nodes %d %d", d, nr); 406 nr = d; 407 for(i = 0; i < nr / 2; i++) { 408 r1 = rpo2r[i]; 409 rpo2r[i] = rpo2r[nr - 1 - i]; 410 rpo2r[nr - 1 - i] = r1; 411 } 412 for(i = 0; i < nr; i++) 413 rpo2r[i]->rpo = i; 414 415 idom[0] = 0; 416 for(i = 0; i < nr; i++) { 417 r1 = rpo2r[i]; 418 me = r1->rpo; 419 d = -1; 420 // rpo2r[r->rpo] == r protects against considering dead code, 421 // which has r->rpo == 0. 422 if(r1->p1 != nil && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me) 423 d = r1->p1->rpo; 424 for(r1 = r1->p2; r1 != nil; r1 = r1->p2link) 425 if(rpo2r[r1->rpo] == r1 && r1->rpo < me) 426 d = rpolca(idom, d, r1->rpo); 427 idom[i] = d; 428 } 429 430 for(i = 0; i < nr; i++) { 431 r1 = rpo2r[i]; 432 r1->loop++; 433 if(r1->p2 != nil && loophead(idom, r1)) 434 loopmark(rpo2r, i, r1); 435 } 436 free(idom); 437 438 for(r1 = g->start; r1 != nil; r1 = r1->link) 439 r1->active = 0; 440 } 441 442 Flow* 443 uniqp(Flow *r) 444 { 445 Flow *r1; 446 447 r1 = r->p1; 448 if(r1 == nil) { 449 r1 = r->p2; 450 if(r1 == nil || r1->p2link != nil) 451 return nil; 452 } else 453 if(r->p2 != nil) 454 return nil; 455 return r1; 456 } 457 458 Flow* 459 uniqs(Flow *r) 460 { 461 Flow *r1; 462 463 r1 = r->s1; 464 if(r1 == nil) { 465 r1 = r->s2; 466 if(r1 == nil) 467 return nil; 468 } else 469 if(r->s2 != nil) 470 return nil; 471 return r1; 472 } 473 474 // The compilers assume they can generate temporary variables 475 // as needed to preserve the right semantics or simplify code 476 // generation and the back end will still generate good code. 477 // This results in a large number of ephemeral temporary variables. 478 // Merge temps with non-overlapping lifetimes and equal types using the 479 // greedy algorithm in Poletto and Sarkar, "Linear Scan Register Allocation", 480 // ACM TOPLAS 1999. 481 482 typedef struct TempVar TempVar; 483 typedef struct TempFlow TempFlow; 484 485 struct TempVar 486 { 487 Node *node; 488 TempFlow *def; // definition of temp var 489 TempFlow *use; // use list, chained through TempFlow.uselink 490 TempVar *freelink; // next free temp in Type.opt list 491 TempVar *merge; // merge var with this one 492 uint32 start; // smallest Prog.loc in live range 493 uint32 end; // largest Prog.loc in live range 494 uchar addr; // address taken - no accurate end 495 uchar removed; // removed from program 496 }; 497 498 struct TempFlow 499 { 500 Flow f; 501 TempFlow *uselink; 502 }; 503 504 static int 505 startcmp(const void *va, const void *vb) 506 { 507 TempVar *a, *b; 508 509 a = *(TempVar**)va; 510 b = *(TempVar**)vb; 511 512 if(a->start < b->start) 513 return -1; 514 if(a->start > b->start) 515 return +1; 516 return 0; 517 } 518 519 // Is n available for merging? 520 static int 521 canmerge(Node *n) 522 { 523 return n->class == PAUTO && !n->addrtaken && strncmp(n->sym->name, "autotmp", 7) == 0; 524 } 525 526 static void mergewalk(TempVar*, TempFlow*, uint32); 527 528 void 529 mergetemp(Prog *firstp) 530 { 531 int i, j, nvar, ninuse, nfree, nkill; 532 TempVar *var, *v, *v1, **bystart, **inuse; 533 TempFlow *r; 534 NodeList *l, **lp; 535 Node *n; 536 Prog *p, *p1; 537 Type *t; 538 ProgInfo info, info1; 539 int32 gen; 540 Graph *g; 541 542 enum { Debug = 0 }; 543 544 g = flowstart(firstp, sizeof(TempFlow)); 545 if(g == nil) 546 return; 547 548 // Build list of all mergeable variables. 549 nvar = 0; 550 for(l = curfn->dcl; l != nil; l = l->next) 551 if(canmerge(l->n)) 552 nvar++; 553 554 var = calloc(nvar*sizeof var[0], 1); 555 nvar = 0; 556 for(l = curfn->dcl; l != nil; l = l->next) { 557 n = l->n; 558 if(canmerge(n)) { 559 v = &var[nvar++]; 560 n->opt = v; 561 v->node = n; 562 } 563 } 564 565 // Build list of uses. 566 // We assume that the earliest reference to a temporary is its definition. 567 // This is not true of variables in general but our temporaries are all 568 // single-use (that's why we have so many!). 569 for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) { 570 p = r->f.prog; 571 proginfo(&info, p); 572 573 if(p->from.node != N && p->from.node->opt && p->to.node != N && p->to.node->opt) 574 fatal("double node %P", p); 575 if((n = p->from.node) != N && (v = n->opt) != nil || 576 (n = p->to.node) != N && (v = n->opt) != nil) { 577 if(v->def == nil) 578 v->def = r; 579 r->uselink = v->use; 580 v->use = r; 581 if(n == p->from.node && (info.flags & LeftAddr)) 582 v->addr = 1; 583 } 584 } 585 586 if(Debug > 1) 587 dumpit("before", g->start, 0); 588 589 nkill = 0; 590 591 // Special case. 592 for(v = var; v < var+nvar; v++) { 593 if(v->addr) 594 continue; 595 // Used in only one instruction, which had better be a write. 596 if((r = v->use) != nil && r->uselink == nil) { 597 p = r->f.prog; 598 proginfo(&info, p); 599 if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) { 600 p->as = ANOP; 601 p->to = zprog.to; 602 v->removed = 1; 603 if(Debug) 604 print("drop write-only %S\n", v->node->sym); 605 } else 606 fatal("temp used and not set: %P", p); 607 nkill++; 608 continue; 609 } 610 611 // Written in one instruction, read in the next, otherwise unused, 612 // no jumps to the next instruction. Happens mainly in 386 compiler. 613 if((r = v->use) != nil && r->f.link == &r->uselink->f && r->uselink->uselink == nil && uniqp(r->f.link) == &r->f) { 614 p = r->f.prog; 615 proginfo(&info, p); 616 p1 = r->f.link->prog; 617 proginfo(&info1, p1); 618 enum { 619 SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD, 620 }; 621 if(p->from.node == v->node && p1->to.node == v->node && (info.flags & Move) && 622 !((info.flags|info1.flags) & (LeftAddr|RightAddr)) && 623 (info.flags & SizeAny) == (info1.flags & SizeAny)) { 624 p1->from = p->from; 625 excise(&r->f); 626 v->removed = 1; 627 if(Debug) 628 print("drop immediate-use %S\n", v->node->sym); 629 } 630 nkill++; 631 continue; 632 } 633 } 634 635 // Traverse live range of each variable to set start, end. 636 // Each flood uses a new value of gen so that we don't have 637 // to clear all the r->f.active words after each variable. 638 gen = 0; 639 for(v = var; v < var+nvar; v++) { 640 gen++; 641 for(r = v->use; r != nil; r = r->uselink) 642 mergewalk(v, r, gen); 643 } 644 645 // Sort variables by start. 646 bystart = malloc(nvar*sizeof bystart[0]); 647 for(i=0; i<nvar; i++) 648 bystart[i] = &var[i]; 649 qsort(bystart, nvar, sizeof bystart[0], startcmp); 650 651 // List of in-use variables, sorted by end, so that the ones that 652 // will last the longest are the earliest ones in the array. 653 // The tail inuse[nfree:] holds no-longer-used variables. 654 // In theory we should use a sorted tree so that insertions are 655 // guaranteed O(log n) and then the loop is guaranteed O(n log n). 656 // In practice, it doesn't really matter. 657 inuse = malloc(nvar*sizeof inuse[0]); 658 ninuse = 0; 659 nfree = nvar; 660 for(i=0; i<nvar; i++) { 661 v = bystart[i]; 662 if(v->addr || v->removed) 663 continue; 664 665 // Expire no longer in use. 666 while(ninuse > 0 && inuse[ninuse-1]->end < v->start) { 667 v1 = inuse[--ninuse]; 668 inuse[--nfree] = v1; 669 } 670 671 // Find old temp to reuse if possible. 672 t = v->node->type; 673 for(j=nfree; j<nvar; j++) { 674 v1 = inuse[j]; 675 if(eqtype(t, v1->node->type)) { 676 inuse[j] = inuse[nfree++]; 677 if(v1->merge) 678 v->merge = v1->merge; 679 else 680 v->merge = v1; 681 nkill++; 682 break; 683 } 684 } 685 686 // Sort v into inuse. 687 j = ninuse++; 688 while(j > 0 && inuse[j-1]->end < v->end) { 689 inuse[j] = inuse[j-1]; 690 j--; 691 } 692 inuse[j] = v; 693 } 694 695 if(Debug) { 696 print("%S [%d - %d]\n", curfn->nname->sym, nvar, nkill); 697 for(v=var; v<var+nvar; v++) { 698 print("var %#N %T %d-%d", v->node, v->node->type, v->start, v->end); 699 if(v->addr) 700 print(" addr=1"); 701 if(v->removed) 702 print(" dead=1"); 703 if(v->merge) 704 print(" merge %#N", v->merge->node); 705 if(v->start == v->end) 706 print(" %P", v->def->f.prog); 707 print("\n"); 708 } 709 710 if(Debug > 1) 711 dumpit("after", g->start, 0); 712 } 713 714 // Update node references to use merged temporaries. 715 for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) { 716 p = r->f.prog; 717 if((n = p->from.node) != N && (v = n->opt) != nil && v->merge != nil) 718 p->from.node = v->merge->node; 719 if((n = p->to.node) != N && (v = n->opt) != nil && v->merge != nil) 720 p->to.node = v->merge->node; 721 } 722 723 // Delete merged nodes from declaration list. 724 for(lp = &curfn->dcl; (l = *lp); ) { 725 curfn->dcl->end = l; 726 n = l->n; 727 v = n->opt; 728 if(v && (v->merge || v->removed)) { 729 *lp = l->next; 730 continue; 731 } 732 lp = &l->next; 733 } 734 735 // Clear aux structures. 736 for(v=var; v<var+nvar; v++) 737 v->node->opt = nil; 738 free(var); 739 free(bystart); 740 free(inuse); 741 flowend(g); 742 } 743 744 static void 745 mergewalk(TempVar *v, TempFlow *r0, uint32 gen) 746 { 747 Prog *p; 748 TempFlow *r1, *r, *r2; 749 750 for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.p1) { 751 if(r1->f.active == gen) 752 break; 753 r1->f.active = gen; 754 p = r1->f.prog; 755 if(v->end < p->loc) 756 v->end = p->loc; 757 if(r1 == v->def) { 758 v->start = p->loc; 759 break; 760 } 761 } 762 763 for(r = r0; r != r1; r = (TempFlow*)r->f.p1) 764 for(r2 = (TempFlow*)r->f.p2; r2 != nil; r2 = (TempFlow*)r2->f.p2link) 765 mergewalk(v, r2, gen); 766 } 767 768 // Eliminate redundant nil pointer checks. 769 // 770 // The code generation pass emits a CHECKNIL for every possibly nil pointer. 771 // This pass removes a CHECKNIL if every predecessor path has already 772 // checked this value for nil. 773 // 774 // Simple backwards flood from check to definition. 775 // Run prog loop backward from end of program to beginning to avoid quadratic 776 // behavior removing a run of checks. 777 // 778 // Assume that stack variables with address not taken can be loaded multiple times 779 // from memory without being rechecked. Other variables need to be checked on 780 // each load. 781 782 typedef struct NilVar NilVar; 783 typedef struct NilFlow NilFlow; 784 785 struct NilFlow { 786 Flow f; 787 int kill; 788 }; 789 790 static void nilwalkback(NilFlow *rcheck); 791 static void nilwalkfwd(NilFlow *rcheck); 792 793 void 794 nilopt(Prog *firstp) 795 { 796 NilFlow *r; 797 Prog *p; 798 Graph *g; 799 int ncheck, nkill; 800 801 g = flowstart(firstp, sizeof(NilFlow)); 802 if(g == nil) 803 return; 804 805 if(debug_checknil > 1 /* || strcmp(curfn->nname->sym->name, "f1") == 0 */) 806 dumpit("nilopt", g->start, 0); 807 808 ncheck = 0; 809 nkill = 0; 810 for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) { 811 p = r->f.prog; 812 if(p->as != ACHECKNIL || !regtyp(&p->from)) 813 continue; 814 ncheck++; 815 if(stackaddr(&p->from)) { 816 if(debug_checknil && p->lineno > 1) 817 warnl(p->lineno, "removed nil check of SP address"); 818 r->kill = 1; 819 continue; 820 } 821 nilwalkfwd(r); 822 if(r->kill) { 823 if(debug_checknil && p->lineno > 1) 824 warnl(p->lineno, "removed nil check before indirect"); 825 continue; 826 } 827 nilwalkback(r); 828 if(r->kill) { 829 if(debug_checknil && p->lineno > 1) 830 warnl(p->lineno, "removed repeated nil check"); 831 continue; 832 } 833 } 834 835 for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) { 836 if(r->kill) { 837 nkill++; 838 excise(&r->f); 839 } 840 } 841 842 flowend(g); 843 844 if(debug_checknil > 1) 845 print("%S: removed %d of %d nil checks\n", curfn->nname->sym, nkill, ncheck); 846 } 847 848 static void 849 nilwalkback(NilFlow *rcheck) 850 { 851 Prog *p; 852 ProgInfo info; 853 NilFlow *r; 854 855 for(r = rcheck; r != nil; r = (NilFlow*)uniqp(&r->f)) { 856 p = r->f.prog; 857 proginfo(&info, p); 858 if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) { 859 // Found initialization of value we're checking for nil. 860 // without first finding the check, so this one is unchecked. 861 return; 862 } 863 if(r != rcheck && p->as == ACHECKNIL && sameaddr(&p->from, &rcheck->f.prog->from)) { 864 rcheck->kill = 1; 865 return; 866 } 867 } 868 869 // Here is a more complex version that scans backward across branches. 870 // It assumes rcheck->kill = 1 has been set on entry, and its job is to find a reason 871 // to keep the check (setting rcheck->kill = 0). 872 // It doesn't handle copying of aggregates as well as I would like, 873 // nor variables with their address taken, 874 // and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3. 875 /* 876 for(r1 = r0; r1 != nil; r1 = (NilFlow*)r1->f.p1) { 877 if(r1->f.active == gen) 878 break; 879 r1->f.active = gen; 880 p = r1->f.prog; 881 882 // If same check, stop this loop but still check 883 // alternate predecessors up to this point. 884 if(r1 != rcheck && p->as == ACHECKNIL && sameaddr(&p->from, &rcheck->f.prog->from)) 885 break; 886 887 proginfo(&info, p); 888 if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) { 889 // Found initialization of value we're checking for nil. 890 // without first finding the check, so this one is unchecked. 891 rcheck->kill = 0; 892 return; 893 } 894 895 if(r1->f.p1 == nil && r1->f.p2 == nil) { 896 print("lost pred for %P\n", rcheck->f.prog); 897 for(r1=r0; r1!=nil; r1=(NilFlow*)r1->f.p1) { 898 proginfo(&info, r1->f.prog); 899 print("\t%P %d %d %D %D\n", r1->f.prog, info.flags&RightWrite, sameaddr(&r1->f.prog->to, &rcheck->f.prog->from), &r1->f.prog->to, &rcheck->f.prog->from); 900 } 901 fatal("lost pred trail"); 902 } 903 } 904 905 for(r = r0; r != r1; r = (NilFlow*)r->f.p1) 906 for(r2 = (NilFlow*)r->f.p2; r2 != nil; r2 = (NilFlow*)r2->f.p2link) 907 nilwalkback(rcheck, r2, gen); 908 */ 909 } 910 911 static void 912 nilwalkfwd(NilFlow *rcheck) 913 { 914 NilFlow *r; 915 Prog *p; 916 ProgInfo info; 917 918 // If the path down from rcheck dereferences the address 919 // (possibly with a small offset) before writing to memory 920 // and before any subsequent checks, it's okay to wait for 921 // that implicit check. Only consider this basic block to 922 // avoid problems like: 923 // _ = *x // should panic 924 // for {} // no writes but infinite loop may be considered visible 925 for(r = (NilFlow*)uniqs(&rcheck->f); r != nil; r = (NilFlow*)uniqs(&r->f)) { 926 p = r->f.prog; 927 proginfo(&info, p); 928 929 if((info.flags & LeftRead) && smallindir(&p->from, &rcheck->f.prog->from)) { 930 rcheck->kill = 1; 931 return; 932 } 933 if((info.flags & (RightRead|RightWrite)) && smallindir(&p->to, &rcheck->f.prog->from)) { 934 rcheck->kill = 1; 935 return; 936 } 937 938 // Stop if another nil check happens. 939 if(p->as == ACHECKNIL) 940 return; 941 // Stop if value is lost. 942 if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) 943 return; 944 // Stop if memory write. 945 if((info.flags & RightWrite) && !regtyp(&p->to)) 946 return; 947 } 948 }