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