github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/src/cmd/5g/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, f0, f1; 19 int a, w, rg; 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 switch(n->op) { 34 case OSLICE: 35 case OSLICEARR: 36 case OSLICESTR: 37 case OSLICE3: 38 case OSLICE3ARR: 39 if (res->op != ONAME || !res->addable) { 40 tempname(&n1, n->type); 41 cgen_slice(n, &n1); 42 cgen(&n1, res); 43 } else 44 cgen_slice(n, res); 45 return; 46 case OEFACE: 47 if (res->op != ONAME || !res->addable) { 48 tempname(&n1, n->type); 49 cgen_eface(n, &n1); 50 cgen(&n1, res); 51 } else 52 cgen_eface(n, res); 53 return; 54 } 55 56 while(n->op == OCONVNOP) 57 n = n->left; 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 78 // update addressability for string, slice 79 // can't do in walk because n->left->addable 80 // changes if n->left is an escaping local variable. 81 switch(n->op) { 82 case OSPTR: 83 case OLEN: 84 if(isslice(n->left->type) || istype(n->left->type, TSTRING)) 85 n->addable = n->left->addable; 86 break; 87 case OCAP: 88 if(isslice(n->left->type)) 89 n->addable = n->left->addable; 90 break; 91 case OITAB: 92 n->addable = n->left->addable; 93 break; 94 } 95 96 // if both are addressable, move 97 if(n->addable && res->addable) { 98 if(is64(n->type) || is64(res->type) || 99 n->op == OREGISTER || res->op == OREGISTER || 100 iscomplex[n->type->etype] || iscomplex[res->type->etype]) { 101 gmove(n, res); 102 } else { 103 regalloc(&n1, n->type, N); 104 gmove(n, &n1); 105 cgen(&n1, res); 106 regfree(&n1); 107 } 108 goto ret; 109 } 110 111 // if both are not addressable, use a temporary. 112 if(!n->addable && !res->addable) { 113 // could use regalloc here sometimes, 114 // but have to check for ullman >= UINF. 115 tempname(&n1, n->type); 116 cgen(n, &n1); 117 cgen(&n1, res); 118 return; 119 } 120 121 // if result is not addressable directly but n is, 122 // compute its address and then store via the address. 123 if(!res->addable) { 124 igen(res, &n1, N); 125 cgen(n, &n1); 126 regfree(&n1); 127 return; 128 } 129 130 if(complexop(n, res)) { 131 complexgen(n, res); 132 return; 133 } 134 135 // if n is sudoaddable generate addr and move 136 if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) { 137 a = optoas(OAS, n->type); 138 if(sudoaddable(a, n, &addr, &w)) { 139 if (res->op != OREGISTER) { 140 regalloc(&n2, res->type, N); 141 p1 = gins(a, N, &n2); 142 p1->from = addr; 143 if(debug['g']) 144 print("%P [ignore previous line]\n", p1); 145 gmove(&n2, res); 146 regfree(&n2); 147 } else { 148 p1 = gins(a, N, res); 149 p1->from = addr; 150 if(debug['g']) 151 print("%P [ignore previous line]\n", p1); 152 } 153 sudoclean(); 154 goto ret; 155 } 156 } 157 158 // otherwise, the result is addressable but n is not. 159 // let's do some computation. 160 161 nl = n->left; 162 nr = n->right; 163 164 if(nl != N && nl->ullman >= UINF) 165 if(nr != N && nr->ullman >= UINF) { 166 tempname(&n1, nl->type); 167 cgen(nl, &n1); 168 n2 = *n; 169 n2.left = &n1; 170 cgen(&n2, res); 171 goto ret; 172 } 173 174 // 64-bit ops are hard on 32-bit machine. 175 if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) { 176 switch(n->op) { 177 // math goes to cgen64. 178 case OMINUS: 179 case OCOM: 180 case OADD: 181 case OSUB: 182 case OMUL: 183 case OLROT: 184 case OLSH: 185 case ORSH: 186 case OAND: 187 case OOR: 188 case OXOR: 189 cgen64(n, res); 190 return; 191 } 192 } 193 194 if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) 195 goto flt; 196 switch(n->op) { 197 default: 198 dump("cgen", n); 199 fatal("cgen: unknown op %+hN", n); 200 break; 201 202 case OREAL: 203 case OIMAG: 204 case OCOMPLEX: 205 fatal("unexpected complex"); 206 break; 207 208 // these call bgen to get a bool value 209 case OOROR: 210 case OANDAND: 211 case OEQ: 212 case ONE: 213 case OLT: 214 case OLE: 215 case OGE: 216 case OGT: 217 case ONOT: 218 p1 = gbranch(AB, T, 0); 219 p2 = pc; 220 gmove(nodbool(1), res); 221 p3 = gbranch(AB, T, 0); 222 patch(p1, pc); 223 bgen(n, 1, 0, p2); 224 gmove(nodbool(0), res); 225 patch(p3, pc); 226 goto ret; 227 228 case OPLUS: 229 cgen(nl, res); 230 goto ret; 231 232 // unary 233 case OCOM: 234 a = optoas(OXOR, nl->type); 235 regalloc(&n1, nl->type, N); 236 cgen(nl, &n1); 237 nodconst(&n2, nl->type, -1); 238 gins(a, &n2, &n1); 239 goto norm; 240 241 case OMINUS: 242 regalloc(&n1, nl->type, N); 243 cgen(nl, &n1); 244 nodconst(&n2, nl->type, 0); 245 gins(optoas(OMINUS, nl->type), &n2, &n1); 246 goto norm; 247 248 // symmetric binary 249 case OAND: 250 case OOR: 251 case OXOR: 252 case OADD: 253 case OMUL: 254 a = optoas(n->op, nl->type); 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 OLROT: 267 case OLSH: 268 case ORSH: 269 cgen_shift(n->op, n->bounded, nl, nr, res); 270 break; 271 272 case OCONV: 273 if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) { 274 cgen(nl, res); 275 break; 276 } 277 if(nl->addable && !is64(nl->type)) { 278 regalloc(&n1, nl->type, res); 279 gmove(nl, &n1); 280 } else { 281 if(n->type->width > widthptr || is64(nl->type) || isfloat[nl->type->etype]) 282 tempname(&n1, nl->type); 283 else 284 regalloc(&n1, nl->type, res); 285 cgen(nl, &n1); 286 } 287 if(n->type->width > widthptr || is64(n->type) || isfloat[n->type->etype]) 288 tempname(&n2, n->type); 289 else 290 regalloc(&n2, n->type, N); 291 gmove(&n1, &n2); 292 gmove(&n2, res); 293 if(n1.op == OREGISTER) 294 regfree(&n1); 295 if(n2.op == OREGISTER) 296 regfree(&n2); 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 OSPTR: 318 // pointer is the first word of string or slice. 319 if(isconst(nl, CTSTR)) { 320 regalloc(&n1, types[tptr], res); 321 p1 = gins(AMOVW, N, &n1); 322 datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); 323 gmove(&n1, res); 324 regfree(&n1); 325 break; 326 } 327 igen(nl, &n1, res); 328 n1.type = n->type; 329 gmove(&n1, res); 330 regfree(&n1); 331 break; 332 333 case OLEN: 334 if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) { 335 // map has len in the first 32-bit word. 336 // a zero pointer means zero length 337 regalloc(&n1, types[tptr], res); 338 cgen(nl, &n1); 339 340 nodconst(&n2, types[tptr], 0); 341 gcmp(optoas(OCMP, types[tptr]), &n1, &n2); 342 p1 = gbranch(optoas(OEQ, types[tptr]), T, -1); 343 344 n2 = n1; 345 n2.op = OINDREG; 346 n2.type = types[TINT32]; 347 gmove(&n2, &n1); 348 349 patch(p1, pc); 350 351 gmove(&n1, res); 352 regfree(&n1); 353 break; 354 } 355 if(istype(nl->type, TSTRING) || isslice(nl->type)) { 356 // both slice and string have len one pointer into the struct. 357 igen(nl, &n1, res); 358 n1.type = types[TUINT32]; 359 n1.xoffset += Array_nel; 360 gmove(&n1, res); 361 regfree(&n1); 362 break; 363 } 364 fatal("cgen: OLEN: unknown type %lT", nl->type); 365 break; 366 367 case OCAP: 368 if(istype(nl->type, TCHAN)) { 369 // chan has cap in the second 32-bit word. 370 // a zero pointer means zero length 371 regalloc(&n1, types[tptr], res); 372 cgen(nl, &n1); 373 374 nodconst(&n2, types[tptr], 0); 375 gcmp(optoas(OCMP, types[tptr]), &n1, &n2); 376 p1 = gbranch(optoas(OEQ, types[tptr]), T, -1); 377 378 n2 = n1; 379 n2.op = OINDREG; 380 n2.xoffset = 4; 381 n2.type = types[TINT32]; 382 gmove(&n2, &n1); 383 384 patch(p1, pc); 385 386 gmove(&n1, res); 387 regfree(&n1); 388 break; 389 } 390 if(isslice(nl->type)) { 391 igen(nl, &n1, res); 392 n1.type = types[TUINT32]; 393 n1.xoffset += Array_cap; 394 gmove(&n1, res); 395 regfree(&n1); 396 break; 397 } 398 fatal("cgen: OCAP: unknown type %lT", nl->type); 399 break; 400 401 case OADDR: 402 agen(nl, res); 403 break; 404 405 case OCALLMETH: 406 case OCALLFUNC: 407 // Release res so that it is available for cgen_call. 408 // Pick it up again after the call. 409 rg = -1; 410 if(n->ullman >= UINF) { 411 if(res != N && (res->op == OREGISTER || res->op == OINDREG)) { 412 rg = res->val.u.reg; 413 reg[rg]--; 414 } 415 } 416 if(n->op == OCALLMETH) 417 cgen_callmeth(n, 0); 418 else 419 cgen_call(n, 0); 420 if(rg >= 0) 421 reg[rg]++; 422 cgen_callret(n, res); 423 break; 424 425 case OCALLINTER: 426 cgen_callinter(n, res, 0); 427 cgen_callret(n, res); 428 break; 429 430 case OMOD: 431 case ODIV: 432 a = optoas(n->op, nl->type); 433 goto abop; 434 } 435 goto ret; 436 437 sbop: // symmetric binary 438 if(nl->ullman < nr->ullman) { 439 r = nl; 440 nl = nr; 441 nr = r; 442 } 443 444 abop: // asymmetric binary 445 // TODO(kaib): use fewer registers here. 446 if(nl->ullman >= nr->ullman) { 447 regalloc(&n1, nl->type, res); 448 cgen(nl, &n1); 449 switch(n->op) { 450 case OADD: 451 case OSUB: 452 case OAND: 453 case OOR: 454 case OXOR: 455 if(smallintconst(nr)) { 456 n2 = *nr; 457 break; 458 } 459 default: 460 regalloc(&n2, nr->type, N); 461 cgen(nr, &n2); 462 } 463 } else { 464 switch(n->op) { 465 case OADD: 466 case OSUB: 467 case OAND: 468 case OOR: 469 case OXOR: 470 if(smallintconst(nr)) { 471 n2 = *nr; 472 break; 473 } 474 default: 475 regalloc(&n2, nr->type, res); 476 cgen(nr, &n2); 477 } 478 regalloc(&n1, nl->type, N); 479 cgen(nl, &n1); 480 } 481 gins(a, &n2, &n1); 482 norm: 483 // Normalize result for types smaller than word. 484 if(n->type->width < widthptr) { 485 switch(n->op) { 486 case OADD: 487 case OSUB: 488 case OMUL: 489 case OCOM: 490 case OMINUS: 491 gins(optoas(OAS, n->type), &n1, &n1); 492 break; 493 } 494 } 495 gmove(&n1, res); 496 regfree(&n1); 497 if(n2.op != OLITERAL) 498 regfree(&n2); 499 goto ret; 500 501 flt: // floating-point. 502 regalloc(&f0, nl->type, res); 503 if(nr != N) 504 goto flt2; 505 506 if(n->op == OMINUS) { 507 nr = nodintconst(-1); 508 convlit(&nr, n->type); 509 n->op = OMUL; 510 goto flt2; 511 } 512 513 // unary 514 cgen(nl, &f0); 515 if(n->op != OCONV && n->op != OPLUS) 516 gins(optoas(n->op, n->type), &f0, &f0); 517 gmove(&f0, res); 518 regfree(&f0); 519 goto ret; 520 521 flt2: // binary 522 if(nl->ullman >= nr->ullman) { 523 cgen(nl, &f0); 524 regalloc(&f1, n->type, N); 525 gmove(&f0, &f1); 526 cgen(nr, &f0); 527 gins(optoas(n->op, n->type), &f0, &f1); 528 } else { 529 cgen(nr, &f0); 530 regalloc(&f1, n->type, N); 531 cgen(nl, &f1); 532 gins(optoas(n->op, n->type), &f0, &f1); 533 } 534 gmove(&f1, res); 535 regfree(&f0); 536 regfree(&f1); 537 goto ret; 538 539 ret: 540 ; 541 } 542 543 /* 544 * generate array index into res. 545 * n might be any size; res is 32-bit. 546 * returns Prog* to patch to panic call. 547 */ 548 Prog* 549 cgenindex(Node *n, Node *res, int bounded) 550 { 551 Node tmp, lo, hi, zero, n1, n2; 552 553 if(!is64(n->type)) { 554 cgen(n, res); 555 return nil; 556 } 557 558 tempname(&tmp, types[TINT64]); 559 cgen(n, &tmp); 560 split64(&tmp, &lo, &hi); 561 gmove(&lo, res); 562 if(bounded) { 563 splitclean(); 564 return nil; 565 } 566 regalloc(&n1, types[TINT32], N); 567 regalloc(&n2, types[TINT32], N); 568 nodconst(&zero, types[TINT32], 0); 569 gmove(&hi, &n1); 570 gmove(&zero, &n2); 571 gcmp(ACMP, &n1, &n2); 572 regfree(&n2); 573 regfree(&n1); 574 splitclean(); 575 return gbranch(ABNE, T, -1); 576 } 577 578 /* 579 * generate: 580 * res = &n; 581 * The generated code checks that the result is not nil. 582 */ 583 void 584 agen(Node *n, Node *res) 585 { 586 Node *nl; 587 Node n1, n2, n3; 588 int r; 589 590 if(debug['g']) { 591 dump("\nagen-res", res); 592 dump("agen-r", n); 593 } 594 if(n == N || n->type == T || res == N || res->type == T) 595 fatal("agen"); 596 597 while(n->op == OCONVNOP) 598 n = n->left; 599 600 if(isconst(n, CTNIL) && n->type->width > widthptr) { 601 // Use of a nil interface or nil slice. 602 // Create a temporary we can take the address of and read. 603 // The generated code is just going to panic, so it need not 604 // be terribly efficient. See issue 3670. 605 tempname(&n1, n->type); 606 gvardef(&n1); 607 clearfat(&n1); 608 regalloc(&n2, types[tptr], res); 609 gins(AMOVW, &n1, &n2); 610 gmove(&n2, res); 611 regfree(&n2); 612 goto ret; 613 } 614 615 616 if(n->addable) { 617 memset(&n1, 0, sizeof n1); 618 n1.op = OADDR; 619 n1.left = n; 620 regalloc(&n2, types[tptr], res); 621 gins(AMOVW, &n1, &n2); 622 gmove(&n2, res); 623 regfree(&n2); 624 goto ret; 625 } 626 627 nl = n->left; 628 629 switch(n->op) { 630 default: 631 fatal("agen: unknown op %+hN", n); 632 break; 633 634 case OCALLMETH: 635 case OCALLFUNC: 636 // Release res so that it is available for cgen_call. 637 // Pick it up again after the call. 638 r = -1; 639 if(n->ullman >= UINF) { 640 if(res->op == OREGISTER || res->op == OINDREG) { 641 r = res->val.u.reg; 642 reg[r]--; 643 } 644 } 645 if(n->op == OCALLMETH) 646 cgen_callmeth(n, 0); 647 else 648 cgen_call(n, 0); 649 if(r >= 0) 650 reg[r]++; 651 cgen_aret(n, res); 652 break; 653 654 case OCALLINTER: 655 cgen_callinter(n, res, 0); 656 cgen_aret(n, res); 657 break; 658 659 case OSLICE: 660 case OSLICEARR: 661 case OSLICESTR: 662 case OSLICE3: 663 case OSLICE3ARR: 664 tempname(&n1, n->type); 665 cgen_slice(n, &n1); 666 agen(&n1, res); 667 break; 668 669 case OEFACE: 670 tempname(&n1, n->type); 671 cgen_eface(n, &n1); 672 agen(&n1, res); 673 break; 674 675 case OINDEX: 676 agenr(n, &n1, res); 677 gmove(&n1, res); 678 regfree(&n1); 679 break; 680 681 case ONAME: 682 // should only get here with names in this func. 683 if(n->funcdepth > 0 && n->funcdepth != funcdepth) { 684 dump("bad agen", n); 685 fatal("agen: bad ONAME funcdepth %d != %d", 686 n->funcdepth, funcdepth); 687 } 688 689 // should only get here for heap vars or paramref 690 if(!(n->class & PHEAP) && n->class != PPARAMREF) { 691 dump("bad agen", n); 692 fatal("agen: bad ONAME class %#x", n->class); 693 } 694 cgen(n->heapaddr, res); 695 if(n->xoffset != 0) { 696 nodconst(&n1, types[TINT32], n->xoffset); 697 regalloc(&n2, n1.type, N); 698 regalloc(&n3, types[TINT32], N); 699 gmove(&n1, &n2); 700 gmove(res, &n3); 701 gins(optoas(OADD, types[tptr]), &n2, &n3); 702 gmove(&n3, res); 703 regfree(&n2); 704 regfree(&n3); 705 } 706 break; 707 708 case OIND: 709 cgen(nl, res); 710 cgen_checknil(res); 711 break; 712 713 case ODOT: 714 agen(nl, res); 715 if(n->xoffset != 0) { 716 nodconst(&n1, types[TINT32], n->xoffset); 717 regalloc(&n2, n1.type, N); 718 regalloc(&n3, types[TINT32], N); 719 gmove(&n1, &n2); 720 gmove(res, &n3); 721 gins(optoas(OADD, types[tptr]), &n2, &n3); 722 gmove(&n3, res); 723 regfree(&n2); 724 regfree(&n3); 725 } 726 break; 727 728 case ODOTPTR: 729 cgen(nl, res); 730 cgen_checknil(res); 731 if(n->xoffset != 0) { 732 nodconst(&n1, types[TINT32], n->xoffset); 733 regalloc(&n2, n1.type, N); 734 regalloc(&n3, types[tptr], N); 735 gmove(&n1, &n2); 736 gmove(res, &n3); 737 gins(optoas(OADD, types[tptr]), &n2, &n3); 738 gmove(&n3, res); 739 regfree(&n2); 740 regfree(&n3); 741 } 742 break; 743 } 744 745 ret: 746 ; 747 } 748 749 /* 750 * generate: 751 * newreg = &n; 752 * res = newreg 753 * 754 * on exit, a has been changed to be *newreg. 755 * caller must regfree(a). 756 * The generated code checks that the result is not *nil. 757 */ 758 void 759 igen(Node *n, Node *a, Node *res) 760 { 761 Node n1; 762 int r; 763 764 if(debug['g']) { 765 dump("\nigen-n", n); 766 } 767 switch(n->op) { 768 case ONAME: 769 if((n->class&PHEAP) || n->class == PPARAMREF) 770 break; 771 *a = *n; 772 return; 773 774 case OINDREG: 775 // Increase the refcount of the register so that igen's caller 776 // has to call regfree. 777 if(n->val.u.reg != REGSP) 778 reg[n->val.u.reg]++; 779 *a = *n; 780 return; 781 782 case ODOT: 783 igen(n->left, a, res); 784 a->xoffset += n->xoffset; 785 a->type = n->type; 786 return; 787 788 case ODOTPTR: 789 if(n->left->addable 790 || n->left->op == OCALLFUNC 791 || n->left->op == OCALLMETH 792 || n->left->op == OCALLINTER) { 793 // igen-able nodes. 794 igen(n->left, &n1, res); 795 regalloc(a, types[tptr], &n1); 796 gmove(&n1, a); 797 regfree(&n1); 798 } else { 799 regalloc(a, types[tptr], res); 800 cgen(n->left, a); 801 } 802 cgen_checknil(a); 803 a->op = OINDREG; 804 a->xoffset = n->xoffset; 805 a->type = n->type; 806 return; 807 808 case OCALLMETH: 809 case OCALLFUNC: 810 case OCALLINTER: 811 // Release res so that it is available for cgen_call. 812 // Pick it up again after the call. 813 r = -1; 814 if(n->ullman >= UINF) { 815 if(res != N && (res->op == OREGISTER || res->op == OINDREG)) { 816 r = res->val.u.reg; 817 reg[r]--; 818 } 819 } 820 switch(n->op) { 821 case OCALLMETH: 822 cgen_callmeth(n, 0); 823 break; 824 case OCALLFUNC: 825 cgen_call(n, 0); 826 break; 827 case OCALLINTER: 828 cgen_callinter(n, N, 0); 829 break; 830 } 831 if(r >= 0) 832 reg[r]++; 833 regalloc(a, types[tptr], res); 834 cgen_aret(n, a); 835 a->op = OINDREG; 836 a->type = n->type; 837 return; 838 } 839 840 agenr(n, a, res); 841 a->op = OINDREG; 842 a->type = n->type; 843 } 844 845 /* 846 * allocate a register in res and generate 847 * newreg = &n 848 * The caller must call regfree(a). 849 */ 850 void 851 cgenr(Node *n, Node *a, Node *res) 852 { 853 Node n1; 854 855 if(debug['g']) 856 dump("cgenr-n", n); 857 858 if(isfat(n->type)) 859 fatal("cgenr on fat node"); 860 861 if(n->addable) { 862 regalloc(a, types[tptr], res); 863 gmove(n, a); 864 return; 865 } 866 867 switch(n->op) { 868 case ONAME: 869 case ODOT: 870 case ODOTPTR: 871 case OINDEX: 872 case OCALLFUNC: 873 case OCALLMETH: 874 case OCALLINTER: 875 igen(n, &n1, res); 876 regalloc(a, types[tptr], &n1); 877 gmove(&n1, a); 878 regfree(&n1); 879 break; 880 default: 881 regalloc(a, n->type, res); 882 cgen(n, a); 883 break; 884 } 885 } 886 887 /* 888 * generate: 889 * newreg = &n; 890 * 891 * caller must regfree(a). 892 * The generated code checks that the result is not nil. 893 */ 894 void 895 agenr(Node *n, Node *a, Node *res) 896 { 897 Node *nl, *nr; 898 Node n1, n2, n3, n4, tmp; 899 Prog *p1, *p2; 900 uint32 w; 901 uint64 v; 902 int bounded; 903 904 if(debug['g']) 905 dump("agenr-n", n); 906 907 nl = n->left; 908 nr = n->right; 909 910 switch(n->op) { 911 case ODOT: 912 case ODOTPTR: 913 case OCALLFUNC: 914 case OCALLMETH: 915 case OCALLINTER: 916 igen(n, &n1, res); 917 regalloc(a, types[tptr], &n1); 918 agen(&n1, a); 919 regfree(&n1); 920 break; 921 922 case OIND: 923 cgenr(n->left, a, res); 924 cgen_checknil(a); 925 break; 926 927 case OINDEX: 928 p2 = nil; // to be patched to panicindex. 929 w = n->type->width; 930 bounded = debug['B'] || n->bounded; 931 if(nr->addable) { 932 if(!isconst(nr, CTINT)) 933 tempname(&tmp, types[TINT32]); 934 if(!isconst(nl, CTSTR)) 935 agenr(nl, &n3, res); 936 if(!isconst(nr, CTINT)) { 937 p2 = cgenindex(nr, &tmp, bounded); 938 regalloc(&n1, tmp.type, N); 939 gmove(&tmp, &n1); 940 } 941 } else 942 if(nl->addable) { 943 if(!isconst(nr, CTINT)) { 944 tempname(&tmp, types[TINT32]); 945 p2 = cgenindex(nr, &tmp, bounded); 946 regalloc(&n1, tmp.type, N); 947 gmove(&tmp, &n1); 948 } 949 if(!isconst(nl, CTSTR)) { 950 agenr(nl, &n3, res); 951 } 952 } else { 953 tempname(&tmp, types[TINT32]); 954 p2 = cgenindex(nr, &tmp, bounded); 955 nr = &tmp; 956 if(!isconst(nl, CTSTR)) 957 agenr(nl, &n3, res); 958 regalloc(&n1, tmp.type, N); 959 gins(optoas(OAS, tmp.type), &tmp, &n1); 960 } 961 962 // &a is in &n3 (allocated in res) 963 // i is in &n1 (if not constant) 964 // w is width 965 966 // constant index 967 if(isconst(nr, CTINT)) { 968 if(isconst(nl, CTSTR)) 969 fatal("constant string constant index"); 970 v = mpgetfix(nr->val.u.xval); 971 if(isslice(nl->type) || nl->type->etype == TSTRING) { 972 if(!debug['B'] && !n->bounded) { 973 n1 = n3; 974 n1.op = OINDREG; 975 n1.type = types[tptr]; 976 n1.xoffset = Array_nel; 977 regalloc(&n4, n1.type, N); 978 gmove(&n1, &n4); 979 nodconst(&n2, types[TUINT32], v); 980 gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2); 981 regfree(&n4); 982 p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1); 983 ginscall(panicindex, 0); 984 patch(p1, pc); 985 } 986 987 n1 = n3; 988 n1.op = OINDREG; 989 n1.type = types[tptr]; 990 n1.xoffset = Array_array; 991 gmove(&n1, &n3); 992 } 993 994 nodconst(&n2, types[tptr], v*w); 995 gins(optoas(OADD, types[tptr]), &n2, &n3); 996 *a = n3; 997 break; 998 } 999 1000 regalloc(&n2, types[TINT32], &n1); // i 1001 gmove(&n1, &n2); 1002 regfree(&n1); 1003 1004 if(!debug['B'] && !n->bounded) { 1005 // check bounds 1006 if(isconst(nl, CTSTR)) { 1007 nodconst(&n4, types[TUINT32], nl->val.u.sval->len); 1008 } else if(isslice(nl->type) || nl->type->etype == TSTRING) { 1009 n1 = n3; 1010 n1.op = OINDREG; 1011 n1.type = types[tptr]; 1012 n1.xoffset = Array_nel; 1013 regalloc(&n4, types[TUINT32], N); 1014 gmove(&n1, &n4); 1015 } else { 1016 nodconst(&n4, types[TUINT32], nl->type->bound); 1017 } 1018 gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4); 1019 if(n4.op == OREGISTER) 1020 regfree(&n4); 1021 p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1); 1022 if(p2) 1023 patch(p2, pc); 1024 ginscall(panicindex, 0); 1025 patch(p1, pc); 1026 } 1027 1028 if(isconst(nl, CTSTR)) { 1029 regalloc(&n3, types[tptr], res); 1030 p1 = gins(AMOVW, N, &n3); 1031 datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); 1032 p1->from.type = D_CONST; 1033 } else 1034 if(isslice(nl->type) || nl->type->etype == TSTRING) { 1035 n1 = n3; 1036 n1.op = OINDREG; 1037 n1.type = types[tptr]; 1038 n1.xoffset = Array_array; 1039 gmove(&n1, &n3); 1040 } 1041 1042 if(w == 0) { 1043 // nothing to do 1044 } else if(w == 1 || w == 2 || w == 4 || w == 8) { 1045 memset(&n4, 0, sizeof n4); 1046 n4.op = OADDR; 1047 n4.left = &n2; 1048 cgen(&n4, &n3); 1049 if (w == 1) 1050 gins(AADD, &n2, &n3); 1051 else if(w == 2) 1052 gshift(AADD, &n2, SHIFT_LL, 1, &n3); 1053 else if(w == 4) 1054 gshift(AADD, &n2, SHIFT_LL, 2, &n3); 1055 else if(w == 8) 1056 gshift(AADD, &n2, SHIFT_LL, 3, &n3); 1057 } else { 1058 regalloc(&n4, types[TUINT32], N); 1059 nodconst(&n1, types[TUINT32], w); 1060 gmove(&n1, &n4); 1061 gins(optoas(OMUL, types[TUINT32]), &n4, &n2); 1062 gins(optoas(OADD, types[tptr]), &n2, &n3); 1063 regfree(&n4); 1064 } 1065 1066 *a = n3; 1067 regfree(&n2); 1068 break; 1069 1070 default: 1071 regalloc(a, types[tptr], res); 1072 agen(n, a); 1073 break; 1074 } 1075 } 1076 1077 void 1078 gencmp0(Node *n, Type *t, int o, int likely, Prog *to) 1079 { 1080 Node n1, n2, n3; 1081 int a; 1082 1083 regalloc(&n1, t, N); 1084 cgen(n, &n1); 1085 a = optoas(OCMP, t); 1086 if(a != ACMP) { 1087 nodconst(&n2, t, 0); 1088 regalloc(&n3, t, N); 1089 gmove(&n2, &n3); 1090 gcmp(a, &n1, &n3); 1091 regfree(&n3); 1092 } else 1093 gins(ATST, &n1, N); 1094 a = optoas(o, t); 1095 patch(gbranch(a, t, likely), to); 1096 regfree(&n1); 1097 } 1098 1099 /* 1100 * generate: 1101 * if(n == true) goto to; 1102 */ 1103 void 1104 bgen(Node *n, int true, int likely, Prog *to) 1105 { 1106 int et, a; 1107 Node *nl, *nr, *r; 1108 Node n1, n2, n3, tmp; 1109 NodeList *ll; 1110 Prog *p1, *p2; 1111 1112 if(debug['g']) { 1113 dump("\nbgen", n); 1114 } 1115 1116 if(n == N) 1117 n = nodbool(1); 1118 1119 if(n->ninit != nil) 1120 genlist(n->ninit); 1121 1122 if(n->type == T) { 1123 convlit(&n, types[TBOOL]); 1124 if(n->type == T) 1125 goto ret; 1126 } 1127 1128 et = n->type->etype; 1129 if(et != TBOOL) { 1130 yyerror("cgen: bad type %T for %O", n->type, n->op); 1131 patch(gins(AEND, N, N), to); 1132 goto ret; 1133 } 1134 nr = N; 1135 1136 switch(n->op) { 1137 default: 1138 a = ONE; 1139 if(!true) 1140 a = OEQ; 1141 gencmp0(n, n->type, a, likely, to); 1142 goto ret; 1143 1144 case OLITERAL: 1145 // need to ask if it is bool? 1146 if(!true == !n->val.u.bval) 1147 patch(gbranch(AB, T, 0), to); 1148 goto ret; 1149 1150 case OANDAND: 1151 if(!true) 1152 goto caseor; 1153 1154 caseand: 1155 p1 = gbranch(AB, T, 0); 1156 p2 = gbranch(AB, T, 0); 1157 patch(p1, pc); 1158 bgen(n->left, !true, -likely, p2); 1159 bgen(n->right, !true, -likely, p2); 1160 p1 = gbranch(AB, T, 0); 1161 patch(p1, to); 1162 patch(p2, pc); 1163 goto ret; 1164 1165 case OOROR: 1166 if(!true) 1167 goto caseand; 1168 1169 caseor: 1170 bgen(n->left, true, likely, to); 1171 bgen(n->right, true, likely, to); 1172 goto ret; 1173 1174 case OEQ: 1175 case ONE: 1176 case OLT: 1177 case OGT: 1178 case OLE: 1179 case OGE: 1180 nr = n->right; 1181 if(nr == N || nr->type == T) 1182 goto ret; 1183 1184 case ONOT: // unary 1185 nl = n->left; 1186 if(nl == N || nl->type == T) 1187 goto ret; 1188 } 1189 1190 switch(n->op) { 1191 1192 case ONOT: 1193 bgen(nl, !true, likely, to); 1194 goto ret; 1195 1196 case OEQ: 1197 case ONE: 1198 case OLT: 1199 case OGT: 1200 case OLE: 1201 case OGE: 1202 a = n->op; 1203 if(!true) { 1204 if(isfloat[nl->type->etype]) { 1205 // brcom is not valid on floats when NaN is involved. 1206 p1 = gbranch(AB, T, 0); 1207 p2 = gbranch(AB, T, 0); 1208 patch(p1, pc); 1209 ll = n->ninit; 1210 n->ninit = nil; 1211 bgen(n, 1, -likely, p2); 1212 n->ninit = ll; 1213 patch(gbranch(AB, T, 0), to); 1214 patch(p2, pc); 1215 goto ret; 1216 } 1217 a = brcom(a); 1218 true = !true; 1219 } 1220 1221 // make simplest on right 1222 if(nl->op == OLITERAL || (nl->ullman < UINF && nl->ullman < nr->ullman)) { 1223 a = brrev(a); 1224 r = nl; 1225 nl = nr; 1226 nr = r; 1227 } 1228 1229 if(isslice(nl->type)) { 1230 // only valid to cmp darray to literal nil 1231 if((a != OEQ && a != ONE) || nr->op != OLITERAL) { 1232 yyerror("illegal array comparison"); 1233 break; 1234 } 1235 1236 igen(nl, &n1, N); 1237 n1.xoffset += Array_array; 1238 n1.type = types[tptr]; 1239 gencmp0(&n1, types[tptr], a, likely, to); 1240 regfree(&n1); 1241 break; 1242 } 1243 1244 if(isinter(nl->type)) { 1245 // front end shold only leave cmp to literal nil 1246 if((a != OEQ && a != ONE) || nr->op != OLITERAL) { 1247 yyerror("illegal interface comparison"); 1248 break; 1249 } 1250 1251 igen(nl, &n1, N); 1252 n1.type = types[tptr]; 1253 n1.xoffset += 0; 1254 gencmp0(&n1, types[tptr], a, likely, to); 1255 regfree(&n1); 1256 break; 1257 } 1258 1259 if(iscomplex[nl->type->etype]) { 1260 complexbool(a, nl, nr, true, likely, to); 1261 break; 1262 } 1263 1264 if(is64(nr->type)) { 1265 if(!nl->addable) { 1266 tempname(&n1, nl->type); 1267 cgen(nl, &n1); 1268 nl = &n1; 1269 } 1270 if(!nr->addable) { 1271 tempname(&n2, nr->type); 1272 cgen(nr, &n2); 1273 nr = &n2; 1274 } 1275 cmp64(nl, nr, a, likely, to); 1276 break; 1277 } 1278 1279 if(nr->op == OLITERAL) { 1280 if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) == 0) { 1281 gencmp0(nl, nl->type, a, likely, to); 1282 break; 1283 } 1284 if(nr->val.ctype == CTNIL) { 1285 gencmp0(nl, nl->type, a, likely, to); 1286 break; 1287 } 1288 } 1289 1290 a = optoas(a, nr->type); 1291 1292 if(nr->ullman >= UINF) { 1293 regalloc(&n1, nl->type, N); 1294 cgen(nl, &n1); 1295 1296 tempname(&tmp, nl->type); 1297 gmove(&n1, &tmp); 1298 regfree(&n1); 1299 1300 regalloc(&n2, nr->type, N); 1301 cgen(nr, &n2); 1302 1303 regalloc(&n1, nl->type, N); 1304 cgen(&tmp, &n1); 1305 1306 gcmp(optoas(OCMP, nr->type), &n1, &n2); 1307 patch(gbranch(a, nr->type, likely), to); 1308 1309 regfree(&n1); 1310 regfree(&n2); 1311 break; 1312 } 1313 1314 tempname(&n3, nl->type); 1315 cgen(nl, &n3); 1316 1317 tempname(&tmp, nr->type); 1318 cgen(nr, &tmp); 1319 1320 regalloc(&n1, nl->type, N); 1321 gmove(&n3, &n1); 1322 1323 regalloc(&n2, nr->type, N); 1324 gmove(&tmp, &n2); 1325 1326 gcmp(optoas(OCMP, nr->type), &n1, &n2); 1327 if(isfloat[nl->type->etype]) { 1328 if(n->op == ONE) { 1329 p1 = gbranch(ABVS, nr->type, likely); 1330 patch(gbranch(a, nr->type, likely), to); 1331 patch(p1, to); 1332 } else { 1333 p1 = gbranch(ABVS, nr->type, -likely); 1334 patch(gbranch(a, nr->type, likely), to); 1335 patch(p1, pc); 1336 } 1337 } else { 1338 patch(gbranch(a, nr->type, likely), to); 1339 } 1340 regfree(&n1); 1341 regfree(&n2); 1342 break; 1343 } 1344 goto ret; 1345 1346 ret: 1347 ; 1348 } 1349 1350 /* 1351 * n is on stack, either local variable 1352 * or return value from function call. 1353 * return n's offset from SP. 1354 */ 1355 int32 1356 stkof(Node *n) 1357 { 1358 Type *t; 1359 Iter flist; 1360 int32 off; 1361 1362 switch(n->op) { 1363 case OINDREG: 1364 return n->xoffset; 1365 1366 case ODOT: 1367 t = n->left->type; 1368 if(isptr[t->etype]) 1369 break; 1370 off = stkof(n->left); 1371 if(off == -1000 || off == 1000) 1372 return off; 1373 return off + n->xoffset; 1374 1375 case OINDEX: 1376 t = n->left->type; 1377 if(!isfixedarray(t)) 1378 break; 1379 off = stkof(n->left); 1380 if(off == -1000 || off == 1000) 1381 return off; 1382 if(isconst(n->right, CTINT)) 1383 return off + t->type->width * mpgetfix(n->right->val.u.xval); 1384 return 1000; 1385 1386 case OCALLMETH: 1387 case OCALLINTER: 1388 case OCALLFUNC: 1389 t = n->left->type; 1390 if(isptr[t->etype]) 1391 t = t->type; 1392 1393 t = structfirst(&flist, getoutarg(t)); 1394 if(t != T) 1395 return t->width + 4; // correct for LR 1396 break; 1397 } 1398 1399 // botch - probably failing to recognize address 1400 // arithmetic on the above. eg INDEX and DOT 1401 return -1000; 1402 } 1403 1404 /* 1405 * block copy: 1406 * memmove(&res, &n, w); 1407 * NB: character copy assumed little endian architecture 1408 */ 1409 void 1410 sgen(Node *n, Node *res, int64 w) 1411 { 1412 Node dst, src, tmp, nend, r0, r1, r2, *f; 1413 int32 c, odst, osrc; 1414 int dir, align, op; 1415 Prog *p, *ploop; 1416 NodeList *l; 1417 1418 if(debug['g']) { 1419 print("\nsgen w=%lld\n", w); 1420 dump("r", n); 1421 dump("res", res); 1422 } 1423 1424 if(n->ullman >= UINF && res->ullman >= UINF) 1425 fatal("sgen UINF"); 1426 1427 if(w < 0 || (int32)w != w) 1428 fatal("sgen copy %lld", w); 1429 1430 if(n->type == T) 1431 fatal("sgen: missing type"); 1432 1433 if(w == 0) { 1434 // evaluate side effects only. 1435 regalloc(&dst, types[tptr], N); 1436 agen(res, &dst); 1437 agen(n, &dst); 1438 regfree(&dst); 1439 return; 1440 } 1441 1442 // If copying .args, that's all the results, so record definition sites 1443 // for them for the liveness analysis. 1444 if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0) 1445 for(l = curfn->dcl; l != nil; l = l->next) 1446 if(l->n->class == PPARAMOUT) 1447 gvardef(l->n); 1448 1449 // Avoid taking the address for simple enough types. 1450 if(componentgen(n, res)) 1451 return; 1452 1453 // determine alignment. 1454 // want to avoid unaligned access, so have to use 1455 // smaller operations for less aligned types. 1456 // for example moving [4]byte must use 4 MOVB not 1 MOVW. 1457 align = n->type->align; 1458 switch(align) { 1459 default: 1460 fatal("sgen: invalid alignment %d for %T", align, n->type); 1461 case 1: 1462 op = AMOVB; 1463 break; 1464 case 2: 1465 op = AMOVH; 1466 break; 1467 case 4: 1468 op = AMOVW; 1469 break; 1470 } 1471 if(w%align) 1472 fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type); 1473 c = w / align; 1474 1475 // offset on the stack 1476 osrc = stkof(n); 1477 odst = stkof(res); 1478 if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { 1479 // osrc and odst both on stack, and at least one is in 1480 // an unknown position. Could generate code to test 1481 // for forward/backward copy, but instead just copy 1482 // to a temporary location first. 1483 tempname(&tmp, n->type); 1484 sgen(n, &tmp, w); 1485 sgen(&tmp, res, w); 1486 return; 1487 } 1488 if(osrc%align != 0 || odst%align != 0) 1489 fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align); 1490 1491 // if we are copying forward on the stack and 1492 // the src and dst overlap, then reverse direction 1493 dir = align; 1494 if(osrc < odst && odst < osrc+w) 1495 dir = -dir; 1496 1497 if(op == AMOVW && !nacl && dir > 0 && c >= 4 && c <= 128) { 1498 r0.op = OREGISTER; 1499 r0.val.u.reg = REGALLOC_R0; 1500 r1.op = OREGISTER; 1501 r1.val.u.reg = REGALLOC_R0 + 1; 1502 r2.op = OREGISTER; 1503 r2.val.u.reg = REGALLOC_R0 + 2; 1504 1505 regalloc(&src, types[tptr], &r1); 1506 regalloc(&dst, types[tptr], &r2); 1507 if(n->ullman >= res->ullman) { 1508 // eval n first 1509 agen(n, &src); 1510 if(res->op == ONAME) 1511 gvardef(res); 1512 agen(res, &dst); 1513 } else { 1514 // eval res first 1515 if(res->op == ONAME) 1516 gvardef(res); 1517 agen(res, &dst); 1518 agen(n, &src); 1519 } 1520 regalloc(&tmp, types[tptr], &r0); 1521 f = sysfunc("duffcopy"); 1522 p = gins(ADUFFCOPY, N, f); 1523 afunclit(&p->to, f); 1524 // 8 and 128 = magic constants: see ../../runtime/asm_arm.s 1525 p->to.offset = 8*(128-c); 1526 1527 regfree(&tmp); 1528 regfree(&src); 1529 regfree(&dst); 1530 return; 1531 } 1532 1533 if(n->ullman >= res->ullman) { 1534 agenr(n, &dst, res); // temporarily use dst 1535 regalloc(&src, types[tptr], N); 1536 gins(AMOVW, &dst, &src); 1537 if(res->op == ONAME) 1538 gvardef(res); 1539 agen(res, &dst); 1540 } else { 1541 if(res->op == ONAME) 1542 gvardef(res); 1543 agenr(res, &dst, res); 1544 agenr(n, &src, N); 1545 } 1546 1547 regalloc(&tmp, types[TUINT32], N); 1548 1549 // set up end marker 1550 memset(&nend, 0, sizeof nend); 1551 if(c >= 4) { 1552 regalloc(&nend, types[TUINT32], N); 1553 1554 p = gins(AMOVW, &src, &nend); 1555 p->from.type = D_CONST; 1556 if(dir < 0) 1557 p->from.offset = dir; 1558 else 1559 p->from.offset = w; 1560 } 1561 1562 // move src and dest to the end of block if necessary 1563 if(dir < 0) { 1564 p = gins(AMOVW, &src, &src); 1565 p->from.type = D_CONST; 1566 p->from.offset = w + dir; 1567 1568 p = gins(AMOVW, &dst, &dst); 1569 p->from.type = D_CONST; 1570 p->from.offset = w + dir; 1571 } 1572 1573 // move 1574 if(c >= 4) { 1575 p = gins(op, &src, &tmp); 1576 p->from.type = D_OREG; 1577 p->from.offset = dir; 1578 p->scond |= C_PBIT; 1579 ploop = p; 1580 1581 p = gins(op, &tmp, &dst); 1582 p->to.type = D_OREG; 1583 p->to.offset = dir; 1584 p->scond |= C_PBIT; 1585 1586 p = gins(ACMP, &src, N); 1587 raddr(&nend, p); 1588 1589 patch(gbranch(ABNE, T, 0), ploop); 1590 regfree(&nend); 1591 } else { 1592 while(c-- > 0) { 1593 p = gins(op, &src, &tmp); 1594 p->from.type = D_OREG; 1595 p->from.offset = dir; 1596 p->scond |= C_PBIT; 1597 1598 p = gins(op, &tmp, &dst); 1599 p->to.type = D_OREG; 1600 p->to.offset = dir; 1601 p->scond |= C_PBIT; 1602 } 1603 } 1604 1605 regfree(&dst); 1606 regfree(&src); 1607 regfree(&tmp); 1608 } 1609 1610 static int 1611 cadable(Node *n) 1612 { 1613 if(!n->addable) { 1614 // dont know how it happens, 1615 // but it does 1616 return 0; 1617 } 1618 1619 switch(n->op) { 1620 case ONAME: 1621 return 1; 1622 } 1623 return 0; 1624 } 1625 1626 /* 1627 * copy a composite value by moving its individual components. 1628 * Slices, strings and interfaces are supported. 1629 * nr is N when assigning a zero value. 1630 * return 1 if can do, 0 if cant. 1631 */ 1632 int 1633 componentgen(Node *nr, Node *nl) 1634 { 1635 Node nodl, nodr, tmp; 1636 Type *t; 1637 int freel, freer; 1638 vlong fldcount; 1639 vlong loffset, roffset; 1640 1641 freel = 0; 1642 freer = 0; 1643 1644 switch(nl->type->etype) { 1645 default: 1646 goto no; 1647 1648 case TARRAY: 1649 t = nl->type; 1650 1651 // Slices are ok. 1652 if(isslice(t)) 1653 break; 1654 // Small arrays are ok. 1655 if(t->bound > 0 && t->bound <= 3 && !isfat(t->type)) 1656 break; 1657 1658 goto no; 1659 1660 case TSTRUCT: 1661 // Small structs with non-fat types are ok. 1662 // Zero-sized structs are treated separately elsewhere. 1663 fldcount = 0; 1664 for(t=nl->type->type; t; t=t->down) { 1665 if(isfat(t->type)) 1666 goto no; 1667 if(t->etype != TFIELD) 1668 fatal("componentgen: not a TFIELD: %lT", t); 1669 fldcount++; 1670 } 1671 if(fldcount == 0 || fldcount > 4) 1672 goto no; 1673 1674 break; 1675 1676 case TSTRING: 1677 case TINTER: 1678 break; 1679 } 1680 1681 nodl = *nl; 1682 if(!cadable(nl)) { 1683 if(nr == N || !cadable(nr)) 1684 goto no; 1685 igen(nl, &nodl, N); 1686 freel = 1; 1687 } 1688 1689 if(nr != N) { 1690 nodr = *nr; 1691 if(!cadable(nr)) { 1692 igen(nr, &nodr, N); 1693 freer = 1; 1694 } 1695 } else { 1696 // When zeroing, prepare a register containing zero. 1697 nodconst(&tmp, nl->type, 0); 1698 regalloc(&nodr, types[TUINT], N); 1699 gmove(&tmp, &nodr); 1700 freer = 1; 1701 } 1702 1703 1704 // nl and nr are 'cadable' which basically means they are names (variables) now. 1705 // If they are the same variable, don't generate any code, because the 1706 // VARDEF we generate will mark the old value as dead incorrectly. 1707 // (And also the assignments are useless.) 1708 if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) 1709 goto yes; 1710 1711 switch(nl->type->etype) { 1712 case TARRAY: 1713 // componentgen for arrays. 1714 if(nl->op == ONAME) 1715 gvardef(nl); 1716 t = nl->type; 1717 if(!isslice(t)) { 1718 nodl.type = t->type; 1719 nodr.type = nodl.type; 1720 for(fldcount=0; fldcount < t->bound; fldcount++) { 1721 if(nr == N) 1722 clearslim(&nodl); 1723 else 1724 gmove(&nodr, &nodl); 1725 nodl.xoffset += t->type->width; 1726 nodr.xoffset += t->type->width; 1727 } 1728 goto yes; 1729 } 1730 1731 // componentgen for slices. 1732 nodl.xoffset += Array_array; 1733 nodl.type = ptrto(nl->type->type); 1734 1735 if(nr != N) { 1736 nodr.xoffset += Array_array; 1737 nodr.type = nodl.type; 1738 } 1739 gmove(&nodr, &nodl); 1740 1741 nodl.xoffset += Array_nel-Array_array; 1742 nodl.type = types[simtype[TUINT]]; 1743 1744 if(nr != N) { 1745 nodr.xoffset += Array_nel-Array_array; 1746 nodr.type = nodl.type; 1747 } 1748 gmove(&nodr, &nodl); 1749 1750 nodl.xoffset += Array_cap-Array_nel; 1751 nodl.type = types[simtype[TUINT]]; 1752 1753 if(nr != N) { 1754 nodr.xoffset += Array_cap-Array_nel; 1755 nodr.type = nodl.type; 1756 } 1757 gmove(&nodr, &nodl); 1758 1759 goto yes; 1760 1761 case TSTRING: 1762 if(nl->op == ONAME) 1763 gvardef(nl); 1764 nodl.xoffset += Array_array; 1765 nodl.type = ptrto(types[TUINT8]); 1766 1767 if(nr != N) { 1768 nodr.xoffset += Array_array; 1769 nodr.type = nodl.type; 1770 } 1771 gmove(&nodr, &nodl); 1772 1773 nodl.xoffset += Array_nel-Array_array; 1774 nodl.type = types[simtype[TUINT]]; 1775 1776 if(nr != N) { 1777 nodr.xoffset += Array_nel-Array_array; 1778 nodr.type = nodl.type; 1779 } 1780 gmove(&nodr, &nodl); 1781 1782 goto yes; 1783 1784 case TINTER: 1785 if(nl->op == ONAME) 1786 gvardef(nl); 1787 nodl.xoffset += Array_array; 1788 nodl.type = ptrto(types[TUINT8]); 1789 1790 if(nr != N) { 1791 nodr.xoffset += Array_array; 1792 nodr.type = nodl.type; 1793 } 1794 gmove(&nodr, &nodl); 1795 1796 nodl.xoffset += Array_nel-Array_array; 1797 nodl.type = ptrto(types[TUINT8]); 1798 1799 if(nr != N) { 1800 nodr.xoffset += Array_nel-Array_array; 1801 nodr.type = nodl.type; 1802 } 1803 gmove(&nodr, &nodl); 1804 1805 goto yes; 1806 1807 case TSTRUCT: 1808 if(nl->op == ONAME) 1809 gvardef(nl); 1810 loffset = nodl.xoffset; 1811 roffset = nodr.xoffset; 1812 // funarg structs may not begin at offset zero. 1813 if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type) 1814 loffset -= nl->type->type->width; 1815 if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type) 1816 roffset -= nr->type->type->width; 1817 1818 for(t=nl->type->type; t; t=t->down) { 1819 nodl.xoffset = loffset + t->width; 1820 nodl.type = t->type; 1821 1822 if(nr == N) 1823 clearslim(&nodl); 1824 else { 1825 nodr.xoffset = roffset + t->width; 1826 nodr.type = nodl.type; 1827 gmove(&nodr, &nodl); 1828 } 1829 } 1830 goto yes; 1831 } 1832 1833 no: 1834 if(freer) 1835 regfree(&nodr); 1836 if(freel) 1837 regfree(&nodl); 1838 return 0; 1839 1840 yes: 1841 if(freer) 1842 regfree(&nodr); 1843 if(freel) 1844 regfree(&nodl); 1845 return 1; 1846 }