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