github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/cmd/gc/inl.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 // The inlining facility makes 2 passes: first caninl determines which 6 // functions are suitable for inlining, and for those that are it 7 // saves a copy of the body. Then inlcalls walks each function body to 8 // expand calls to inlinable functions. 9 // 10 // The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1, 11 // making 1 the default and -l disable. -ll and more is useful to flush out bugs. 12 // These additional levels (beyond -l) may be buggy and are not supported. 13 // 0: disabled 14 // 1: 40-nodes leaf functions, oneliners, lazy typechecking (default) 15 // 2: early typechecking of all imported bodies 16 // 3: allow variadic functions 17 // 4: allow non-leaf functions , (breaks runtime.Caller) 18 // 5: transitive inlining 19 // 20 // At some point this may get another default and become switch-offable with -N. 21 // 22 // The debug['m'] flag enables diagnostic output. a single -m is useful for verifying 23 // which calls get inlined or not, more is for debugging, and may go away at any point. 24 // 25 // TODO: 26 // - inline functions with ... args 27 // - handle T.meth(f()) with func f() (t T, arg, arg, ) 28 29 #include <u.h> 30 #include <libc.h> 31 #include "go.h" 32 33 // Used by caninl. 34 static Node* inlcopy(Node *n); 35 static NodeList* inlcopylist(NodeList *ll); 36 static int ishairy(Node *n, int *budget); 37 static int ishairylist(NodeList *ll, int *budget); 38 39 // Used by inlcalls 40 static void inlnodelist(NodeList *l); 41 static void inlnode(Node **np); 42 static void mkinlcall(Node **np, Node *fn, int isddd); 43 static Node* inlvar(Node *n); 44 static Node* retvar(Type *n, int i); 45 static Node* argvar(Type *n, int i); 46 static Node* newlabel(void); 47 static Node* inlsubst(Node *n); 48 static NodeList* inlsubstlist(NodeList *l); 49 50 static void setlno(Node*, int); 51 52 // Used during inlsubst[list] 53 static Node *inlfn; // function currently being inlined 54 static Node *inlretlabel; // target of the goto substituted in place of a return 55 static NodeList *inlretvars; // temp out variables 56 57 // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods 58 // the ->sym can be re-used in the local package, so peel it off the receiver's type. 59 static Pkg* 60 fnpkg(Node *fn) 61 { 62 Type *rcvr; 63 64 if(fn->type->thistuple) { 65 // method 66 rcvr = getthisx(fn->type)->type->type; 67 if(isptr[rcvr->etype]) 68 rcvr = rcvr->type; 69 if(!rcvr->sym) 70 fatal("receiver with no sym: [%S] %lN (%T)", fn->sym, fn, rcvr); 71 return rcvr->sym->pkg; 72 } 73 // non-method 74 return fn->sym->pkg; 75 } 76 77 // Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck 78 // because they're a copy of an already checked body. 79 void 80 typecheckinl(Node *fn) 81 { 82 Node *savefn; 83 Pkg *pkg; 84 int save_safemode, lno; 85 86 lno = setlineno(fn); 87 88 // typecheckinl is only for imported functions; 89 // their bodies may refer to unsafe as long as the package 90 // was marked safe during import (which was checked then). 91 // the ->inl of a local function has been typechecked before caninl copied it. 92 pkg = fnpkg(fn); 93 if (pkg == localpkg || pkg == nil) 94 return; // typecheckinl on local function 95 96 if (debug['m']>2) 97 print("typecheck import [%S] %lN { %#H }\n", fn->sym, fn, fn->inl); 98 99 save_safemode = safemode; 100 safemode = 0; 101 102 savefn = curfn; 103 curfn = fn; 104 typechecklist(fn->inl, Etop); 105 curfn = savefn; 106 107 safemode = save_safemode; 108 109 lineno = lno; 110 } 111 112 // Caninl determines whether fn is inlineable. 113 // If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy. 114 // fn and ->nbody will already have been typechecked. 115 void 116 caninl(Node *fn) 117 { 118 Node *savefn; 119 Type *t; 120 int budget; 121 122 if(fn->op != ODCLFUNC) 123 fatal("caninl %N", fn); 124 if(!fn->nname) 125 fatal("caninl no nname %+N", fn); 126 127 // If fn has no body (is defined outside of Go), cannot inline it. 128 if(fn->nbody == nil) 129 return; 130 131 if(fn->typecheck == 0) 132 fatal("caninl on non-typechecked function %N", fn); 133 134 // can't handle ... args yet 135 if(debug['l'] < 3) 136 for(t=fn->type->type->down->down->type; t; t=t->down) 137 if(t->isddd) 138 return; 139 140 budget = 40; // allowed hairyness 141 if(ishairylist(fn->nbody, &budget)) 142 return; 143 144 savefn = curfn; 145 curfn = fn; 146 147 fn->nname->inl = fn->nbody; 148 fn->nbody = inlcopylist(fn->nname->inl); 149 fn->nname->inldcl = inlcopylist(fn->nname->defn->dcl); 150 151 // hack, TODO, check for better way to link method nodes back to the thing with the ->inl 152 // this is so export can find the body of a method 153 fn->type->nname = fn->nname; 154 155 if(debug['m'] > 1) 156 print("%L: can inline %#N as: %#T { %#H }\n", fn->lineno, fn->nname, fn->type, fn->nname->inl); 157 else if(debug['m']) 158 print("%L: can inline %N\n", fn->lineno, fn->nname); 159 160 curfn = savefn; 161 } 162 163 // Look for anything we want to punt on. 164 static int 165 ishairylist(NodeList *ll, int* budget) 166 { 167 for(;ll;ll=ll->next) 168 if(ishairy(ll->n, budget)) 169 return 1; 170 return 0; 171 } 172 173 static int 174 ishairy(Node *n, int *budget) 175 { 176 if(!n) 177 return 0; 178 179 // Things that are too hairy, irrespective of the budget 180 switch(n->op) { 181 case OCALL: 182 case OCALLFUNC: 183 case OCALLINTER: 184 case OCALLMETH: 185 case OPANIC: 186 case ORECOVER: 187 if(debug['l'] < 4) 188 return 1; 189 break; 190 191 case OCLOSURE: 192 case OCALLPART: 193 case ORANGE: 194 case OFOR: 195 case OSELECT: 196 case OSWITCH: 197 case OPROC: 198 case ODEFER: 199 case ODCLTYPE: // can't print yet 200 case ODCLCONST: // can't print yet 201 case ORETJMP: 202 return 1; 203 204 break; 205 } 206 207 (*budget)--; 208 209 return *budget < 0 || 210 ishairy(n->left, budget) || 211 ishairy(n->right, budget) || 212 ishairylist(n->list, budget) || 213 ishairylist(n->rlist, budget) || 214 ishairylist(n->ninit, budget) || 215 ishairy(n->ntest, budget) || 216 ishairy(n->nincr, budget) || 217 ishairylist(n->nbody, budget) || 218 ishairylist(n->nelse, budget); 219 } 220 221 // Inlcopy and inlcopylist recursively copy the body of a function. 222 // Any name-like node of non-local class is marked for re-export by adding it to 223 // the exportlist. 224 static NodeList* 225 inlcopylist(NodeList *ll) 226 { 227 NodeList *l; 228 229 l = nil; 230 for(; ll; ll=ll->next) 231 l = list(l, inlcopy(ll->n)); 232 return l; 233 } 234 235 static Node* 236 inlcopy(Node *n) 237 { 238 Node *m; 239 240 if(n == N) 241 return N; 242 243 switch(n->op) { 244 case ONAME: 245 case OTYPE: 246 case OLITERAL: 247 return n; 248 } 249 250 m = nod(OXXX, N, N); 251 *m = *n; 252 m->inl = nil; 253 m->left = inlcopy(n->left); 254 m->right = inlcopy(n->right); 255 m->list = inlcopylist(n->list); 256 m->rlist = inlcopylist(n->rlist); 257 m->ninit = inlcopylist(n->ninit); 258 m->ntest = inlcopy(n->ntest); 259 m->nincr = inlcopy(n->nincr); 260 m->nbody = inlcopylist(n->nbody); 261 m->nelse = inlcopylist(n->nelse); 262 263 return m; 264 } 265 266 267 // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any 268 // calls made to inlineable functions. This is the external entry point. 269 void 270 inlcalls(Node *fn) 271 { 272 Node *savefn; 273 274 savefn = curfn; 275 curfn = fn; 276 inlnode(&fn); 277 if(fn != curfn) 278 fatal("inlnode replaced curfn"); 279 curfn = savefn; 280 } 281 282 // Turn an OINLCALL into a statement. 283 static void 284 inlconv2stmt(Node *n) 285 { 286 n->op = OBLOCK; 287 // n->ninit stays 288 n->list = n->nbody; 289 n->nbody = nil; 290 n->rlist = nil; 291 } 292 293 // Turn an OINLCALL into a single valued expression. 294 static void 295 inlconv2expr(Node **np) 296 { 297 Node *n, *r; 298 n = *np; 299 r = n->rlist->n; 300 addinit(&r, concat(n->ninit, n->nbody)); 301 *np = r; 302 } 303 304 // Turn the rlist (with the return values) of the OINLCALL in 305 // n into an expression list lumping the ninit and body 306 // containing the inlined statements on the first list element so 307 // order will be preserved Used in return, oas2func and call 308 // statements. 309 static NodeList* 310 inlconv2list(Node *n) 311 { 312 NodeList *l; 313 314 if(n->op != OINLCALL || n->rlist == nil) 315 fatal("inlconv2list %+N\n", n); 316 317 l = n->rlist; 318 addinit(&l->n, concat(n->ninit, n->nbody)); 319 return l; 320 } 321 322 static void 323 inlnodelist(NodeList *l) 324 { 325 for(; l; l=l->next) 326 inlnode(&l->n); 327 } 328 329 // inlnode recurses over the tree to find inlineable calls, which will 330 // be turned into OINLCALLs by mkinlcall. When the recursion comes 331 // back up will examine left, right, list, rlist, ninit, ntest, nincr, 332 // nbody and nelse and use one of the 4 inlconv/glue functions above 333 // to turn the OINLCALL into an expression, a statement, or patch it 334 // in to this nodes list or rlist as appropriate. 335 // NOTE it makes no sense to pass the glue functions down the 336 // recursion to the level where the OINLCALL gets created because they 337 // have to edit /this/ n, so you'd have to push that one down as well, 338 // but then you may as well do it here. so this is cleaner and 339 // shorter and less complicated. 340 static void 341 inlnode(Node **np) 342 { 343 Node *n; 344 NodeList *l; 345 int lno; 346 347 if(*np == nil) 348 return; 349 350 n = *np; 351 352 switch(n->op) { 353 case ODEFER: 354 case OPROC: 355 // inhibit inlining of their argument 356 switch(n->left->op) { 357 case OCALLFUNC: 358 case OCALLMETH: 359 n->left->etype = n->op; 360 } 361 362 case OCLOSURE: 363 // TODO do them here (or earlier), 364 // so escape analysis can avoid more heapmoves. 365 return; 366 } 367 368 lno = setlineno(n); 369 370 inlnodelist(n->ninit); 371 for(l=n->ninit; l; l=l->next) 372 if(l->n->op == OINLCALL) 373 inlconv2stmt(l->n); 374 375 inlnode(&n->left); 376 if(n->left && n->left->op == OINLCALL) 377 inlconv2expr(&n->left); 378 379 inlnode(&n->right); 380 if(n->right && n->right->op == OINLCALL) 381 inlconv2expr(&n->right); 382 383 inlnodelist(n->list); 384 switch(n->op) { 385 case OBLOCK: 386 for(l=n->list; l; l=l->next) 387 if(l->n->op == OINLCALL) 388 inlconv2stmt(l->n); 389 break; 390 391 case ORETURN: 392 case OCALLFUNC: 393 case OCALLMETH: 394 case OCALLINTER: 395 // if we just replaced arg in f(arg()) or return arg with an inlined call 396 // and arg returns multiple values, glue as list 397 if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) { 398 n->list = inlconv2list(n->list->n); 399 break; 400 } 401 402 // fallthrough 403 default: 404 for(l=n->list; l; l=l->next) 405 if(l->n->op == OINLCALL) 406 inlconv2expr(&l->n); 407 } 408 409 inlnodelist(n->rlist); 410 switch(n->op) { 411 case OAS2FUNC: 412 if(n->rlist->n->op == OINLCALL) { 413 n->rlist = inlconv2list(n->rlist->n); 414 n->op = OAS2; 415 n->typecheck = 0; 416 typecheck(np, Etop); 417 break; 418 } 419 420 // fallthrough 421 default: 422 for(l=n->rlist; l; l=l->next) 423 if(l->n->op == OINLCALL) 424 inlconv2expr(&l->n); 425 426 } 427 428 inlnode(&n->ntest); 429 if(n->ntest && n->ntest->op == OINLCALL) 430 inlconv2expr(&n->ntest); 431 432 inlnode(&n->nincr); 433 if(n->nincr && n->nincr->op == OINLCALL) 434 inlconv2stmt(n->nincr); 435 436 inlnodelist(n->nbody); 437 for(l=n->nbody; l; l=l->next) 438 if(l->n->op == OINLCALL) 439 inlconv2stmt(l->n); 440 441 inlnodelist(n->nelse); 442 for(l=n->nelse; l; l=l->next) 443 if(l->n->op == OINLCALL) 444 inlconv2stmt(l->n); 445 446 // with all the branches out of the way, it is now time to 447 // transmogrify this node itself unless inhibited by the 448 // switch at the top of this function. 449 switch(n->op) { 450 case OCALLFUNC: 451 case OCALLMETH: 452 if (n->etype == OPROC || n->etype == ODEFER) 453 return; 454 } 455 456 switch(n->op) { 457 case OCALLFUNC: 458 if(debug['m']>3) 459 print("%L:call to func %+N\n", n->lineno, n->left); 460 if(n->left->inl) // normal case 461 mkinlcall(np, n->left, n->isddd); 462 else if(n->left->op == ONAME && n->left->left && n->left->left->op == OTYPE && n->left->right && n->left->right->op == ONAME) // methods called as functions 463 if(n->left->sym->def) 464 mkinlcall(np, n->left->sym->def, n->isddd); 465 break; 466 467 case OCALLMETH: 468 if(debug['m']>3) 469 print("%L:call to meth %lN\n", n->lineno, n->left->right); 470 // typecheck should have resolved ODOTMETH->type, whose nname points to the actual function. 471 if(n->left->type == T) 472 fatal("no function type for [%p] %+N\n", n->left, n->left); 473 474 if(n->left->type->nname == N) 475 fatal("no function definition for [%p] %+T\n", n->left->type, n->left->type); 476 477 mkinlcall(np, n->left->type->nname, n->isddd); 478 479 break; 480 } 481 482 lineno = lno; 483 } 484 485 static void mkinlcall1(Node **np, Node *fn, int isddd); 486 487 static void 488 mkinlcall(Node **np, Node *fn, int isddd) 489 { 490 int save_safemode; 491 Pkg *pkg; 492 493 save_safemode = safemode; 494 495 // imported functions may refer to unsafe as long as the 496 // package was marked safe during import (already checked). 497 pkg = fnpkg(fn); 498 if(pkg != localpkg && pkg != nil) 499 safemode = 0; 500 mkinlcall1(np, fn, isddd); 501 safemode = save_safemode; 502 } 503 504 static Node* 505 tinlvar(Type *t) 506 { 507 if(t->nname && !isblank(t->nname)) { 508 if(!t->nname->inlvar) 509 fatal("missing inlvar for %N\n", t->nname); 510 return t->nname->inlvar; 511 } 512 typecheck(&nblank, Erv | Easgn); 513 return nblank; 514 } 515 516 static int inlgen; 517 518 // if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL. 519 // On return ninit has the parameter assignments, the nbody is the 520 // inlined function body and list, rlist contain the input, output 521 // parameters. 522 static void 523 mkinlcall1(Node **np, Node *fn, int isddd) 524 { 525 int i; 526 int chkargcount; 527 Node *n, *call, *saveinlfn, *as, *m; 528 NodeList *dcl, *ll, *ninit, *body; 529 Type *t; 530 // For variadic fn. 531 int variadic, varargcount, multiret; 532 Node *vararg; 533 NodeList *varargs; 534 Type *varargtype, *vararrtype; 535 536 if (fn->inl == nil) 537 return; 538 539 if (fn == curfn || fn->defn == curfn) 540 return; 541 542 if(debug['l']<2) 543 typecheckinl(fn); 544 545 n = *np; 546 547 // Bingo, we have a function node, and it has an inlineable body 548 if(debug['m']>1) 549 print("%L: inlining call to %S %#T { %#H }\n", n->lineno, fn->sym, fn->type, fn->inl); 550 else if(debug['m']) 551 print("%L: inlining call to %N\n", n->lineno, fn); 552 553 if(debug['m']>2) 554 print("%L: Before inlining: %+N\n", n->lineno, n); 555 556 saveinlfn = inlfn; 557 inlfn = fn; 558 559 ninit = n->ninit; 560 561 //dumplist("ninit pre", ninit); 562 563 if(fn->defn) // local function 564 dcl = fn->inldcl; 565 else // imported function 566 dcl = fn->dcl; 567 568 inlretvars = nil; 569 i = 0; 570 // Make temp names to use instead of the originals 571 for(ll = dcl; ll; ll=ll->next) { 572 if(ll->n->class == PPARAMOUT) // return values handled below. 573 continue; 574 if(ll->n->op == ONAME) { 575 ll->n->inlvar = inlvar(ll->n); 576 // Typecheck because inlvar is not necessarily a function parameter. 577 typecheck(&ll->n->inlvar, Erv); 578 if ((ll->n->class&~PHEAP) != PAUTO) 579 ninit = list(ninit, nod(ODCL, ll->n->inlvar, N)); // otherwise gen won't emit the allocations for heapallocs 580 } 581 } 582 583 // temporaries for return values. 584 for(t = getoutargx(fn->type)->type; t; t = t->down) { 585 if(t != T && t->nname != N && !isblank(t->nname)) { 586 m = inlvar(t->nname); 587 typecheck(&m, Erv); 588 t->nname->inlvar = m; 589 } else { 590 // anonymous return values, synthesize names for use in assignment that replaces return 591 m = retvar(t, i++); 592 } 593 ninit = list(ninit, nod(ODCL, m, N)); 594 inlretvars = list(inlretvars, m); 595 } 596 597 // assign receiver. 598 if(fn->type->thistuple && n->left->op == ODOTMETH) { 599 // method call with a receiver. 600 t = getthisx(fn->type)->type; 601 if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar) 602 fatal("missing inlvar for %N\n", t->nname); 603 if(!n->left->left) 604 fatal("method call without receiver: %+N", n); 605 if(t == T) 606 fatal("method call unknown receiver type: %+N", n); 607 as = nod(OAS, tinlvar(t), n->left->left); 608 if(as != N) { 609 typecheck(&as, Etop); 610 ninit = list(ninit, as); 611 } 612 } 613 614 // check if inlined function is variadic. 615 variadic = 0; 616 varargtype = T; 617 varargcount = 0; 618 for(t=fn->type->type->down->down->type; t; t=t->down) { 619 if(t->isddd) { 620 variadic = 1; 621 varargtype = t->type; 622 } 623 } 624 // but if argument is dotted too forget about variadicity. 625 if(variadic && isddd) 626 variadic = 0; 627 628 // check if argument is actually a returned tuple from call. 629 multiret = 0; 630 if(n->list && !n->list->next) { 631 switch(n->list->n->op) { 632 case OCALL: 633 case OCALLFUNC: 634 case OCALLINTER: 635 case OCALLMETH: 636 if(n->list->n->left->type->outtuple > 1) 637 multiret = n->list->n->left->type->outtuple-1; 638 } 639 } 640 641 if(variadic) { 642 varargcount = count(n->list) + multiret; 643 if(n->left->op != ODOTMETH) 644 varargcount -= fn->type->thistuple; 645 varargcount -= fn->type->intuple - 1; 646 } 647 648 // assign arguments to the parameters' temp names 649 as = nod(OAS2, N, N); 650 as->rlist = n->list; 651 ll = n->list; 652 653 // TODO: if len(nlist) == 1 but multiple args, check that n->list->n is a call? 654 if(fn->type->thistuple && n->left->op != ODOTMETH) { 655 // non-method call to method 656 if(!n->list) 657 fatal("non-method call to method without first arg: %+N", n); 658 // append receiver inlvar to LHS. 659 t = getthisx(fn->type)->type; 660 if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar) 661 fatal("missing inlvar for %N\n", t->nname); 662 if(t == T) 663 fatal("method call unknown receiver type: %+N", n); 664 as->list = list(as->list, tinlvar(t)); 665 ll = ll->next; // track argument count. 666 } 667 668 // append ordinary arguments to LHS. 669 chkargcount = n->list && n->list->next; 670 vararg = N; // the slice argument to a variadic call 671 varargs = nil; // the list of LHS names to put in vararg. 672 if(!chkargcount) { 673 // 0 or 1 expression on RHS. 674 for(t = getinargx(fn->type)->type; t; t=t->down) { 675 if(variadic && t->isddd) { 676 vararg = tinlvar(t); 677 for(i=0; i<varargcount && ll; i++) { 678 m = argvar(varargtype, i); 679 varargs = list(varargs, m); 680 as->list = list(as->list, m); 681 } 682 break; 683 } 684 as->list = list(as->list, tinlvar(t)); 685 } 686 } else { 687 // match arguments except final variadic (unless the call is dotted itself) 688 for(t = getinargx(fn->type)->type; t;) { 689 if(!ll) 690 break; 691 if(variadic && t->isddd) 692 break; 693 as->list = list(as->list, tinlvar(t)); 694 t=t->down; 695 ll=ll->next; 696 } 697 // match varargcount arguments with variadic parameters. 698 if(variadic && t && t->isddd) { 699 vararg = tinlvar(t); 700 for(i=0; i<varargcount && ll; i++) { 701 m = argvar(varargtype, i); 702 varargs = list(varargs, m); 703 as->list = list(as->list, m); 704 ll=ll->next; 705 } 706 if(i==varargcount) 707 t=t->down; 708 } 709 if(ll || t) 710 fatal("arg count mismatch: %#T vs %,H\n", getinargx(fn->type), n->list); 711 } 712 713 if (as->rlist) { 714 typecheck(&as, Etop); 715 ninit = list(ninit, as); 716 } 717 718 // turn the variadic args into a slice. 719 if(variadic) { 720 as = nod(OAS, vararg, N); 721 if(!varargcount) { 722 as->right = nodnil(); 723 as->right->type = varargtype; 724 } else { 725 vararrtype = typ(TARRAY); 726 vararrtype->type = varargtype->type; 727 vararrtype->bound = varargcount; 728 729 as->right = nod(OCOMPLIT, N, typenod(varargtype)); 730 as->right->list = varargs; 731 as->right = nod(OSLICE, as->right, nod(OKEY, N, N)); 732 } 733 typecheck(&as, Etop); 734 ninit = list(ninit, as); 735 } 736 737 // zero the outparams 738 for(ll = inlretvars; ll; ll=ll->next) { 739 as = nod(OAS, ll->n, N); 740 typecheck(&as, Etop); 741 ninit = list(ninit, as); 742 } 743 744 inlretlabel = newlabel(); 745 inlgen++; 746 body = inlsubstlist(fn->inl); 747 748 body = list(body, nod(OGOTO, inlretlabel, N)); // avoid 'not used' when function doesnt have return 749 body = list(body, nod(OLABEL, inlretlabel, N)); 750 751 typechecklist(body, Etop); 752 //dumplist("ninit post", ninit); 753 754 call = nod(OINLCALL, N, N); 755 call->ninit = ninit; 756 call->nbody = body; 757 call->rlist = inlretvars; 758 call->type = n->type; 759 call->typecheck = 1; 760 761 setlno(call, n->lineno); 762 //dumplist("call body", body); 763 764 *np = call; 765 766 inlfn = saveinlfn; 767 768 // transitive inlining 769 // TODO do this pre-expansion on fn->inl directly. requires 770 // either supporting exporting statemetns with complex ninits 771 // or saving inl and making inlinl 772 if(debug['l'] >= 5) { 773 body = fn->inl; 774 fn->inl = nil; // prevent infinite recursion 775 inlnodelist(call->nbody); 776 for(ll=call->nbody; ll; ll=ll->next) 777 if(ll->n->op == OINLCALL) 778 inlconv2stmt(ll->n); 779 fn->inl = body; 780 } 781 782 if(debug['m']>2) 783 print("%L: After inlining %+N\n\n", n->lineno, *np); 784 785 } 786 787 // Every time we expand a function we generate a new set of tmpnames, 788 // PAUTO's in the calling functions, and link them off of the 789 // PPARAM's, PAUTOS and PPARAMOUTs of the called function. 790 static Node* 791 inlvar(Node *var) 792 { 793 Node *n; 794 795 if(debug['m']>3) 796 print("inlvar %+N\n", var); 797 798 n = newname(var->sym); 799 n->type = var->type; 800 n->class = PAUTO; 801 n->used = 1; 802 n->curfn = curfn; // the calling function, not the called one 803 804 // esc pass wont run if we're inlining into a iface wrapper 805 // luckily, we can steal the results from the target func 806 if(var->esc == EscHeap) 807 addrescapes(n); 808 809 curfn->dcl = list(curfn->dcl, n); 810 return n; 811 } 812 813 // Synthesize a variable to store the inlined function's results in. 814 static Node* 815 retvar(Type *t, int i) 816 { 817 Node *n; 818 819 snprint(namebuf, sizeof(namebuf), "~r%d", i); 820 n = newname(lookup(namebuf)); 821 n->type = t->type; 822 n->class = PAUTO; 823 n->used = 1; 824 n->curfn = curfn; // the calling function, not the called one 825 curfn->dcl = list(curfn->dcl, n); 826 return n; 827 } 828 829 // Synthesize a variable to store the inlined function's arguments 830 // when they come from a multiple return call. 831 static Node* 832 argvar(Type *t, int i) 833 { 834 Node *n; 835 836 snprint(namebuf, sizeof(namebuf), "~arg%d", i); 837 n = newname(lookup(namebuf)); 838 n->type = t->type; 839 n->class = PAUTO; 840 n->used = 1; 841 n->curfn = curfn; // the calling function, not the called one 842 curfn->dcl = list(curfn->dcl, n); 843 return n; 844 } 845 846 static Node* 847 newlabel(void) 848 { 849 Node *n; 850 static int label; 851 852 label++; 853 snprint(namebuf, sizeof(namebuf), ".inlret%.6d", label); 854 n = newname(lookup(namebuf)); 855 n->etype = 1; // flag 'safe' for escape analysis (no backjumps) 856 return n; 857 } 858 859 // inlsubst and inlsubstlist recursively copy the body of the saved 860 // pristine ->inl body of the function while substituting references 861 // to input/output parameters with ones to the tmpnames, and 862 // substituting returns with assignments to the output. 863 static NodeList* 864 inlsubstlist(NodeList *ll) 865 { 866 NodeList *l; 867 868 l = nil; 869 for(; ll; ll=ll->next) 870 l = list(l, inlsubst(ll->n)); 871 return l; 872 } 873 874 static Node* 875 inlsubst(Node *n) 876 { 877 char *p; 878 Node *m, *as; 879 NodeList *ll; 880 881 if(n == N) 882 return N; 883 884 switch(n->op) { 885 case ONAME: 886 if(n->inlvar) { // These will be set during inlnode 887 if (debug['m']>2) 888 print ("substituting name %+N -> %+N\n", n, n->inlvar); 889 return n->inlvar; 890 } 891 if (debug['m']>2) 892 print ("not substituting name %+N\n", n); 893 return n; 894 895 case OLITERAL: 896 case OTYPE: 897 return n; 898 899 case ORETURN: 900 // Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function. 901 902 // dump("Return before substitution", n); 903 m = nod(OGOTO, inlretlabel, N); 904 m->ninit = inlsubstlist(n->ninit); 905 906 if(inlretvars && n->list) { 907 as = nod(OAS2, N, N); 908 // shallow copy or OINLCALL->rlist will be the same list, and later walk and typecheck may clobber that. 909 for(ll=inlretvars; ll; ll=ll->next) 910 as->list = list(as->list, ll->n); 911 as->rlist = inlsubstlist(n->list); 912 typecheck(&as, Etop); 913 m->ninit = list(m->ninit, as); 914 } 915 916 typechecklist(m->ninit, Etop); 917 typecheck(&m, Etop); 918 // dump("Return after substitution", m); 919 return m; 920 921 case OGOTO: 922 case OLABEL: 923 m = nod(OXXX, N, N); 924 *m = *n; 925 m->ninit = nil; 926 p = smprint("%s·%d", n->left->sym->name, inlgen); 927 m->left = newname(lookup(p)); 928 free(p); 929 return m; 930 } 931 932 933 m = nod(OXXX, N, N); 934 *m = *n; 935 m->ninit = nil; 936 937 if(n->op == OCLOSURE) 938 fatal("cannot inline function containing closure: %+N", n); 939 940 m->left = inlsubst(n->left); 941 m->right = inlsubst(n->right); 942 m->list = inlsubstlist(n->list); 943 m->rlist = inlsubstlist(n->rlist); 944 m->ninit = concat(m->ninit, inlsubstlist(n->ninit)); 945 m->ntest = inlsubst(n->ntest); 946 m->nincr = inlsubst(n->nincr); 947 m->nbody = inlsubstlist(n->nbody); 948 m->nelse = inlsubstlist(n->nelse); 949 950 return m; 951 } 952 953 // Plaster over linenumbers 954 static void 955 setlnolist(NodeList *ll, int lno) 956 { 957 for(;ll;ll=ll->next) 958 setlno(ll->n, lno); 959 } 960 961 static void 962 setlno(Node *n, int lno) 963 { 964 if(!n) 965 return; 966 967 // don't clobber names, unless they're freshly synthesized 968 if(n->op != ONAME || n->lineno == 0) 969 n->lineno = lno; 970 971 setlno(n->left, lno); 972 setlno(n->right, lno); 973 setlnolist(n->list, lno); 974 setlnolist(n->rlist, lno); 975 setlnolist(n->ninit, lno); 976 setlno(n->ntest, lno); 977 setlno(n->nincr, lno); 978 setlnolist(n->nbody, lno); 979 setlnolist(n->nelse, lno); 980 }