github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/8g/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 // TODO(rsc): 6 // assume CLD? 7 8 #include <u.h> 9 #include <libc.h> 10 #include "gg.h" 11 12 void 13 mgen(Node *n, Node *n1, Node *rg) 14 { 15 Node n2; 16 17 n1->op = OEMPTY; 18 19 if(n->addable) { 20 *n1 = *n; 21 if(n1->op == OREGISTER || n1->op == OINDREG) 22 reg[n->val.u.reg]++; 23 return; 24 } 25 tempname(n1, n->type); 26 cgen(n, n1); 27 if(n->type->width <= widthptr || isfloat[n->type->etype]) { 28 n2 = *n1; 29 regalloc(n1, n->type, rg); 30 gmove(&n2, n1); 31 } 32 } 33 34 void 35 mfree(Node *n) 36 { 37 if(n->op == OREGISTER) 38 regfree(n); 39 } 40 41 /* 42 * generate: 43 * res = n; 44 * simplifies and calls gmove. 45 * 46 * TODO: 47 * sudoaddable 48 */ 49 void 50 cgen(Node *n, Node *res) 51 { 52 Node *nl, *nr, *r, n1, n2, nt; 53 Prog *p1, *p2, *p3; 54 int a; 55 56 if(debug['g']) { 57 dump("\ncgen-n", n); 58 dump("cgen-res", res); 59 } 60 61 if(n == N || n->type == T) 62 fatal("cgen: n nil"); 63 if(res == N || res->type == T) 64 fatal("cgen: res nil"); 65 66 switch(n->op) { 67 case OSLICE: 68 case OSLICEARR: 69 case OSLICESTR: 70 if (res->op != ONAME || !res->addable) { 71 tempname(&n1, n->type); 72 cgen_slice(n, &n1); 73 cgen(&n1, res); 74 } else 75 cgen_slice(n, res); 76 return; 77 case OEFACE: 78 if (res->op != ONAME || !res->addable) { 79 tempname(&n1, n->type); 80 cgen_eface(n, &n1); 81 cgen(&n1, res); 82 } else 83 cgen_eface(n, res); 84 return; 85 } 86 87 while(n->op == OCONVNOP) 88 n = n->left; 89 90 // function calls on both sides? introduce temporary 91 if(n->ullman >= UINF && res->ullman >= UINF) { 92 tempname(&n1, n->type); 93 cgen(n, &n1); 94 cgen(&n1, res); 95 return; 96 } 97 98 // structs etc get handled specially 99 if(isfat(n->type)) { 100 if(n->type->width < 0) 101 fatal("forgot to compute width for %T", n->type); 102 sgen(n, res, n->type->width); 103 return; 104 } 105 106 // update addressability for string, slice 107 // can't do in walk because n->left->addable 108 // changes if n->left is an escaping local variable. 109 switch(n->op) { 110 case OLEN: 111 if(isslice(n->left->type) || istype(n->left->type, TSTRING)) 112 n->addable = n->left->addable; 113 break; 114 case OCAP: 115 if(isslice(n->left->type)) 116 n->addable = n->left->addable; 117 break; 118 case OITAB: 119 n->addable = n->left->addable; 120 break; 121 } 122 123 // if both are addressable, move 124 if(n->addable && res->addable) { 125 gmove(n, res); 126 return; 127 } 128 129 // if both are not addressable, use a temporary. 130 if(!n->addable && !res->addable) { 131 // could use regalloc here sometimes, 132 // but have to check for ullman >= UINF. 133 tempname(&n1, n->type); 134 cgen(n, &n1); 135 cgen(&n1, res); 136 return; 137 } 138 139 // if result is not addressable directly but n is, 140 // compute its address and then store via the address. 141 if(!res->addable) { 142 igen(res, &n1, N); 143 cgen(n, &n1); 144 regfree(&n1); 145 return; 146 } 147 148 // complex types 149 if(complexop(n, res)) { 150 complexgen(n, res); 151 return; 152 } 153 154 // otherwise, the result is addressable but n is not. 155 // let's do some computation. 156 157 // use ullman to pick operand to eval first. 158 nl = n->left; 159 nr = n->right; 160 if(nl != N && nl->ullman >= UINF) 161 if(nr != N && nr->ullman >= UINF) { 162 // both are hard 163 tempname(&n1, nl->type); 164 cgen(nl, &n1); 165 n2 = *n; 166 n2.left = &n1; 167 cgen(&n2, res); 168 return; 169 } 170 171 // 64-bit ops are hard on 32-bit machine. 172 if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) { 173 switch(n->op) { 174 // math goes to cgen64. 175 case OMINUS: 176 case OCOM: 177 case OADD: 178 case OSUB: 179 case OMUL: 180 case OLROT: 181 case OLSH: 182 case ORSH: 183 case OAND: 184 case OOR: 185 case OXOR: 186 cgen64(n, res); 187 return; 188 } 189 } 190 191 if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) { 192 cgen_float(n, res); 193 return; 194 } 195 196 switch(n->op) { 197 default: 198 dump("cgen", n); 199 fatal("cgen %O", n->op); 200 break; 201 202 case OREAL: 203 case OIMAG: 204 case OCOMPLEX: 205 fatal("unexpected complex"); 206 return; 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(AJMP, T, 0); 219 p2 = pc; 220 gmove(nodbool(1), res); 221 p3 = gbranch(AJMP, T, 0); 222 patch(p1, pc); 223 bgen(n, 1, 0, p2); 224 gmove(nodbool(0), res); 225 patch(p3, pc); 226 return; 227 228 case OPLUS: 229 cgen(nl, res); 230 return; 231 232 case OMINUS: 233 case OCOM: 234 a = optoas(n->op, nl->type); 235 goto uop; 236 237 // symmetric binary 238 case OAND: 239 case OOR: 240 case OXOR: 241 case OADD: 242 case OMUL: 243 a = optoas(n->op, nl->type); 244 if(a == AIMULB) { 245 cgen_bmul(n->op, nl, nr, res); 246 break; 247 } 248 goto sbop; 249 250 // asymmetric binary 251 case OSUB: 252 a = optoas(n->op, nl->type); 253 goto abop; 254 255 case OHMUL: 256 cgen_hmul(nl, nr, res); 257 break; 258 259 case OCONV: 260 if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) { 261 cgen(nl, res); 262 break; 263 } 264 265 tempname(&n2, n->type); 266 mgen(nl, &n1, res); 267 gmove(&n1, &n2); 268 gmove(&n2, res); 269 mfree(&n1); 270 break; 271 272 case ODOT: 273 case ODOTPTR: 274 case OINDEX: 275 case OIND: 276 case ONAME: // PHEAP or PPARAMREF var 277 igen(n, &n1, res); 278 gmove(&n1, res); 279 regfree(&n1); 280 break; 281 282 case OITAB: 283 igen(nl, &n1, res); 284 n1.type = ptrto(types[TUINTPTR]); 285 gmove(&n1, res); 286 regfree(&n1); 287 break; 288 289 case OLEN: 290 if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) { 291 // map has len in the first 32-bit word. 292 // a zero pointer means zero length 293 tempname(&n1, types[tptr]); 294 cgen(nl, &n1); 295 regalloc(&n2, types[tptr], N); 296 gmove(&n1, &n2); 297 n1 = n2; 298 299 nodconst(&n2, types[tptr], 0); 300 gins(optoas(OCMP, types[tptr]), &n1, &n2); 301 p1 = gbranch(optoas(OEQ, types[tptr]), T, -1); 302 303 n2 = n1; 304 n2.op = OINDREG; 305 n2.type = types[TINT32]; 306 gmove(&n2, &n1); 307 308 patch(p1, pc); 309 310 gmove(&n1, res); 311 regfree(&n1); 312 break; 313 } 314 if(istype(nl->type, TSTRING) || isslice(nl->type)) { 315 // both slice and string have len one pointer into the struct. 316 igen(nl, &n1, res); 317 n1.type = types[TUINT32]; 318 n1.xoffset += Array_nel; 319 gmove(&n1, res); 320 regfree(&n1); 321 break; 322 } 323 fatal("cgen: OLEN: unknown type %lT", nl->type); 324 break; 325 326 case OCAP: 327 if(istype(nl->type, TCHAN)) { 328 // chan has cap in the second 32-bit word. 329 // a zero pointer means zero length 330 regalloc(&n1, types[tptr], res); 331 cgen(nl, &n1); 332 333 nodconst(&n2, types[tptr], 0); 334 gins(optoas(OCMP, types[tptr]), &n1, &n2); 335 p1 = gbranch(optoas(OEQ, types[tptr]), T, -1); 336 337 n2 = n1; 338 n2.op = OINDREG; 339 n2.xoffset = 4; 340 n2.type = types[TINT32]; 341 gmove(&n2, &n1); 342 343 patch(p1, pc); 344 345 gmove(&n1, res); 346 regfree(&n1); 347 break; 348 } 349 if(isslice(nl->type)) { 350 igen(nl, &n1, res); 351 n1.type = types[TUINT32]; 352 n1.xoffset += Array_cap; 353 gmove(&n1, res); 354 regfree(&n1); 355 break; 356 } 357 fatal("cgen: OCAP: unknown type %lT", nl->type); 358 break; 359 360 case OADDR: 361 agen(nl, res); 362 break; 363 364 case OCALLMETH: 365 cgen_callmeth(n, 0); 366 cgen_callret(n, res); 367 break; 368 369 case OCALLINTER: 370 cgen_callinter(n, res, 0); 371 cgen_callret(n, res); 372 break; 373 374 case OCALLFUNC: 375 cgen_call(n, 0); 376 cgen_callret(n, res); 377 break; 378 379 case OMOD: 380 case ODIV: 381 cgen_div(n->op, nl, nr, res); 382 break; 383 384 case OLSH: 385 case ORSH: 386 case OLROT: 387 cgen_shift(n->op, n->bounded, nl, nr, res); 388 break; 389 } 390 return; 391 392 sbop: // symmetric binary 393 if(nl->ullman < nr->ullman || nl->op == OLITERAL) { 394 r = nl; 395 nl = nr; 396 nr = r; 397 } 398 399 abop: // asymmetric binary 400 if(smallintconst(nr)) { 401 mgen(nl, &n1, res); 402 regalloc(&n2, nl->type, &n1); 403 gmove(&n1, &n2); 404 gins(a, nr, &n2); 405 gmove(&n2, res); 406 regfree(&n2); 407 mfree(&n1); 408 } else if(nl->ullman >= nr->ullman) { 409 tempname(&nt, nl->type); 410 cgen(nl, &nt); 411 mgen(nr, &n2, N); 412 regalloc(&n1, nl->type, res); 413 gmove(&nt, &n1); 414 gins(a, &n2, &n1); 415 gmove(&n1, res); 416 regfree(&n1); 417 mfree(&n2); 418 } else { 419 regalloc(&n2, nr->type, res); 420 cgen(nr, &n2); 421 regalloc(&n1, nl->type, N); 422 cgen(nl, &n1); 423 gins(a, &n2, &n1); 424 regfree(&n2); 425 gmove(&n1, res); 426 regfree(&n1); 427 } 428 return; 429 430 uop: // unary 431 tempname(&n1, nl->type); 432 cgen(nl, &n1); 433 gins(a, N, &n1); 434 gmove(&n1, res); 435 return; 436 } 437 438 /* 439 * generate an addressable node in res, containing the value of n. 440 * n is an array index, and might be any size; res width is <= 32-bit. 441 * returns Prog* to patch to panic call. 442 */ 443 static Prog* 444 igenindex(Node *n, Node *res, int bounded) 445 { 446 Node tmp, lo, hi, zero; 447 448 if(!is64(n->type)) { 449 if(n->addable) { 450 // nothing to do. 451 *res = *n; 452 } else { 453 tempname(res, types[TUINT32]); 454 cgen(n, res); 455 } 456 return nil; 457 } 458 459 tempname(&tmp, types[TINT64]); 460 cgen(n, &tmp); 461 split64(&tmp, &lo, &hi); 462 tempname(res, types[TUINT32]); 463 gmove(&lo, res); 464 if(bounded) { 465 splitclean(); 466 return nil; 467 } 468 nodconst(&zero, types[TINT32], 0); 469 gins(ACMPL, &hi, &zero); 470 splitclean(); 471 return gbranch(AJNE, T, +1); 472 } 473 474 /* 475 * address gen 476 * res = &n; 477 */ 478 void 479 agen(Node *n, Node *res) 480 { 481 Node *nl, *nr; 482 Node n1, n2, n3, n4, tmp, nlen; 483 Type *t; 484 uint32 w; 485 uint64 v; 486 Prog *p1, *p2; 487 int bounded; 488 489 if(debug['g']) { 490 dump("\nagen-res", res); 491 dump("agen-r", n); 492 } 493 if(n == N || n->type == T || res == N || res->type == T) 494 fatal("agen"); 495 496 while(n->op == OCONVNOP) 497 n = n->left; 498 499 if(isconst(n, CTNIL) && n->type->width > widthptr) { 500 // Use of a nil interface or nil slice. 501 // Create a temporary we can take the address of and read. 502 // The generated code is just going to panic, so it need not 503 // be terribly efficient. See issue 3670. 504 tempname(&n1, n->type); 505 clearfat(&n1); 506 regalloc(&n2, types[tptr], res); 507 gins(ALEAL, &n1, &n2); 508 gmove(&n2, res); 509 regfree(&n2); 510 return; 511 } 512 513 // addressable var is easy 514 if(n->addable) { 515 if(n->op == OREGISTER) 516 fatal("agen OREGISTER"); 517 regalloc(&n1, types[tptr], res); 518 gins(ALEAL, n, &n1); 519 gmove(&n1, res); 520 regfree(&n1); 521 return; 522 } 523 524 // let's compute 525 nl = n->left; 526 nr = n->right; 527 528 switch(n->op) { 529 default: 530 fatal("agen %O", n->op); 531 532 case OCALLMETH: 533 cgen_callmeth(n, 0); 534 cgen_aret(n, res); 535 break; 536 537 case OCALLINTER: 538 cgen_callinter(n, res, 0); 539 cgen_aret(n, res); 540 break; 541 542 case OCALLFUNC: 543 cgen_call(n, 0); 544 cgen_aret(n, res); 545 break; 546 547 case OSLICE: 548 case OSLICEARR: 549 case OSLICESTR: 550 tempname(&n1, n->type); 551 cgen_slice(n, &n1); 552 agen(&n1, res); 553 break; 554 555 case OEFACE: 556 tempname(&n1, n->type); 557 cgen_eface(n, &n1); 558 agen(&n1, res); 559 break; 560 561 case OINDEX: 562 p2 = nil; // to be patched to panicindex. 563 w = n->type->width; 564 bounded = debug['B'] || n->bounded; 565 if(nr->addable) { 566 // Generate &nl first, and move nr into register. 567 if(!isconst(nl, CTSTR)) 568 igen(nl, &n3, res); 569 if(!isconst(nr, CTINT)) { 570 p2 = igenindex(nr, &tmp, bounded); 571 regalloc(&n1, tmp.type, N); 572 gmove(&tmp, &n1); 573 } 574 } else if(nl->addable) { 575 // Generate nr first, and move &nl into register. 576 if(!isconst(nr, CTINT)) { 577 p2 = igenindex(nr, &tmp, bounded); 578 regalloc(&n1, tmp.type, N); 579 gmove(&tmp, &n1); 580 } 581 if(!isconst(nl, CTSTR)) 582 igen(nl, &n3, res); 583 } else { 584 p2 = igenindex(nr, &tmp, bounded); 585 nr = &tmp; 586 if(!isconst(nl, CTSTR)) 587 igen(nl, &n3, res); 588 regalloc(&n1, tmp.type, N); 589 gins(optoas(OAS, tmp.type), &tmp, &n1); 590 } 591 592 // For fixed array we really want the pointer in n3. 593 if(isfixedarray(nl->type)) { 594 regalloc(&n2, types[tptr], &n3); 595 agen(&n3, &n2); 596 regfree(&n3); 597 n3 = n2; 598 } 599 600 // &a[0] is in n3 (allocated in res) 601 // i is in n1 (if not constant) 602 // len(a) is in nlen (if needed) 603 // w is width 604 605 // explicit check for nil if array is large enough 606 // that we might derive too big a pointer. 607 if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) { 608 n4 = n3; 609 n4.op = OINDREG; 610 n4.type = types[TUINT8]; 611 n4.xoffset = 0; 612 gins(ATESTB, nodintconst(0), &n4); 613 } 614 615 // constant index 616 if(isconst(nr, CTINT)) { 617 if(isconst(nl, CTSTR)) 618 fatal("constant string constant index"); // front end should handle 619 v = mpgetfix(nr->val.u.xval); 620 if(isslice(nl->type) || nl->type->etype == TSTRING) { 621 if(!debug['B'] && !n->bounded) { 622 nlen = n3; 623 nlen.type = types[TUINT32]; 624 nlen.xoffset += Array_nel; 625 nodconst(&n2, types[TUINT32], v); 626 gins(optoas(OCMP, types[TUINT32]), &nlen, &n2); 627 p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1); 628 ginscall(panicindex, -1); 629 patch(p1, pc); 630 } 631 } 632 633 // Load base pointer in n2 = n3. 634 regalloc(&n2, types[tptr], &n3); 635 n3.type = types[tptr]; 636 n3.xoffset += Array_array; 637 gmove(&n3, &n2); 638 regfree(&n3); 639 if (v*w != 0) { 640 nodconst(&n1, types[tptr], v*w); 641 gins(optoas(OADD, types[tptr]), &n1, &n2); 642 } 643 gmove(&n2, res); 644 regfree(&n2); 645 break; 646 } 647 648 // i is in register n1, extend to 32 bits. 649 t = types[TUINT32]; 650 if(issigned[n1.type->etype]) 651 t = types[TINT32]; 652 653 regalloc(&n2, t, &n1); // i 654 gmove(&n1, &n2); 655 regfree(&n1); 656 657 if(!debug['B'] && !n->bounded) { 658 // check bounds 659 t = types[TUINT32]; 660 if(isconst(nl, CTSTR)) { 661 nodconst(&nlen, t, nl->val.u.sval->len); 662 } else if(isslice(nl->type) || nl->type->etype == TSTRING) { 663 nlen = n3; 664 nlen.type = t; 665 nlen.xoffset += Array_nel; 666 } else { 667 nodconst(&nlen, t, nl->type->bound); 668 } 669 gins(optoas(OCMP, t), &n2, &nlen); 670 p1 = gbranch(optoas(OLT, t), T, +1); 671 if(p2) 672 patch(p2, pc); 673 ginscall(panicindex, -1); 674 patch(p1, pc); 675 } 676 677 if(isconst(nl, CTSTR)) { 678 regalloc(&n3, types[tptr], res); 679 p1 = gins(ALEAL, N, &n3); 680 datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); 681 p1->from.scale = 1; 682 p1->from.index = n2.val.u.reg; 683 goto indexdone; 684 } 685 686 // Load base pointer in n3. 687 regalloc(&tmp, types[tptr], &n3); 688 if(isslice(nl->type) || nl->type->etype == TSTRING) { 689 n3.type = types[tptr]; 690 n3.xoffset += Array_array; 691 gmove(&n3, &tmp); 692 } 693 regfree(&n3); 694 n3 = tmp; 695 696 if(w == 0) { 697 // nothing to do 698 } else if(w == 1 || w == 2 || w == 4 || w == 8) { 699 // LEAL (n3)(n2*w), n3 700 p1 = gins(ALEAL, &n2, &n3); 701 p1->from.scale = w; 702 p1->from.index = p1->from.type; 703 p1->from.type = p1->to.type + D_INDIR; 704 } else { 705 nodconst(&tmp, types[TUINT32], w); 706 gins(optoas(OMUL, types[TUINT32]), &tmp, &n2); 707 gins(optoas(OADD, types[tptr]), &n2, &n3); 708 } 709 710 indexdone: 711 gmove(&n3, res); 712 regfree(&n2); 713 regfree(&n3); 714 break; 715 716 case ONAME: 717 // should only get here with names in this func. 718 if(n->funcdepth > 0 && n->funcdepth != funcdepth) { 719 dump("bad agen", n); 720 fatal("agen: bad ONAME funcdepth %d != %d", 721 n->funcdepth, funcdepth); 722 } 723 724 // should only get here for heap vars or paramref 725 if(!(n->class & PHEAP) && n->class != PPARAMREF) { 726 dump("bad agen", n); 727 fatal("agen: bad ONAME class %#x", n->class); 728 } 729 cgen(n->heapaddr, res); 730 if(n->xoffset != 0) { 731 nodconst(&n1, types[tptr], n->xoffset); 732 gins(optoas(OADD, types[tptr]), &n1, res); 733 } 734 break; 735 736 case OIND: 737 cgen(nl, res); 738 break; 739 740 case ODOT: 741 agen(nl, res); 742 // explicit check for nil if struct is large enough 743 // that we might derive too big a pointer. If the left node 744 // was ODOT we have already done the nil check. 745 if(nl->op != ODOT) 746 if(nl->type->width >= unmappedzero) { 747 regalloc(&n1, types[tptr], res); 748 gmove(res, &n1); 749 n1.op = OINDREG; 750 n1.type = types[TUINT8]; 751 n1.xoffset = 0; 752 gins(ATESTB, nodintconst(0), &n1); 753 regfree(&n1); 754 } 755 if(n->xoffset != 0) { 756 nodconst(&n1, types[tptr], n->xoffset); 757 gins(optoas(OADD, types[tptr]), &n1, res); 758 } 759 break; 760 761 case ODOTPTR: 762 t = nl->type; 763 if(!isptr[t->etype]) 764 fatal("agen: not ptr %N", n); 765 cgen(nl, res); 766 // explicit check for nil if struct is large enough 767 // that we might derive too big a pointer. 768 if(nl->type->type->width >= unmappedzero) { 769 regalloc(&n1, types[tptr], res); 770 gmove(res, &n1); 771 n1.op = OINDREG; 772 n1.type = types[TUINT8]; 773 n1.xoffset = 0; 774 gins(ATESTB, nodintconst(0), &n1); 775 regfree(&n1); 776 } 777 if(n->xoffset != 0) { 778 nodconst(&n1, types[tptr], n->xoffset); 779 gins(optoas(OADD, types[tptr]), &n1, res); 780 } 781 break; 782 } 783 } 784 785 /* 786 * generate: 787 * newreg = &n; 788 * res = newreg 789 * 790 * on exit, a has been changed to be *newreg. 791 * caller must regfree(a). 792 */ 793 void 794 igen(Node *n, Node *a, Node *res) 795 { 796 Type *fp; 797 Iter flist; 798 Node n1; 799 800 if(debug['g']) { 801 dump("\nigen-n", n); 802 } 803 switch(n->op) { 804 case ONAME: 805 if((n->class&PHEAP) || n->class == PPARAMREF) 806 break; 807 *a = *n; 808 return; 809 810 case OINDREG: 811 // Increase the refcount of the register so that igen's caller 812 // has to call regfree. 813 if(n->val.u.reg != D_SP) 814 reg[n->val.u.reg]++; 815 *a = *n; 816 return; 817 818 case ODOT: 819 igen(n->left, a, res); 820 a->xoffset += n->xoffset; 821 a->type = n->type; 822 return; 823 824 case ODOTPTR: 825 switch(n->left->op) { 826 case ODOT: 827 case ODOTPTR: 828 case OCALLFUNC: 829 case OCALLMETH: 830 case OCALLINTER: 831 // igen-able nodes. 832 igen(n->left, &n1, res); 833 regalloc(a, types[tptr], &n1); 834 gmove(&n1, a); 835 regfree(&n1); 836 break; 837 default: 838 regalloc(a, types[tptr], res); 839 cgen(n->left, a); 840 } 841 // explicit check for nil if struct is large enough 842 // that we might derive too big a pointer. 843 if(n->left->type->type->width >= unmappedzero) { 844 n1 = *a; 845 n1.op = OINDREG; 846 n1.type = types[TUINT8]; 847 n1.xoffset = 0; 848 gins(ATESTB, nodintconst(0), &n1); 849 } 850 a->op = OINDREG; 851 a->xoffset += n->xoffset; 852 a->type = n->type; 853 return; 854 855 case OCALLFUNC: 856 case OCALLMETH: 857 case OCALLINTER: 858 switch(n->op) { 859 case OCALLFUNC: 860 cgen_call(n, 0); 861 break; 862 case OCALLMETH: 863 cgen_callmeth(n, 0); 864 break; 865 case OCALLINTER: 866 cgen_callinter(n, N, 0); 867 break; 868 } 869 fp = structfirst(&flist, getoutarg(n->left->type)); 870 memset(a, 0, sizeof *a); 871 a->op = OINDREG; 872 a->val.u.reg = D_SP; 873 a->addable = 1; 874 a->xoffset = fp->width; 875 a->type = n->type; 876 return; 877 } 878 // release register for now, to avoid 879 // confusing tempname. 880 if(res != N && res->op == OREGISTER) 881 reg[res->val.u.reg]--; 882 tempname(&n1, types[tptr]); 883 agen(n, &n1); 884 if(res != N && res->op == OREGISTER) 885 reg[res->val.u.reg]++; 886 regalloc(a, types[tptr], res); 887 gmove(&n1, a); 888 a->op = OINDREG; 889 a->type = n->type; 890 } 891 892 /* 893 * branch gen 894 * if(n == true) goto to; 895 */ 896 void 897 bgen(Node *n, int true, int likely, Prog *to) 898 { 899 int et, a; 900 Node *nl, *nr, *r; 901 Node n1, n2, tmp; 902 Prog *p1, *p2; 903 904 if(debug['g']) { 905 dump("\nbgen", n); 906 } 907 908 if(n == N) 909 n = nodbool(1); 910 911 if(n->ninit != nil) 912 genlist(n->ninit); 913 914 if(n->type == T) { 915 convlit(&n, types[TBOOL]); 916 if(n->type == T) 917 return; 918 } 919 920 et = n->type->etype; 921 if(et != TBOOL) { 922 yyerror("cgen: bad type %T for %O", n->type, n->op); 923 patch(gins(AEND, N, N), to); 924 return; 925 } 926 nl = n->left; 927 nr = N; 928 929 if(nl != N && isfloat[nl->type->etype]) { 930 bgen_float(n, true, likely, to); 931 return; 932 } 933 934 switch(n->op) { 935 default: 936 def: 937 regalloc(&n1, n->type, N); 938 cgen(n, &n1); 939 nodconst(&n2, n->type, 0); 940 gins(optoas(OCMP, n->type), &n1, &n2); 941 a = AJNE; 942 if(!true) 943 a = AJEQ; 944 patch(gbranch(a, n->type, likely), to); 945 regfree(&n1); 946 return; 947 948 case OLITERAL: 949 // need to ask if it is bool? 950 if(!true == !n->val.u.bval) 951 patch(gbranch(AJMP, T, 0), to); 952 return; 953 954 case ONAME: 955 if(!n->addable) 956 goto def; 957 nodconst(&n1, n->type, 0); 958 gins(optoas(OCMP, n->type), n, &n1); 959 a = AJNE; 960 if(!true) 961 a = AJEQ; 962 patch(gbranch(a, n->type, likely), to); 963 return; 964 965 case OANDAND: 966 if(!true) 967 goto caseor; 968 969 caseand: 970 p1 = gbranch(AJMP, T, 0); 971 p2 = gbranch(AJMP, T, 0); 972 patch(p1, pc); 973 bgen(n->left, !true, -likely, p2); 974 bgen(n->right, !true, -likely, p2); 975 p1 = gbranch(AJMP, T, 0); 976 patch(p1, to); 977 patch(p2, pc); 978 return; 979 980 case OOROR: 981 if(!true) 982 goto caseand; 983 984 caseor: 985 bgen(n->left, true, likely, to); 986 bgen(n->right, true, likely, to); 987 return; 988 989 case OEQ: 990 case ONE: 991 case OLT: 992 case OGT: 993 case OLE: 994 case OGE: 995 nr = n->right; 996 if(nr == N || nr->type == T) 997 return; 998 999 case ONOT: // unary 1000 nl = n->left; 1001 if(nl == N || nl->type == T) 1002 return; 1003 } 1004 1005 switch(n->op) { 1006 case ONOT: 1007 bgen(nl, !true, likely, to); 1008 break; 1009 1010 case OEQ: 1011 case ONE: 1012 case OLT: 1013 case OGT: 1014 case OLE: 1015 case OGE: 1016 a = n->op; 1017 if(!true) { 1018 a = brcom(a); 1019 true = !true; 1020 } 1021 1022 // make simplest on right 1023 if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) { 1024 a = brrev(a); 1025 r = nl; 1026 nl = nr; 1027 nr = r; 1028 } 1029 1030 if(isslice(nl->type)) { 1031 // front end should only leave cmp to literal nil 1032 if((a != OEQ && a != ONE) || nr->op != OLITERAL) { 1033 yyerror("illegal slice comparison"); 1034 break; 1035 } 1036 a = optoas(a, types[tptr]); 1037 igen(nl, &n1, N); 1038 n1.xoffset += Array_array; 1039 n1.type = types[tptr]; 1040 nodconst(&tmp, types[tptr], 0); 1041 gins(optoas(OCMP, types[tptr]), &n1, &tmp); 1042 patch(gbranch(a, types[tptr], likely), to); 1043 regfree(&n1); 1044 break; 1045 } 1046 1047 if(isinter(nl->type)) { 1048 // front end should only leave cmp to literal nil 1049 if((a != OEQ && a != ONE) || nr->op != OLITERAL) { 1050 yyerror("illegal interface comparison"); 1051 break; 1052 } 1053 a = optoas(a, types[tptr]); 1054 igen(nl, &n1, N); 1055 n1.type = types[tptr]; 1056 nodconst(&tmp, types[tptr], 0); 1057 gins(optoas(OCMP, types[tptr]), &n1, &tmp); 1058 patch(gbranch(a, types[tptr], likely), to); 1059 regfree(&n1); 1060 break; 1061 } 1062 1063 if(iscomplex[nl->type->etype]) { 1064 complexbool(a, nl, nr, true, likely, to); 1065 break; 1066 } 1067 1068 if(is64(nr->type)) { 1069 if(!nl->addable || isconst(nl, CTINT)) { 1070 tempname(&n1, nl->type); 1071 cgen(nl, &n1); 1072 nl = &n1; 1073 } 1074 if(!nr->addable) { 1075 tempname(&n2, nr->type); 1076 cgen(nr, &n2); 1077 nr = &n2; 1078 } 1079 cmp64(nl, nr, a, likely, to); 1080 break; 1081 } 1082 1083 if(nr->ullman >= UINF) { 1084 if(!nl->addable) { 1085 tempname(&n1, nl->type); 1086 cgen(nl, &n1); 1087 nl = &n1; 1088 } 1089 if(!nr->addable) { 1090 tempname(&tmp, nr->type); 1091 cgen(nr, &tmp); 1092 nr = &tmp; 1093 } 1094 regalloc(&n2, nr->type, N); 1095 cgen(nr, &n2); 1096 nr = &n2; 1097 goto cmp; 1098 } 1099 1100 if(!nl->addable) { 1101 tempname(&n1, nl->type); 1102 cgen(nl, &n1); 1103 nl = &n1; 1104 } 1105 1106 if(smallintconst(nr)) { 1107 gins(optoas(OCMP, nr->type), nl, nr); 1108 patch(gbranch(optoas(a, nr->type), nr->type, likely), to); 1109 break; 1110 } 1111 1112 if(!nr->addable) { 1113 tempname(&tmp, nr->type); 1114 cgen(nr, &tmp); 1115 nr = &tmp; 1116 } 1117 regalloc(&n2, nr->type, N); 1118 gmove(nr, &n2); 1119 nr = &n2; 1120 1121 cmp: 1122 gins(optoas(OCMP, nr->type), nl, nr); 1123 patch(gbranch(optoas(a, nr->type), nr->type, likely), to); 1124 1125 if(nl->op == OREGISTER) 1126 regfree(nl); 1127 regfree(nr); 1128 break; 1129 } 1130 } 1131 1132 /* 1133 * n is on stack, either local variable 1134 * or return value from function call. 1135 * return n's offset from SP. 1136 */ 1137 int32 1138 stkof(Node *n) 1139 { 1140 Type *t; 1141 Iter flist; 1142 int32 off; 1143 1144 switch(n->op) { 1145 case OINDREG: 1146 return n->xoffset; 1147 1148 case ODOT: 1149 t = n->left->type; 1150 if(isptr[t->etype]) 1151 break; 1152 off = stkof(n->left); 1153 if(off == -1000 || off == 1000) 1154 return off; 1155 return off + n->xoffset; 1156 1157 case OINDEX: 1158 t = n->left->type; 1159 if(!isfixedarray(t)) 1160 break; 1161 off = stkof(n->left); 1162 if(off == -1000 || off == 1000) 1163 return off; 1164 if(isconst(n->right, CTINT)) 1165 return off + t->type->width * mpgetfix(n->right->val.u.xval); 1166 return 1000; 1167 1168 case OCALLMETH: 1169 case OCALLINTER: 1170 case OCALLFUNC: 1171 t = n->left->type; 1172 if(isptr[t->etype]) 1173 t = t->type; 1174 1175 t = structfirst(&flist, getoutarg(t)); 1176 if(t != T) 1177 return t->width; 1178 break; 1179 } 1180 1181 // botch - probably failing to recognize address 1182 // arithmetic on the above. eg INDEX and DOT 1183 return -1000; 1184 } 1185 1186 /* 1187 * struct gen 1188 * memmove(&res, &n, w); 1189 */ 1190 void 1191 sgen(Node *n, Node *res, int64 w) 1192 { 1193 Node dst, src, tdst, tsrc; 1194 int32 c, q, odst, osrc; 1195 1196 if(debug['g']) { 1197 print("\nsgen w=%lld\n", w); 1198 dump("r", n); 1199 dump("res", res); 1200 } 1201 if(n->ullman >= UINF && res->ullman >= UINF) 1202 fatal("sgen UINF"); 1203 1204 if(w < 0 || (int32)w != w) 1205 fatal("sgen copy %lld", w); 1206 1207 if(w == 0) { 1208 // evaluate side effects only. 1209 tempname(&tdst, types[tptr]); 1210 agen(res, &tdst); 1211 agen(n, &tdst); 1212 return; 1213 } 1214 1215 // Avoid taking the address for simple enough types. 1216 if(componentgen(n, res)) 1217 return; 1218 1219 // offset on the stack 1220 osrc = stkof(n); 1221 odst = stkof(res); 1222 1223 if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { 1224 // osrc and odst both on stack, and at least one is in 1225 // an unknown position. Could generate code to test 1226 // for forward/backward copy, but instead just copy 1227 // to a temporary location first. 1228 tempname(&tsrc, n->type); 1229 sgen(n, &tsrc, w); 1230 sgen(&tsrc, res, w); 1231 return; 1232 } 1233 1234 nodreg(&dst, types[tptr], D_DI); 1235 nodreg(&src, types[tptr], D_SI); 1236 1237 tempname(&tsrc, types[tptr]); 1238 tempname(&tdst, types[tptr]); 1239 if(!n->addable) 1240 agen(n, &tsrc); 1241 if(!res->addable) 1242 agen(res, &tdst); 1243 if(n->addable) 1244 agen(n, &src); 1245 else 1246 gmove(&tsrc, &src); 1247 if(res->addable) 1248 agen(res, &dst); 1249 else 1250 gmove(&tdst, &dst); 1251 1252 c = w % 4; // bytes 1253 q = w / 4; // doublewords 1254 1255 // if we are copying forward on the stack and 1256 // the src and dst overlap, then reverse direction 1257 if(osrc < odst && odst < osrc+w) { 1258 // reverse direction 1259 gins(ASTD, N, N); // set direction flag 1260 if(c > 0) { 1261 gconreg(AADDL, w-1, D_SI); 1262 gconreg(AADDL, w-1, D_DI); 1263 1264 gconreg(AMOVL, c, D_CX); 1265 gins(AREP, N, N); // repeat 1266 gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)- 1267 } 1268 1269 if(q > 0) { 1270 if(c > 0) { 1271 gconreg(AADDL, -3, D_SI); 1272 gconreg(AADDL, -3, D_DI); 1273 } else { 1274 gconreg(AADDL, w-4, D_SI); 1275 gconreg(AADDL, w-4, D_DI); 1276 } 1277 gconreg(AMOVL, q, D_CX); 1278 gins(AREP, N, N); // repeat 1279 gins(AMOVSL, N, N); // MOVL *(SI)-,*(DI)- 1280 } 1281 // we leave with the flag clear 1282 gins(ACLD, N, N); 1283 } else { 1284 gins(ACLD, N, N); // paranoia. TODO(rsc): remove? 1285 // normal direction 1286 if(q >= 4) { 1287 gconreg(AMOVL, q, D_CX); 1288 gins(AREP, N, N); // repeat 1289 gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ 1290 } else 1291 while(q > 0) { 1292 gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ 1293 q--; 1294 } 1295 while(c > 0) { 1296 gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+ 1297 c--; 1298 } 1299 } 1300 } 1301 1302 static int 1303 cadable(Node *n) 1304 { 1305 if(!n->addable) { 1306 // dont know how it happens, 1307 // but it does 1308 return 0; 1309 } 1310 1311 switch(n->op) { 1312 case ONAME: 1313 return 1; 1314 } 1315 return 0; 1316 } 1317 1318 /* 1319 * copy a composite value by moving its individual components. 1320 * Slices, strings and interfaces are supported. 1321 * nr is N when assigning a zero value. 1322 * return 1 if can do, 0 if cant. 1323 */ 1324 int 1325 componentgen(Node *nr, Node *nl) 1326 { 1327 Node nodl, nodr; 1328 int freel, freer; 1329 1330 freel = 0; 1331 freer = 0; 1332 1333 switch(nl->type->etype) { 1334 default: 1335 goto no; 1336 1337 case TARRAY: 1338 if(!isslice(nl->type)) 1339 goto no; 1340 case TSTRING: 1341 case TINTER: 1342 break; 1343 } 1344 1345 nodl = *nl; 1346 if(!cadable(nl)) { 1347 if(nr == N || !cadable(nr)) 1348 goto no; 1349 igen(nl, &nodl, N); 1350 freel = 1; 1351 } 1352 1353 if(nr != N) { 1354 nodr = *nr; 1355 if(!cadable(nr)) { 1356 igen(nr, &nodr, N); 1357 freer = 1; 1358 } 1359 } 1360 1361 switch(nl->type->etype) { 1362 case TARRAY: 1363 nodl.xoffset += Array_array; 1364 nodl.type = ptrto(nl->type->type); 1365 1366 if(nr != N) { 1367 nodr.xoffset += Array_array; 1368 nodr.type = nodl.type; 1369 } else 1370 nodconst(&nodr, nodl.type, 0); 1371 gmove(&nodr, &nodl); 1372 1373 nodl.xoffset += Array_nel-Array_array; 1374 nodl.type = types[TUINT32]; 1375 1376 if(nr != N) { 1377 nodr.xoffset += Array_nel-Array_array; 1378 nodr.type = nodl.type; 1379 } else 1380 nodconst(&nodr, nodl.type, 0); 1381 gmove(&nodr, &nodl); 1382 1383 nodl.xoffset += Array_cap-Array_nel; 1384 nodl.type = types[TUINT32]; 1385 1386 if(nr != N) { 1387 nodr.xoffset += Array_cap-Array_nel; 1388 nodr.type = nodl.type; 1389 } else 1390 nodconst(&nodr, nodl.type, 0); 1391 gmove(&nodr, &nodl); 1392 1393 goto yes; 1394 1395 case TSTRING: 1396 nodl.xoffset += Array_array; 1397 nodl.type = ptrto(types[TUINT8]); 1398 1399 if(nr != N) { 1400 nodr.xoffset += Array_array; 1401 nodr.type = nodl.type; 1402 } else 1403 nodconst(&nodr, nodl.type, 0); 1404 gmove(&nodr, &nodl); 1405 1406 nodl.xoffset += Array_nel-Array_array; 1407 nodl.type = types[TUINT32]; 1408 1409 if(nr != N) { 1410 nodr.xoffset += Array_nel-Array_array; 1411 nodr.type = nodl.type; 1412 } else 1413 nodconst(&nodr, nodl.type, 0); 1414 gmove(&nodr, &nodl); 1415 1416 goto yes; 1417 1418 case TINTER: 1419 nodl.xoffset += Array_array; 1420 nodl.type = ptrto(types[TUINT8]); 1421 1422 if(nr != N) { 1423 nodr.xoffset += Array_array; 1424 nodr.type = nodl.type; 1425 } else 1426 nodconst(&nodr, nodl.type, 0); 1427 gmove(&nodr, &nodl); 1428 1429 nodl.xoffset += Array_nel-Array_array; 1430 nodl.type = ptrto(types[TUINT8]); 1431 1432 if(nr != N) { 1433 nodr.xoffset += Array_nel-Array_array; 1434 nodr.type = nodl.type; 1435 } else 1436 nodconst(&nodr, nodl.type, 0); 1437 gmove(&nodr, &nodl); 1438 1439 goto yes; 1440 } 1441 1442 no: 1443 if(freer) 1444 regfree(&nodr); 1445 if(freel) 1446 regfree(&nodl); 1447 return 0; 1448 1449 yes: 1450 if(freer) 1451 regfree(&nodr); 1452 if(freel) 1453 regfree(&nodl); 1454 return 1; 1455 }