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