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