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