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