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