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