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