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