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