github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/5g/ggen.c (about) 1 // Copyright 2009 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 #undef EXTERN 6 #define EXTERN 7 #include <u.h> 8 #include <libc.h> 9 #include "gg.h" 10 #include "opt.h" 11 12 void 13 defframe(Prog *ptxt) 14 { 15 // fill in argument size 16 ptxt->to.type = D_CONST2; 17 ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr); 18 19 // fill in final stack size 20 if(stksize > maxstksize) 21 maxstksize = stksize; 22 ptxt->to.offset = rnd(maxstksize+maxarg, widthptr); 23 maxstksize = 0; 24 } 25 26 // Sweep the prog list to mark any used nodes. 27 void 28 markautoused(Prog* p) 29 { 30 for (; p; p = p->link) { 31 if (p->as == ATYPE) 32 continue; 33 34 if (p->from.name == D_AUTO && p->from.node) 35 p->from.node->used = 1; 36 37 if (p->to.name == D_AUTO && p->to.node) 38 p->to.node->used = 1; 39 } 40 } 41 42 // Fixup instructions after compactframe has moved all autos around. 43 void 44 fixautoused(Prog* p) 45 { 46 Prog **lp; 47 48 for (lp=&p; (p=*lp) != P; ) { 49 if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) { 50 *lp = p->link; 51 continue; 52 } 53 54 if (p->from.name == D_AUTO && p->from.node) 55 p->from.offset += p->from.node->stkdelta; 56 57 if (p->to.name == D_AUTO && p->to.node) 58 p->to.offset += p->to.node->stkdelta; 59 60 lp = &p->link; 61 } 62 } 63 64 /* 65 * generate: 66 * call f 67 * proc=-1 normal call but no return 68 * proc=0 normal call 69 * proc=1 goroutine run in new proc 70 * proc=2 defer call save away stack 71 * proc=3 normal call to C pointer (not Go func value) 72 */ 73 void 74 ginscall(Node *f, int proc) 75 { 76 Prog *p; 77 Node n1, r, r1, con; 78 79 switch(proc) { 80 default: 81 fatal("ginscall: bad proc %d", proc); 82 break; 83 84 case 0: // normal call 85 case -1: // normal call but no return 86 if(f->op == ONAME && f->class == PFUNC) { 87 p = gins(ABL, N, f); 88 afunclit(&p->to, f); 89 if(proc == -1 || noreturn(p)) 90 gins(AUNDEF, N, N); 91 break; 92 } 93 nodreg(&r, types[tptr], 7); 94 nodreg(&r1, types[tptr], 1); 95 gmove(f, &r); 96 r.op = OINDREG; 97 gmove(&r, &r1); 98 r.op = OREGISTER; 99 r1.op = OINDREG; 100 gins(ABL, &r, &r1); 101 break; 102 103 case 3: // normal call of c function pointer 104 gins(ABL, N, f); 105 break; 106 107 case 1: // call in new proc (go) 108 case 2: // deferred call (defer) 109 regalloc(&r, types[tptr], N); 110 p = gins(AMOVW, N, &r); 111 p->from.type = D_OREG; 112 p->from.reg = REGSP; 113 114 p = gins(AMOVW, &r, N); 115 p->to.type = D_OREG; 116 p->to.reg = REGSP; 117 p->to.offset = -12; 118 p->scond |= C_WBIT; 119 120 memset(&n1, 0, sizeof n1); 121 n1.op = OADDR; 122 n1.left = f; 123 gins(AMOVW, &n1, &r); 124 125 p = gins(AMOVW, &r, N); 126 p->to.type = D_OREG; 127 p->to.reg = REGSP; 128 p->to.offset = 8; 129 130 nodconst(&con, types[TINT32], argsize(f->type)); 131 gins(AMOVW, &con, &r); 132 p = gins(AMOVW, &r, N); 133 p->to.type = D_OREG; 134 p->to.reg = REGSP; 135 p->to.offset = 4; 136 regfree(&r); 137 138 if(proc == 1) 139 ginscall(newproc, 0); 140 else 141 ginscall(deferproc, 0); 142 143 nodreg(&r, types[tptr], 1); 144 p = gins(AMOVW, N, N); 145 p->from.type = D_CONST; 146 p->from.reg = REGSP; 147 p->from.offset = 12; 148 p->to.reg = REGSP; 149 p->to.type = D_REG; 150 151 if(proc == 2) { 152 nodconst(&con, types[TINT32], 0); 153 p = gins(ACMP, &con, N); 154 p->reg = 0; 155 patch(gbranch(ABNE, T, -1), retpc); 156 } 157 break; 158 } 159 } 160 161 /* 162 * n is call to interface method. 163 * generate res = n. 164 */ 165 void 166 cgen_callinter(Node *n, Node *res, int proc) 167 { 168 int r; 169 Node *i, *f; 170 Node tmpi, nodo, nodr, nodsp; 171 Prog *p; 172 173 i = n->left; 174 if(i->op != ODOTINTER) 175 fatal("cgen_callinter: not ODOTINTER %O", i->op); 176 177 f = i->right; // field 178 if(f->op != ONAME) 179 fatal("cgen_callinter: not ONAME %O", f->op); 180 181 i = i->left; // interface 182 183 // Release res register during genlist and cgen, 184 // which might have their own function calls. 185 r = -1; 186 if(res != N && (res->op == OREGISTER || res->op == OINDREG)) { 187 r = res->val.u.reg; 188 reg[r]--; 189 } 190 191 if(!i->addable) { 192 tempname(&tmpi, i->type); 193 cgen(i, &tmpi); 194 i = &tmpi; 195 } 196 197 genlist(n->list); // args 198 if(r >= 0) 199 reg[r]++; 200 201 regalloc(&nodr, types[tptr], res); 202 regalloc(&nodo, types[tptr], &nodr); 203 nodo.op = OINDREG; 204 205 agen(i, &nodr); // REG = &inter 206 207 nodindreg(&nodsp, types[tptr], REGSP); 208 nodsp.xoffset = 4; 209 nodo.xoffset += widthptr; 210 cgen(&nodo, &nodsp); // 4(SP) = 4(REG) -- i.data 211 212 nodo.xoffset -= widthptr; 213 cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab 214 215 nodo.xoffset = n->left->xoffset + 3*widthptr + 8; 216 217 if(proc == 0) { 218 // plain call: use direct c function pointer - more efficient 219 cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f] 220 nodr.op = OINDREG; 221 proc = 3; 222 } else { 223 // go/defer. generate go func value. 224 p = gins(AMOVW, &nodo, &nodr); 225 p->from.type = D_CONST; // REG = &(20+offset(REG)) -- i.tab->fun[f] 226 } 227 228 // BOTCH nodr.type = fntype; 229 nodr.type = n->left->type; 230 ginscall(&nodr, proc); 231 232 regfree(&nodr); 233 regfree(&nodo); 234 235 setmaxarg(n->left->type); 236 } 237 238 /* 239 * generate function call; 240 * proc=0 normal call 241 * proc=1 goroutine run in new proc 242 * proc=2 defer call save away stack 243 */ 244 void 245 cgen_call(Node *n, int proc) 246 { 247 Type *t; 248 Node nod, afun; 249 250 if(n == N) 251 return; 252 253 if(n->left->ullman >= UINF) { 254 // if name involves a fn call 255 // precompute the address of the fn 256 tempname(&afun, types[tptr]); 257 cgen(n->left, &afun); 258 } 259 260 genlist(n->list); // assign the args 261 t = n->left->type; 262 263 setmaxarg(t); 264 265 // call tempname pointer 266 if(n->left->ullman >= UINF) { 267 regalloc(&nod, types[tptr], N); 268 cgen_as(&nod, &afun); 269 nod.type = t; 270 ginscall(&nod, proc); 271 regfree(&nod); 272 goto ret; 273 } 274 275 // call pointer 276 if(n->left->op != ONAME || n->left->class != PFUNC) { 277 regalloc(&nod, types[tptr], N); 278 cgen_as(&nod, n->left); 279 nod.type = t; 280 ginscall(&nod, proc); 281 regfree(&nod); 282 goto ret; 283 } 284 285 // call direct 286 n->left->method = 1; 287 ginscall(n->left, proc); 288 289 290 ret: 291 ; 292 } 293 294 /* 295 * call to n has already been generated. 296 * generate: 297 * res = return value from call. 298 */ 299 void 300 cgen_callret(Node *n, Node *res) 301 { 302 Node nod; 303 Type *fp, *t; 304 Iter flist; 305 306 t = n->left->type; 307 if(t->etype == TPTR32 || t->etype == TPTR64) 308 t = t->type; 309 310 fp = structfirst(&flist, getoutarg(t)); 311 if(fp == T) 312 fatal("cgen_callret: nil"); 313 314 memset(&nod, 0, sizeof(nod)); 315 nod.op = OINDREG; 316 nod.val.u.reg = REGSP; 317 nod.addable = 1; 318 319 nod.xoffset = fp->width + 4; // +4: saved lr at 0(SP) 320 nod.type = fp->type; 321 cgen_as(res, &nod); 322 } 323 324 /* 325 * call to n has already been generated. 326 * generate: 327 * res = &return value from call. 328 */ 329 void 330 cgen_aret(Node *n, Node *res) 331 { 332 Node nod1, nod2; 333 Type *fp, *t; 334 Iter flist; 335 336 t = n->left->type; 337 if(isptr[t->etype]) 338 t = t->type; 339 340 fp = structfirst(&flist, getoutarg(t)); 341 if(fp == T) 342 fatal("cgen_aret: nil"); 343 344 memset(&nod1, 0, sizeof(nod1)); 345 nod1.op = OINDREG; 346 nod1.val.u.reg = REGSP; 347 nod1.addable = 1; 348 349 nod1.xoffset = fp->width + 4; // +4: saved lr at 0(SP) 350 nod1.type = fp->type; 351 352 if(res->op != OREGISTER) { 353 regalloc(&nod2, types[tptr], res); 354 agen(&nod1, &nod2); 355 gins(AMOVW, &nod2, res); 356 regfree(&nod2); 357 } else 358 agen(&nod1, res); 359 } 360 361 /* 362 * generate return. 363 * n->left is assignments to return values. 364 */ 365 void 366 cgen_ret(Node *n) 367 { 368 genlist(n->list); // copy out args 369 if(hasdefer || curfn->exit) 370 gjmp(retpc); 371 else 372 gins(ARET, N, N); 373 } 374 375 /* 376 * generate += *= etc. 377 */ 378 void 379 cgen_asop(Node *n) 380 { 381 Node n1, n2, n3, n4; 382 Node *nl, *nr; 383 Prog *p1; 384 Addr addr; 385 int a, w; 386 387 nl = n->left; 388 nr = n->right; 389 390 if(nr->ullman >= UINF && nl->ullman >= UINF) { 391 tempname(&n1, nr->type); 392 cgen(nr, &n1); 393 n2 = *n; 394 n2.right = &n1; 395 cgen_asop(&n2); 396 goto ret; 397 } 398 399 if(!isint[nl->type->etype]) 400 goto hard; 401 if(!isint[nr->type->etype]) 402 goto hard; 403 if(is64(nl->type) || is64(nr->type)) 404 goto hard64; 405 406 switch(n->etype) { 407 case OADD: 408 case OSUB: 409 case OXOR: 410 case OAND: 411 case OOR: 412 a = optoas(n->etype, nl->type); 413 if(nl->addable) { 414 if(smallintconst(nr)) 415 n3 = *nr; 416 else { 417 regalloc(&n3, nr->type, N); 418 cgen(nr, &n3); 419 } 420 regalloc(&n2, nl->type, N); 421 cgen(nl, &n2); 422 gins(a, &n3, &n2); 423 cgen(&n2, nl); 424 regfree(&n2); 425 if(n3.op != OLITERAL) 426 regfree(&n3); 427 goto ret; 428 } 429 if(nr->ullman < UINF) 430 if(sudoaddable(a, nl, &addr, &w)) { 431 w = optoas(OAS, nl->type); 432 regalloc(&n2, nl->type, N); 433 p1 = gins(w, N, &n2); 434 p1->from = addr; 435 regalloc(&n3, nr->type, N); 436 cgen(nr, &n3); 437 gins(a, &n3, &n2); 438 p1 = gins(w, &n2, N); 439 p1->to = addr; 440 regfree(&n2); 441 regfree(&n3); 442 sudoclean(); 443 goto ret; 444 } 445 } 446 447 hard: 448 n2.op = 0; 449 n1.op = 0; 450 if(nr->op == OLITERAL) { 451 // don't allocate a register for literals. 452 } else if(nr->ullman >= nl->ullman || nl->addable) { 453 regalloc(&n2, nr->type, N); 454 cgen(nr, &n2); 455 nr = &n2; 456 } else { 457 tempname(&n2, nr->type); 458 cgen(nr, &n2); 459 nr = &n2; 460 } 461 if(!nl->addable) { 462 igen(nl, &n1, N); 463 nl = &n1; 464 } 465 466 n3 = *n; 467 n3.left = nl; 468 n3.right = nr; 469 n3.op = n->etype; 470 471 regalloc(&n4, nl->type, N); 472 cgen(&n3, &n4); 473 gmove(&n4, nl); 474 475 if(n1.op) 476 regfree(&n1); 477 if(n2.op == OREGISTER) 478 regfree(&n2); 479 regfree(&n4); 480 goto ret; 481 482 hard64: 483 if(nr->ullman > nl->ullman) { 484 tempname(&n2, nr->type); 485 cgen(nr, &n2); 486 igen(nl, &n1, N); 487 } else { 488 igen(nl, &n1, N); 489 tempname(&n2, nr->type); 490 cgen(nr, &n2); 491 } 492 493 n3 = *n; 494 n3.left = &n1; 495 n3.right = &n2; 496 n3.op = n->etype; 497 498 cgen(&n3, &n1); 499 500 ret: 501 ; 502 } 503 504 int 505 samereg(Node *a, Node *b) 506 { 507 if(a->op != OREGISTER) 508 return 0; 509 if(b->op != OREGISTER) 510 return 0; 511 if(a->val.u.reg != b->val.u.reg) 512 return 0; 513 return 1; 514 } 515 516 /* 517 * generate high multiply 518 * res = (nl * nr) >> wordsize 519 */ 520 void 521 cgen_hmul(Node *nl, Node *nr, Node *res) 522 { 523 int w; 524 Node n1, n2, *tmp; 525 Type *t; 526 Prog *p; 527 528 if(nl->ullman < nr->ullman) { 529 tmp = nl; 530 nl = nr; 531 nr = tmp; 532 } 533 t = nl->type; 534 w = t->width * 8; 535 regalloc(&n1, t, res); 536 cgen(nl, &n1); 537 regalloc(&n2, t, N); 538 cgen(nr, &n2); 539 switch(simtype[t->etype]) { 540 case TINT8: 541 case TINT16: 542 gins(optoas(OMUL, t), &n2, &n1); 543 gshift(AMOVW, &n1, SHIFT_AR, w, &n1); 544 break; 545 case TUINT8: 546 case TUINT16: 547 gins(optoas(OMUL, t), &n2, &n1); 548 gshift(AMOVW, &n1, SHIFT_LR, w, &n1); 549 break; 550 case TINT32: 551 case TUINT32: 552 // perform a long multiplication. 553 if(issigned[t->etype]) 554 p = gins(AMULL, &n2, N); 555 else 556 p = gins(AMULLU, &n2, N); 557 // n2 * n1 -> (n1 n2) 558 p->reg = n1.val.u.reg; 559 p->to.type = D_REGREG; 560 p->to.reg = n1.val.u.reg; 561 p->to.offset = n2.val.u.reg; 562 break; 563 default: 564 fatal("cgen_hmul %T", t); 565 break; 566 } 567 cgen(&n1, res); 568 regfree(&n1); 569 regfree(&n2); 570 } 571 572 /* 573 * generate shift according to op, one of: 574 * res = nl << nr 575 * res = nl >> nr 576 */ 577 void 578 cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res) 579 { 580 Node n1, n2, n3, nt, t, lo, hi; 581 int w, v; 582 Prog *p1, *p2, *p3; 583 Type *tr; 584 uvlong sc; 585 586 USED(bounded); 587 if(nl->type->width > 4) 588 fatal("cgen_shift %T", nl->type); 589 590 w = nl->type->width * 8; 591 592 if(op == OLROT) { 593 v = mpgetfix(nr->val.u.xval); 594 regalloc(&n1, nl->type, res); 595 if(w == 32) { 596 cgen(nl, &n1); 597 gshift(AMOVW, &n1, SHIFT_RR, w-v, &n1); 598 } else { 599 regalloc(&n2, nl->type, N); 600 cgen(nl, &n2); 601 gshift(AMOVW, &n2, SHIFT_LL, v, &n1); 602 gshift(AORR, &n2, SHIFT_LR, w-v, &n1); 603 regfree(&n2); 604 } 605 gmove(&n1, res); 606 regfree(&n1); 607 return; 608 } 609 610 if(nr->op == OLITERAL) { 611 regalloc(&n1, nl->type, res); 612 cgen(nl, &n1); 613 sc = mpgetfix(nr->val.u.xval); 614 if(sc == 0) { 615 // nothing to do 616 } else if(sc >= nl->type->width*8) { 617 if(op == ORSH && issigned[nl->type->etype]) 618 gshift(AMOVW, &n1, SHIFT_AR, w, &n1); 619 else 620 gins(AEOR, &n1, &n1); 621 } else { 622 if(op == ORSH && issigned[nl->type->etype]) 623 gshift(AMOVW, &n1, SHIFT_AR, sc, &n1); 624 else if(op == ORSH) 625 gshift(AMOVW, &n1, SHIFT_LR, sc, &n1); 626 else // OLSH 627 gshift(AMOVW, &n1, SHIFT_LL, sc, &n1); 628 } 629 gmove(&n1, res); 630 regfree(&n1); 631 return; 632 } 633 634 tr = nr->type; 635 if(tr->width > 4) { 636 tempname(&nt, nr->type); 637 if(nl->ullman >= nr->ullman) { 638 regalloc(&n2, nl->type, res); 639 cgen(nl, &n2); 640 cgen(nr, &nt); 641 n1 = nt; 642 } else { 643 cgen(nr, &nt); 644 regalloc(&n2, nl->type, res); 645 cgen(nl, &n2); 646 } 647 split64(&nt, &lo, &hi); 648 regalloc(&n1, types[TUINT32], N); 649 regalloc(&n3, types[TUINT32], N); 650 gmove(&lo, &n1); 651 gmove(&hi, &n3); 652 splitclean(); 653 gins(ATST, &n3, N); 654 nodconst(&t, types[TUINT32], w); 655 p1 = gins(AMOVW, &t, &n1); 656 p1->scond = C_SCOND_NE; 657 tr = types[TUINT32]; 658 regfree(&n3); 659 } else { 660 if(nl->ullman >= nr->ullman) { 661 regalloc(&n2, nl->type, res); 662 cgen(nl, &n2); 663 regalloc(&n1, nr->type, N); 664 cgen(nr, &n1); 665 } else { 666 regalloc(&n1, nr->type, N); 667 cgen(nr, &n1); 668 regalloc(&n2, nl->type, res); 669 cgen(nl, &n2); 670 } 671 } 672 673 // test for shift being 0 674 gins(ATST, &n1, N); 675 p3 = gbranch(ABEQ, T, -1); 676 677 // test and fix up large shifts 678 // TODO: if(!bounded), don't emit some of this. 679 regalloc(&n3, tr, N); 680 nodconst(&t, types[TUINT32], w); 681 gmove(&t, &n3); 682 gcmp(ACMP, &n1, &n3); 683 if(op == ORSH) { 684 if(issigned[nl->type->etype]) { 685 p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2); 686 p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2); 687 } else { 688 p1 = gins(AEOR, &n2, &n2); 689 p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2); 690 } 691 p1->scond = C_SCOND_HS; 692 p2->scond = C_SCOND_LO; 693 } else { 694 p1 = gins(AEOR, &n2, &n2); 695 p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2); 696 p1->scond = C_SCOND_HS; 697 p2->scond = C_SCOND_LO; 698 } 699 regfree(&n3); 700 701 patch(p3, pc); 702 gmove(&n2, res); 703 704 regfree(&n1); 705 regfree(&n2); 706 } 707 708 void 709 clearfat(Node *nl) 710 { 711 uint32 w, c, q; 712 Node dst, nc, nz, end; 713 Prog *p, *pl; 714 715 /* clear a fat object */ 716 if(debug['g']) 717 dump("\nclearfat", nl); 718 719 720 w = nl->type->width; 721 // Avoid taking the address for simple enough types. 722 if(componentgen(N, nl)) 723 return; 724 725 c = w % 4; // bytes 726 q = w / 4; // quads 727 728 regalloc(&dst, types[tptr], N); 729 agen(nl, &dst); 730 nodconst(&nc, types[TUINT32], 0); 731 regalloc(&nz, types[TUINT32], 0); 732 cgen(&nc, &nz); 733 734 if(q >= 4) { 735 regalloc(&end, types[tptr], N); 736 p = gins(AMOVW, &dst, &end); 737 p->from.type = D_CONST; 738 p->from.offset = q*4; 739 740 p = gins(AMOVW, &nz, &dst); 741 p->to.type = D_OREG; 742 p->to.offset = 4; 743 p->scond |= C_PBIT; 744 pl = p; 745 746 p = gins(ACMP, &dst, N); 747 raddr(&end, p); 748 patch(gbranch(ABNE, T, 0), pl); 749 750 regfree(&end); 751 } else 752 while(q > 0) { 753 p = gins(AMOVW, &nz, &dst); 754 p->to.type = D_OREG; 755 p->to.offset = 4; 756 p->scond |= C_PBIT; 757 //print("1. %P\n", p); 758 q--; 759 } 760 761 while(c > 0) { 762 p = gins(AMOVBU, &nz, &dst); 763 p->to.type = D_OREG; 764 p->to.offset = 1; 765 p->scond |= C_PBIT; 766 //print("2. %P\n", p); 767 c--; 768 } 769 regfree(&dst); 770 regfree(&nz); 771 }