github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/gc/cgen.go (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 package gc 6 7 import ( 8 "cmd/internal/obj" 9 "fmt" 10 ) 11 12 /* 13 * generate: 14 * res = n; 15 * simplifies and calls Thearch.Gmove. 16 */ 17 func Cgen(n *Node, res *Node) { 18 if Debug['g'] != 0 { 19 Dump("\ncgen-n", n) 20 Dump("cgen-res", res) 21 } 22 23 if n == nil || n.Type == nil { 24 return 25 } 26 27 if res == nil || res.Type == nil { 28 Fatal("cgen: res nil") 29 } 30 31 for n.Op == OCONVNOP { 32 n = n.Left 33 } 34 35 switch n.Op { 36 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: 37 if res.Op != ONAME || !res.Addable { 38 var n1 Node 39 Tempname(&n1, n.Type) 40 Cgen_slice(n, &n1) 41 Cgen(&n1, res) 42 } else { 43 Cgen_slice(n, res) 44 } 45 return 46 47 case OEFACE: 48 if res.Op != ONAME || !res.Addable { 49 var n1 Node 50 Tempname(&n1, n.Type) 51 Cgen_eface(n, &n1) 52 Cgen(&n1, res) 53 } else { 54 Cgen_eface(n, res) 55 } 56 return 57 58 case ODOTTYPE: 59 cgen_dottype(n, res, nil) 60 return 61 } 62 63 if n.Ullman >= UINF { 64 if n.Op == OINDREG { 65 Fatal("cgen: this is going to miscompile") 66 } 67 if res.Ullman >= UINF { 68 var n1 Node 69 Tempname(&n1, n.Type) 70 Cgen(n, &n1) 71 Cgen(&n1, res) 72 return 73 } 74 } 75 76 if Isfat(n.Type) { 77 if n.Type.Width < 0 { 78 Fatal("forgot to compute width for %v", Tconv(n.Type, 0)) 79 } 80 sgen(n, res, n.Type.Width) 81 return 82 } 83 84 if !res.Addable { 85 if n.Ullman > res.Ullman { 86 if Ctxt.Arch.Regsize == 4 && Is64(n.Type) { 87 var n1 Node 88 Tempname(&n1, n.Type) 89 Cgen(n, &n1) 90 Cgen(&n1, res) 91 return 92 } 93 94 var n1 Node 95 Regalloc(&n1, n.Type, res) 96 Cgen(n, &n1) 97 if n1.Ullman > res.Ullman { 98 Dump("n1", &n1) 99 Dump("res", res) 100 Fatal("loop in cgen") 101 } 102 103 Cgen(&n1, res) 104 Regfree(&n1) 105 return 106 } 107 108 var f int 109 if res.Ullman >= UINF { 110 goto gen 111 } 112 113 if Complexop(n, res) { 114 Complexgen(n, res) 115 return 116 } 117 118 f = 1 // gen thru register 119 switch n.Op { 120 case OLITERAL: 121 if Smallintconst(n) { 122 f = 0 123 } 124 125 case OREGISTER: 126 f = 0 127 } 128 129 if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 { 130 a := Thearch.Optoas(OAS, res.Type) 131 var addr obj.Addr 132 if Thearch.Sudoaddable(a, res, &addr) { 133 var p1 *obj.Prog 134 if f != 0 { 135 var n2 Node 136 Regalloc(&n2, res.Type, nil) 137 Cgen(n, &n2) 138 p1 = Thearch.Gins(a, &n2, nil) 139 Regfree(&n2) 140 } else { 141 p1 = Thearch.Gins(a, n, nil) 142 } 143 p1.To = addr 144 if Debug['g'] != 0 { 145 fmt.Printf("%v [ignore previous line]\n", p1) 146 } 147 Thearch.Sudoclean() 148 return 149 } 150 } 151 152 gen: 153 if Ctxt.Arch.Thechar == '8' { 154 // no registers to speak of 155 var n1, n2 Node 156 Tempname(&n1, n.Type) 157 Cgen(n, &n1) 158 Igen(res, &n2, nil) 159 Thearch.Gmove(&n1, &n2) 160 Regfree(&n2) 161 return 162 } 163 164 var n1 Node 165 Igen(res, &n1, nil) 166 Cgen(n, &n1) 167 Regfree(&n1) 168 return 169 } 170 171 // update addressability for string, slice 172 // can't do in walk because n->left->addable 173 // changes if n->left is an escaping local variable. 174 switch n.Op { 175 case OSPTR, OLEN: 176 if Isslice(n.Left.Type) || Istype(n.Left.Type, TSTRING) { 177 n.Addable = n.Left.Addable 178 } 179 180 case OCAP: 181 if Isslice(n.Left.Type) { 182 n.Addable = n.Left.Addable 183 } 184 185 case OITAB: 186 n.Addable = n.Left.Addable 187 } 188 189 if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often? 190 // if both are addressable, move 191 if n.Addable && res.Addable { 192 if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || Iscomplex[n.Type.Etype] || Iscomplex[res.Type.Etype] { 193 Thearch.Gmove(n, res) 194 } else { 195 var n1 Node 196 Regalloc(&n1, n.Type, nil) 197 Thearch.Gmove(n, &n1) 198 Cgen(&n1, res) 199 Regfree(&n1) 200 } 201 202 return 203 } 204 205 // if both are not addressable, use a temporary. 206 if !n.Addable && !res.Addable { 207 // could use regalloc here sometimes, 208 // but have to check for ullman >= UINF. 209 var n1 Node 210 Tempname(&n1, n.Type) 211 Cgen(n, &n1) 212 Cgen(&n1, res) 213 return 214 } 215 216 // if result is not addressable directly but n is, 217 // compute its address and then store via the address. 218 if !res.Addable { 219 var n1 Node 220 Igen(res, &n1, nil) 221 Cgen(n, &n1) 222 Regfree(&n1) 223 return 224 } 225 } 226 227 if Complexop(n, res) { 228 Complexgen(n, res) 229 return 230 } 231 232 if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable { 233 Thearch.Gmove(n, res) 234 return 235 } 236 237 if Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { 238 // if both are addressable, move 239 if n.Addable { 240 if n.Op == OREGISTER || res.Op == OREGISTER { 241 Thearch.Gmove(n, res) 242 } else { 243 var n1 Node 244 Regalloc(&n1, n.Type, nil) 245 Thearch.Gmove(n, &n1) 246 Cgen(&n1, res) 247 Regfree(&n1) 248 } 249 return 250 } 251 } 252 253 // if n is sudoaddable generate addr and move 254 if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !Iscomplex[n.Type.Etype] && !Iscomplex[res.Type.Etype] { 255 a := Thearch.Optoas(OAS, n.Type) 256 var addr obj.Addr 257 if Thearch.Sudoaddable(a, n, &addr) { 258 if res.Op != OREGISTER { 259 var n2 Node 260 Regalloc(&n2, res.Type, nil) 261 p1 := Thearch.Gins(a, nil, &n2) 262 p1.From = addr 263 if Debug['g'] != 0 { 264 fmt.Printf("%v [ignore previous line]\n", p1) 265 } 266 Thearch.Gmove(&n2, res) 267 Regfree(&n2) 268 } else { 269 p1 := Thearch.Gins(a, nil, res) 270 p1.From = addr 271 if Debug['g'] != 0 { 272 fmt.Printf("%v [ignore previous line]\n", p1) 273 } 274 } 275 Thearch.Sudoclean() 276 return 277 } 278 } 279 280 nl := n.Left 281 nr := n.Right 282 283 if nl != nil && nl.Ullman >= UINF { 284 if nr != nil && nr.Ullman >= UINF { 285 var n1 Node 286 Tempname(&n1, nl.Type) 287 Cgen(nl, &n1) 288 n2 := *n 289 n2.Left = &n1 290 Cgen(&n2, res) 291 return 292 } 293 } 294 295 // 64-bit ops are hard on 32-bit machine. 296 if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) { 297 switch n.Op { 298 // math goes to cgen64. 299 case OMINUS, 300 OCOM, 301 OADD, 302 OSUB, 303 OMUL, 304 OLROT, 305 OLSH, 306 ORSH, 307 OAND, 308 OOR, 309 OXOR: 310 Thearch.Cgen64(n, res) 311 return 312 } 313 } 314 315 if Thearch.Cgen_float != nil && nl != nil && Isfloat[n.Type.Etype] && Isfloat[nl.Type.Etype] { 316 Thearch.Cgen_float(n, res) 317 return 318 } 319 320 if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 { 321 a := Thearch.Optoas(OAS, n.Type) 322 var addr obj.Addr 323 if Thearch.Sudoaddable(a, n, &addr) { 324 if res.Op == OREGISTER { 325 p1 := Thearch.Gins(a, nil, res) 326 p1.From = addr 327 } else { 328 var n2 Node 329 Regalloc(&n2, n.Type, nil) 330 p1 := Thearch.Gins(a, nil, &n2) 331 p1.From = addr 332 Thearch.Gins(a, &n2, res) 333 Regfree(&n2) 334 } 335 336 Thearch.Sudoclean() 337 return 338 } 339 } 340 341 var a int 342 switch n.Op { 343 default: 344 Dump("cgen", n) 345 Dump("cgen-res", res) 346 Fatal("cgen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign)) 347 348 // these call bgen to get a bool value 349 case OOROR, 350 OANDAND, 351 OEQ, 352 ONE, 353 OLT, 354 OLE, 355 OGE, 356 OGT, 357 ONOT: 358 p1 := Gbranch(obj.AJMP, nil, 0) 359 360 p2 := Pc 361 Thearch.Gmove(Nodbool(true), res) 362 p3 := Gbranch(obj.AJMP, nil, 0) 363 Patch(p1, Pc) 364 Bgen(n, true, 0, p2) 365 Thearch.Gmove(Nodbool(false), res) 366 Patch(p3, Pc) 367 return 368 369 case OPLUS: 370 Cgen(nl, res) 371 return 372 373 // unary 374 case OCOM: 375 a := Thearch.Optoas(OXOR, nl.Type) 376 377 var n1 Node 378 Regalloc(&n1, nl.Type, nil) 379 Cgen(nl, &n1) 380 var n2 Node 381 Nodconst(&n2, nl.Type, -1) 382 Thearch.Gins(a, &n2, &n1) 383 cgen_norm(n, &n1, res) 384 return 385 386 case OMINUS: 387 if Isfloat[nl.Type.Etype] { 388 nr = Nodintconst(-1) 389 Convlit(&nr, n.Type) 390 a = Thearch.Optoas(OMUL, nl.Type) 391 goto sbop 392 } 393 394 a := Thearch.Optoas(int(n.Op), nl.Type) 395 // unary 396 var n1 Node 397 Regalloc(&n1, nl.Type, res) 398 399 Cgen(nl, &n1) 400 if Ctxt.Arch.Thechar == '5' { 401 var n2 Node 402 Nodconst(&n2, nl.Type, 0) 403 Thearch.Gins(a, &n2, &n1) 404 } else if Ctxt.Arch.Thechar == '7' { 405 Thearch.Gins(a, &n1, &n1) 406 } else { 407 Thearch.Gins(a, nil, &n1) 408 } 409 cgen_norm(n, &n1, res) 410 return 411 412 case OSQRT: 413 var n1 Node 414 Regalloc(&n1, nl.Type, res) 415 Cgen(n.Left, &n1) 416 Thearch.Gins(Thearch.Optoas(OSQRT, nl.Type), &n1, &n1) 417 Thearch.Gmove(&n1, res) 418 Regfree(&n1) 419 return 420 421 case OGETG: 422 Thearch.Getg(res) 423 return 424 425 // symmetric binary 426 case OAND, 427 OOR, 428 OXOR, 429 OADD, 430 OMUL: 431 if n.Op == OMUL && Thearch.Cgen_bmul != nil && Thearch.Cgen_bmul(int(n.Op), nl, nr, res) { 432 break 433 } 434 a = Thearch.Optoas(int(n.Op), nl.Type) 435 goto sbop 436 437 // asymmetric binary 438 case OSUB: 439 a = Thearch.Optoas(int(n.Op), nl.Type) 440 goto abop 441 442 case OHMUL: 443 Thearch.Cgen_hmul(nl, nr, res) 444 445 case OCONV: 446 if Eqtype(n.Type, nl.Type) || Noconv(n.Type, nl.Type) { 447 Cgen(nl, res) 448 return 449 } 450 451 if Ctxt.Arch.Thechar == '8' { 452 var n1 Node 453 var n2 Node 454 Tempname(&n2, n.Type) 455 Mgen(nl, &n1, res) 456 Thearch.Gmove(&n1, &n2) 457 Thearch.Gmove(&n2, res) 458 Mfree(&n1) 459 break 460 } 461 462 var n1 Node 463 var n2 Node 464 if Ctxt.Arch.Thechar == '5' { 465 if nl.Addable && !Is64(nl.Type) { 466 Regalloc(&n1, nl.Type, res) 467 Thearch.Gmove(nl, &n1) 468 } else { 469 if n.Type.Width > int64(Widthptr) || Is64(nl.Type) || Isfloat[nl.Type.Etype] { 470 Tempname(&n1, nl.Type) 471 } else { 472 Regalloc(&n1, nl.Type, res) 473 } 474 Cgen(nl, &n1) 475 } 476 if n.Type.Width > int64(Widthptr) || Is64(n.Type) || Isfloat[n.Type.Etype] { 477 Tempname(&n2, n.Type) 478 } else { 479 Regalloc(&n2, n.Type, nil) 480 } 481 } else { 482 if n.Type.Width > nl.Type.Width { 483 // If loading from memory, do conversion during load, 484 // so as to avoid use of 8-bit register in, say, int(*byteptr). 485 switch nl.Op { 486 case ODOT, ODOTPTR, OINDEX, OIND, ONAME: 487 Igen(nl, &n1, res) 488 Regalloc(&n2, n.Type, res) 489 Thearch.Gmove(&n1, &n2) 490 Thearch.Gmove(&n2, res) 491 Regfree(&n2) 492 Regfree(&n1) 493 return 494 } 495 } 496 Regalloc(&n1, nl.Type, res) 497 Regalloc(&n2, n.Type, &n1) 498 Cgen(nl, &n1) 499 } 500 501 // if we do the conversion n1 -> n2 here 502 // reusing the register, then gmove won't 503 // have to allocate its own register. 504 Thearch.Gmove(&n1, &n2) 505 Thearch.Gmove(&n2, res) 506 if n2.Op == OREGISTER { 507 Regfree(&n2) 508 } 509 if n1.Op == OREGISTER { 510 Regfree(&n1) 511 } 512 513 case ODOT, 514 ODOTPTR, 515 OINDEX, 516 OIND, 517 ONAME: // PHEAP or PPARAMREF var 518 var n1 Node 519 Igen(n, &n1, res) 520 521 Thearch.Gmove(&n1, res) 522 Regfree(&n1) 523 524 // interface table is first word of interface value 525 case OITAB: 526 var n1 Node 527 Igen(nl, &n1, res) 528 529 n1.Type = n.Type 530 Thearch.Gmove(&n1, res) 531 Regfree(&n1) 532 533 case OSPTR: 534 // pointer is the first word of string or slice. 535 if Isconst(nl, CTSTR) { 536 var n1 Node 537 Regalloc(&n1, Types[Tptr], res) 538 p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1) 539 Datastring(nl.Val.U.Sval, &p1.From) 540 p1.From.Type = obj.TYPE_ADDR 541 Thearch.Gmove(&n1, res) 542 Regfree(&n1) 543 break 544 } 545 546 var n1 Node 547 Igen(nl, &n1, res) 548 n1.Type = n.Type 549 Thearch.Gmove(&n1, res) 550 Regfree(&n1) 551 552 case OLEN: 553 if Istype(nl.Type, TMAP) || Istype(nl.Type, TCHAN) { 554 // map and chan have len in the first int-sized word. 555 // a zero pointer means zero length 556 var n1 Node 557 Regalloc(&n1, Types[Tptr], res) 558 559 Cgen(nl, &n1) 560 561 var n2 Node 562 Nodconst(&n2, Types[Tptr], 0) 563 Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2) 564 p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0) 565 566 n2 = n1 567 n2.Op = OINDREG 568 n2.Type = Types[Simtype[TINT]] 569 Thearch.Gmove(&n2, &n1) 570 571 Patch(p1, Pc) 572 573 Thearch.Gmove(&n1, res) 574 Regfree(&n1) 575 break 576 } 577 578 if Istype(nl.Type, TSTRING) || Isslice(nl.Type) { 579 // both slice and string have len one pointer into the struct. 580 // a zero pointer means zero length 581 var n1 Node 582 Igen(nl, &n1, res) 583 584 n1.Type = Types[Simtype[TUINT]] 585 n1.Xoffset += int64(Array_nel) 586 Thearch.Gmove(&n1, res) 587 Regfree(&n1) 588 break 589 } 590 591 Fatal("cgen: OLEN: unknown type %v", Tconv(nl.Type, obj.FmtLong)) 592 593 case OCAP: 594 if Istype(nl.Type, TCHAN) { 595 // chan has cap in the second int-sized word. 596 // a zero pointer means zero length 597 var n1 Node 598 Regalloc(&n1, Types[Tptr], res) 599 600 Cgen(nl, &n1) 601 602 var n2 Node 603 Nodconst(&n2, Types[Tptr], 0) 604 Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2) 605 p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0) 606 607 n2 = n1 608 n2.Op = OINDREG 609 n2.Xoffset = int64(Widthint) 610 n2.Type = Types[Simtype[TINT]] 611 Thearch.Gmove(&n2, &n1) 612 613 Patch(p1, Pc) 614 615 Thearch.Gmove(&n1, res) 616 Regfree(&n1) 617 break 618 } 619 620 if Isslice(nl.Type) { 621 var n1 Node 622 Igen(nl, &n1, res) 623 n1.Type = Types[Simtype[TUINT]] 624 n1.Xoffset += int64(Array_cap) 625 Thearch.Gmove(&n1, res) 626 Regfree(&n1) 627 break 628 } 629 630 Fatal("cgen: OCAP: unknown type %v", Tconv(nl.Type, obj.FmtLong)) 631 632 case OADDR: 633 if n.Bounded { // let race detector avoid nil checks 634 Disable_checknil++ 635 } 636 Agen(nl, res) 637 if n.Bounded { 638 Disable_checknil-- 639 } 640 641 case OCALLMETH: 642 cgen_callmeth(n, 0) 643 cgen_callret(n, res) 644 645 case OCALLINTER: 646 cgen_callinter(n, res, 0) 647 cgen_callret(n, res) 648 649 case OCALLFUNC: 650 cgen_call(n, 0) 651 cgen_callret(n, res) 652 653 case OMOD, ODIV: 654 if Isfloat[n.Type.Etype] || Thearch.Dodiv == nil { 655 a = Thearch.Optoas(int(n.Op), nl.Type) 656 goto abop 657 } 658 659 if nl.Ullman >= nr.Ullman { 660 var n1 Node 661 Regalloc(&n1, nl.Type, res) 662 Cgen(nl, &n1) 663 cgen_div(int(n.Op), &n1, nr, res) 664 Regfree(&n1) 665 } else { 666 var n2 Node 667 if !Smallintconst(nr) { 668 Regalloc(&n2, nr.Type, res) 669 Cgen(nr, &n2) 670 } else { 671 n2 = *nr 672 } 673 674 cgen_div(int(n.Op), nl, &n2, res) 675 if n2.Op != OLITERAL { 676 Regfree(&n2) 677 } 678 } 679 680 case OLSH, ORSH, OLROT: 681 Thearch.Cgen_shift(int(n.Op), n.Bounded, nl, nr, res) 682 } 683 684 return 685 686 /* 687 * put simplest on right - we'll generate into left 688 * and then adjust it using the computation of right. 689 * constants and variables have the same ullman 690 * count, so look for constants specially. 691 * 692 * an integer constant we can use as an immediate 693 * is simpler than a variable - we can use the immediate 694 * in the adjustment instruction directly - so it goes 695 * on the right. 696 * 697 * other constants, like big integers or floating point 698 * constants, require a mov into a register, so those 699 * might as well go on the left, so we can reuse that 700 * register for the computation. 701 */ 702 sbop: // symmetric binary 703 if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (Smallintconst(nl) || (nr.Op == OLITERAL && !Smallintconst(nr)))) { 704 r := nl 705 nl = nr 706 nr = r 707 } 708 709 abop: // asymmetric binary 710 var n1 Node 711 var n2 Node 712 if Ctxt.Arch.Thechar == '8' { 713 // no registers, sigh 714 if Smallintconst(nr) { 715 var n1 Node 716 Mgen(nl, &n1, res) 717 var n2 Node 718 Regalloc(&n2, nl.Type, &n1) 719 Thearch.Gmove(&n1, &n2) 720 Thearch.Gins(a, nr, &n2) 721 Thearch.Gmove(&n2, res) 722 Regfree(&n2) 723 Mfree(&n1) 724 } else if nl.Ullman >= nr.Ullman { 725 var nt Node 726 Tempname(&nt, nl.Type) 727 Cgen(nl, &nt) 728 var n2 Node 729 Mgen(nr, &n2, nil) 730 var n1 Node 731 Regalloc(&n1, nl.Type, res) 732 Thearch.Gmove(&nt, &n1) 733 Thearch.Gins(a, &n2, &n1) 734 Thearch.Gmove(&n1, res) 735 Regfree(&n1) 736 Mfree(&n2) 737 } else { 738 var n2 Node 739 Regalloc(&n2, nr.Type, res) 740 Cgen(nr, &n2) 741 var n1 Node 742 Regalloc(&n1, nl.Type, nil) 743 Cgen(nl, &n1) 744 Thearch.Gins(a, &n2, &n1) 745 Regfree(&n2) 746 Thearch.Gmove(&n1, res) 747 Regfree(&n1) 748 } 749 return 750 } 751 752 if nl.Ullman >= nr.Ullman { 753 Regalloc(&n1, nl.Type, res) 754 Cgen(nl, &n1) 755 756 if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm 757 n2 = *nr 758 } else { 759 Regalloc(&n2, nr.Type, nil) 760 Cgen(nr, &n2) 761 } 762 } else { 763 if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm 764 n2 = *nr 765 } else { 766 Regalloc(&n2, nr.Type, res) 767 Cgen(nr, &n2) 768 } 769 770 Regalloc(&n1, nl.Type, nil) 771 Cgen(nl, &n1) 772 } 773 774 Thearch.Gins(a, &n2, &n1) 775 if n2.Op != OLITERAL { 776 Regfree(&n2) 777 } 778 cgen_norm(n, &n1, res) 779 } 780 781 // cgen_norm moves n1 to res, truncating to expected type if necessary. 782 // n1 is a register, and cgen_norm frees it. 783 func cgen_norm(n, n1, res *Node) { 784 switch Ctxt.Arch.Thechar { 785 case '6', '8': 786 // We use sized math, so the result is already truncated. 787 default: 788 switch n.Op { 789 case OADD, OSUB, OMUL, ODIV, OCOM, OMINUS: 790 // TODO(rsc): What about left shift? 791 Thearch.Gins(Thearch.Optoas(OAS, n.Type), n1, n1) 792 } 793 } 794 795 Thearch.Gmove(n1, res) 796 Regfree(n1) 797 } 798 799 func Mgen(n *Node, n1 *Node, rg *Node) { 800 n1.Op = OEMPTY 801 802 if n.Addable { 803 *n1 = *n 804 if n1.Op == OREGISTER || n1.Op == OINDREG { 805 reg[n.Reg-int16(Thearch.REGMIN)]++ 806 } 807 return 808 } 809 810 Tempname(n1, n.Type) 811 Cgen(n, n1) 812 if n.Type.Width <= int64(Widthptr) || Isfloat[n.Type.Etype] { 813 n2 := *n1 814 Regalloc(n1, n.Type, rg) 815 Thearch.Gmove(&n2, n1) 816 } 817 } 818 819 func Mfree(n *Node) { 820 if n.Op == OREGISTER { 821 Regfree(n) 822 } 823 } 824 825 /* 826 * allocate a register (reusing res if possible) and generate 827 * a = n 828 * The caller must call Regfree(a). 829 */ 830 func Cgenr(n *Node, a *Node, res *Node) { 831 if Debug['g'] != 0 { 832 Dump("cgenr-n", n) 833 } 834 835 if Isfat(n.Type) { 836 Fatal("cgenr on fat node") 837 } 838 839 if n.Addable { 840 Regalloc(a, n.Type, res) 841 Thearch.Gmove(n, a) 842 return 843 } 844 845 switch n.Op { 846 case ONAME, 847 ODOT, 848 ODOTPTR, 849 OINDEX, 850 OCALLFUNC, 851 OCALLMETH, 852 OCALLINTER: 853 var n1 Node 854 Igen(n, &n1, res) 855 Regalloc(a, Types[Tptr], &n1) 856 Thearch.Gmove(&n1, a) 857 Regfree(&n1) 858 859 default: 860 Regalloc(a, n.Type, res) 861 Cgen(n, a) 862 } 863 } 864 865 /* 866 * allocate a register (reusing res if possible) and generate 867 * a = &n 868 * The caller must call Regfree(a). 869 * The generated code checks that the result is not nil. 870 */ 871 func Agenr(n *Node, a *Node, res *Node) { 872 if Debug['g'] != 0 { 873 Dump("\nagenr-n", n) 874 } 875 876 nl := n.Left 877 nr := n.Right 878 879 switch n.Op { 880 case ODOT, ODOTPTR, OCALLFUNC, OCALLMETH, OCALLINTER: 881 var n1 Node 882 Igen(n, &n1, res) 883 Regalloc(a, Types[Tptr], &n1) 884 Agen(&n1, a) 885 Regfree(&n1) 886 887 case OIND: 888 Cgenr(n.Left, a, res) 889 Cgen_checknil(a) 890 891 case OINDEX: 892 if Ctxt.Arch.Thechar == '5' { 893 var p2 *obj.Prog // to be patched to panicindex. 894 w := uint32(n.Type.Width) 895 bounded := Debug['B'] != 0 || n.Bounded 896 var n1 Node 897 var n3 Node 898 if nr.Addable { 899 var tmp Node 900 if !Isconst(nr, CTINT) { 901 Tempname(&tmp, Types[TINT32]) 902 } 903 if !Isconst(nl, CTSTR) { 904 Agenr(nl, &n3, res) 905 } 906 if !Isconst(nr, CTINT) { 907 p2 = Thearch.Cgenindex(nr, &tmp, bounded) 908 Regalloc(&n1, tmp.Type, nil) 909 Thearch.Gmove(&tmp, &n1) 910 } 911 } else if nl.Addable { 912 if !Isconst(nr, CTINT) { 913 var tmp Node 914 Tempname(&tmp, Types[TINT32]) 915 p2 = Thearch.Cgenindex(nr, &tmp, bounded) 916 Regalloc(&n1, tmp.Type, nil) 917 Thearch.Gmove(&tmp, &n1) 918 } 919 920 if !Isconst(nl, CTSTR) { 921 Agenr(nl, &n3, res) 922 } 923 } else { 924 var tmp Node 925 Tempname(&tmp, Types[TINT32]) 926 p2 = Thearch.Cgenindex(nr, &tmp, bounded) 927 nr = &tmp 928 if !Isconst(nl, CTSTR) { 929 Agenr(nl, &n3, res) 930 } 931 Regalloc(&n1, tmp.Type, nil) 932 Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1) 933 } 934 935 // &a is in &n3 (allocated in res) 936 // i is in &n1 (if not constant) 937 // w is width 938 939 // constant index 940 if Isconst(nr, CTINT) { 941 if Isconst(nl, CTSTR) { 942 Fatal("constant string constant index") 943 } 944 v := uint64(Mpgetfix(nr.Val.U.Xval)) 945 var n2 Node 946 if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 947 if Debug['B'] == 0 && !n.Bounded { 948 n1 = n3 949 n1.Op = OINDREG 950 n1.Type = Types[Tptr] 951 n1.Xoffset = int64(Array_nel) 952 var n4 Node 953 Regalloc(&n4, n1.Type, nil) 954 Thearch.Gmove(&n1, &n4) 955 Nodconst(&n2, Types[TUINT32], int64(v)) 956 Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n4, &n2) 957 Regfree(&n4) 958 p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1) 959 Ginscall(Panicindex, 0) 960 Patch(p1, Pc) 961 } 962 963 n1 = n3 964 n1.Op = OINDREG 965 n1.Type = Types[Tptr] 966 n1.Xoffset = int64(Array_array) 967 Thearch.Gmove(&n1, &n3) 968 } 969 970 Nodconst(&n2, Types[Tptr], int64(v*uint64(w))) 971 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 972 *a = n3 973 break 974 } 975 976 var n2 Node 977 Regalloc(&n2, Types[TINT32], &n1) // i 978 Thearch.Gmove(&n1, &n2) 979 Regfree(&n1) 980 981 var n4 Node 982 if Debug['B'] == 0 && !n.Bounded { 983 // check bounds 984 if Isconst(nl, CTSTR) { 985 Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.Sval))) 986 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 987 n1 = n3 988 n1.Op = OINDREG 989 n1.Type = Types[Tptr] 990 n1.Xoffset = int64(Array_nel) 991 Regalloc(&n4, Types[TUINT32], nil) 992 Thearch.Gmove(&n1, &n4) 993 } else { 994 Nodconst(&n4, Types[TUINT32], nl.Type.Bound) 995 } 996 997 Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n2, &n4) 998 if n4.Op == OREGISTER { 999 Regfree(&n4) 1000 } 1001 p1 := Gbranch(Thearch.Optoas(OLT, Types[TUINT32]), nil, +1) 1002 if p2 != nil { 1003 Patch(p2, Pc) 1004 } 1005 Ginscall(Panicindex, 0) 1006 Patch(p1, Pc) 1007 } 1008 1009 if Isconst(nl, CTSTR) { 1010 Regalloc(&n3, Types[Tptr], res) 1011 p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3) 1012 Datastring(nl.Val.U.Sval, &p1.From) 1013 p1.From.Type = obj.TYPE_ADDR 1014 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1015 n1 = n3 1016 n1.Op = OINDREG 1017 n1.Type = Types[Tptr] 1018 n1.Xoffset = int64(Array_array) 1019 Thearch.Gmove(&n1, &n3) 1020 } 1021 1022 if w == 0 { 1023 // nothing to do 1024 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) { 1025 // done by back end 1026 } else if w == 1 { 1027 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1028 } else { 1029 Regalloc(&n4, Types[TUINT32], nil) 1030 Nodconst(&n1, Types[TUINT32], int64(w)) 1031 Thearch.Gmove(&n1, &n4) 1032 Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2) 1033 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1034 Regfree(&n4) 1035 } 1036 *a = n3 1037 Regfree(&n2) 1038 break 1039 } 1040 if Ctxt.Arch.Thechar == '8' { 1041 var p2 *obj.Prog // to be patched to panicindex. 1042 w := uint32(n.Type.Width) 1043 bounded := Debug['B'] != 0 || n.Bounded 1044 var n3 Node 1045 var tmp Node 1046 var n1 Node 1047 if nr.Addable { 1048 // Generate &nl first, and move nr into register. 1049 if !Isconst(nl, CTSTR) { 1050 Igen(nl, &n3, res) 1051 } 1052 if !Isconst(nr, CTINT) { 1053 p2 = Thearch.Igenindex(nr, &tmp, bounded) 1054 Regalloc(&n1, tmp.Type, nil) 1055 Thearch.Gmove(&tmp, &n1) 1056 } 1057 } else if nl.Addable { 1058 // Generate nr first, and move &nl into register. 1059 if !Isconst(nr, CTINT) { 1060 p2 = Thearch.Igenindex(nr, &tmp, bounded) 1061 Regalloc(&n1, tmp.Type, nil) 1062 Thearch.Gmove(&tmp, &n1) 1063 } 1064 1065 if !Isconst(nl, CTSTR) { 1066 Igen(nl, &n3, res) 1067 } 1068 } else { 1069 p2 = Thearch.Igenindex(nr, &tmp, bounded) 1070 nr = &tmp 1071 if !Isconst(nl, CTSTR) { 1072 Igen(nl, &n3, res) 1073 } 1074 Regalloc(&n1, tmp.Type, nil) 1075 Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1) 1076 } 1077 1078 // For fixed array we really want the pointer in n3. 1079 var n2 Node 1080 if Isfixedarray(nl.Type) { 1081 Regalloc(&n2, Types[Tptr], &n3) 1082 Agen(&n3, &n2) 1083 Regfree(&n3) 1084 n3 = n2 1085 } 1086 1087 // &a[0] is in n3 (allocated in res) 1088 // i is in n1 (if not constant) 1089 // len(a) is in nlen (if needed) 1090 // w is width 1091 1092 // constant index 1093 if Isconst(nr, CTINT) { 1094 if Isconst(nl, CTSTR) { 1095 Fatal("constant string constant index") // front end should handle 1096 } 1097 v := uint64(Mpgetfix(nr.Val.U.Xval)) 1098 if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1099 if Debug['B'] == 0 && !n.Bounded { 1100 nlen := n3 1101 nlen.Type = Types[TUINT32] 1102 nlen.Xoffset += int64(Array_nel) 1103 Nodconst(&n2, Types[TUINT32], int64(v)) 1104 Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &nlen, &n2) 1105 p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1) 1106 Ginscall(Panicindex, -1) 1107 Patch(p1, Pc) 1108 } 1109 } 1110 1111 // Load base pointer in n2 = n3. 1112 Regalloc(&n2, Types[Tptr], &n3) 1113 1114 n3.Type = Types[Tptr] 1115 n3.Xoffset += int64(Array_array) 1116 Thearch.Gmove(&n3, &n2) 1117 Regfree(&n3) 1118 if v*uint64(w) != 0 { 1119 Nodconst(&n1, Types[Tptr], int64(v*uint64(w))) 1120 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n1, &n2) 1121 } 1122 *a = n2 1123 break 1124 } 1125 1126 // i is in register n1, extend to 32 bits. 1127 t := Types[TUINT32] 1128 1129 if Issigned[n1.Type.Etype] { 1130 t = Types[TINT32] 1131 } 1132 1133 Regalloc(&n2, t, &n1) // i 1134 Thearch.Gmove(&n1, &n2) 1135 Regfree(&n1) 1136 1137 if Debug['B'] == 0 && !n.Bounded { 1138 // check bounds 1139 t := Types[TUINT32] 1140 1141 var nlen Node 1142 if Isconst(nl, CTSTR) { 1143 Nodconst(&nlen, t, int64(len(nl.Val.U.Sval))) 1144 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1145 nlen = n3 1146 nlen.Type = t 1147 nlen.Xoffset += int64(Array_nel) 1148 } else { 1149 Nodconst(&nlen, t, nl.Type.Bound) 1150 } 1151 1152 Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen) 1153 p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1) 1154 if p2 != nil { 1155 Patch(p2, Pc) 1156 } 1157 Ginscall(Panicindex, -1) 1158 Patch(p1, Pc) 1159 } 1160 1161 if Isconst(nl, CTSTR) { 1162 Regalloc(&n3, Types[Tptr], res) 1163 p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3) 1164 Datastring(nl.Val.U.Sval, &p1.From) 1165 p1.From.Type = obj.TYPE_ADDR 1166 Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3) 1167 goto indexdone1 1168 } 1169 1170 // Load base pointer in n3. 1171 Regalloc(&tmp, Types[Tptr], &n3) 1172 1173 if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1174 n3.Type = Types[Tptr] 1175 n3.Xoffset += int64(Array_array) 1176 Thearch.Gmove(&n3, &tmp) 1177 } 1178 1179 Regfree(&n3) 1180 n3 = tmp 1181 1182 if w == 0 { 1183 // nothing to do 1184 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) { 1185 // done by back end 1186 } else if w == 1 { 1187 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1188 } else { 1189 Nodconst(&tmp, Types[TUINT32], int64(w)) 1190 Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &tmp, &n2) 1191 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1192 } 1193 1194 indexdone1: 1195 *a = n3 1196 Regfree(&n2) 1197 break 1198 } 1199 1200 freelen := 0 1201 w := uint64(n.Type.Width) 1202 1203 // Generate the non-addressable child first. 1204 var n3 Node 1205 var nlen Node 1206 var tmp Node 1207 var n1 Node 1208 if nr.Addable { 1209 goto irad 1210 } 1211 if nl.Addable { 1212 Cgenr(nr, &n1, nil) 1213 if !Isconst(nl, CTSTR) { 1214 if Isfixedarray(nl.Type) { 1215 Agenr(nl, &n3, res) 1216 } else { 1217 Igen(nl, &nlen, res) 1218 freelen = 1 1219 nlen.Type = Types[Tptr] 1220 nlen.Xoffset += int64(Array_array) 1221 Regalloc(&n3, Types[Tptr], res) 1222 Thearch.Gmove(&nlen, &n3) 1223 nlen.Type = Types[Simtype[TUINT]] 1224 nlen.Xoffset += int64(Array_nel) - int64(Array_array) 1225 } 1226 } 1227 1228 goto index 1229 } 1230 1231 Tempname(&tmp, nr.Type) 1232 Cgen(nr, &tmp) 1233 nr = &tmp 1234 1235 irad: 1236 if !Isconst(nl, CTSTR) { 1237 if Isfixedarray(nl.Type) { 1238 Agenr(nl, &n3, res) 1239 } else { 1240 if !nl.Addable { 1241 if res != nil && res.Op == OREGISTER { // give up res, which we don't need yet. 1242 Regfree(res) 1243 } 1244 1245 // igen will need an addressable node. 1246 var tmp2 Node 1247 Tempname(&tmp2, nl.Type) 1248 Cgen(nl, &tmp2) 1249 nl = &tmp2 1250 1251 if res != nil && res.Op == OREGISTER { // reacquire res 1252 Regrealloc(res) 1253 } 1254 } 1255 1256 Igen(nl, &nlen, res) 1257 freelen = 1 1258 nlen.Type = Types[Tptr] 1259 nlen.Xoffset += int64(Array_array) 1260 Regalloc(&n3, Types[Tptr], res) 1261 Thearch.Gmove(&nlen, &n3) 1262 nlen.Type = Types[Simtype[TUINT]] 1263 nlen.Xoffset += int64(Array_nel) - int64(Array_array) 1264 } 1265 } 1266 1267 if !Isconst(nr, CTINT) { 1268 Cgenr(nr, &n1, nil) 1269 } 1270 1271 goto index 1272 1273 // &a is in &n3 (allocated in res) 1274 // i is in &n1 (if not constant) 1275 // len(a) is in nlen (if needed) 1276 // w is width 1277 1278 // constant index 1279 index: 1280 if Isconst(nr, CTINT) { 1281 if Isconst(nl, CTSTR) { 1282 Fatal("constant string constant index") // front end should handle 1283 } 1284 v := uint64(Mpgetfix(nr.Val.U.Xval)) 1285 if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1286 if Debug['B'] == 0 && !n.Bounded { 1287 if nlen.Op != OREGISTER && (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') { 1288 var tmp2 Node 1289 Regalloc(&tmp2, Types[Simtype[TUINT]], nil) 1290 Thearch.Gmove(&nlen, &tmp2) 1291 Regfree(&nlen) // in case it is OINDREG 1292 nlen = tmp2 1293 } 1294 var n2 Node 1295 Nodconst(&n2, Types[Simtype[TUINT]], int64(v)) 1296 if Smallintconst(nr) { 1297 Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &n2) 1298 } else { 1299 Regalloc(&tmp, Types[Simtype[TUINT]], nil) 1300 Thearch.Gmove(&n2, &tmp) 1301 Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &tmp) 1302 Regfree(&tmp) 1303 } 1304 1305 p1 := Gbranch(Thearch.Optoas(OGT, Types[Simtype[TUINT]]), nil, +1) 1306 Ginscall(Panicindex, -1) 1307 Patch(p1, Pc) 1308 } 1309 1310 Regfree(&nlen) 1311 } 1312 1313 if v*w != 0 { 1314 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), int64(v*w), &n3) 1315 } 1316 *a = n3 1317 break 1318 } 1319 1320 // type of the index 1321 t := Types[TUINT64] 1322 1323 if Issigned[n1.Type.Etype] { 1324 t = Types[TINT64] 1325 } 1326 1327 var n2 Node 1328 Regalloc(&n2, t, &n1) // i 1329 Thearch.Gmove(&n1, &n2) 1330 Regfree(&n1) 1331 1332 if Debug['B'] == 0 && !n.Bounded { 1333 // check bounds 1334 t = Types[Simtype[TUINT]] 1335 1336 if Is64(nr.Type) { 1337 t = Types[TUINT64] 1338 } 1339 if Isconst(nl, CTSTR) { 1340 Nodconst(&nlen, t, int64(len(nl.Val.U.Sval))) 1341 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1342 if Is64(nr.Type) || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { 1343 var n5 Node 1344 Regalloc(&n5, t, nil) 1345 Thearch.Gmove(&nlen, &n5) 1346 Regfree(&nlen) 1347 nlen = n5 1348 } 1349 } else { 1350 Nodconst(&nlen, t, nl.Type.Bound) 1351 if !Smallintconst(&nlen) { 1352 var n5 Node 1353 Regalloc(&n5, t, nil) 1354 Thearch.Gmove(&nlen, &n5) 1355 nlen = n5 1356 freelen = 1 1357 } 1358 } 1359 1360 Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen) 1361 p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1) 1362 Ginscall(Panicindex, -1) 1363 Patch(p1, Pc) 1364 } 1365 1366 if Isconst(nl, CTSTR) { 1367 Regalloc(&n3, Types[Tptr], res) 1368 p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ! 1369 Datastring(nl.Val.U.Sval, &p1.From) 1370 p1.From.Type = obj.TYPE_ADDR 1371 Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3) 1372 goto indexdone 1373 } 1374 1375 if w == 0 { 1376 // nothing to do 1377 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) { 1378 // done by back end 1379 } else if w == 1 { 1380 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1381 } else { 1382 Thearch.Ginscon(Thearch.Optoas(OMUL, t), int64(w), &n2) 1383 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1384 } 1385 1386 indexdone: 1387 *a = n3 1388 Regfree(&n2) 1389 if freelen != 0 { 1390 Regfree(&nlen) 1391 } 1392 1393 default: 1394 Regalloc(a, Types[Tptr], res) 1395 Agen(n, a) 1396 } 1397 } 1398 1399 /* 1400 * generate: 1401 * res = &n; 1402 * The generated code checks that the result is not nil. 1403 */ 1404 func Agen(n *Node, res *Node) { 1405 if Debug['g'] != 0 { 1406 Dump("\nagen-res", res) 1407 Dump("agen-r", n) 1408 } 1409 1410 if n == nil || n.Type == nil { 1411 return 1412 } 1413 1414 for n.Op == OCONVNOP { 1415 n = n.Left 1416 } 1417 1418 if Isconst(n, CTNIL) && n.Type.Width > int64(Widthptr) { 1419 // Use of a nil interface or nil slice. 1420 // Create a temporary we can take the address of and read. 1421 // The generated code is just going to panic, so it need not 1422 // be terribly efficient. See issue 3670. 1423 var n1 Node 1424 Tempname(&n1, n.Type) 1425 1426 Gvardef(&n1) 1427 Thearch.Clearfat(&n1) 1428 var n2 Node 1429 Regalloc(&n2, Types[Tptr], res) 1430 var n3 Node 1431 n3.Op = OADDR 1432 n3.Left = &n1 1433 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n3, &n2) 1434 Thearch.Gmove(&n2, res) 1435 Regfree(&n2) 1436 return 1437 } 1438 1439 if n.Addable { 1440 if n.Op == OREGISTER { 1441 Fatal("agen OREGISTER") 1442 } 1443 var n1 Node 1444 n1.Op = OADDR 1445 n1.Left = n 1446 var n2 Node 1447 Regalloc(&n2, Types[Tptr], res) 1448 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n1, &n2) 1449 Thearch.Gmove(&n2, res) 1450 Regfree(&n2) 1451 return 1452 } 1453 1454 nl := n.Left 1455 1456 switch n.Op { 1457 default: 1458 Fatal("agen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign)) 1459 1460 case OCALLMETH: 1461 cgen_callmeth(n, 0) 1462 cgen_aret(n, res) 1463 1464 case OCALLINTER: 1465 cgen_callinter(n, res, 0) 1466 cgen_aret(n, res) 1467 1468 case OCALLFUNC: 1469 cgen_call(n, 0) 1470 cgen_aret(n, res) 1471 1472 case OEFACE, ODOTTYPE, OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: 1473 var n1 Node 1474 Tempname(&n1, n.Type) 1475 Cgen(n, &n1) 1476 Agen(&n1, res) 1477 1478 case OINDEX: 1479 var n1 Node 1480 Agenr(n, &n1, res) 1481 Thearch.Gmove(&n1, res) 1482 Regfree(&n1) 1483 1484 case ONAME: 1485 // should only get here with names in this func. 1486 if n.Funcdepth > 0 && n.Funcdepth != Funcdepth { 1487 Dump("bad agen", n) 1488 Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, Funcdepth) 1489 } 1490 1491 // should only get here for heap vars or paramref 1492 if n.Class&PHEAP == 0 && n.Class != PPARAMREF { 1493 Dump("bad agen", n) 1494 Fatal("agen: bad ONAME class %#x", n.Class) 1495 } 1496 1497 Cgen(n.Heapaddr, res) 1498 if n.Xoffset != 0 { 1499 addOffset(res, n.Xoffset) 1500 } 1501 1502 case OIND: 1503 Cgen(nl, res) 1504 Cgen_checknil(res) 1505 1506 case ODOT: 1507 Agen(nl, res) 1508 if n.Xoffset != 0 { 1509 addOffset(res, n.Xoffset) 1510 } 1511 1512 case ODOTPTR: 1513 Cgen(nl, res) 1514 Cgen_checknil(res) 1515 if n.Xoffset != 0 { 1516 addOffset(res, n.Xoffset) 1517 } 1518 } 1519 } 1520 1521 func addOffset(res *Node, offset int64) { 1522 if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' { 1523 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res) 1524 return 1525 } 1526 1527 var n1, n2 Node 1528 Regalloc(&n1, Types[Tptr], nil) 1529 Thearch.Gmove(res, &n1) 1530 Regalloc(&n2, Types[Tptr], nil) 1531 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), Nodintconst(offset), &n2) 1532 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n1) 1533 Thearch.Gmove(&n1, res) 1534 Regfree(&n1) 1535 Regfree(&n2) 1536 } 1537 1538 // Igen computes the address &n, stores it in a register r, 1539 // and rewrites a to refer to *r. The chosen r may be the 1540 // stack pointer, it may be borrowed from res, or it may 1541 // be a newly allocated register. The caller must call Regfree(a) 1542 // to free r when the address is no longer needed. 1543 // The generated code ensures that &n is not nil. 1544 func Igen(n *Node, a *Node, res *Node) { 1545 if Debug['g'] != 0 { 1546 Dump("\nigen-n", n) 1547 } 1548 1549 switch n.Op { 1550 case ONAME: 1551 if (n.Class&PHEAP != 0) || n.Class == PPARAMREF { 1552 break 1553 } 1554 *a = *n 1555 return 1556 1557 case OINDREG: 1558 // Increase the refcount of the register so that igen's caller 1559 // has to call Regfree. 1560 if n.Reg != int16(Thearch.REGSP) { 1561 reg[n.Reg-int16(Thearch.REGMIN)]++ 1562 } 1563 *a = *n 1564 return 1565 1566 case ODOT: 1567 Igen(n.Left, a, res) 1568 a.Xoffset += n.Xoffset 1569 a.Type = n.Type 1570 Fixlargeoffset(a) 1571 return 1572 1573 case ODOTPTR: 1574 Cgenr(n.Left, a, res) 1575 Cgen_checknil(a) 1576 a.Op = OINDREG 1577 a.Xoffset += n.Xoffset 1578 a.Type = n.Type 1579 Fixlargeoffset(a) 1580 return 1581 1582 case OCALLFUNC, OCALLMETH, OCALLINTER: 1583 switch n.Op { 1584 case OCALLFUNC: 1585 cgen_call(n, 0) 1586 1587 case OCALLMETH: 1588 cgen_callmeth(n, 0) 1589 1590 case OCALLINTER: 1591 cgen_callinter(n, nil, 0) 1592 } 1593 1594 var flist Iter 1595 fp := Structfirst(&flist, Getoutarg(n.Left.Type)) 1596 *a = Node{} 1597 a.Op = OINDREG 1598 a.Reg = int16(Thearch.REGSP) 1599 a.Addable = true 1600 a.Xoffset = fp.Width 1601 if HasLinkRegister() { 1602 a.Xoffset += int64(Ctxt.Arch.Ptrsize) 1603 } 1604 a.Type = n.Type 1605 return 1606 1607 // Index of fixed-size array by constant can 1608 // put the offset in the addressing. 1609 // Could do the same for slice except that we need 1610 // to use the real index for the bounds checking. 1611 case OINDEX: 1612 if Isfixedarray(n.Left.Type) || (Isptr[n.Left.Type.Etype] && Isfixedarray(n.Left.Left.Type)) { 1613 if Isconst(n.Right, CTINT) { 1614 // Compute &a. 1615 if !Isptr[n.Left.Type.Etype] { 1616 Igen(n.Left, a, res) 1617 } else { 1618 var n1 Node 1619 Igen(n.Left, &n1, res) 1620 Cgen_checknil(&n1) 1621 Regalloc(a, Types[Tptr], res) 1622 Thearch.Gmove(&n1, a) 1623 Regfree(&n1) 1624 a.Op = OINDREG 1625 } 1626 1627 // Compute &a[i] as &a + i*width. 1628 a.Type = n.Type 1629 1630 a.Xoffset += Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width 1631 Fixlargeoffset(a) 1632 return 1633 } 1634 } 1635 } 1636 1637 Agenr(n, a, res) 1638 a.Op = OINDREG 1639 a.Type = n.Type 1640 } 1641 1642 /* 1643 * generate: 1644 * if(n == true) goto to; 1645 */ 1646 func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) { 1647 if Debug['g'] != 0 { 1648 Dump("\nbgen", n) 1649 } 1650 1651 if n == nil { 1652 n = Nodbool(true) 1653 } 1654 1655 if n.Ninit != nil { 1656 Genlist(n.Ninit) 1657 } 1658 1659 if n.Type == nil { 1660 Convlit(&n, Types[TBOOL]) 1661 if n.Type == nil { 1662 return 1663 } 1664 } 1665 1666 et := int(n.Type.Etype) 1667 if et != TBOOL { 1668 Yyerror("cgen: bad type %v for %v", Tconv(n.Type, 0), Oconv(int(n.Op), 0)) 1669 Patch(Thearch.Gins(obj.AEND, nil, nil), to) 1670 return 1671 } 1672 1673 for n.Op == OCONVNOP { 1674 n = n.Left 1675 if n.Ninit != nil { 1676 Genlist(n.Ninit) 1677 } 1678 } 1679 1680 if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] { 1681 Thearch.Bgen_float(n, bool2int(true_), likely, to) 1682 return 1683 } 1684 1685 var nl *Node 1686 var nr *Node 1687 switch n.Op { 1688 default: 1689 goto def 1690 1691 // need to ask if it is bool? 1692 case OLITERAL: 1693 if true_ == n.Val.U.Bval { 1694 Patch(Gbranch(obj.AJMP, nil, likely), to) 1695 } 1696 return 1697 1698 case ONAME: 1699 if !n.Addable || Ctxt.Arch.Thechar == '5' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { 1700 goto def 1701 } 1702 var n1 Node 1703 Nodconst(&n1, n.Type, 0) 1704 Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &n1) 1705 a := Thearch.Optoas(ONE, n.Type) 1706 if !true_ { 1707 a = Thearch.Optoas(OEQ, n.Type) 1708 } 1709 Patch(Gbranch(a, n.Type, likely), to) 1710 return 1711 1712 case OANDAND, OOROR: 1713 if (n.Op == OANDAND) == true_ { 1714 p1 := Gbranch(obj.AJMP, nil, 0) 1715 p2 := Gbranch(obj.AJMP, nil, 0) 1716 Patch(p1, Pc) 1717 Bgen(n.Left, !true_, -likely, p2) 1718 Bgen(n.Right, !true_, -likely, p2) 1719 p1 = Gbranch(obj.AJMP, nil, 0) 1720 Patch(p1, to) 1721 Patch(p2, Pc) 1722 } else { 1723 Bgen(n.Left, true_, likely, to) 1724 Bgen(n.Right, true_, likely, to) 1725 } 1726 1727 return 1728 1729 case OEQ, ONE, OLT, OGT, OLE, OGE: 1730 nr = n.Right 1731 if nr == nil || nr.Type == nil { 1732 return 1733 } 1734 fallthrough 1735 1736 case ONOT: // unary 1737 nl = n.Left 1738 1739 if nl == nil || nl.Type == nil { 1740 return 1741 } 1742 } 1743 1744 switch n.Op { 1745 case ONOT: 1746 Bgen(nl, !true_, likely, to) 1747 return 1748 1749 case OEQ, ONE, OLT, OGT, OLE, OGE: 1750 a := int(n.Op) 1751 if !true_ { 1752 if Isfloat[nr.Type.Etype] { 1753 // brcom is not valid on floats when NaN is involved. 1754 p1 := Gbranch(obj.AJMP, nil, 0) 1755 p2 := Gbranch(obj.AJMP, nil, 0) 1756 Patch(p1, Pc) 1757 ll := n.Ninit // avoid re-genning ninit 1758 n.Ninit = nil 1759 Bgen(n, true, -likely, p2) 1760 n.Ninit = ll 1761 Patch(Gbranch(obj.AJMP, nil, 0), to) 1762 Patch(p2, Pc) 1763 return 1764 } 1765 1766 a = Brcom(a) 1767 true_ = !true_ 1768 } 1769 1770 // make simplest on right 1771 if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) { 1772 a = Brrev(a) 1773 r := nl 1774 nl = nr 1775 nr = r 1776 } 1777 1778 if Isslice(nl.Type) { 1779 // front end should only leave cmp to literal nil 1780 if (a != OEQ && a != ONE) || nr.Op != OLITERAL { 1781 Yyerror("illegal slice comparison") 1782 break 1783 } 1784 1785 a = Thearch.Optoas(a, Types[Tptr]) 1786 var n1 Node 1787 Igen(nl, &n1, nil) 1788 n1.Xoffset += int64(Array_array) 1789 n1.Type = Types[Tptr] 1790 var n2 Node 1791 Regalloc(&n2, Types[Tptr], &n1) 1792 Cgen(&n1, &n2) 1793 Regfree(&n1) 1794 var tmp Node 1795 Nodconst(&tmp, Types[Tptr], 0) 1796 Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp) 1797 Patch(Gbranch(a, Types[Tptr], likely), to) 1798 Regfree(&n2) 1799 break 1800 } 1801 1802 if Isinter(nl.Type) { 1803 // front end should only leave cmp to literal nil 1804 if (a != OEQ && a != ONE) || nr.Op != OLITERAL { 1805 Yyerror("illegal interface comparison") 1806 break 1807 } 1808 1809 a = Thearch.Optoas(a, Types[Tptr]) 1810 var n1 Node 1811 Igen(nl, &n1, nil) 1812 n1.Type = Types[Tptr] 1813 var n2 Node 1814 Regalloc(&n2, Types[Tptr], &n1) 1815 Cgen(&n1, &n2) 1816 Regfree(&n1) 1817 var tmp Node 1818 Nodconst(&tmp, Types[Tptr], 0) 1819 Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp) 1820 Patch(Gbranch(a, Types[Tptr], likely), to) 1821 Regfree(&n2) 1822 break 1823 } 1824 1825 if Iscomplex[nl.Type.Etype] { 1826 Complexbool(a, nl, nr, true_, likely, to) 1827 break 1828 } 1829 1830 if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) { 1831 if !nl.Addable || Isconst(nl, CTINT) { 1832 var n1 Node 1833 Tempname(&n1, nl.Type) 1834 Cgen(nl, &n1) 1835 nl = &n1 1836 } 1837 1838 if !nr.Addable { 1839 var n2 Node 1840 Tempname(&n2, nr.Type) 1841 Cgen(nr, &n2) 1842 nr = &n2 1843 } 1844 1845 Thearch.Cmp64(nl, nr, a, likely, to) 1846 break 1847 } 1848 1849 var n1 Node 1850 var n2 Node 1851 if nr.Ullman >= UINF { 1852 Regalloc(&n1, nl.Type, nil) 1853 Cgen(nl, &n1) 1854 1855 var tmp Node 1856 Tempname(&tmp, nl.Type) 1857 Thearch.Gmove(&n1, &tmp) 1858 Regfree(&n1) 1859 1860 Regalloc(&n2, nr.Type, nil) 1861 Cgen(nr, &n2) 1862 1863 Regalloc(&n1, nl.Type, nil) 1864 Cgen(&tmp, &n1) 1865 1866 goto cmp 1867 } 1868 1869 if !nl.Addable && Ctxt.Arch.Thechar == '8' { 1870 Tempname(&n1, nl.Type) 1871 } else { 1872 Regalloc(&n1, nl.Type, nil) 1873 } 1874 Cgen(nl, &n1) 1875 nl = &n1 1876 1877 if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' { 1878 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr) 1879 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 1880 if n1.Op == OREGISTER { 1881 Regfree(&n1) 1882 } 1883 break 1884 } 1885 1886 if !nr.Addable && Ctxt.Arch.Thechar == '8' { 1887 var tmp Node 1888 Tempname(&tmp, nr.Type) 1889 Cgen(nr, &tmp) 1890 nr = &tmp 1891 } 1892 1893 Regalloc(&n2, nr.Type, nil) 1894 Cgen(nr, &n2) 1895 nr = &n2 1896 1897 cmp: 1898 l, r := nl, nr 1899 // On x86, only < and <= work right with NaN; reverse if needed 1900 if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) { 1901 l, r = r, l 1902 a = Brrev(a) 1903 } 1904 1905 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r) 1906 1907 if Ctxt.Arch.Thechar == '6' && Isfloat[nr.Type.Etype] && (n.Op == OEQ || n.Op == ONE) { 1908 if n.Op == OEQ { 1909 // neither NE nor P 1910 p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely) 1911 p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely) 1912 Patch(Gbranch(obj.AJMP, nil, 0), to) 1913 Patch(p1, Pc) 1914 Patch(p2, Pc) 1915 } else { 1916 // either NE or P 1917 Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to) 1918 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to) 1919 } 1920 } else if Ctxt.Arch.Thechar == '5' && Isfloat[nl.Type.Etype] { 1921 if n.Op == ONE { 1922 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to) 1923 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 1924 } else { 1925 p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely) 1926 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 1927 Patch(p, Pc) 1928 } 1929 } else if (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') && Isfloat[nl.Type.Etype] && (a == OLE || a == OGE) { 1930 // On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =. 1931 if a == OLE { 1932 a = OLT 1933 } else { 1934 a = OGT 1935 } 1936 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 1937 Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to) 1938 } else { 1939 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 1940 } 1941 if n1.Op == OREGISTER { 1942 Regfree(&n1) 1943 } 1944 if n2.Op == OREGISTER { 1945 Regfree(&n2) 1946 } 1947 } 1948 1949 return 1950 1951 def: 1952 // TODO: Optimize on systems that can compare to zero easily. 1953 var n1 Node 1954 Regalloc(&n1, n.Type, nil) 1955 Cgen(n, &n1) 1956 var n2 Node 1957 Nodconst(&n2, n.Type, 0) 1958 Thearch.Gins(Thearch.Optoas(OCMP, n.Type), &n1, &n2) 1959 a := Thearch.Optoas(ONE, n.Type) 1960 if !true_ { 1961 a = Thearch.Optoas(OEQ, n.Type) 1962 } 1963 Patch(Gbranch(a, n.Type, likely), to) 1964 Regfree(&n1) 1965 return 1966 } 1967 1968 /* 1969 * n is on stack, either local variable 1970 * or return value from function call. 1971 * return n's offset from SP. 1972 */ 1973 func stkof(n *Node) int64 { 1974 switch n.Op { 1975 case OINDREG: 1976 return n.Xoffset 1977 1978 case ODOT: 1979 t := n.Left.Type 1980 if Isptr[t.Etype] { 1981 break 1982 } 1983 off := stkof(n.Left) 1984 if off == -1000 || off == 1000 { 1985 return off 1986 } 1987 return off + n.Xoffset 1988 1989 case OINDEX: 1990 t := n.Left.Type 1991 if !Isfixedarray(t) { 1992 break 1993 } 1994 off := stkof(n.Left) 1995 if off == -1000 || off == 1000 { 1996 return off 1997 } 1998 if Isconst(n.Right, CTINT) { 1999 return off + t.Type.Width*Mpgetfix(n.Right.Val.U.Xval) 2000 } 2001 return 1000 2002 2003 case OCALLMETH, OCALLINTER, OCALLFUNC: 2004 t := n.Left.Type 2005 if Isptr[t.Etype] { 2006 t = t.Type 2007 } 2008 2009 var flist Iter 2010 t = Structfirst(&flist, Getoutarg(t)) 2011 if t != nil { 2012 w := t.Width 2013 if HasLinkRegister() { 2014 w += int64(Ctxt.Arch.Ptrsize) 2015 } 2016 return w 2017 } 2018 } 2019 2020 // botch - probably failing to recognize address 2021 // arithmetic on the above. eg INDEX and DOT 2022 return -1000 2023 } 2024 2025 /* 2026 * block copy: 2027 * memmove(&ns, &n, w); 2028 */ 2029 func sgen(n *Node, ns *Node, w int64) { 2030 if Debug['g'] != 0 { 2031 fmt.Printf("\nsgen w=%d\n", w) 2032 Dump("r", n) 2033 Dump("res", ns) 2034 } 2035 2036 if n.Ullman >= UINF && ns.Ullman >= UINF { 2037 Fatal("sgen UINF") 2038 } 2039 2040 if w < 0 { 2041 Fatal("sgen copy %d", w) 2042 } 2043 2044 // If copying .args, that's all the results, so record definition sites 2045 // for them for the liveness analysis. 2046 if ns.Op == ONAME && ns.Sym.Name == ".args" { 2047 for l := Curfn.Func.Dcl; l != nil; l = l.Next { 2048 if l.N.Class == PPARAMOUT { 2049 Gvardef(l.N) 2050 } 2051 } 2052 } 2053 2054 // Avoid taking the address for simple enough types. 2055 if Componentgen(n, ns) { 2056 return 2057 } 2058 2059 if w == 0 { 2060 // evaluate side effects only 2061 var nodr Node 2062 Regalloc(&nodr, Types[Tptr], nil) 2063 Agen(ns, &nodr) 2064 Agen(n, &nodr) 2065 Regfree(&nodr) 2066 return 2067 } 2068 2069 // offset on the stack 2070 osrc := stkof(n) 2071 odst := stkof(ns) 2072 2073 if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) { 2074 // osrc and odst both on stack, and at least one is in 2075 // an unknown position. Could generate code to test 2076 // for forward/backward copy, but instead just copy 2077 // to a temporary location first. 2078 var tmp Node 2079 Tempname(&tmp, n.Type) 2080 sgen(n, &tmp, w) 2081 sgen(&tmp, ns, w) 2082 return 2083 } 2084 2085 Thearch.Stackcopy(n, ns, osrc, odst, w) 2086 } 2087 2088 /* 2089 * generate: 2090 * call f 2091 * proc=-1 normal call but no return 2092 * proc=0 normal call 2093 * proc=1 goroutine run in new proc 2094 * proc=2 defer call save away stack 2095 * proc=3 normal call to C pointer (not Go func value) 2096 */ 2097 func Ginscall(f *Node, proc int) { 2098 if f.Type != nil { 2099 extra := int32(0) 2100 if proc == 1 || proc == 2 { 2101 extra = 2 * int32(Widthptr) 2102 } 2103 Setmaxarg(f.Type, extra) 2104 } 2105 2106 switch proc { 2107 default: 2108 Fatal("Ginscall: bad proc %d", proc) 2109 2110 case 0, // normal call 2111 -1: // normal call but no return 2112 if f.Op == ONAME && f.Class == PFUNC { 2113 if f == Deferreturn { 2114 // Deferred calls will appear to be returning to 2115 // the CALL deferreturn(SB) that we are about to emit. 2116 // However, the stack trace code will show the line 2117 // of the instruction byte before the return PC. 2118 // To avoid that being an unrelated instruction, 2119 // insert an actual hardware NOP that will have the right line number. 2120 // This is different from obj.ANOP, which is a virtual no-op 2121 // that doesn't make it into the instruction stream. 2122 Thearch.Ginsnop() 2123 } 2124 2125 p := Thearch.Gins(obj.ACALL, nil, f) 2126 Afunclit(&p.To, f) 2127 if proc == -1 || Noreturn(p) { 2128 Thearch.Gins(obj.AUNDEF, nil, nil) 2129 } 2130 break 2131 } 2132 2133 var reg Node 2134 Nodreg(®, Types[Tptr], Thearch.REGCTXT) 2135 var r1 Node 2136 Nodreg(&r1, Types[Tptr], Thearch.REGCALLX) 2137 Thearch.Gmove(f, ®) 2138 reg.Op = OINDREG 2139 Thearch.Gmove(®, &r1) 2140 reg.Op = OREGISTER 2141 Thearch.Gins(obj.ACALL, ®, &r1) 2142 2143 case 3: // normal call of c function pointer 2144 Thearch.Gins(obj.ACALL, nil, f) 2145 2146 case 1, // call in new proc (go) 2147 2: // deferred call (defer) 2148 var stk Node 2149 2150 // size of arguments at 0(SP) 2151 stk.Op = OINDREG 2152 stk.Reg = int16(Thearch.REGSP) 2153 stk.Xoffset = 0 2154 if HasLinkRegister() { 2155 stk.Xoffset += int64(Ctxt.Arch.Ptrsize) 2156 } 2157 Thearch.Ginscon(Thearch.Optoas(OAS, Types[Tptr]), int64(Argsize(f.Type)), &stk) 2158 2159 // FuncVal* at 8(SP) 2160 stk.Xoffset = int64(Widthptr) 2161 if HasLinkRegister() { 2162 stk.Xoffset += int64(Ctxt.Arch.Ptrsize) 2163 } 2164 2165 var reg Node 2166 Nodreg(®, Types[Tptr], Thearch.REGCALLX2) 2167 Thearch.Gmove(f, ®) 2168 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), ®, &stk) 2169 2170 if proc == 1 { 2171 Ginscall(Newproc, 0) 2172 } else { 2173 if Hasdefer == 0 { 2174 Fatal("hasdefer=0 but has defer") 2175 } 2176 Ginscall(Deferproc, 0) 2177 } 2178 2179 if proc == 2 { 2180 Nodreg(®, Types[TINT32], Thearch.REGRETURN) 2181 Thearch.Gins(Thearch.Optoas(OCMP, Types[TINT32]), ®, Nodintconst(0)) 2182 p := Gbranch(Thearch.Optoas(OEQ, Types[TINT32]), nil, +1) 2183 cgen_ret(nil) 2184 Patch(p, Pc) 2185 } 2186 } 2187 } 2188 2189 /* 2190 * n is call to interface method. 2191 * generate res = n. 2192 */ 2193 func cgen_callinter(n *Node, res *Node, proc int) { 2194 i := n.Left 2195 if i.Op != ODOTINTER { 2196 Fatal("cgen_callinter: not ODOTINTER %v", Oconv(int(i.Op), 0)) 2197 } 2198 2199 f := i.Right // field 2200 if f.Op != ONAME { 2201 Fatal("cgen_callinter: not ONAME %v", Oconv(int(f.Op), 0)) 2202 } 2203 2204 i = i.Left // interface 2205 2206 if !i.Addable { 2207 var tmpi Node 2208 Tempname(&tmpi, i.Type) 2209 Cgen(i, &tmpi) 2210 i = &tmpi 2211 } 2212 2213 Genlist(n.List) // assign the args 2214 2215 // i is now addable, prepare an indirected 2216 // register to hold its address. 2217 var nodi Node 2218 Igen(i, &nodi, res) // REG = &inter 2219 2220 var nodsp Node 2221 Nodindreg(&nodsp, Types[Tptr], Thearch.REGSP) 2222 nodsp.Xoffset = 0 2223 if HasLinkRegister() { 2224 nodsp.Xoffset += int64(Ctxt.Arch.Ptrsize) 2225 } 2226 if proc != 0 { 2227 nodsp.Xoffset += 2 * int64(Widthptr) // leave room for size & fn 2228 } 2229 nodi.Type = Types[Tptr] 2230 nodi.Xoffset += int64(Widthptr) 2231 Cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data 2232 2233 var nodo Node 2234 Regalloc(&nodo, Types[Tptr], res) 2235 2236 nodi.Type = Types[Tptr] 2237 nodi.Xoffset -= int64(Widthptr) 2238 Cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab 2239 Regfree(&nodi) 2240 2241 var nodr Node 2242 Regalloc(&nodr, Types[Tptr], &nodo) 2243 if n.Left.Xoffset == BADWIDTH { 2244 Fatal("cgen_callinter: badwidth") 2245 } 2246 Cgen_checknil(&nodo) // in case offset is huge 2247 nodo.Op = OINDREG 2248 nodo.Xoffset = n.Left.Xoffset + 3*int64(Widthptr) + 8 2249 if proc == 0 { 2250 // plain call: use direct c function pointer - more efficient 2251 Cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f] 2252 proc = 3 2253 } else { 2254 // go/defer. generate go func value. 2255 Agen(&nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f] 2256 } 2257 2258 nodr.Type = n.Left.Type 2259 Ginscall(&nodr, proc) 2260 2261 Regfree(&nodr) 2262 Regfree(&nodo) 2263 } 2264 2265 /* 2266 * generate function call; 2267 * proc=0 normal call 2268 * proc=1 goroutine run in new proc 2269 * proc=2 defer call save away stack 2270 */ 2271 func cgen_call(n *Node, proc int) { 2272 if n == nil { 2273 return 2274 } 2275 2276 var afun Node 2277 if n.Left.Ullman >= UINF { 2278 // if name involves a fn call 2279 // precompute the address of the fn 2280 Tempname(&afun, Types[Tptr]) 2281 2282 Cgen(n.Left, &afun) 2283 } 2284 2285 Genlist(n.List) // assign the args 2286 t := n.Left.Type 2287 2288 // call tempname pointer 2289 if n.Left.Ullman >= UINF { 2290 var nod Node 2291 Regalloc(&nod, Types[Tptr], nil) 2292 Cgen_as(&nod, &afun) 2293 nod.Type = t 2294 Ginscall(&nod, proc) 2295 Regfree(&nod) 2296 return 2297 } 2298 2299 // call pointer 2300 if n.Left.Op != ONAME || n.Left.Class != PFUNC { 2301 var nod Node 2302 Regalloc(&nod, Types[Tptr], nil) 2303 Cgen_as(&nod, n.Left) 2304 nod.Type = t 2305 Ginscall(&nod, proc) 2306 Regfree(&nod) 2307 return 2308 } 2309 2310 // call direct 2311 n.Left.Method = true 2312 2313 Ginscall(n.Left, proc) 2314 } 2315 2316 func HasLinkRegister() bool { 2317 c := Ctxt.Arch.Thechar 2318 return c != '6' && c != '8' 2319 } 2320 2321 /* 2322 * call to n has already been generated. 2323 * generate: 2324 * res = return value from call. 2325 */ 2326 func cgen_callret(n *Node, res *Node) { 2327 t := n.Left.Type 2328 if t.Etype == TPTR32 || t.Etype == TPTR64 { 2329 t = t.Type 2330 } 2331 2332 var flist Iter 2333 fp := Structfirst(&flist, Getoutarg(t)) 2334 if fp == nil { 2335 Fatal("cgen_callret: nil") 2336 } 2337 2338 var nod Node 2339 nod.Op = OINDREG 2340 nod.Reg = int16(Thearch.REGSP) 2341 nod.Addable = true 2342 2343 nod.Xoffset = fp.Width 2344 if HasLinkRegister() { 2345 nod.Xoffset += int64(Ctxt.Arch.Ptrsize) 2346 } 2347 nod.Type = fp.Type 2348 Cgen_as(res, &nod) 2349 } 2350 2351 /* 2352 * call to n has already been generated. 2353 * generate: 2354 * res = &return value from call. 2355 */ 2356 func cgen_aret(n *Node, res *Node) { 2357 t := n.Left.Type 2358 if Isptr[t.Etype] { 2359 t = t.Type 2360 } 2361 2362 var flist Iter 2363 fp := Structfirst(&flist, Getoutarg(t)) 2364 if fp == nil { 2365 Fatal("cgen_aret: nil") 2366 } 2367 2368 var nod1 Node 2369 nod1.Op = OINDREG 2370 nod1.Reg = int16(Thearch.REGSP) 2371 nod1.Addable = true 2372 nod1.Xoffset = fp.Width 2373 if HasLinkRegister() { 2374 nod1.Xoffset += int64(Ctxt.Arch.Ptrsize) 2375 } 2376 nod1.Type = fp.Type 2377 2378 if res.Op != OREGISTER { 2379 var nod2 Node 2380 Regalloc(&nod2, Types[Tptr], res) 2381 Agen(&nod1, &nod2) 2382 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &nod2, res) 2383 Regfree(&nod2) 2384 } else { 2385 Agen(&nod1, res) 2386 } 2387 } 2388 2389 /* 2390 * generate return. 2391 * n->left is assignments to return values. 2392 */ 2393 func cgen_ret(n *Node) { 2394 if n != nil { 2395 Genlist(n.List) // copy out args 2396 } 2397 if Hasdefer != 0 { 2398 Ginscall(Deferreturn, 0) 2399 } 2400 Genlist(Curfn.Func.Exit) 2401 p := Thearch.Gins(obj.ARET, nil, nil) 2402 if n != nil && n.Op == ORETJMP { 2403 p.To.Type = obj.TYPE_MEM 2404 p.To.Name = obj.NAME_EXTERN 2405 p.To.Sym = Linksym(n.Left.Sym) 2406 } 2407 } 2408 2409 /* 2410 * generate division according to op, one of: 2411 * res = nl / nr 2412 * res = nl % nr 2413 */ 2414 func cgen_div(op int, nl *Node, nr *Node, res *Node) { 2415 var w int 2416 2417 // TODO(rsc): arm64 needs to support the relevant instructions 2418 // in peep and optoas in order to enable this. 2419 // TODO(rsc): ppc64 needs to support the relevant instructions 2420 // in peep and optoas in order to enable this. 2421 if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { 2422 goto longdiv 2423 } 2424 w = int(nl.Type.Width * 8) 2425 2426 // Front end handled 32-bit division. We only need to handle 64-bit. 2427 // try to do division by multiply by (2^w)/d 2428 // see hacker's delight chapter 10 2429 switch Simtype[nl.Type.Etype] { 2430 default: 2431 goto longdiv 2432 2433 case TUINT64: 2434 var m Magic 2435 m.W = w 2436 m.Ud = uint64(Mpgetfix(nr.Val.U.Xval)) 2437 Umagic(&m) 2438 if m.Bad != 0 { 2439 break 2440 } 2441 if op == OMOD { 2442 goto longmod 2443 } 2444 2445 var n1 Node 2446 Cgenr(nl, &n1, nil) 2447 var n2 Node 2448 Nodconst(&n2, nl.Type, int64(m.Um)) 2449 var n3 Node 2450 Regalloc(&n3, nl.Type, res) 2451 Thearch.Cgen_hmul(&n1, &n2, &n3) 2452 2453 if m.Ua != 0 { 2454 // need to add numerator accounting for overflow 2455 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3) 2456 2457 Nodconst(&n2, nl.Type, 1) 2458 Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3) 2459 Nodconst(&n2, nl.Type, int64(m.S)-1) 2460 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) 2461 } else { 2462 Nodconst(&n2, nl.Type, int64(m.S)) 2463 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift dx 2464 } 2465 2466 Thearch.Gmove(&n3, res) 2467 Regfree(&n1) 2468 Regfree(&n3) 2469 return 2470 2471 case TINT64: 2472 var m Magic 2473 m.W = w 2474 m.Sd = Mpgetfix(nr.Val.U.Xval) 2475 Smagic(&m) 2476 if m.Bad != 0 { 2477 break 2478 } 2479 if op == OMOD { 2480 goto longmod 2481 } 2482 2483 var n1 Node 2484 Cgenr(nl, &n1, res) 2485 var n2 Node 2486 Nodconst(&n2, nl.Type, m.Sm) 2487 var n3 Node 2488 Regalloc(&n3, nl.Type, nil) 2489 Thearch.Cgen_hmul(&n1, &n2, &n3) 2490 2491 if m.Sm < 0 { 2492 // need to add numerator 2493 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3) 2494 } 2495 2496 Nodconst(&n2, nl.Type, int64(m.S)) 2497 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift n3 2498 2499 Nodconst(&n2, nl.Type, int64(w)-1) 2500 2501 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n1) // -1 iff num is neg 2502 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n1, &n3) // added 2503 2504 if m.Sd < 0 { 2505 // this could probably be removed 2506 // by factoring it into the multiplier 2507 Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3) 2508 } 2509 2510 Thearch.Gmove(&n3, res) 2511 Regfree(&n1) 2512 Regfree(&n3) 2513 return 2514 } 2515 2516 goto longdiv 2517 2518 // division and mod using (slow) hardware instruction 2519 longdiv: 2520 Thearch.Dodiv(op, nl, nr, res) 2521 2522 return 2523 2524 // mod using formula A%B = A-(A/B*B) but 2525 // we know that there is a fast algorithm for A/B 2526 longmod: 2527 var n1 Node 2528 Regalloc(&n1, nl.Type, res) 2529 2530 Cgen(nl, &n1) 2531 var n2 Node 2532 Regalloc(&n2, nl.Type, nil) 2533 cgen_div(ODIV, &n1, nr, &n2) 2534 a := Thearch.Optoas(OMUL, nl.Type) 2535 if w == 8 { 2536 // use 2-operand 16-bit multiply 2537 // because there is no 2-operand 8-bit multiply 2538 a = Thearch.Optoas(OMUL, Types[TINT16]) // XXX was IMULW 2539 } 2540 2541 if !Smallintconst(nr) { 2542 var n3 Node 2543 Regalloc(&n3, nl.Type, nil) 2544 Cgen(nr, &n3) 2545 Thearch.Gins(a, &n3, &n2) 2546 Regfree(&n3) 2547 } else { 2548 Thearch.Gins(a, nr, &n2) 2549 } 2550 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n2, &n1) 2551 Thearch.Gmove(&n1, res) 2552 Regfree(&n1) 2553 Regfree(&n2) 2554 } 2555 2556 func Fixlargeoffset(n *Node) { 2557 if n == nil { 2558 return 2559 } 2560 if n.Op != OINDREG { 2561 return 2562 } 2563 if n.Reg == int16(Thearch.REGSP) { // stack offset cannot be large 2564 return 2565 } 2566 if n.Xoffset != int64(int32(n.Xoffset)) { 2567 // offset too large, add to register instead. 2568 a := *n 2569 2570 a.Op = OREGISTER 2571 a.Type = Types[Tptr] 2572 a.Xoffset = 0 2573 Cgen_checknil(&a) 2574 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), n.Xoffset, &a) 2575 n.Xoffset = 0 2576 } 2577 }