github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/zz2 (about) 1 // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/zz2 2 3 //line /Users/rsc/g/go/src/cmd/internal/gc/zz2: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 func cgen_wbptr(n, res *Node) { 792 if Debug_wb > 0 { 793 Warn("write barrier") 794 } 795 var dst, src Node 796 Igen(res, &dst, nil) 797 Cgenr(n, &src, nil) 798 Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), syslook("gcphase", 0), Nodintconst(0)) 799 pbr := Gbranch(Thearch.Optoas(ONE, Types[TUINT32]), nil, -1) 800 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst) 801 pjmp := Gbranch(obj.AJMP, nil, 0) 802 Patch(pbr, Pc) 803 var adst Node 804 Agenr(&dst, &adst, &dst) 805 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &adst, nil) 806 a := &p.To 807 a.Type = obj.TYPE_MEM 808 a.Reg = int16(Thearch.REGSP) 809 a.Offset = 0 810 if HasLinkRegister() { 811 a.Offset += int64(Ctxt.Arch.Ptrsize) 812 } 813 p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil) 814 p2.To = p.To 815 p2.To.Offset += int64(Widthptr) 816 Regfree(&adst) 817 Regfree(&dst) 818 Regfree(&src) 819 Ginscall(syslook("writebarrierptr", 0), 0) 820 Patch(pjmp, Pc) 821 } 822 823 func cgen_wbfat(n, res *Node) { 824 if Debug_wb > 0 { 825 Warn("write barrier") 826 } 827 needType := true 828 funcName := "typedmemmove" 829 var dst, src Node 830 if n.Ullman >= res.Ullman { 831 Agenr(n, &src, nil) 832 Agenr(res, &dst, nil) 833 } else { 834 Agenr(res, &dst, nil) 835 Agenr(n, &src, nil) 836 } 837 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &dst, nil) 838 a := &p.To 839 a.Type = obj.TYPE_MEM 840 a.Reg = int16(Thearch.REGSP) 841 a.Offset = 0 842 if HasLinkRegister() { 843 a.Offset += int64(Widthptr) 844 } 845 p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil) 846 p2.To = p.To 847 p2.To.Offset += int64(Widthptr) 848 Regfree(&dst) 849 Regfree(&src) 850 if needType { 851 p3 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), typename(n.Type), nil) 852 p3.To = p2.To 853 p3.To.Offset += int64(Widthptr) 854 } 855 Ginscall(syslook(funcName, 0), 0) 856 } 857 858 // cgen_norm moves n1 to res, truncating to expected type if necessary. 859 // n1 is a register, and cgen_norm frees it. 860 func cgen_norm(n, n1, res *Node) { 861 switch Ctxt.Arch.Thechar { 862 case '6', '8': 863 // We use sized math, so the result is already truncated. 864 default: 865 switch n.Op { 866 case OADD, OSUB, OMUL, ODIV, OCOM, OMINUS: 867 // TODO(rsc): What about left shift? 868 Thearch.Gins(Thearch.Optoas(OAS, n.Type), n1, n1) 869 } 870 } 871 872 Thearch.Gmove(n1, res) 873 Regfree(n1) 874 } 875 876 func Mgen(n *Node, n1 *Node, rg *Node) { 877 n1.Op = OEMPTY 878 879 if n.Addable { 880 *n1 = *n 881 if n1.Op == OREGISTER || n1.Op == OINDREG { 882 reg[n.Reg-int16(Thearch.REGMIN)]++ 883 } 884 return 885 } 886 887 Tempname(n1, n.Type) 888 Cgen(n, n1) 889 if n.Type.Width <= int64(Widthptr) || Isfloat[n.Type.Etype] { 890 n2 := *n1 891 Regalloc(n1, n.Type, rg) 892 Thearch.Gmove(&n2, n1) 893 } 894 } 895 896 func Mfree(n *Node) { 897 if n.Op == OREGISTER { 898 Regfree(n) 899 } 900 } 901 902 /* 903 * allocate a register (reusing res if possible) and generate 904 * a = n 905 * The caller must call Regfree(a). 906 */ 907 func Cgenr(n *Node, a *Node, res *Node) { 908 if Debug['g'] != 0 { 909 Dump("cgenr-n", n) 910 } 911 912 if Isfat(n.Type) { 913 Fatal("cgenr on fat node") 914 } 915 916 if n.Addable { 917 Regalloc(a, n.Type, res) 918 Thearch.Gmove(n, a) 919 return 920 } 921 922 switch n.Op { 923 case ONAME, 924 ODOT, 925 ODOTPTR, 926 OINDEX, 927 OCALLFUNC, 928 OCALLMETH, 929 OCALLINTER: 930 var n1 Node 931 Igen(n, &n1, res) 932 Regalloc(a, Types[Tptr], &n1) 933 Thearch.Gmove(&n1, a) 934 Regfree(&n1) 935 936 default: 937 Regalloc(a, n.Type, res) 938 Cgen(n, a) 939 } 940 } 941 942 /* 943 * allocate a register (reusing res if possible) and generate 944 * a = &n 945 * The caller must call Regfree(a). 946 * The generated code checks that the result is not nil. 947 */ 948 func Agenr(n *Node, a *Node, res *Node) { 949 if Debug['g'] != 0 { 950 Dump("\nagenr-n", n) 951 } 952 953 nl := n.Left 954 nr := n.Right 955 956 switch n.Op { 957 case ODOT, ODOTPTR, OCALLFUNC, OCALLMETH, OCALLINTER: 958 var n1 Node 959 Igen(n, &n1, res) 960 Regalloc(a, Types[Tptr], &n1) 961 Agen(&n1, a) 962 Regfree(&n1) 963 964 case OIND: 965 Cgenr(n.Left, a, res) 966 Cgen_checknil(a) 967 968 case OINDEX: 969 if Ctxt.Arch.Thechar == '5' { 970 var p2 *obj.Prog // to be patched to panicindex. 971 w := uint32(n.Type.Width) 972 bounded := Debug['B'] != 0 || n.Bounded 973 var n1 Node 974 var n3 Node 975 if nr.Addable { 976 var tmp Node 977 if !Isconst(nr, CTINT) { 978 Tempname(&tmp, Types[TINT32]) 979 } 980 if !Isconst(nl, CTSTR) { 981 Agenr(nl, &n3, res) 982 } 983 if !Isconst(nr, CTINT) { 984 p2 = Thearch.Cgenindex(nr, &tmp, bounded) 985 Regalloc(&n1, tmp.Type, nil) 986 Thearch.Gmove(&tmp, &n1) 987 } 988 } else if nl.Addable { 989 if !Isconst(nr, CTINT) { 990 var tmp Node 991 Tempname(&tmp, Types[TINT32]) 992 p2 = Thearch.Cgenindex(nr, &tmp, bounded) 993 Regalloc(&n1, tmp.Type, nil) 994 Thearch.Gmove(&tmp, &n1) 995 } 996 997 if !Isconst(nl, CTSTR) { 998 Agenr(nl, &n3, res) 999 } 1000 } else { 1001 var tmp Node 1002 Tempname(&tmp, Types[TINT32]) 1003 p2 = Thearch.Cgenindex(nr, &tmp, bounded) 1004 nr = &tmp 1005 if !Isconst(nl, CTSTR) { 1006 Agenr(nl, &n3, res) 1007 } 1008 Regalloc(&n1, tmp.Type, nil) 1009 Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1) 1010 } 1011 1012 // &a is in &n3 (allocated in res) 1013 // i is in &n1 (if not constant) 1014 // w is width 1015 1016 // constant index 1017 if Isconst(nr, CTINT) { 1018 if Isconst(nl, CTSTR) { 1019 Fatal("constant string constant index") 1020 } 1021 v := uint64(Mpgetfix(nr.Val.U.Xval)) 1022 var n2 Node 1023 if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1024 if Debug['B'] == 0 && !n.Bounded { 1025 n1 = n3 1026 n1.Op = OINDREG 1027 n1.Type = Types[Tptr] 1028 n1.Xoffset = int64(Array_nel) 1029 var n4 Node 1030 Regalloc(&n4, n1.Type, nil) 1031 Thearch.Gmove(&n1, &n4) 1032 Nodconst(&n2, Types[TUINT32], int64(v)) 1033 Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n4, &n2) 1034 Regfree(&n4) 1035 p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1) 1036 Ginscall(Panicindex, 0) 1037 Patch(p1, Pc) 1038 } 1039 1040 n1 = n3 1041 n1.Op = OINDREG 1042 n1.Type = Types[Tptr] 1043 n1.Xoffset = int64(Array_array) 1044 Thearch.Gmove(&n1, &n3) 1045 } 1046 1047 Nodconst(&n2, Types[Tptr], int64(v*uint64(w))) 1048 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1049 *a = n3 1050 break 1051 } 1052 1053 var n2 Node 1054 Regalloc(&n2, Types[TINT32], &n1) // i 1055 Thearch.Gmove(&n1, &n2) 1056 Regfree(&n1) 1057 1058 var n4 Node 1059 if Debug['B'] == 0 && !n.Bounded { 1060 // check bounds 1061 if Isconst(nl, CTSTR) { 1062 Nodconst(&n4, Types[TUINT32], int64(len(nl.Val.U.Sval))) 1063 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1064 n1 = n3 1065 n1.Op = OINDREG 1066 n1.Type = Types[Tptr] 1067 n1.Xoffset = int64(Array_nel) 1068 Regalloc(&n4, Types[TUINT32], nil) 1069 Thearch.Gmove(&n1, &n4) 1070 } else { 1071 Nodconst(&n4, Types[TUINT32], nl.Type.Bound) 1072 } 1073 1074 Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &n2, &n4) 1075 if n4.Op == OREGISTER { 1076 Regfree(&n4) 1077 } 1078 p1 := Gbranch(Thearch.Optoas(OLT, Types[TUINT32]), nil, +1) 1079 if p2 != nil { 1080 Patch(p2, Pc) 1081 } 1082 Ginscall(Panicindex, 0) 1083 Patch(p1, Pc) 1084 } 1085 1086 if Isconst(nl, CTSTR) { 1087 Regalloc(&n3, Types[Tptr], res) 1088 p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3) 1089 Datastring(nl.Val.U.Sval, &p1.From) 1090 p1.From.Type = obj.TYPE_ADDR 1091 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1092 n1 = n3 1093 n1.Op = OINDREG 1094 n1.Type = Types[Tptr] 1095 n1.Xoffset = int64(Array_array) 1096 Thearch.Gmove(&n1, &n3) 1097 } 1098 1099 if w == 0 { 1100 // nothing to do 1101 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) { 1102 // done by back end 1103 } else if w == 1 { 1104 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1105 } else { 1106 Regalloc(&n4, Types[TUINT32], nil) 1107 Nodconst(&n1, Types[TUINT32], int64(w)) 1108 Thearch.Gmove(&n1, &n4) 1109 Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2) 1110 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1111 Regfree(&n4) 1112 } 1113 *a = n3 1114 Regfree(&n2) 1115 break 1116 } 1117 if Ctxt.Arch.Thechar == '8' { 1118 var p2 *obj.Prog // to be patched to panicindex. 1119 w := uint32(n.Type.Width) 1120 bounded := Debug['B'] != 0 || n.Bounded 1121 var n3 Node 1122 var tmp Node 1123 var n1 Node 1124 if nr.Addable { 1125 // Generate &nl first, and move nr into register. 1126 if !Isconst(nl, CTSTR) { 1127 Igen(nl, &n3, res) 1128 } 1129 if !Isconst(nr, CTINT) { 1130 p2 = Thearch.Igenindex(nr, &tmp, bounded) 1131 Regalloc(&n1, tmp.Type, nil) 1132 Thearch.Gmove(&tmp, &n1) 1133 } 1134 } else if nl.Addable { 1135 // Generate nr first, and move &nl into register. 1136 if !Isconst(nr, CTINT) { 1137 p2 = Thearch.Igenindex(nr, &tmp, bounded) 1138 Regalloc(&n1, tmp.Type, nil) 1139 Thearch.Gmove(&tmp, &n1) 1140 } 1141 1142 if !Isconst(nl, CTSTR) { 1143 Igen(nl, &n3, res) 1144 } 1145 } else { 1146 p2 = Thearch.Igenindex(nr, &tmp, bounded) 1147 nr = &tmp 1148 if !Isconst(nl, CTSTR) { 1149 Igen(nl, &n3, res) 1150 } 1151 Regalloc(&n1, tmp.Type, nil) 1152 Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1) 1153 } 1154 1155 // For fixed array we really want the pointer in n3. 1156 var n2 Node 1157 if Isfixedarray(nl.Type) { 1158 Regalloc(&n2, Types[Tptr], &n3) 1159 Agen(&n3, &n2) 1160 Regfree(&n3) 1161 n3 = n2 1162 } 1163 1164 // &a[0] is in n3 (allocated in res) 1165 // i is in n1 (if not constant) 1166 // len(a) is in nlen (if needed) 1167 // w is width 1168 1169 // constant index 1170 if Isconst(nr, CTINT) { 1171 if Isconst(nl, CTSTR) { 1172 Fatal("constant string constant index") // front end should handle 1173 } 1174 v := uint64(Mpgetfix(nr.Val.U.Xval)) 1175 if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1176 if Debug['B'] == 0 && !n.Bounded { 1177 nlen := n3 1178 nlen.Type = Types[TUINT32] 1179 nlen.Xoffset += int64(Array_nel) 1180 Nodconst(&n2, Types[TUINT32], int64(v)) 1181 Thearch.Gins(Thearch.Optoas(OCMP, Types[TUINT32]), &nlen, &n2) 1182 p1 := Gbranch(Thearch.Optoas(OGT, Types[TUINT32]), nil, +1) 1183 Ginscall(Panicindex, -1) 1184 Patch(p1, Pc) 1185 } 1186 } 1187 1188 // Load base pointer in n2 = n3. 1189 Regalloc(&n2, Types[Tptr], &n3) 1190 1191 n3.Type = Types[Tptr] 1192 n3.Xoffset += int64(Array_array) 1193 Thearch.Gmove(&n3, &n2) 1194 Regfree(&n3) 1195 if v*uint64(w) != 0 { 1196 Nodconst(&n1, Types[Tptr], int64(v*uint64(w))) 1197 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n1, &n2) 1198 } 1199 *a = n2 1200 break 1201 } 1202 1203 // i is in register n1, extend to 32 bits. 1204 t := Types[TUINT32] 1205 1206 if Issigned[n1.Type.Etype] { 1207 t = Types[TINT32] 1208 } 1209 1210 Regalloc(&n2, t, &n1) // i 1211 Thearch.Gmove(&n1, &n2) 1212 Regfree(&n1) 1213 1214 if Debug['B'] == 0 && !n.Bounded { 1215 // check bounds 1216 t := Types[TUINT32] 1217 1218 var nlen Node 1219 if Isconst(nl, CTSTR) { 1220 Nodconst(&nlen, t, int64(len(nl.Val.U.Sval))) 1221 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1222 nlen = n3 1223 nlen.Type = t 1224 nlen.Xoffset += int64(Array_nel) 1225 } else { 1226 Nodconst(&nlen, t, nl.Type.Bound) 1227 } 1228 1229 Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen) 1230 p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1) 1231 if p2 != nil { 1232 Patch(p2, Pc) 1233 } 1234 Ginscall(Panicindex, -1) 1235 Patch(p1, Pc) 1236 } 1237 1238 if Isconst(nl, CTSTR) { 1239 Regalloc(&n3, Types[Tptr], res) 1240 p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3) 1241 Datastring(nl.Val.U.Sval, &p1.From) 1242 p1.From.Type = obj.TYPE_ADDR 1243 Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3) 1244 goto indexdone1 1245 } 1246 1247 // Load base pointer in n3. 1248 Regalloc(&tmp, Types[Tptr], &n3) 1249 1250 if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1251 n3.Type = Types[Tptr] 1252 n3.Xoffset += int64(Array_array) 1253 Thearch.Gmove(&n3, &tmp) 1254 } 1255 1256 Regfree(&n3) 1257 n3 = tmp 1258 1259 if w == 0 { 1260 // nothing to do 1261 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) { 1262 // done by back end 1263 } else if w == 1 { 1264 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1265 } else { 1266 Nodconst(&tmp, Types[TUINT32], int64(w)) 1267 Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &tmp, &n2) 1268 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1269 } 1270 1271 indexdone1: 1272 *a = n3 1273 Regfree(&n2) 1274 break 1275 } 1276 1277 freelen := 0 1278 w := uint64(n.Type.Width) 1279 1280 // Generate the non-addressable child first. 1281 var n3 Node 1282 var nlen Node 1283 var tmp Node 1284 var n1 Node 1285 if nr.Addable { 1286 goto irad 1287 } 1288 if nl.Addable { 1289 Cgenr(nr, &n1, nil) 1290 if !Isconst(nl, CTSTR) { 1291 if Isfixedarray(nl.Type) { 1292 Agenr(nl, &n3, res) 1293 } else { 1294 Igen(nl, &nlen, res) 1295 freelen = 1 1296 nlen.Type = Types[Tptr] 1297 nlen.Xoffset += int64(Array_array) 1298 Regalloc(&n3, Types[Tptr], res) 1299 Thearch.Gmove(&nlen, &n3) 1300 nlen.Type = Types[Simtype[TUINT]] 1301 nlen.Xoffset += int64(Array_nel) - int64(Array_array) 1302 } 1303 } 1304 1305 goto index 1306 } 1307 1308 Tempname(&tmp, nr.Type) 1309 Cgen(nr, &tmp) 1310 nr = &tmp 1311 1312 irad: 1313 if !Isconst(nl, CTSTR) { 1314 if Isfixedarray(nl.Type) { 1315 Agenr(nl, &n3, res) 1316 } else { 1317 if !nl.Addable { 1318 if res != nil && res.Op == OREGISTER { // give up res, which we don't need yet. 1319 Regfree(res) 1320 } 1321 1322 // igen will need an addressable node. 1323 var tmp2 Node 1324 Tempname(&tmp2, nl.Type) 1325 Cgen(nl, &tmp2) 1326 nl = &tmp2 1327 1328 if res != nil && res.Op == OREGISTER { // reacquire res 1329 Regrealloc(res) 1330 } 1331 } 1332 1333 Igen(nl, &nlen, res) 1334 freelen = 1 1335 nlen.Type = Types[Tptr] 1336 nlen.Xoffset += int64(Array_array) 1337 Regalloc(&n3, Types[Tptr], res) 1338 Thearch.Gmove(&nlen, &n3) 1339 nlen.Type = Types[Simtype[TUINT]] 1340 nlen.Xoffset += int64(Array_nel) - int64(Array_array) 1341 } 1342 } 1343 1344 if !Isconst(nr, CTINT) { 1345 Cgenr(nr, &n1, nil) 1346 } 1347 1348 goto index 1349 1350 // &a is in &n3 (allocated in res) 1351 // i is in &n1 (if not constant) 1352 // len(a) is in nlen (if needed) 1353 // w is width 1354 1355 // constant index 1356 index: 1357 if Isconst(nr, CTINT) { 1358 if Isconst(nl, CTSTR) { 1359 Fatal("constant string constant index") // front end should handle 1360 } 1361 v := uint64(Mpgetfix(nr.Val.U.Xval)) 1362 if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1363 if Debug['B'] == 0 && !n.Bounded { 1364 if nlen.Op != OREGISTER && (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') { 1365 var tmp2 Node 1366 Regalloc(&tmp2, Types[Simtype[TUINT]], nil) 1367 Thearch.Gmove(&nlen, &tmp2) 1368 Regfree(&nlen) // in case it is OINDREG 1369 nlen = tmp2 1370 } 1371 var n2 Node 1372 Nodconst(&n2, Types[Simtype[TUINT]], int64(v)) 1373 if Smallintconst(nr) { 1374 Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &n2) 1375 } else { 1376 Regalloc(&tmp, Types[Simtype[TUINT]], nil) 1377 Thearch.Gmove(&n2, &tmp) 1378 Thearch.Gins(Thearch.Optoas(OCMP, Types[Simtype[TUINT]]), &nlen, &tmp) 1379 Regfree(&tmp) 1380 } 1381 1382 p1 := Gbranch(Thearch.Optoas(OGT, Types[Simtype[TUINT]]), nil, +1) 1383 Ginscall(Panicindex, -1) 1384 Patch(p1, Pc) 1385 } 1386 1387 Regfree(&nlen) 1388 } 1389 1390 if v*w != 0 { 1391 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), int64(v*w), &n3) 1392 } 1393 *a = n3 1394 break 1395 } 1396 1397 // type of the index 1398 t := Types[TUINT64] 1399 1400 if Issigned[n1.Type.Etype] { 1401 t = Types[TINT64] 1402 } 1403 1404 var n2 Node 1405 Regalloc(&n2, t, &n1) // i 1406 Thearch.Gmove(&n1, &n2) 1407 Regfree(&n1) 1408 1409 if Debug['B'] == 0 && !n.Bounded { 1410 // check bounds 1411 t = Types[Simtype[TUINT]] 1412 1413 if Is64(nr.Type) { 1414 t = Types[TUINT64] 1415 } 1416 if Isconst(nl, CTSTR) { 1417 Nodconst(&nlen, t, int64(len(nl.Val.U.Sval))) 1418 } else if Isslice(nl.Type) || nl.Type.Etype == TSTRING { 1419 if Is64(nr.Type) || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { 1420 var n5 Node 1421 Regalloc(&n5, t, nil) 1422 Thearch.Gmove(&nlen, &n5) 1423 Regfree(&nlen) 1424 nlen = n5 1425 } 1426 } else { 1427 Nodconst(&nlen, t, nl.Type.Bound) 1428 if !Smallintconst(&nlen) { 1429 var n5 Node 1430 Regalloc(&n5, t, nil) 1431 Thearch.Gmove(&nlen, &n5) 1432 nlen = n5 1433 freelen = 1 1434 } 1435 } 1436 1437 Thearch.Gins(Thearch.Optoas(OCMP, t), &n2, &nlen) 1438 p1 := Gbranch(Thearch.Optoas(OLT, t), nil, +1) 1439 Ginscall(Panicindex, -1) 1440 Patch(p1, Pc) 1441 } 1442 1443 if Isconst(nl, CTSTR) { 1444 Regalloc(&n3, Types[Tptr], res) 1445 p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ! 1446 Datastring(nl.Val.U.Sval, &p1.From) 1447 p1.From.Type = obj.TYPE_ADDR 1448 Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3) 1449 goto indexdone 1450 } 1451 1452 if w == 0 { 1453 // nothing to do 1454 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) { 1455 // done by back end 1456 } else if w == 1 { 1457 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1458 } else { 1459 Thearch.Ginscon(Thearch.Optoas(OMUL, t), int64(w), &n2) 1460 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1461 } 1462 1463 indexdone: 1464 *a = n3 1465 Regfree(&n2) 1466 if freelen != 0 { 1467 Regfree(&nlen) 1468 } 1469 1470 default: 1471 Regalloc(a, Types[Tptr], res) 1472 Agen(n, a) 1473 } 1474 } 1475 1476 /* 1477 * generate: 1478 * res = &n; 1479 * The generated code checks that the result is not nil. 1480 */ 1481 func Agen(n *Node, res *Node) { 1482 if Debug['g'] != 0 { 1483 Dump("\nagen-res", res) 1484 Dump("agen-r", n) 1485 } 1486 1487 if n == nil || n.Type == nil { 1488 return 1489 } 1490 1491 for n.Op == OCONVNOP { 1492 n = n.Left 1493 } 1494 1495 if Isconst(n, CTNIL) && n.Type.Width > int64(Widthptr) { 1496 // Use of a nil interface or nil slice. 1497 // Create a temporary we can take the address of and read. 1498 // The generated code is just going to panic, so it need not 1499 // be terribly efficient. See issue 3670. 1500 var n1 Node 1501 Tempname(&n1, n.Type) 1502 1503 Gvardef(&n1) 1504 Thearch.Clearfat(&n1) 1505 var n2 Node 1506 Regalloc(&n2, Types[Tptr], res) 1507 var n3 Node 1508 n3.Op = OADDR 1509 n3.Left = &n1 1510 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n3, &n2) 1511 Thearch.Gmove(&n2, res) 1512 Regfree(&n2) 1513 return 1514 } 1515 1516 if n.Op == OINDREG && n.Xoffset == 0 { 1517 // Generate MOVW R0, R1 instead of MOVW $0(R0), R1. 1518 n1 := *n 1519 n1.Op = OREGISTER 1520 n1.Type = res.Type 1521 Thearch.Gmove(&n1, res) 1522 return 1523 } 1524 1525 if n.Addable { 1526 if n.Op == OREGISTER { 1527 Fatal("agen OREGISTER") 1528 } 1529 var n1 Node 1530 n1.Op = OADDR 1531 n1.Left = n 1532 var n2 Node 1533 Regalloc(&n2, Types[Tptr], res) 1534 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n1, &n2) 1535 Thearch.Gmove(&n2, res) 1536 Regfree(&n2) 1537 return 1538 } 1539 1540 nl := n.Left 1541 1542 switch n.Op { 1543 default: 1544 Fatal("agen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign)) 1545 1546 case OCALLMETH: 1547 cgen_callmeth(n, 0) 1548 cgen_aret(n, res) 1549 1550 case OCALLINTER: 1551 cgen_callinter(n, res, 0) 1552 cgen_aret(n, res) 1553 1554 case OCALLFUNC: 1555 cgen_call(n, 0) 1556 cgen_aret(n, res) 1557 1558 case OEFACE, ODOTTYPE, OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: 1559 var n1 Node 1560 Tempname(&n1, n.Type) 1561 Cgen(n, &n1) 1562 Agen(&n1, res) 1563 1564 case OINDEX: 1565 var n1 Node 1566 Agenr(n, &n1, res) 1567 Thearch.Gmove(&n1, res) 1568 Regfree(&n1) 1569 1570 case ONAME: 1571 // should only get here with names in this func. 1572 if n.Funcdepth > 0 && n.Funcdepth != Funcdepth { 1573 Dump("bad agen", n) 1574 Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, Funcdepth) 1575 } 1576 1577 // should only get here for heap vars or paramref 1578 if n.Class&PHEAP == 0 && n.Class != PPARAMREF { 1579 Dump("bad agen", n) 1580 Fatal("agen: bad ONAME class %#x", n.Class) 1581 } 1582 1583 Cgen(n.Heapaddr, res) 1584 if n.Xoffset != 0 { 1585 addOffset(res, n.Xoffset) 1586 } 1587 1588 case OIND: 1589 Cgen(nl, res) 1590 Cgen_checknil(res) 1591 1592 case ODOT: 1593 Agen(nl, res) 1594 if n.Xoffset != 0 { 1595 addOffset(res, n.Xoffset) 1596 } 1597 1598 case ODOTPTR: 1599 Cgen(nl, res) 1600 Cgen_checknil(res) 1601 if n.Xoffset != 0 { 1602 addOffset(res, n.Xoffset) 1603 } 1604 } 1605 } 1606 1607 func addOffset(res *Node, offset int64) { 1608 if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' { 1609 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res) 1610 return 1611 } 1612 1613 var n1, n2 Node 1614 Regalloc(&n1, Types[Tptr], nil) 1615 Thearch.Gmove(res, &n1) 1616 Regalloc(&n2, Types[Tptr], nil) 1617 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), Nodintconst(offset), &n2) 1618 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n1) 1619 Thearch.Gmove(&n1, res) 1620 Regfree(&n1) 1621 Regfree(&n2) 1622 } 1623 1624 // Igen computes the address &n, stores it in a register r, 1625 // and rewrites a to refer to *r. The chosen r may be the 1626 // stack pointer, it may be borrowed from res, or it may 1627 // be a newly allocated register. The caller must call Regfree(a) 1628 // to free r when the address is no longer needed. 1629 // The generated code ensures that &n is not nil. 1630 func Igen(n *Node, a *Node, res *Node) { 1631 if Debug['g'] != 0 { 1632 Dump("\nigen-n", n) 1633 } 1634 1635 switch n.Op { 1636 case ONAME: 1637 if (n.Class&PHEAP != 0) || n.Class == PPARAMREF { 1638 break 1639 } 1640 *a = *n 1641 return 1642 1643 case OINDREG: 1644 // Increase the refcount of the register so that igen's caller 1645 // has to call Regfree. 1646 if n.Reg != int16(Thearch.REGSP) { 1647 reg[n.Reg-int16(Thearch.REGMIN)]++ 1648 } 1649 *a = *n 1650 return 1651 1652 case ODOT: 1653 Igen(n.Left, a, res) 1654 a.Xoffset += n.Xoffset 1655 a.Type = n.Type 1656 Fixlargeoffset(a) 1657 return 1658 1659 case ODOTPTR: 1660 Cgenr(n.Left, a, res) 1661 Cgen_checknil(a) 1662 a.Op = OINDREG 1663 a.Xoffset += n.Xoffset 1664 a.Type = n.Type 1665 Fixlargeoffset(a) 1666 return 1667 1668 case OCALLFUNC, OCALLMETH, OCALLINTER: 1669 switch n.Op { 1670 case OCALLFUNC: 1671 cgen_call(n, 0) 1672 1673 case OCALLMETH: 1674 cgen_callmeth(n, 0) 1675 1676 case OCALLINTER: 1677 cgen_callinter(n, nil, 0) 1678 } 1679 1680 var flist Iter 1681 fp := Structfirst(&flist, Getoutarg(n.Left.Type)) 1682 *a = Node{} 1683 a.Op = OINDREG 1684 a.Reg = int16(Thearch.REGSP) 1685 a.Addable = true 1686 a.Xoffset = fp.Width 1687 if HasLinkRegister() { 1688 a.Xoffset += int64(Ctxt.Arch.Ptrsize) 1689 } 1690 a.Type = n.Type 1691 return 1692 1693 // Index of fixed-size array by constant can 1694 // put the offset in the addressing. 1695 // Could do the same for slice except that we need 1696 // to use the real index for the bounds checking. 1697 case OINDEX: 1698 if Isfixedarray(n.Left.Type) || (Isptr[n.Left.Type.Etype] && Isfixedarray(n.Left.Left.Type)) { 1699 if Isconst(n.Right, CTINT) { 1700 // Compute &a. 1701 if !Isptr[n.Left.Type.Etype] { 1702 Igen(n.Left, a, res) 1703 } else { 1704 var n1 Node 1705 Igen(n.Left, &n1, res) 1706 Cgen_checknil(&n1) 1707 Regalloc(a, Types[Tptr], res) 1708 Thearch.Gmove(&n1, a) 1709 Regfree(&n1) 1710 a.Op = OINDREG 1711 } 1712 1713 // Compute &a[i] as &a + i*width. 1714 a.Type = n.Type 1715 1716 a.Xoffset += Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width 1717 Fixlargeoffset(a) 1718 return 1719 } 1720 } 1721 } 1722 1723 Agenr(n, a, res) 1724 a.Op = OINDREG 1725 a.Type = n.Type 1726 } 1727 1728 // Bgen generates code for branches: 1729 // 1730 // if n == wantTrue { 1731 // goto to 1732 // } 1733 func Bgen(n *Node, wantTrue bool, likely int, to *obj.Prog) { 1734 bgenx(n, nil, wantTrue, likely, to) 1735 } 1736 1737 // Bvgen generates code for calculating boolean values: 1738 // res = n == wantTrue 1739 func Bvgen(n, res *Node, wantTrue bool) { 1740 if Thearch.Ginsboolval == nil { 1741 // Direct value generation not implemented for this architecture. 1742 // Implement using jumps. 1743 bvgenjump(n, res, wantTrue, true) 1744 return 1745 } 1746 bgenx(n, res, wantTrue, 0, nil) 1747 } 1748 1749 // bvgenjump implements boolean value generation using jumps: 1750 // if n == wantTrue { 1751 // res = 1 1752 // } else { 1753 // res = 0 1754 // } 1755 // geninit controls whether n's Ninit is generated. 1756 func bvgenjump(n, res *Node, wantTrue, geninit bool) { 1757 init := n.Ninit 1758 if !geninit { 1759 n.Ninit = nil 1760 } 1761 p1 := Gbranch(obj.AJMP, nil, 0) 1762 p2 := Pc 1763 Thearch.Gmove(Nodbool(true), res) 1764 p3 := Gbranch(obj.AJMP, nil, 0) 1765 Patch(p1, Pc) 1766 Bgen(n, wantTrue, 0, p2) 1767 Thearch.Gmove(Nodbool(false), res) 1768 Patch(p3, Pc) 1769 n.Ninit = init 1770 } 1771 1772 // bgenx is the backend for Bgen and Bvgen. 1773 // If res is nil, it generates a branch. 1774 // Otherwise, it generates a boolean value. 1775 func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { 1776 if Debug['g'] != 0 { 1777 fmt.Printf("\nbgenx wantTrue=%t likely=%d to=%v\n", wantTrue, likely, to) 1778 Dump("n", n) 1779 Dump("res", res) 1780 } 1781 1782 genval := res != nil 1783 1784 if n == nil { 1785 n = Nodbool(true) 1786 } 1787 1788 Genlist(n.Ninit) 1789 1790 if n.Type == nil { 1791 Convlit(&n, Types[TBOOL]) 1792 if n.Type == nil { 1793 return 1794 } 1795 } 1796 1797 if n.Type.Etype != TBOOL { 1798 Fatal("bgen: bad type %v for %v", n.Type, Oconv(int(n.Op), 0)) 1799 } 1800 1801 for n.Op == OCONVNOP { 1802 n = n.Left 1803 Genlist(n.Ninit) 1804 } 1805 1806 if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] { 1807 if genval { 1808 bvgenjump(n, res, wantTrue, false) 1809 return 1810 } 1811 Thearch.Bgen_float(n, wantTrue, likely, to) 1812 return 1813 } 1814 1815 switch n.Op { 1816 default: 1817 if genval { 1818 Cgen(n, res) 1819 if !wantTrue { 1820 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) 1821 } 1822 return 1823 } 1824 1825 var tmp Node 1826 Regalloc(&tmp, n.Type, nil) 1827 Cgen(n, &tmp) 1828 bgenNonZero(&tmp, nil, wantTrue, likely, to) 1829 Regfree(&tmp) 1830 return 1831 1832 case ONAME: 1833 if genval { 1834 // 5g, 7g, and 9g might need a temporary or other help here, 1835 // but they don't support direct generation of a bool value yet. 1836 // We can fix that as we go. 1837 switch Ctxt.Arch.Thechar { 1838 case '5', '7', '9': 1839 Fatal("genval 5g, 7g, 9g ONAMES not fully implemented") 1840 } 1841 Cgen(n, res) 1842 if !wantTrue { 1843 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) 1844 } 1845 return 1846 } 1847 1848 if n.Addable && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { 1849 // no need for a temporary 1850 bgenNonZero(n, nil, wantTrue, likely, to) 1851 return 1852 } 1853 var tmp Node 1854 Regalloc(&tmp, n.Type, nil) 1855 Cgen(n, &tmp) 1856 bgenNonZero(&tmp, nil, wantTrue, likely, to) 1857 Regfree(&tmp) 1858 return 1859 1860 case OLITERAL: 1861 // n is a constant. 1862 if !Isconst(n, CTBOOL) { 1863 Fatal("bgen: non-bool const %v\n", Nconv(n, obj.FmtLong)) 1864 } 1865 if genval { 1866 Cgen(Nodbool(wantTrue == n.Val.U.Bval), res) 1867 return 1868 } 1869 // If n == wantTrue, jump; otherwise do nothing. 1870 if wantTrue == n.Val.U.Bval { 1871 Patch(Gbranch(obj.AJMP, nil, likely), to) 1872 } 1873 return 1874 1875 case OANDAND, OOROR: 1876 and := (n.Op == OANDAND) == wantTrue 1877 if genval { 1878 p1 := Gbranch(obj.AJMP, nil, 0) 1879 p2 := Gbranch(obj.AJMP, nil, 0) 1880 Patch(p2, Pc) 1881 Cgen(Nodbool(!and), res) 1882 p3 := Gbranch(obj.AJMP, nil, 0) 1883 Patch(p1, Pc) 1884 Bgen(n.Left, wantTrue != and, 0, p2) 1885 Bvgen(n.Right, res, wantTrue) 1886 Patch(p3, Pc) 1887 return 1888 } 1889 1890 if and { 1891 p1 := Gbranch(obj.AJMP, nil, 0) 1892 p2 := Gbranch(obj.AJMP, nil, 0) 1893 Patch(p1, Pc) 1894 Bgen(n.Left, !wantTrue, -likely, p2) 1895 Bgen(n.Right, !wantTrue, -likely, p2) 1896 p1 = Gbranch(obj.AJMP, nil, 0) 1897 Patch(p1, to) 1898 Patch(p2, Pc) 1899 } else { 1900 Bgen(n.Left, wantTrue, likely, to) 1901 Bgen(n.Right, wantTrue, likely, to) 1902 } 1903 return 1904 1905 case ONOT: // unary 1906 if n.Left == nil || n.Left.Type == nil { 1907 return 1908 } 1909 bgenx(n.Left, res, !wantTrue, likely, to) 1910 return 1911 1912 case OEQ, ONE, OLT, OGT, OLE, OGE: 1913 if n.Left == nil || n.Left.Type == nil || n.Right == nil || n.Right.Type == nil { 1914 return 1915 } 1916 } 1917 1918 // n.Op is one of OEQ, ONE, OLT, OGT, OLE, OGE 1919 nl := n.Left 1920 nr := n.Right 1921 a := int(n.Op) 1922 1923 if !wantTrue { 1924 if Isfloat[nr.Type.Etype] { 1925 // Brcom is not valid on floats when NaN is involved. 1926 ll := n.Ninit // avoid re-genning Ninit 1927 n.Ninit = nil 1928 if genval { 1929 bgenx(n, res, true, likely, to) 1930 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) // res = !res 1931 n.Ninit = ll 1932 return 1933 } 1934 p1 := Gbranch(obj.AJMP, nil, 0) 1935 p2 := Gbranch(obj.AJMP, nil, 0) 1936 Patch(p1, Pc) 1937 bgenx(n, res, true, -likely, p2) 1938 Patch(Gbranch(obj.AJMP, nil, 0), to) 1939 Patch(p2, Pc) 1940 n.Ninit = ll 1941 return 1942 } 1943 1944 a = Brcom(a) 1945 } 1946 wantTrue = true 1947 1948 // make simplest on right 1949 if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) { 1950 a = Brrev(a) 1951 nl, nr = nr, nl 1952 } 1953 1954 if Isslice(nl.Type) || Isinter(nl.Type) { 1955 // front end should only leave cmp to literal nil 1956 if (a != OEQ && a != ONE) || nr.Op != OLITERAL { 1957 if Isslice(nl.Type) { 1958 Yyerror("illegal slice comparison") 1959 } else { 1960 Yyerror("illegal interface comparison") 1961 } 1962 return 1963 } 1964 1965 var ptr Node 1966 Igen(nl, &ptr, nil) 1967 if Isslice(nl.Type) { 1968 ptr.Xoffset += int64(Array_array) 1969 } 1970 ptr.Type = Types[Tptr] 1971 var tmp Node 1972 Regalloc(&tmp, ptr.Type, &ptr) 1973 Cgen(&ptr, &tmp) 1974 Regfree(&ptr) 1975 bgenNonZero(&tmp, res, a == OEQ != wantTrue, likely, to) 1976 Regfree(&tmp) 1977 return 1978 } 1979 1980 if Iscomplex[nl.Type.Etype] { 1981 complexbool(a, nl, nr, res, wantTrue, likely, to) 1982 return 1983 } 1984 1985 if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) { 1986 if genval { 1987 // TODO: Teach Cmp64 to generate boolean values and remove this. 1988 bvgenjump(n, res, wantTrue, false) 1989 return 1990 } 1991 if !nl.Addable || Isconst(nl, CTINT) { 1992 nl = CgenTemp(nl) 1993 } 1994 if !nr.Addable { 1995 nr = CgenTemp(nr) 1996 } 1997 Thearch.Cmp64(nl, nr, a, likely, to) 1998 return 1999 } 2000 2001 if nr.Ullman >= UINF { 2002 var n1 Node 2003 Regalloc(&n1, nl.Type, nil) 2004 Cgen(nl, &n1) 2005 2006 var tmp Node 2007 Tempname(&tmp, nl.Type) 2008 Thearch.Gmove(&n1, &tmp) 2009 Regfree(&n1) 2010 2011 var n2 Node 2012 Regalloc(&n2, nr.Type, nil) 2013 Cgen(nr, &n2) 2014 Regfree(&n2) 2015 2016 Regalloc(&n1, nl.Type, nil) 2017 Cgen(&tmp, &n1) 2018 Regfree(&n1) 2019 } else { 2020 var n1 Node 2021 if !nl.Addable && Ctxt.Arch.Thechar == '8' { 2022 Tempname(&n1, nl.Type) 2023 } else { 2024 Regalloc(&n1, nl.Type, nil) 2025 defer Regfree(&n1) 2026 } 2027 Cgen(nl, &n1) 2028 nl = &n1 2029 2030 if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' { 2031 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr) 2032 bins(nr.Type, res, a, likely, to) 2033 return 2034 } 2035 2036 if !nr.Addable && Ctxt.Arch.Thechar == '8' { 2037 nr = CgenTemp(nr) 2038 } 2039 2040 var n2 Node 2041 Regalloc(&n2, nr.Type, nil) 2042 Cgen(nr, &n2) 2043 nr = &n2 2044 Regfree(&n2) 2045 } 2046 2047 l, r := nl, nr 2048 2049 // On x86, only < and <= work right with NaN; reverse if needed 2050 if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) { 2051 l, r = r, l 2052 a = Brrev(a) 2053 } 2054 2055 // Do the comparison. 2056 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r) 2057 2058 // Handle floating point special cases. 2059 // Note that 8g has Bgen_float and is handled above. 2060 if Isfloat[nl.Type.Etype] { 2061 switch Ctxt.Arch.Thechar { 2062 case '5': 2063 if genval { 2064 Fatal("genval 5g Isfloat special cases not implemented") 2065 } 2066 switch n.Op { 2067 case ONE: 2068 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to) 2069 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 2070 default: 2071 p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely) 2072 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 2073 Patch(p, Pc) 2074 } 2075 return 2076 case '6': 2077 switch n.Op { 2078 case OEQ: 2079 // neither NE nor P 2080 if genval { 2081 var reg Node 2082 Regalloc(®, Types[TBOOL], nil) 2083 Thearch.Ginsboolval(Thearch.Optoas(OEQ, nr.Type), ®) 2084 Thearch.Ginsboolval(Thearch.Optoas(OPC, nr.Type), res) 2085 Thearch.Gins(Thearch.Optoas(OAND, Types[TBOOL]), ®, res) 2086 Regfree(®) 2087 } else { 2088 p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely) 2089 p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely) 2090 Patch(Gbranch(obj.AJMP, nil, 0), to) 2091 Patch(p1, Pc) 2092 Patch(p2, Pc) 2093 } 2094 return 2095 case ONE: 2096 // either NE or P 2097 if genval { 2098 var reg Node 2099 Regalloc(®, Types[TBOOL], nil) 2100 Thearch.Ginsboolval(Thearch.Optoas(ONE, nr.Type), ®) 2101 Thearch.Ginsboolval(Thearch.Optoas(OPS, nr.Type), res) 2102 Thearch.Gins(Thearch.Optoas(OOR, Types[TBOOL]), ®, res) 2103 Regfree(®) 2104 } else { 2105 Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to) 2106 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to) 2107 } 2108 return 2109 } 2110 case '7', '9': 2111 if genval { 2112 Fatal("genval 7g, 9g Isfloat special cases not implemented") 2113 } 2114 switch n.Op { 2115 // On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =. 2116 // TODO(josh): Convert a <= b to b > a instead? 2117 case OLE, OGE: 2118 if a == OLE { 2119 a = OLT 2120 } else { 2121 a = OGT 2122 } 2123 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 2124 Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to) 2125 return 2126 } 2127 } 2128 } 2129 2130 // Not a special case. Insert the conditional jump or value gen. 2131 bins(nr.Type, res, a, likely, to) 2132 } 2133 2134 func bgenNonZero(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { 2135 // TODO: Optimize on systems that can compare to zero easily. 2136 a := ONE 2137 if !wantTrue { 2138 a = OEQ 2139 } 2140 var zero Node 2141 Nodconst(&zero, n.Type, 0) 2142 Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &zero) 2143 bins(n.Type, res, a, likely, to) 2144 } 2145 2146 // bins inserts an instruction to handle the result of a compare. 2147 // If res is non-nil, it inserts appropriate value generation instructions. 2148 // If res is nil, it inserts a branch to to. 2149 func bins(typ *Type, res *Node, a, likely int, to *obj.Prog) { 2150 a = Thearch.Optoas(a, typ) 2151 if res != nil { 2152 // value gen 2153 Thearch.Ginsboolval(a, res) 2154 } else { 2155 // jump 2156 Patch(Gbranch(a, typ, likely), to) 2157 } 2158 } 2159 2160 /* 2161 * n is on stack, either local variable 2162 * or return value from function call. 2163 * return n's offset from SP. 2164 */ 2165 func stkof(n *Node) int64 { 2166 switch n.Op { 2167 case OINDREG: 2168 return n.Xoffset 2169 2170 case ODOT: 2171 t := n.Left.Type 2172 if Isptr[t.Etype] { 2173 break 2174 } 2175 off := stkof(n.Left) 2176 if off == -1000 || off == 1000 { 2177 return off 2178 } 2179 return off + n.Xoffset 2180 2181 case OINDEX: 2182 t := n.Left.Type 2183 if !Isfixedarray(t) { 2184 break 2185 } 2186 off := stkof(n.Left) 2187 if off == -1000 || off == 1000 { 2188 return off 2189 } 2190 if Isconst(n.Right, CTINT) { 2191 return off + t.Type.Width*Mpgetfix(n.Right.Val.U.Xval) 2192 } 2193 return 1000 2194 2195 case OCALLMETH, OCALLINTER, OCALLFUNC: 2196 t := n.Left.Type 2197 if Isptr[t.Etype] { 2198 t = t.Type 2199 } 2200 2201 var flist Iter 2202 t = Structfirst(&flist, Getoutarg(t)) 2203 if t != nil { 2204 w := t.Width 2205 if HasLinkRegister() { 2206 w += int64(Ctxt.Arch.Ptrsize) 2207 } 2208 return w 2209 } 2210 } 2211 2212 // botch - probably failing to recognize address 2213 // arithmetic on the above. eg INDEX and DOT 2214 return -1000 2215 } 2216 2217 /* 2218 * block copy: 2219 * memmove(&ns, &n, w); 2220 * if wb is true, needs write barrier. 2221 */ 2222 func sgen_wb(n *Node, ns *Node, w int64, wb bool) { 2223 if Debug['g'] != 0 { 2224 op := "sgen" 2225 if wb { 2226 op = "sgen-wb" 2227 } 2228 fmt.Printf("\n%s w=%d\n", op, w) 2229 Dump("r", n) 2230 Dump("res", ns) 2231 } 2232 2233 if n.Ullman >= UINF && ns.Ullman >= UINF { 2234 Fatal("sgen UINF") 2235 } 2236 2237 if w < 0 { 2238 Fatal("sgen copy %d", w) 2239 } 2240 2241 // If copying .args, that's all the results, so record definition sites 2242 // for them for the liveness analysis. 2243 if ns.Op == ONAME && ns.Sym.Name == ".args" { 2244 for l := Curfn.Func.Dcl; l != nil; l = l.Next { 2245 if l.N.Class == PPARAMOUT { 2246 Gvardef(l.N) 2247 } 2248 } 2249 } 2250 2251 // Avoid taking the address for simple enough types. 2252 if componentgen_wb(n, ns, wb) { 2253 return 2254 } 2255 2256 if w == 0 { 2257 // evaluate side effects only 2258 var nodr Node 2259 Regalloc(&nodr, Types[Tptr], nil) 2260 Agen(ns, &nodr) 2261 Agen(n, &nodr) 2262 Regfree(&nodr) 2263 return 2264 } 2265 2266 // offset on the stack 2267 osrc := stkof(n) 2268 odst := stkof(ns) 2269 2270 if odst != -1000 { 2271 // on stack, write barrier not needed after all 2272 wb = false 2273 } 2274 2275 if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) || wb && osrc != -1000 { 2276 // osrc and odst both on stack, and at least one is in 2277 // an unknown position. Could generate code to test 2278 // for forward/backward copy, but instead just copy 2279 // to a temporary location first. 2280 // 2281 // OR: write barrier needed and source is on stack. 2282 // Invoking the write barrier will use the stack to prepare its call. 2283 // Copy to temporary. 2284 var tmp Node 2285 Tempname(&tmp, n.Type) 2286 sgen_wb(n, &tmp, w, false) 2287 sgen_wb(&tmp, ns, w, wb) 2288 return 2289 } 2290 2291 if wb { 2292 cgen_wbfat(n, ns) 2293 return 2294 } 2295 2296 Thearch.Stackcopy(n, ns, osrc, odst, w) 2297 } 2298 2299 /* 2300 * generate: 2301 * call f 2302 * proc=-1 normal call but no return 2303 * proc=0 normal call 2304 * proc=1 goroutine run in new proc 2305 * proc=2 defer call save away stack 2306 * proc=3 normal call to C pointer (not Go func value) 2307 */ 2308 func Ginscall(f *Node, proc int) { 2309 if f.Type != nil { 2310 extra := int32(0) 2311 if proc == 1 || proc == 2 { 2312 extra = 2 * int32(Widthptr) 2313 } 2314 Setmaxarg(f.Type, extra) 2315 } 2316 2317 switch proc { 2318 default: 2319 Fatal("Ginscall: bad proc %d", proc) 2320 2321 case 0, // normal call 2322 -1: // normal call but no return 2323 if f.Op == ONAME && f.Class == PFUNC { 2324 if f == Deferreturn { 2325 // Deferred calls will appear to be returning to 2326 // the CALL deferreturn(SB) that we are about to emit. 2327 // However, the stack trace code will show the line 2328 // of the instruction byte before the return PC. 2329 // To avoid that being an unrelated instruction, 2330 // insert an actual hardware NOP that will have the right line number. 2331 // This is different from obj.ANOP, which is a virtual no-op 2332 // that doesn't make it into the instruction stream. 2333 Thearch.Ginsnop() 2334 } 2335 2336 p := Thearch.Gins(obj.ACALL, nil, f) 2337 Afunclit(&p.To, f) 2338 if proc == -1 || Noreturn(p) { 2339 Thearch.Gins(obj.AUNDEF, nil, nil) 2340 } 2341 break 2342 } 2343 2344 var reg Node 2345 Nodreg(®, Types[Tptr], Thearch.REGCTXT) 2346 var r1 Node 2347 Nodreg(&r1, Types[Tptr], Thearch.REGCALLX) 2348 Thearch.Gmove(f, ®) 2349 reg.Op = OINDREG 2350 Thearch.Gmove(®, &r1) 2351 reg.Op = OREGISTER 2352 Thearch.Gins(obj.ACALL, ®, &r1) 2353 2354 case 3: // normal call of c function pointer 2355 Thearch.Gins(obj.ACALL, nil, f) 2356 2357 case 1, // call in new proc (go) 2358 2: // deferred call (defer) 2359 var stk Node 2360 2361 // size of arguments at 0(SP) 2362 stk.Op = OINDREG 2363 stk.Reg = int16(Thearch.REGSP) 2364 stk.Xoffset = 0 2365 if HasLinkRegister() { 2366 stk.Xoffset += int64(Ctxt.Arch.Ptrsize) 2367 } 2368 Thearch.Ginscon(Thearch.Optoas(OAS, Types[Tptr]), int64(Argsize(f.Type)), &stk) 2369 2370 // FuncVal* at 8(SP) 2371 stk.Xoffset = int64(Widthptr) 2372 if HasLinkRegister() { 2373 stk.Xoffset += int64(Ctxt.Arch.Ptrsize) 2374 } 2375 2376 var reg Node 2377 Nodreg(®, Types[Tptr], Thearch.REGCALLX2) 2378 Thearch.Gmove(f, ®) 2379 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), ®, &stk) 2380 2381 if proc == 1 { 2382 Ginscall(Newproc, 0) 2383 } else { 2384 if Hasdefer == 0 { 2385 Fatal("hasdefer=0 but has defer") 2386 } 2387 Ginscall(Deferproc, 0) 2388 } 2389 2390 if proc == 2 { 2391 Nodreg(®, Types[TINT32], Thearch.REGRETURN) 2392 Thearch.Gins(Thearch.Optoas(OCMP, Types[TINT32]), ®, Nodintconst(0)) 2393 p := Gbranch(Thearch.Optoas(OEQ, Types[TINT32]), nil, +1) 2394 cgen_ret(nil) 2395 Patch(p, Pc) 2396 } 2397 } 2398 } 2399 2400 /* 2401 * n is call to interface method. 2402 * generate res = n. 2403 */ 2404 func cgen_callinter(n *Node, res *Node, proc int) { 2405 i := n.Left 2406 if i.Op != ODOTINTER { 2407 Fatal("cgen_callinter: not ODOTINTER %v", Oconv(int(i.Op), 0)) 2408 } 2409 2410 f := i.Right // field 2411 if f.Op != ONAME { 2412 Fatal("cgen_callinter: not ONAME %v", Oconv(int(f.Op), 0)) 2413 } 2414 2415 i = i.Left // interface 2416 2417 if !i.Addable { 2418 var tmpi Node 2419 Tempname(&tmpi, i.Type) 2420 Cgen(i, &tmpi) 2421 i = &tmpi 2422 } 2423 2424 Genlist(n.List) // assign the args 2425 2426 // i is now addable, prepare an indirected 2427 // register to hold its address. 2428 var nodi Node 2429 Igen(i, &nodi, res) // REG = &inter 2430 2431 var nodsp Node 2432 Nodindreg(&nodsp, Types[Tptr], Thearch.REGSP) 2433 nodsp.Xoffset = 0 2434 if HasLinkRegister() { 2435 nodsp.Xoffset += int64(Ctxt.Arch.Ptrsize) 2436 } 2437 if proc != 0 { 2438 nodsp.Xoffset += 2 * int64(Widthptr) // leave room for size & fn 2439 } 2440 nodi.Type = Types[Tptr] 2441 nodi.Xoffset += int64(Widthptr) 2442 Cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data 2443 2444 var nodo Node 2445 Regalloc(&nodo, Types[Tptr], res) 2446 2447 nodi.Type = Types[Tptr] 2448 nodi.Xoffset -= int64(Widthptr) 2449 Cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab 2450 Regfree(&nodi) 2451 2452 var nodr Node 2453 Regalloc(&nodr, Types[Tptr], &nodo) 2454 if n.Left.Xoffset == BADWIDTH { 2455 Fatal("cgen_callinter: badwidth") 2456 } 2457 Cgen_checknil(&nodo) // in case offset is huge 2458 nodo.Op = OINDREG 2459 nodo.Xoffset = n.Left.Xoffset + 3*int64(Widthptr) + 8 2460 if proc == 0 { 2461 // plain call: use direct c function pointer - more efficient 2462 Cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f] 2463 proc = 3 2464 } else { 2465 // go/defer. generate go func value. 2466 Agen(&nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f] 2467 } 2468 2469 nodr.Type = n.Left.Type 2470 Ginscall(&nodr, proc) 2471 2472 Regfree(&nodr) 2473 Regfree(&nodo) 2474 } 2475 2476 /* 2477 * generate function call; 2478 * proc=0 normal call 2479 * proc=1 goroutine run in new proc 2480 * proc=2 defer call save away stack 2481 */ 2482 func cgen_call(n *Node, proc int) { 2483 if n == nil { 2484 return 2485 } 2486 2487 var afun Node 2488 if n.Left.Ullman >= UINF { 2489 // if name involves a fn call 2490 // precompute the address of the fn 2491 Tempname(&afun, Types[Tptr]) 2492 2493 Cgen(n.Left, &afun) 2494 } 2495 2496 Genlist(n.List) // assign the args 2497 t := n.Left.Type 2498 2499 // call tempname pointer 2500 if n.Left.Ullman >= UINF { 2501 var nod Node 2502 Regalloc(&nod, Types[Tptr], nil) 2503 Cgen_as(&nod, &afun) 2504 nod.Type = t 2505 Ginscall(&nod, proc) 2506 Regfree(&nod) 2507 return 2508 } 2509 2510 // call pointer 2511 if n.Left.Op != ONAME || n.Left.Class != PFUNC { 2512 var nod Node 2513 Regalloc(&nod, Types[Tptr], nil) 2514 Cgen_as(&nod, n.Left) 2515 nod.Type = t 2516 Ginscall(&nod, proc) 2517 Regfree(&nod) 2518 return 2519 } 2520 2521 // call direct 2522 n.Left.Method = true 2523 2524 Ginscall(n.Left, proc) 2525 } 2526 2527 func HasLinkRegister() bool { 2528 c := Ctxt.Arch.Thechar 2529 return c != '6' && c != '8' 2530 } 2531 2532 /* 2533 * call to n has already been generated. 2534 * generate: 2535 * res = return value from call. 2536 */ 2537 func cgen_callret(n *Node, res *Node) { 2538 t := n.Left.Type 2539 if t.Etype == TPTR32 || t.Etype == TPTR64 { 2540 t = t.Type 2541 } 2542 2543 var flist Iter 2544 fp := Structfirst(&flist, Getoutarg(t)) 2545 if fp == nil { 2546 Fatal("cgen_callret: nil") 2547 } 2548 2549 var nod Node 2550 nod.Op = OINDREG 2551 nod.Reg = int16(Thearch.REGSP) 2552 nod.Addable = true 2553 2554 nod.Xoffset = fp.Width 2555 if HasLinkRegister() { 2556 nod.Xoffset += int64(Ctxt.Arch.Ptrsize) 2557 } 2558 nod.Type = fp.Type 2559 Cgen_as(res, &nod) 2560 } 2561 2562 /* 2563 * call to n has already been generated. 2564 * generate: 2565 * res = &return value from call. 2566 */ 2567 func cgen_aret(n *Node, res *Node) { 2568 t := n.Left.Type 2569 if Isptr[t.Etype] { 2570 t = t.Type 2571 } 2572 2573 var flist Iter 2574 fp := Structfirst(&flist, Getoutarg(t)) 2575 if fp == nil { 2576 Fatal("cgen_aret: nil") 2577 } 2578 2579 var nod1 Node 2580 nod1.Op = OINDREG 2581 nod1.Reg = int16(Thearch.REGSP) 2582 nod1.Addable = true 2583 nod1.Xoffset = fp.Width 2584 if HasLinkRegister() { 2585 nod1.Xoffset += int64(Ctxt.Arch.Ptrsize) 2586 } 2587 nod1.Type = fp.Type 2588 2589 if res.Op != OREGISTER { 2590 var nod2 Node 2591 Regalloc(&nod2, Types[Tptr], res) 2592 Agen(&nod1, &nod2) 2593 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &nod2, res) 2594 Regfree(&nod2) 2595 } else { 2596 Agen(&nod1, res) 2597 } 2598 } 2599 2600 /* 2601 * generate return. 2602 * n->left is assignments to return values. 2603 */ 2604 func cgen_ret(n *Node) { 2605 if n != nil { 2606 Genlist(n.List) // copy out args 2607 } 2608 if Hasdefer != 0 { 2609 Ginscall(Deferreturn, 0) 2610 } 2611 Genlist(Curfn.Func.Exit) 2612 p := Thearch.Gins(obj.ARET, nil, nil) 2613 if n != nil && n.Op == ORETJMP { 2614 p.To.Type = obj.TYPE_MEM 2615 p.To.Name = obj.NAME_EXTERN 2616 p.To.Sym = Linksym(n.Left.Sym) 2617 } 2618 } 2619 2620 /* 2621 * generate division according to op, one of: 2622 * res = nl / nr 2623 * res = nl % nr 2624 */ 2625 func cgen_div(op int, nl *Node, nr *Node, res *Node) { 2626 var w int 2627 2628 // TODO(rsc): arm64 needs to support the relevant instructions 2629 // in peep and optoas in order to enable this. 2630 // TODO(rsc): ppc64 needs to support the relevant instructions 2631 // in peep and optoas in order to enable this. 2632 if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { 2633 goto longdiv 2634 } 2635 w = int(nl.Type.Width * 8) 2636 2637 // Front end handled 32-bit division. We only need to handle 64-bit. 2638 // try to do division by multiply by (2^w)/d 2639 // see hacker's delight chapter 10 2640 switch Simtype[nl.Type.Etype] { 2641 default: 2642 goto longdiv 2643 2644 case TUINT64: 2645 var m Magic 2646 m.W = w 2647 m.Ud = uint64(Mpgetfix(nr.Val.U.Xval)) 2648 Umagic(&m) 2649 if m.Bad != 0 { 2650 break 2651 } 2652 if op == OMOD { 2653 goto longmod 2654 } 2655 2656 var n1 Node 2657 Cgenr(nl, &n1, nil) 2658 var n2 Node 2659 Nodconst(&n2, nl.Type, int64(m.Um)) 2660 var n3 Node 2661 Regalloc(&n3, nl.Type, res) 2662 Thearch.Cgen_hmul(&n1, &n2, &n3) 2663 2664 if m.Ua != 0 { 2665 // need to add numerator accounting for overflow 2666 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3) 2667 2668 Nodconst(&n2, nl.Type, 1) 2669 Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3) 2670 Nodconst(&n2, nl.Type, int64(m.S)-1) 2671 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) 2672 } else { 2673 Nodconst(&n2, nl.Type, int64(m.S)) 2674 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift dx 2675 } 2676 2677 Thearch.Gmove(&n3, res) 2678 Regfree(&n1) 2679 Regfree(&n3) 2680 return 2681 2682 case TINT64: 2683 var m Magic 2684 m.W = w 2685 m.Sd = Mpgetfix(nr.Val.U.Xval) 2686 Smagic(&m) 2687 if m.Bad != 0 { 2688 break 2689 } 2690 if op == OMOD { 2691 goto longmod 2692 } 2693 2694 var n1 Node 2695 Cgenr(nl, &n1, res) 2696 var n2 Node 2697 Nodconst(&n2, nl.Type, m.Sm) 2698 var n3 Node 2699 Regalloc(&n3, nl.Type, nil) 2700 Thearch.Cgen_hmul(&n1, &n2, &n3) 2701 2702 if m.Sm < 0 { 2703 // need to add numerator 2704 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3) 2705 } 2706 2707 Nodconst(&n2, nl.Type, int64(m.S)) 2708 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift n3 2709 2710 Nodconst(&n2, nl.Type, int64(w)-1) 2711 2712 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n1) // -1 iff num is neg 2713 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n1, &n3) // added 2714 2715 if m.Sd < 0 { 2716 // this could probably be removed 2717 // by factoring it into the multiplier 2718 Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3) 2719 } 2720 2721 Thearch.Gmove(&n3, res) 2722 Regfree(&n1) 2723 Regfree(&n3) 2724 return 2725 } 2726 2727 goto longdiv 2728 2729 // division and mod using (slow) hardware instruction 2730 longdiv: 2731 Thearch.Dodiv(op, nl, nr, res) 2732 2733 return 2734 2735 // mod using formula A%B = A-(A/B*B) but 2736 // we know that there is a fast algorithm for A/B 2737 longmod: 2738 var n1 Node 2739 Regalloc(&n1, nl.Type, res) 2740 2741 Cgen(nl, &n1) 2742 var n2 Node 2743 Regalloc(&n2, nl.Type, nil) 2744 cgen_div(ODIV, &n1, nr, &n2) 2745 a := Thearch.Optoas(OMUL, nl.Type) 2746 if w == 8 { 2747 // use 2-operand 16-bit multiply 2748 // because there is no 2-operand 8-bit multiply 2749 a = Thearch.Optoas(OMUL, Types[TINT16]) // XXX was IMULW 2750 } 2751 2752 if !Smallintconst(nr) { 2753 var n3 Node 2754 Regalloc(&n3, nl.Type, nil) 2755 Cgen(nr, &n3) 2756 Thearch.Gins(a, &n3, &n2) 2757 Regfree(&n3) 2758 } else { 2759 Thearch.Gins(a, nr, &n2) 2760 } 2761 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n2, &n1) 2762 Thearch.Gmove(&n1, res) 2763 Regfree(&n1) 2764 Regfree(&n2) 2765 } 2766 2767 func Fixlargeoffset(n *Node) { 2768 if n == nil { 2769 return 2770 } 2771 if n.Op != OINDREG { 2772 return 2773 } 2774 if n.Reg == int16(Thearch.REGSP) { // stack offset cannot be large 2775 return 2776 } 2777 if n.Xoffset != int64(int32(n.Xoffset)) { 2778 // offset too large, add to register instead. 2779 a := *n 2780 2781 a.Op = OREGISTER 2782 a.Type = Types[Tptr] 2783 a.Xoffset = 0 2784 Cgen_checknil(&a) 2785 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), n.Xoffset, &a) 2786 n.Xoffset = 0 2787 } 2788 }