github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/cmd/6g/cgen.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 #include <u.h> 6 #include <libc.h> 7 #include "gg.h" 8 9 /* 10 * generate: 11 * res = n; 12 * simplifies and calls gmove. 13 */ 14 void 15 cgen(Node *n, Node *res) 16 { 17 Node *nl, *nr, *r; 18 Node n1, n2; 19 int a, f; 20 Prog *p1, *p2, *p3; 21 Addr addr; 22 23 if(debug['g']) { 24 dump("\ncgen-n", n); 25 dump("cgen-res", res); 26 } 27 if(n == N || n->type == T) 28 goto ret; 29 30 if(res == N || res->type == T) 31 fatal("cgen: res nil"); 32 33 while(n->op == OCONVNOP) 34 n = n->left; 35 36 switch(n->op) { 37 case OSLICE: 38 case OSLICEARR: 39 case OSLICESTR: 40 case OSLICE3: 41 case OSLICE3ARR: 42 if (res->op != ONAME || !res->addable) { 43 tempname(&n1, n->type); 44 cgen_slice(n, &n1); 45 cgen(&n1, res); 46 } else 47 cgen_slice(n, res); 48 goto ret; 49 case OEFACE: 50 if (res->op != ONAME || !res->addable) { 51 tempname(&n1, n->type); 52 cgen_eface(n, &n1); 53 cgen(&n1, res); 54 } else 55 cgen_eface(n, res); 56 goto ret; 57 } 58 59 if(n->ullman >= UINF) { 60 if(n->op == OINDREG) 61 fatal("cgen: this is going to misscompile"); 62 if(res->ullman >= UINF) { 63 tempname(&n1, n->type); 64 cgen(n, &n1); 65 cgen(&n1, res); 66 goto ret; 67 } 68 } 69 70 if(isfat(n->type)) { 71 if(n->type->width < 0) 72 fatal("forgot to compute width for %T", n->type); 73 sgen(n, res, n->type->width); 74 goto ret; 75 } 76 77 if(!res->addable) { 78 if(n->ullman > res->ullman) { 79 regalloc(&n1, n->type, res); 80 cgen(n, &n1); 81 if(n1.ullman > res->ullman) { 82 dump("n1", &n1); 83 dump("res", res); 84 fatal("loop in cgen"); 85 } 86 cgen(&n1, res); 87 regfree(&n1); 88 goto ret; 89 } 90 91 if(res->ullman >= UINF) 92 goto gen; 93 94 if(complexop(n, res)) { 95 complexgen(n, res); 96 goto ret; 97 } 98 99 f = 1; // gen thru register 100 switch(n->op) { 101 case OLITERAL: 102 if(smallintconst(n)) 103 f = 0; 104 break; 105 case OREGISTER: 106 f = 0; 107 break; 108 } 109 110 if(!iscomplex[n->type->etype]) { 111 a = optoas(OAS, res->type); 112 if(sudoaddable(a, res, &addr)) { 113 if(f) { 114 regalloc(&n2, res->type, N); 115 cgen(n, &n2); 116 p1 = gins(a, &n2, N); 117 regfree(&n2); 118 } else 119 p1 = gins(a, n, N); 120 p1->to = addr; 121 if(debug['g']) 122 print("%P [ignore previous line]\n", p1); 123 sudoclean(); 124 goto ret; 125 } 126 } 127 128 gen: 129 igen(res, &n1, N); 130 cgen(n, &n1); 131 regfree(&n1); 132 goto ret; 133 } 134 135 // update addressability for string, slice 136 // can't do in walk because n->left->addable 137 // changes if n->left is an escaping local variable. 138 switch(n->op) { 139 case OLEN: 140 if(isslice(n->left->type) || istype(n->left->type, TSTRING)) 141 n->addable = n->left->addable; 142 break; 143 case OCAP: 144 if(isslice(n->left->type)) 145 n->addable = n->left->addable; 146 break; 147 case OITAB: 148 n->addable = n->left->addable; 149 break; 150 } 151 152 if(complexop(n, res)) { 153 complexgen(n, res); 154 goto ret; 155 } 156 157 if(n->addable) { 158 gmove(n, res); 159 goto ret; 160 } 161 162 nl = n->left; 163 nr = n->right; 164 165 if(nl != N && nl->ullman >= UINF) 166 if(nr != N && nr->ullman >= UINF) { 167 tempname(&n1, nl->type); 168 cgen(nl, &n1); 169 n2 = *n; 170 n2.left = &n1; 171 cgen(&n2, res); 172 goto ret; 173 } 174 175 if(!iscomplex[n->type->etype]) { 176 a = optoas(OAS, n->type); 177 if(sudoaddable(a, n, &addr)) { 178 if(res->op == OREGISTER) { 179 p1 = gins(a, N, res); 180 p1->from = addr; 181 } else { 182 regalloc(&n2, n->type, N); 183 p1 = gins(a, N, &n2); 184 p1->from = addr; 185 gins(a, &n2, res); 186 regfree(&n2); 187 } 188 sudoclean(); 189 goto ret; 190 } 191 } 192 193 switch(n->op) { 194 default: 195 dump("cgen", n); 196 fatal("cgen: unknown op %+hN", n); 197 break; 198 199 // these call bgen to get a bool value 200 case OOROR: 201 case OANDAND: 202 case OEQ: 203 case ONE: 204 case OLT: 205 case OLE: 206 case OGE: 207 case OGT: 208 case ONOT: 209 p1 = gbranch(AJMP, T, 0); 210 p2 = pc; 211 gmove(nodbool(1), res); 212 p3 = gbranch(AJMP, T, 0); 213 patch(p1, pc); 214 bgen(n, 1, 0, p2); 215 gmove(nodbool(0), res); 216 patch(p3, pc); 217 goto ret; 218 219 case OPLUS: 220 cgen(nl, res); 221 goto ret; 222 223 // unary 224 case OCOM: 225 a = optoas(OXOR, nl->type); 226 regalloc(&n1, nl->type, N); 227 cgen(nl, &n1); 228 nodconst(&n2, nl->type, -1); 229 gins(a, &n2, &n1); 230 gmove(&n1, res); 231 regfree(&n1); 232 goto ret; 233 234 case OMINUS: 235 if(isfloat[nl->type->etype]) { 236 nr = nodintconst(-1); 237 convlit(&nr, n->type); 238 a = optoas(OMUL, nl->type); 239 goto sbop; 240 } 241 a = optoas(n->op, nl->type); 242 goto uop; 243 244 // symmetric binary 245 case OAND: 246 case OOR: 247 case OXOR: 248 case OADD: 249 case OMUL: 250 a = optoas(n->op, nl->type); 251 if(a == AIMULB) { 252 cgen_bmul(n->op, nl, nr, res); 253 break; 254 } 255 goto sbop; 256 257 // asymmetric binary 258 case OSUB: 259 a = optoas(n->op, nl->type); 260 goto abop; 261 262 case OHMUL: 263 cgen_hmul(nl, nr, res); 264 break; 265 266 case OCONV: 267 if(n->type->width > nl->type->width) { 268 // If loading from memory, do conversion during load, 269 // so as to avoid use of 8-bit register in, say, int(*byteptr). 270 switch(nl->op) { 271 case ODOT: 272 case ODOTPTR: 273 case OINDEX: 274 case OIND: 275 case ONAME: 276 igen(nl, &n1, res); 277 regalloc(&n2, n->type, res); 278 gmove(&n1, &n2); 279 gmove(&n2, res); 280 regfree(&n2); 281 regfree(&n1); 282 goto ret; 283 } 284 } 285 286 regalloc(&n1, nl->type, res); 287 regalloc(&n2, n->type, &n1); 288 cgen(nl, &n1); 289 290 // if we do the conversion n1 -> n2 here 291 // reusing the register, then gmove won't 292 // have to allocate its own register. 293 gmove(&n1, &n2); 294 gmove(&n2, res); 295 regfree(&n2); 296 regfree(&n1); 297 break; 298 299 case ODOT: 300 case ODOTPTR: 301 case OINDEX: 302 case OIND: 303 case ONAME: // PHEAP or PPARAMREF var 304 igen(n, &n1, res); 305 gmove(&n1, res); 306 regfree(&n1); 307 break; 308 309 case OITAB: 310 // interface table is first word of interface value 311 igen(nl, &n1, res); 312 n1.type = n->type; 313 gmove(&n1, res); 314 regfree(&n1); 315 break; 316 317 case OLEN: 318 if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) { 319 // map and chan have len in the first int-sized word. 320 // a zero pointer means zero length 321 regalloc(&n1, types[tptr], res); 322 cgen(nl, &n1); 323 324 nodconst(&n2, types[tptr], 0); 325 gins(optoas(OCMP, types[tptr]), &n1, &n2); 326 p1 = gbranch(optoas(OEQ, types[tptr]), T, 0); 327 328 n2 = n1; 329 n2.op = OINDREG; 330 n2.type = types[simtype[TINT]]; 331 gmove(&n2, &n1); 332 333 patch(p1, pc); 334 335 gmove(&n1, res); 336 regfree(&n1); 337 break; 338 } 339 if(istype(nl->type, TSTRING) || isslice(nl->type)) { 340 // both slice and string have len one pointer into the struct. 341 // a zero pointer means zero length 342 igen(nl, &n1, res); 343 n1.type = types[simtype[TUINT]]; 344 n1.xoffset += Array_nel; 345 gmove(&n1, res); 346 regfree(&n1); 347 break; 348 } 349 fatal("cgen: OLEN: unknown type %lT", nl->type); 350 break; 351 352 case OCAP: 353 if(istype(nl->type, TCHAN)) { 354 // chan has cap in the second int-sized word. 355 // a zero pointer means zero length 356 regalloc(&n1, types[tptr], res); 357 cgen(nl, &n1); 358 359 nodconst(&n2, types[tptr], 0); 360 gins(optoas(OCMP, types[tptr]), &n1, &n2); 361 p1 = gbranch(optoas(OEQ, types[tptr]), T, 0); 362 363 n2 = n1; 364 n2.op = OINDREG; 365 n2.xoffset = widthint; 366 n2.type = types[simtype[TINT]]; 367 gmove(&n2, &n1); 368 369 patch(p1, pc); 370 371 gmove(&n1, res); 372 regfree(&n1); 373 break; 374 } 375 if(isslice(nl->type)) { 376 igen(nl, &n1, res); 377 n1.type = types[simtype[TUINT]]; 378 n1.xoffset += Array_cap; 379 gmove(&n1, res); 380 regfree(&n1); 381 break; 382 } 383 fatal("cgen: OCAP: unknown type %lT", nl->type); 384 break; 385 386 case OADDR: 387 if(n->bounded) // let race detector avoid nil checks 388 disable_checknil++; 389 agen(nl, res); 390 if(n->bounded) 391 disable_checknil--; 392 break; 393 394 case OCALLMETH: 395 cgen_callmeth(n, 0); 396 cgen_callret(n, res); 397 break; 398 399 case OCALLINTER: 400 cgen_callinter(n, res, 0); 401 cgen_callret(n, res); 402 break; 403 404 case OCALLFUNC: 405 cgen_call(n, 0); 406 cgen_callret(n, res); 407 break; 408 409 case OMOD: 410 case ODIV: 411 if(isfloat[n->type->etype]) { 412 a = optoas(n->op, nl->type); 413 goto abop; 414 } 415 416 if(nl->ullman >= nr->ullman) { 417 regalloc(&n1, nl->type, res); 418 cgen(nl, &n1); 419 cgen_div(n->op, &n1, nr, res); 420 regfree(&n1); 421 } else { 422 if(!smallintconst(nr)) { 423 regalloc(&n2, nr->type, res); 424 cgen(nr, &n2); 425 } else { 426 n2 = *nr; 427 } 428 cgen_div(n->op, nl, &n2, res); 429 if(n2.op != OLITERAL) 430 regfree(&n2); 431 } 432 break; 433 434 case OLSH: 435 case ORSH: 436 case OLROT: 437 cgen_shift(n->op, n->bounded, nl, nr, res); 438 break; 439 } 440 goto ret; 441 442 sbop: // symmetric binary 443 /* 444 * put simplest on right - we'll generate into left 445 * and then adjust it using the computation of right. 446 * constants and variables have the same ullman 447 * count, so look for constants specially. 448 * 449 * an integer constant we can use as an immediate 450 * is simpler than a variable - we can use the immediate 451 * in the adjustment instruction directly - so it goes 452 * on the right. 453 * 454 * other constants, like big integers or floating point 455 * constants, require a mov into a register, so those 456 * might as well go on the left, so we can reuse that 457 * register for the computation. 458 */ 459 if(nl->ullman < nr->ullman || 460 (nl->ullman == nr->ullman && 461 (smallintconst(nl) || (nr->op == OLITERAL && !smallintconst(nr))))) { 462 r = nl; 463 nl = nr; 464 nr = r; 465 } 466 467 abop: // asymmetric binary 468 if(nl->ullman >= nr->ullman) { 469 regalloc(&n1, nl->type, res); 470 cgen(nl, &n1); 471 /* 472 * This generates smaller code - it avoids a MOV - but it's 473 * easily 10% slower due to not being able to 474 * optimize/manipulate the move. 475 * To see, run: go test -bench . crypto/md5 476 * with and without. 477 * 478 if(sudoaddable(a, nr, &addr)) { 479 p1 = gins(a, N, &n1); 480 p1->from = addr; 481 gmove(&n1, res); 482 sudoclean(); 483 regfree(&n1); 484 goto ret; 485 } 486 * 487 */ 488 489 if(smallintconst(nr)) 490 n2 = *nr; 491 else { 492 regalloc(&n2, nr->type, N); 493 cgen(nr, &n2); 494 } 495 } else { 496 if(smallintconst(nr)) 497 n2 = *nr; 498 else { 499 regalloc(&n2, nr->type, res); 500 cgen(nr, &n2); 501 } 502 regalloc(&n1, nl->type, N); 503 cgen(nl, &n1); 504 } 505 gins(a, &n2, &n1); 506 gmove(&n1, res); 507 regfree(&n1); 508 if(n2.op != OLITERAL) 509 regfree(&n2); 510 goto ret; 511 512 uop: // unary 513 regalloc(&n1, nl->type, res); 514 cgen(nl, &n1); 515 gins(a, N, &n1); 516 gmove(&n1, res); 517 regfree(&n1); 518 goto ret; 519 520 ret: 521 ; 522 } 523 524 /* 525 * allocate a register (reusing res if possible) and generate 526 * a = n 527 * The caller must call regfree(a). 528 */ 529 void 530 cgenr(Node *n, Node *a, Node *res) 531 { 532 Node n1; 533 534 if(debug['g']) 535 dump("cgenr-n", n); 536 537 if(isfat(n->type)) 538 fatal("cgenr on fat node"); 539 540 if(n->addable) { 541 regalloc(a, n->type, res); 542 gmove(n, a); 543 return; 544 } 545 546 switch(n->op) { 547 case ONAME: 548 case ODOT: 549 case ODOTPTR: 550 case OINDEX: 551 case OCALLFUNC: 552 case OCALLMETH: 553 case OCALLINTER: 554 igen(n, &n1, res); 555 regalloc(a, types[tptr], &n1); 556 gmove(&n1, a); 557 regfree(&n1); 558 break; 559 default: 560 regalloc(a, n->type, res); 561 cgen(n, a); 562 break; 563 } 564 } 565 566 /* 567 * allocate a register (reusing res if possible) and generate 568 * a = &n 569 * The caller must call regfree(a). 570 * The generated code checks that the result is not nil. 571 */ 572 void 573 agenr(Node *n, Node *a, Node *res) 574 { 575 Node *nl, *nr; 576 Node n1, n2, n3, n5, tmp, tmp2, nlen; 577 Prog *p1; 578 Type *t; 579 uint64 w; 580 uint64 v; 581 int freelen; 582 583 if(debug['g']) { 584 dump("\nagenr-n", n); 585 } 586 587 nl = n->left; 588 nr = n->right; 589 590 switch(n->op) { 591 case ODOT: 592 case ODOTPTR: 593 case OCALLFUNC: 594 case OCALLMETH: 595 case OCALLINTER: 596 igen(n, &n1, res); 597 regalloc(a, types[tptr], &n1); 598 agen(&n1, a); 599 regfree(&n1); 600 break; 601 602 case OIND: 603 cgenr(n->left, a, res); 604 cgen_checknil(a); 605 break; 606 607 case OINDEX: 608 freelen = 0; 609 w = n->type->width; 610 // Generate the non-addressable child first. 611 if(nr->addable) 612 goto irad; 613 if(nl->addable) { 614 cgenr(nr, &n1, N); 615 if(!isconst(nl, CTSTR)) { 616 if(isfixedarray(nl->type)) { 617 agenr(nl, &n3, res); 618 } else { 619 igen(nl, &nlen, res); 620 freelen = 1; 621 nlen.type = types[tptr]; 622 nlen.xoffset += Array_array; 623 regalloc(&n3, types[tptr], res); 624 gmove(&nlen, &n3); 625 nlen.type = types[simtype[TUINT]]; 626 nlen.xoffset += Array_nel-Array_array; 627 } 628 } 629 goto index; 630 } 631 tempname(&tmp, nr->type); 632 cgen(nr, &tmp); 633 nr = &tmp; 634 irad: 635 if(!isconst(nl, CTSTR)) { 636 if(isfixedarray(nl->type)) { 637 agenr(nl, &n3, res); 638 } else { 639 if(!nl->addable) { 640 // igen will need an addressable node. 641 tempname(&tmp2, nl->type); 642 cgen(nl, &tmp2); 643 nl = &tmp2; 644 } 645 igen(nl, &nlen, res); 646 freelen = 1; 647 nlen.type = types[tptr]; 648 nlen.xoffset += Array_array; 649 regalloc(&n3, types[tptr], res); 650 gmove(&nlen, &n3); 651 nlen.type = types[simtype[TUINT]]; 652 nlen.xoffset += Array_nel-Array_array; 653 } 654 } 655 if(!isconst(nr, CTINT)) { 656 cgenr(nr, &n1, N); 657 } 658 goto index; 659 660 index: 661 // &a is in &n3 (allocated in res) 662 // i is in &n1 (if not constant) 663 // len(a) is in nlen (if needed) 664 // w is width 665 666 // constant index 667 if(isconst(nr, CTINT)) { 668 if(isconst(nl, CTSTR)) 669 fatal("constant string constant index"); // front end should handle 670 v = mpgetfix(nr->val.u.xval); 671 if(isslice(nl->type) || nl->type->etype == TSTRING) { 672 if(!debug['B'] && !n->bounded) { 673 nodconst(&n2, types[simtype[TUINT]], v); 674 if(smallintconst(nr)) { 675 gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &n2); 676 } else { 677 regalloc(&tmp, types[simtype[TUINT]], N); 678 gmove(&n2, &tmp); 679 gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &tmp); 680 regfree(&tmp); 681 } 682 p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1); 683 ginscall(panicindex, -1); 684 patch(p1, pc); 685 } 686 regfree(&nlen); 687 } 688 689 if (v*w != 0) 690 ginscon(optoas(OADD, types[tptr]), v*w, &n3); 691 *a = n3; 692 break; 693 } 694 695 // type of the index 696 t = types[TUINT64]; 697 if(issigned[n1.type->etype]) 698 t = types[TINT64]; 699 700 regalloc(&n2, t, &n1); // i 701 gmove(&n1, &n2); 702 regfree(&n1); 703 704 if(!debug['B'] && !n->bounded) { 705 // check bounds 706 t = types[simtype[TUINT]]; 707 if(is64(nr->type)) 708 t = types[TUINT64]; 709 if(isconst(nl, CTSTR)) { 710 nodconst(&nlen, t, nl->val.u.sval->len); 711 } else if(isslice(nl->type) || nl->type->etype == TSTRING) { 712 if(is64(nr->type)) { 713 regalloc(&n5, t, N); 714 gmove(&nlen, &n5); 715 regfree(&nlen); 716 nlen = n5; 717 } 718 } else { 719 nodconst(&nlen, t, nl->type->bound); 720 if(!smallintconst(&nlen)) { 721 regalloc(&n5, t, N); 722 gmove(&nlen, &n5); 723 nlen = n5; 724 freelen = 1; 725 } 726 } 727 gins(optoas(OCMP, t), &n2, &nlen); 728 p1 = gbranch(optoas(OLT, t), T, +1); 729 ginscall(panicindex, -1); 730 patch(p1, pc); 731 } 732 733 if(isconst(nl, CTSTR)) { 734 regalloc(&n3, types[tptr], res); 735 p1 = gins(ALEAQ, N, &n3); 736 datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); 737 if(flag_largemodel) { 738 gins(AADDQ, &n2, &n3); 739 } else { 740 p1->from.scale = 1; 741 p1->from.index = n2.val.u.reg; 742 } 743 goto indexdone; 744 } 745 746 if(w == 0) { 747 // nothing to do 748 } else if(w == 1 || w == 2 || w == 4 || w == 8) { 749 p1 = gins(ALEAQ, &n2, &n3); 750 p1->from.scale = w; 751 p1->from.index = p1->from.type; 752 p1->from.type = p1->to.type + D_INDIR; 753 } else { 754 ginscon(optoas(OMUL, t), w, &n2); 755 gins(optoas(OADD, types[tptr]), &n2, &n3); 756 } 757 758 indexdone: 759 *a = n3; 760 regfree(&n2); 761 if(freelen) 762 regfree(&nlen); 763 break; 764 765 default: 766 regalloc(a, types[tptr], res); 767 agen(n, a); 768 break; 769 } 770 } 771 772 /* 773 * generate: 774 * res = &n; 775 * The generated code checks that the result is not nil. 776 */ 777 void 778 agen(Node *n, Node *res) 779 { 780 Node *nl, *nr; 781 Node n1, n2; 782 783 if(debug['g']) { 784 dump("\nagen-res", res); 785 dump("agen-r", n); 786 } 787 if(n == N || n->type == T) 788 return; 789 790 while(n->op == OCONVNOP) 791 n = n->left; 792 793 if(isconst(n, CTNIL) && n->type->width > widthptr) { 794 // Use of a nil interface or nil slice. 795 // Create a temporary we can take the address of and read. 796 // The generated code is just going to panic, so it need not 797 // be terribly efficient. See issue 3670. 798 tempname(&n1, n->type); 799 clearfat(&n1); 800 regalloc(&n2, types[tptr], res); 801 gins(ALEAQ, &n1, &n2); 802 gmove(&n2, res); 803 regfree(&n2); 804 goto ret; 805 } 806 807 if(n->addable) { 808 regalloc(&n1, types[tptr], res); 809 gins(ALEAQ, n, &n1); 810 gmove(&n1, res); 811 regfree(&n1); 812 goto ret; 813 } 814 815 nl = n->left; 816 nr = n->right; 817 USED(nr); 818 819 switch(n->op) { 820 default: 821 fatal("agen: unknown op %+hN", n); 822 break; 823 824 case OCALLMETH: 825 cgen_callmeth(n, 0); 826 cgen_aret(n, res); 827 break; 828 829 case OCALLINTER: 830 cgen_callinter(n, res, 0); 831 cgen_aret(n, res); 832 break; 833 834 case OCALLFUNC: 835 cgen_call(n, 0); 836 cgen_aret(n, res); 837 break; 838 839 case OSLICE: 840 case OSLICEARR: 841 case OSLICESTR: 842 case OSLICE3: 843 case OSLICE3ARR: 844 tempname(&n1, n->type); 845 cgen_slice(n, &n1); 846 agen(&n1, res); 847 break; 848 849 case OEFACE: 850 tempname(&n1, n->type); 851 cgen_eface(n, &n1); 852 agen(&n1, res); 853 break; 854 855 case OINDEX: 856 agenr(n, &n1, res); 857 gmove(&n1, res); 858 regfree(&n1); 859 break; 860 861 case ONAME: 862 // should only get here with names in this func. 863 if(n->funcdepth > 0 && n->funcdepth != funcdepth) { 864 dump("bad agen", n); 865 fatal("agen: bad ONAME funcdepth %d != %d", 866 n->funcdepth, funcdepth); 867 } 868 869 // should only get here for heap vars or paramref 870 if(!(n->class & PHEAP) && n->class != PPARAMREF) { 871 dump("bad agen", n); 872 fatal("agen: bad ONAME class %#x", n->class); 873 } 874 cgen(n->heapaddr, res); 875 if(n->xoffset != 0) 876 ginscon(optoas(OADD, types[tptr]), n->xoffset, res); 877 break; 878 879 case OIND: 880 cgen(nl, res); 881 cgen_checknil(res); 882 break; 883 884 case ODOT: 885 agen(nl, res); 886 if(n->xoffset != 0) 887 ginscon(optoas(OADD, types[tptr]), n->xoffset, res); 888 break; 889 890 case ODOTPTR: 891 cgen(nl, res); 892 cgen_checknil(res); 893 if(n->xoffset != 0) 894 ginscon(optoas(OADD, types[tptr]), n->xoffset, res); 895 break; 896 } 897 898 ret: 899 ; 900 } 901 902 /* 903 * generate: 904 * newreg = &n; 905 * res = newreg 906 * 907 * on exit, a has been changed to be *newreg. 908 * caller must regfree(a). 909 * The generated code checks that the result is not *nil. 910 */ 911 void 912 igen(Node *n, Node *a, Node *res) 913 { 914 Type *fp; 915 Iter flist; 916 Node n1; 917 918 if(debug['g']) { 919 dump("\nigen-n", n); 920 } 921 switch(n->op) { 922 case ONAME: 923 if((n->class&PHEAP) || n->class == PPARAMREF) 924 break; 925 *a = *n; 926 return; 927 928 case OINDREG: 929 // Increase the refcount of the register so that igen's caller 930 // has to call regfree. 931 if(n->val.u.reg != D_SP) 932 reg[n->val.u.reg]++; 933 *a = *n; 934 return; 935 936 case ODOT: 937 igen(n->left, a, res); 938 a->xoffset += n->xoffset; 939 a->type = n->type; 940 return; 941 942 case ODOTPTR: 943 cgenr(n->left, a, res); 944 cgen_checknil(a); 945 a->op = OINDREG; 946 a->xoffset += n->xoffset; 947 a->type = n->type; 948 return; 949 950 case OCALLFUNC: 951 case OCALLMETH: 952 case OCALLINTER: 953 switch(n->op) { 954 case OCALLFUNC: 955 cgen_call(n, 0); 956 break; 957 case OCALLMETH: 958 cgen_callmeth(n, 0); 959 break; 960 case OCALLINTER: 961 cgen_callinter(n, N, 0); 962 break; 963 } 964 fp = structfirst(&flist, getoutarg(n->left->type)); 965 memset(a, 0, sizeof *a); 966 a->op = OINDREG; 967 a->val.u.reg = D_SP; 968 a->addable = 1; 969 a->xoffset = fp->width; 970 a->type = n->type; 971 return; 972 973 case OINDEX: 974 // Index of fixed-size array by constant can 975 // put the offset in the addressing. 976 // Could do the same for slice except that we need 977 // to use the real index for the bounds checking. 978 if(isfixedarray(n->left->type) || 979 (isptr[n->left->type->etype] && isfixedarray(n->left->left->type))) 980 if(isconst(n->right, CTINT)) { 981 // Compute &a. 982 if(!isptr[n->left->type->etype]) 983 igen(n->left, a, res); 984 else { 985 igen(n->left, &n1, res); 986 cgen_checknil(&n1); 987 regalloc(a, types[tptr], res); 988 gmove(&n1, a); 989 regfree(&n1); 990 a->op = OINDREG; 991 } 992 993 // Compute &a[i] as &a + i*width. 994 a->type = n->type; 995 a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width; 996 return; 997 } 998 } 999 1000 agenr(n, a, res); 1001 a->op = OINDREG; 1002 a->type = n->type; 1003 } 1004 1005 /* 1006 * generate: 1007 * if(n == true) goto to; 1008 */ 1009 void 1010 bgen(Node *n, int true, int likely, Prog *to) 1011 { 1012 int et, a; 1013 Node *nl, *nr, *l, *r; 1014 Node n1, n2, tmp; 1015 NodeList *ll; 1016 Prog *p1, *p2; 1017 1018 if(debug['g']) { 1019 dump("\nbgen", n); 1020 } 1021 1022 if(n == N) 1023 n = nodbool(1); 1024 1025 if(n->ninit != nil) 1026 genlist(n->ninit); 1027 1028 if(n->type == T) { 1029 convlit(&n, types[TBOOL]); 1030 if(n->type == T) 1031 goto ret; 1032 } 1033 1034 et = n->type->etype; 1035 if(et != TBOOL) { 1036 yyerror("cgen: bad type %T for %O", n->type, n->op); 1037 patch(gins(AEND, N, N), to); 1038 goto ret; 1039 } 1040 nr = N; 1041 1042 switch(n->op) { 1043 default: 1044 def: 1045 regalloc(&n1, n->type, N); 1046 cgen(n, &n1); 1047 nodconst(&n2, n->type, 0); 1048 gins(optoas(OCMP, n->type), &n1, &n2); 1049 a = AJNE; 1050 if(!true) 1051 a = AJEQ; 1052 patch(gbranch(a, n->type, likely), to); 1053 regfree(&n1); 1054 goto ret; 1055 1056 case OLITERAL: 1057 // need to ask if it is bool? 1058 if(!true == !n->val.u.bval) 1059 patch(gbranch(AJMP, T, likely), to); 1060 goto ret; 1061 1062 case ONAME: 1063 if(n->addable == 0) 1064 goto def; 1065 nodconst(&n1, n->type, 0); 1066 gins(optoas(OCMP, n->type), n, &n1); 1067 a = AJNE; 1068 if(!true) 1069 a = AJEQ; 1070 patch(gbranch(a, n->type, likely), to); 1071 goto ret; 1072 1073 case OANDAND: 1074 if(!true) 1075 goto caseor; 1076 1077 caseand: 1078 p1 = gbranch(AJMP, T, 0); 1079 p2 = gbranch(AJMP, T, 0); 1080 patch(p1, pc); 1081 bgen(n->left, !true, -likely, p2); 1082 bgen(n->right, !true, -likely, p2); 1083 p1 = gbranch(AJMP, T, 0); 1084 patch(p1, to); 1085 patch(p2, pc); 1086 goto ret; 1087 1088 case OOROR: 1089 if(!true) 1090 goto caseand; 1091 1092 caseor: 1093 bgen(n->left, true, likely, to); 1094 bgen(n->right, true, likely, to); 1095 goto ret; 1096 1097 case OEQ: 1098 case ONE: 1099 case OLT: 1100 case OGT: 1101 case OLE: 1102 case OGE: 1103 nr = n->right; 1104 if(nr == N || nr->type == T) 1105 goto ret; 1106 1107 case ONOT: // unary 1108 nl = n->left; 1109 if(nl == N || nl->type == T) 1110 goto ret; 1111 break; 1112 } 1113 1114 switch(n->op) { 1115 1116 case ONOT: 1117 bgen(nl, !true, likely, to); 1118 goto ret; 1119 1120 case OEQ: 1121 case ONE: 1122 case OLT: 1123 case OGT: 1124 case OLE: 1125 case OGE: 1126 a = n->op; 1127 if(!true) { 1128 if(isfloat[nr->type->etype]) { 1129 // brcom is not valid on floats when NaN is involved. 1130 p1 = gbranch(AJMP, T, 0); 1131 p2 = gbranch(AJMP, T, 0); 1132 patch(p1, pc); 1133 ll = n->ninit; // avoid re-genning ninit 1134 n->ninit = nil; 1135 bgen(n, 1, -likely, p2); 1136 n->ninit = ll; 1137 patch(gbranch(AJMP, T, 0), to); 1138 patch(p2, pc); 1139 goto ret; 1140 } 1141 a = brcom(a); 1142 true = !true; 1143 } 1144 1145 // make simplest on right 1146 if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) { 1147 a = brrev(a); 1148 r = nl; 1149 nl = nr; 1150 nr = r; 1151 } 1152 1153 if(isslice(nl->type)) { 1154 // front end should only leave cmp to literal nil 1155 if((a != OEQ && a != ONE) || nr->op != OLITERAL) { 1156 yyerror("illegal slice comparison"); 1157 break; 1158 } 1159 a = optoas(a, types[tptr]); 1160 igen(nl, &n1, N); 1161 n1.xoffset += Array_array; 1162 n1.type = types[tptr]; 1163 nodconst(&tmp, types[tptr], 0); 1164 gins(optoas(OCMP, types[tptr]), &n1, &tmp); 1165 patch(gbranch(a, types[tptr], likely), to); 1166 regfree(&n1); 1167 break; 1168 } 1169 1170 if(isinter(nl->type)) { 1171 // front end should only leave cmp to literal nil 1172 if((a != OEQ && a != ONE) || nr->op != OLITERAL) { 1173 yyerror("illegal interface comparison"); 1174 break; 1175 } 1176 a = optoas(a, types[tptr]); 1177 igen(nl, &n1, N); 1178 n1.type = types[tptr]; 1179 nodconst(&tmp, types[tptr], 0); 1180 gins(optoas(OCMP, types[tptr]), &n1, &tmp); 1181 patch(gbranch(a, types[tptr], likely), to); 1182 regfree(&n1); 1183 break; 1184 } 1185 if(iscomplex[nl->type->etype]) { 1186 complexbool(a, nl, nr, true, likely, to); 1187 break; 1188 } 1189 1190 if(nr->ullman >= UINF) { 1191 regalloc(&n1, nl->type, N); 1192 cgen(nl, &n1); 1193 1194 tempname(&tmp, nl->type); 1195 gmove(&n1, &tmp); 1196 regfree(&n1); 1197 1198 regalloc(&n2, nr->type, N); 1199 cgen(nr, &n2); 1200 1201 regalloc(&n1, nl->type, N); 1202 cgen(&tmp, &n1); 1203 1204 goto cmp; 1205 } 1206 1207 regalloc(&n1, nl->type, N); 1208 cgen(nl, &n1); 1209 1210 if(smallintconst(nr)) { 1211 gins(optoas(OCMP, nr->type), &n1, nr); 1212 patch(gbranch(optoas(a, nr->type), nr->type, likely), to); 1213 regfree(&n1); 1214 break; 1215 } 1216 1217 regalloc(&n2, nr->type, N); 1218 cgen(nr, &n2); 1219 cmp: 1220 // only < and <= work right with NaN; reverse if needed 1221 l = &n1; 1222 r = &n2; 1223 if(isfloat[nl->type->etype] && (a == OGT || a == OGE)) { 1224 l = &n2; 1225 r = &n1; 1226 a = brrev(a); 1227 } 1228 1229 gins(optoas(OCMP, nr->type), l, r); 1230 1231 if(isfloat[nr->type->etype] && (n->op == OEQ || n->op == ONE)) { 1232 if(n->op == OEQ) { 1233 // neither NE nor P 1234 p1 = gbranch(AJNE, T, -likely); 1235 p2 = gbranch(AJPS, T, -likely); 1236 patch(gbranch(AJMP, T, 0), to); 1237 patch(p1, pc); 1238 patch(p2, pc); 1239 } else { 1240 // either NE or P 1241 patch(gbranch(AJNE, T, likely), to); 1242 patch(gbranch(AJPS, T, likely), to); 1243 } 1244 } else 1245 patch(gbranch(optoas(a, nr->type), nr->type, likely), to); 1246 regfree(&n1); 1247 regfree(&n2); 1248 break; 1249 } 1250 goto ret; 1251 1252 ret: 1253 ; 1254 } 1255 1256 /* 1257 * n is on stack, either local variable 1258 * or return value from function call. 1259 * return n's offset from SP. 1260 */ 1261 int64 1262 stkof(Node *n) 1263 { 1264 Type *t; 1265 Iter flist; 1266 int64 off; 1267 1268 switch(n->op) { 1269 case OINDREG: 1270 return n->xoffset; 1271 1272 case ODOT: 1273 t = n->left->type; 1274 if(isptr[t->etype]) 1275 break; 1276 off = stkof(n->left); 1277 if(off == -1000 || off == 1000) 1278 return off; 1279 return off + n->xoffset; 1280 1281 case OINDEX: 1282 t = n->left->type; 1283 if(!isfixedarray(t)) 1284 break; 1285 off = stkof(n->left); 1286 if(off == -1000 || off == 1000) 1287 return off; 1288 if(isconst(n->right, CTINT)) 1289 return off + t->type->width * mpgetfix(n->right->val.u.xval); 1290 return 1000; 1291 1292 case OCALLMETH: 1293 case OCALLINTER: 1294 case OCALLFUNC: 1295 t = n->left->type; 1296 if(isptr[t->etype]) 1297 t = t->type; 1298 1299 t = structfirst(&flist, getoutarg(t)); 1300 if(t != T) 1301 return t->width; 1302 break; 1303 } 1304 1305 // botch - probably failing to recognize address 1306 // arithmetic on the above. eg INDEX and DOT 1307 return -1000; 1308 } 1309 1310 /* 1311 * block copy: 1312 * memmove(&ns, &n, w); 1313 */ 1314 void 1315 sgen(Node *n, Node *ns, int64 w) 1316 { 1317 Node nodl, nodr, nodsi, noddi, cx, oldcx, tmp; 1318 vlong c, q, odst, osrc; 1319 1320 if(debug['g']) { 1321 print("\nsgen w=%lld\n", w); 1322 dump("r", n); 1323 dump("res", ns); 1324 } 1325 1326 if(n->ullman >= UINF && ns->ullman >= UINF) 1327 fatal("sgen UINF"); 1328 1329 if(w < 0) 1330 fatal("sgen copy %lld", w); 1331 1332 // Avoid taking the address for simple enough types. 1333 if(componentgen(n, ns)) 1334 return; 1335 1336 if(w == 0) { 1337 // evaluate side effects only 1338 regalloc(&nodr, types[tptr], N); 1339 agen(ns, &nodr); 1340 agen(n, &nodr); 1341 regfree(&nodr); 1342 return; 1343 } 1344 1345 // offset on the stack 1346 osrc = stkof(n); 1347 odst = stkof(ns); 1348 1349 if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { 1350 // osrc and odst both on stack, and at least one is in 1351 // an unknown position. Could generate code to test 1352 // for forward/backward copy, but instead just copy 1353 // to a temporary location first. 1354 tempname(&tmp, n->type); 1355 sgen(n, &tmp, w); 1356 sgen(&tmp, ns, w); 1357 return; 1358 } 1359 1360 if(n->ullman >= ns->ullman) { 1361 agenr(n, &nodr, N); 1362 agenr(ns, &nodl, N); 1363 } else { 1364 agenr(ns, &nodl, N); 1365 agenr(n, &nodr, N); 1366 } 1367 nodreg(&noddi, types[tptr], D_DI); 1368 nodreg(&nodsi, types[tptr], D_SI); 1369 gmove(&nodl, &noddi); 1370 gmove(&nodr, &nodsi); 1371 regfree(&nodl); 1372 regfree(&nodr); 1373 1374 c = w % 8; // bytes 1375 q = w / 8; // quads 1376 1377 savex(D_CX, &cx, &oldcx, N, types[TINT64]); 1378 1379 // if we are copying forward on the stack and 1380 // the src and dst overlap, then reverse direction 1381 if(osrc < odst && odst < osrc+w) { 1382 // reverse direction 1383 gins(ASTD, N, N); // set direction flag 1384 if(c > 0) { 1385 gconreg(AADDQ, w-1, D_SI); 1386 gconreg(AADDQ, w-1, D_DI); 1387 1388 gconreg(AMOVQ, c, D_CX); 1389 gins(AREP, N, N); // repeat 1390 gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)- 1391 } 1392 1393 if(q > 0) { 1394 if(c > 0) { 1395 gconreg(AADDQ, -7, D_SI); 1396 gconreg(AADDQ, -7, D_DI); 1397 } else { 1398 gconreg(AADDQ, w-8, D_SI); 1399 gconreg(AADDQ, w-8, D_DI); 1400 } 1401 gconreg(AMOVQ, q, D_CX); 1402 gins(AREP, N, N); // repeat 1403 gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)- 1404 } 1405 // we leave with the flag clear 1406 gins(ACLD, N, N); 1407 } else { 1408 // normal direction 1409 if(q >= 4) { 1410 gconreg(AMOVQ, q, D_CX); 1411 gins(AREP, N, N); // repeat 1412 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ 1413 } else 1414 while(q > 0) { 1415 gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ 1416 q--; 1417 } 1418 1419 if(c >= 4) { 1420 gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ 1421 c -= 4; 1422 } 1423 while(c > 0) { 1424 gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+ 1425 c--; 1426 } 1427 } 1428 1429 restx(&cx, &oldcx); 1430 } 1431 1432 static int 1433 cadable(Node *n) 1434 { 1435 if(!n->addable) { 1436 // dont know how it happens, 1437 // but it does 1438 return 0; 1439 } 1440 1441 switch(n->op) { 1442 case ONAME: 1443 return 1; 1444 } 1445 return 0; 1446 } 1447 1448 /* 1449 * copy a composite value by moving its individual components. 1450 * Slices, strings and interfaces are supported. 1451 * Small structs or arrays with elements of basic type are 1452 * also supported. 1453 * nr is N when assigning a zero value. 1454 * return 1 if can do, 0 if can't. 1455 */ 1456 int 1457 componentgen(Node *nr, Node *nl) 1458 { 1459 Node nodl, nodr; 1460 Type *t; 1461 int freel, freer; 1462 vlong fldcount; 1463 vlong loffset, roffset; 1464 1465 freel = 0; 1466 freer = 0; 1467 1468 switch(nl->type->etype) { 1469 default: 1470 goto no; 1471 1472 case TARRAY: 1473 t = nl->type; 1474 1475 // Slices are ok. 1476 if(isslice(t)) 1477 break; 1478 // Small arrays are ok. 1479 if(t->bound > 0 && t->bound <= 3 && !isfat(t->type)) 1480 break; 1481 1482 goto no; 1483 1484 case TSTRUCT: 1485 // Small structs with non-fat types are ok. 1486 // Zero-sized structs are treated separately elsewhere. 1487 fldcount = 0; 1488 for(t=nl->type->type; t; t=t->down) { 1489 if(isfat(t->type)) 1490 goto no; 1491 if(t->etype != TFIELD) 1492 fatal("componentgen: not a TFIELD: %lT", t); 1493 fldcount++; 1494 } 1495 if(fldcount == 0 || fldcount > 3) 1496 goto no; 1497 1498 break; 1499 1500 case TSTRING: 1501 case TINTER: 1502 break; 1503 } 1504 1505 nodl = *nl; 1506 if(!cadable(nl)) { 1507 if(nr == N || !cadable(nr)) 1508 goto no; 1509 igen(nl, &nodl, N); 1510 freel = 1; 1511 } 1512 1513 if(nr != N) { 1514 nodr = *nr; 1515 if(!cadable(nr)) { 1516 igen(nr, &nodr, N); 1517 freer = 1; 1518 } 1519 } 1520 1521 switch(nl->type->etype) { 1522 case TARRAY: 1523 // componentgen for arrays. 1524 t = nl->type; 1525 if(!isslice(t)) { 1526 nodl.type = t->type; 1527 nodr.type = nodl.type; 1528 for(fldcount=0; fldcount < t->bound; fldcount++) { 1529 if(nr == N) 1530 clearslim(&nodl); 1531 else 1532 gmove(&nodr, &nodl); 1533 nodl.xoffset += t->type->width; 1534 nodr.xoffset += t->type->width; 1535 } 1536 goto yes; 1537 } 1538 1539 // componentgen for slices. 1540 nodl.xoffset += Array_array; 1541 nodl.type = ptrto(nl->type->type); 1542 1543 if(nr != N) { 1544 nodr.xoffset += Array_array; 1545 nodr.type = nodl.type; 1546 } else 1547 nodconst(&nodr, nodl.type, 0); 1548 gmove(&nodr, &nodl); 1549 1550 nodl.xoffset += Array_nel-Array_array; 1551 nodl.type = types[simtype[TUINT]]; 1552 1553 if(nr != N) { 1554 nodr.xoffset += Array_nel-Array_array; 1555 nodr.type = nodl.type; 1556 } else 1557 nodconst(&nodr, nodl.type, 0); 1558 gmove(&nodr, &nodl); 1559 1560 nodl.xoffset += Array_cap-Array_nel; 1561 nodl.type = types[simtype[TUINT]]; 1562 1563 if(nr != N) { 1564 nodr.xoffset += Array_cap-Array_nel; 1565 nodr.type = nodl.type; 1566 } else 1567 nodconst(&nodr, nodl.type, 0); 1568 gmove(&nodr, &nodl); 1569 1570 goto yes; 1571 1572 case TSTRING: 1573 nodl.xoffset += Array_array; 1574 nodl.type = ptrto(types[TUINT8]); 1575 1576 if(nr != N) { 1577 nodr.xoffset += Array_array; 1578 nodr.type = nodl.type; 1579 } else 1580 nodconst(&nodr, nodl.type, 0); 1581 gmove(&nodr, &nodl); 1582 1583 nodl.xoffset += Array_nel-Array_array; 1584 nodl.type = types[simtype[TUINT]]; 1585 1586 if(nr != N) { 1587 nodr.xoffset += Array_nel-Array_array; 1588 nodr.type = nodl.type; 1589 } else 1590 nodconst(&nodr, nodl.type, 0); 1591 gmove(&nodr, &nodl); 1592 1593 goto yes; 1594 1595 case TINTER: 1596 nodl.xoffset += Array_array; 1597 nodl.type = ptrto(types[TUINT8]); 1598 1599 if(nr != N) { 1600 nodr.xoffset += Array_array; 1601 nodr.type = nodl.type; 1602 } else 1603 nodconst(&nodr, nodl.type, 0); 1604 gmove(&nodr, &nodl); 1605 1606 nodl.xoffset += Array_nel-Array_array; 1607 nodl.type = ptrto(types[TUINT8]); 1608 1609 if(nr != N) { 1610 nodr.xoffset += Array_nel-Array_array; 1611 nodr.type = nodl.type; 1612 } else 1613 nodconst(&nodr, nodl.type, 0); 1614 gmove(&nodr, &nodl); 1615 1616 goto yes; 1617 1618 case TSTRUCT: 1619 loffset = nodl.xoffset; 1620 roffset = nodr.xoffset; 1621 // funarg structs may not begin at offset zero. 1622 if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type) 1623 loffset -= nl->type->type->width; 1624 if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type) 1625 roffset -= nr->type->type->width; 1626 1627 for(t=nl->type->type; t; t=t->down) { 1628 nodl.xoffset = loffset + t->width; 1629 nodl.type = t->type; 1630 1631 if(nr == N) 1632 clearslim(&nodl); 1633 else { 1634 nodr.xoffset = roffset + t->width; 1635 nodr.type = nodl.type; 1636 gmove(&nodr, &nodl); 1637 } 1638 } 1639 goto yes; 1640 } 1641 1642 no: 1643 if(freer) 1644 regfree(&nodr); 1645 if(freel) 1646 regfree(&nodl); 1647 return 0; 1648 1649 yes: 1650 if(freer) 1651 regfree(&nodr); 1652 if(freel) 1653 regfree(&nodl); 1654 return 1; 1655 }