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