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