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