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