github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/zz1 (about) 1 // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/zz1 2 3 //line /Users/rsc/g/go/src/cmd/internal/gc/zz1:1 4 // Copyright 2009 The Go Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file. 7 8 package gc 9 10 import ( 11 "bootstrap/internal/obj" 12 "fmt" 13 ) 14 15 /* 16 * generate: 17 * res = n; 18 * simplifies and calls Thearch.Gmove. 19 * if wb is true, need to emit write barriers. 20 */ 21 func Cgen(n, res *Node) { 22 cgen_wb(n, res, false) 23 } 24 25 func cgen_wb(n, res *Node, wb bool) { 26 if Debug['g'] != 0 { 27 op := "cgen" 28 if wb { 29 op = "cgen_wb" 30 } 31 Dump("\n"+op+"-n", n) 32 Dump(op+"-res", res) 33 } 34 35 if n == nil || n.Type == nil { 36 return 37 } 38 39 if res == nil || res.Type == nil { 40 Fatal("cgen: res nil") 41 } 42 43 for n.Op == OCONVNOP { 44 n = n.Left 45 } 46 47 switch n.Op { 48 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: 49 if res.Op != ONAME || !res.Addable || wb { 50 var n1 Node 51 Tempname(&n1, n.Type) 52 Cgen_slice(n, &n1) 53 cgen_wb(&n1, res, wb) 54 } else { 55 Cgen_slice(n, res) 56 } 57 return 58 59 case OEFACE: 60 if res.Op != ONAME || !res.Addable || wb { 61 var n1 Node 62 Tempname(&n1, n.Type) 63 Cgen_eface(n, &n1) 64 cgen_wb(&n1, res, wb) 65 } else { 66 Cgen_eface(n, res) 67 } 68 return 69 70 case ODOTTYPE: 71 cgen_dottype(n, res, nil, wb) 72 return 73 } 74 75 if n.Ullman >= UINF { 76 if n.Op == OINDREG { 77 Fatal("cgen: this is going to miscompile") 78 } 79 if res.Ullman >= UINF { 80 var n1 Node 81 Tempname(&n1, n.Type) 82 Cgen(n, &n1) 83 cgen_wb(&n1, res, wb) 84 return 85 } 86 } 87 88 if Isfat(n.Type) { 89 if n.Type.Width < 0 { 90 Fatal("forgot to compute width for %v", n.Type) 91 } 92 sgen_wb(n, res, n.Type.Width, wb) 93 return 94 } 95 96 if !res.Addable { 97 if n.Ullman > res.Ullman { 98 if Ctxt.Arch.Regsize == 4 && Is64(n.Type) { 99 var n1 Node 100 Tempname(&n1, n.Type) 101 Cgen(n, &n1) 102 cgen_wb(&n1, res, wb) 103 return 104 } 105 106 var n1 Node 107 Regalloc(&n1, n.Type, res) 108 Cgen(n, &n1) 109 if n1.Ullman > res.Ullman { 110 Dump("n1", &n1) 111 Dump("res", res) 112 Fatal("loop in cgen") 113 } 114 115 cgen_wb(&n1, res, wb) 116 Regfree(&n1) 117 return 118 } 119 120 var f int 121 if res.Ullman < UINF { 122 if Complexop(n, res) { 123 Complexgen(n, res) 124 return 125 } 126 127 f = 1 // gen thru register 128 switch n.Op { 129 case OLITERAL: 130 if Smallintconst(n) { 131 f = 0 132 } 133 134 case OREGISTER: 135 f = 0 136 } 137 138 if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 && !wb { 139 a := Thearch.Optoas(OAS, res.Type) 140 var addr obj.Addr 141 if Thearch.Sudoaddable(a, res, &addr) { 142 var p1 *obj.Prog 143 if f != 0 { 144 var n2 Node 145 Regalloc(&n2, res.Type, nil) 146 Cgen(n, &n2) 147 p1 = Thearch.Gins(a, &n2, nil) 148 Regfree(&n2) 149 } else { 150 p1 = Thearch.Gins(a, n, nil) 151 } 152 p1.To = addr 153 if Debug['g'] != 0 { 154 fmt.Printf("%v [ignore previous line]\n", p1) 155 } 156 Thearch.Sudoclean() 157 return 158 } 159 } 160 } 161 162 if Ctxt.Arch.Thechar == '8' { 163 // no registers to speak of 164 var n1 Node 165 Tempname(&n1, n.Type) 166 Cgen(n, &n1) 167 cgen_wb(&n1, res, wb) 168 return 169 } 170 171 var n1 Node 172 Igen(res, &n1, nil) 173 cgen_wb(n, &n1, wb) 174 Regfree(&n1) 175 return 176 } 177 178 // update addressability for string, slice 179 // can't do in walk because n->left->addable 180 // changes if n->left is an escaping local variable. 181 switch n.Op { 182 case OSPTR, OLEN: 183 if Isslice(n.Left.Type) || Istype(n.Left.Type, TSTRING) { 184 n.Addable = n.Left.Addable 185 } 186 187 case OCAP: 188 if Isslice(n.Left.Type) { 189 n.Addable = n.Left.Addable 190 } 191 192 case OITAB: 193 n.Addable = n.Left.Addable 194 } 195 196 if wb { 197 if int(Simtype[res.Type.Etype]) != Tptr { 198 Fatal("cgen_wb of type %v", res.Type) 199 } 200 if n.Ullman >= UINF { 201 var n1 Node 202 Tempname(&n1, n.Type) 203 Cgen(n, &n1) 204 n = &n1 205 } 206 cgen_wbptr(n, res) 207 return 208 } 209 210 // Write barrier now handled. Code below this line can ignore wb. 211 212 if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often? 213 // if both are addressable, move 214 if n.Addable && res.Addable { 215 if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || Iscomplex[n.Type.Etype] || Iscomplex[res.Type.Etype] { 216 Thearch.Gmove(n, res) 217 } else { 218 var n1 Node 219 Regalloc(&n1, n.Type, nil) 220 Thearch.Gmove(n, &n1) 221 Cgen(&n1, res) 222 Regfree(&n1) 223 } 224 225 return 226 } 227 228 // if both are not addressable, use a temporary. 229 if !n.Addable && !res.Addable { 230 // could use regalloc here sometimes, 231 // but have to check for ullman >= UINF. 232 var n1 Node 233 Tempname(&n1, n.Type) 234 Cgen(n, &n1) 235 Cgen(&n1, res) 236 return 237 } 238 239 // if result is not addressable directly but n is, 240 // compute its address and then store via the address. 241 if !res.Addable { 242 var n1 Node 243 Igen(res, &n1, nil) 244 Cgen(n, &n1) 245 Regfree(&n1) 246 return 247 } 248 } 249 250 if Complexop(n, res) { 251 Complexgen(n, res) 252 return 253 } 254 255 if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable { 256 Thearch.Gmove(n, res) 257 return 258 } 259 260 if Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { 261 // if both are addressable, move 262 if n.Addable { 263 if n.Op == OREGISTER || res.Op == OREGISTER { 264 Thearch.Gmove(n, res) 265 } else { 266 var n1 Node 267 Regalloc(&n1, n.Type, nil) 268 Thearch.Gmove(n, &n1) 269 Cgen(&n1, res) 270 Regfree(&n1) 271 } 272 return 273 } 274 } 275 276 // if n is sudoaddable generate addr and move 277 if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !Iscomplex[n.Type.Etype] && !Iscomplex[res.Type.Etype] { 278 a := Thearch.Optoas(OAS, n.Type) 279 var addr obj.Addr 280 if Thearch.Sudoaddable(a, n, &addr) { 281 if res.Op != OREGISTER { 282 var n2 Node 283 Regalloc(&n2, res.Type, nil) 284 p1 := Thearch.Gins(a, nil, &n2) 285 p1.From = addr 286 if Debug['g'] != 0 { 287 fmt.Printf("%v [ignore previous line]\n", p1) 288 } 289 Thearch.Gmove(&n2, res) 290 Regfree(&n2) 291 } else { 292 p1 := Thearch.Gins(a, nil, res) 293 p1.From = addr 294 if Debug['g'] != 0 { 295 fmt.Printf("%v [ignore previous line]\n", p1) 296 } 297 } 298 Thearch.Sudoclean() 299 return 300 } 301 } 302 303 nl := n.Left 304 nr := n.Right 305 306 if nl != nil && nl.Ullman >= UINF { 307 if nr != nil && nr.Ullman >= UINF { 308 var n1 Node 309 Tempname(&n1, nl.Type) 310 Cgen(nl, &n1) 311 n2 := *n 312 n2.Left = &n1 313 Cgen(&n2, res) 314 return 315 } 316 } 317 318 // 64-bit ops are hard on 32-bit machine. 319 if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) { 320 switch n.Op { 321 // math goes to cgen64. 322 case OMINUS, 323 OCOM, 324 OADD, 325 OSUB, 326 OMUL, 327 OLROT, 328 OLSH, 329 ORSH, 330 OAND, 331 OOR, 332 OXOR: 333 Thearch.Cgen64(n, res) 334 return 335 } 336 } 337 338 if Thearch.Cgen_float != nil && nl != nil && Isfloat[n.Type.Etype] && Isfloat[nl.Type.Etype] { 339 Thearch.Cgen_float(n, res) 340 return 341 } 342 343 if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 { 344 a := Thearch.Optoas(OAS, n.Type) 345 var addr obj.Addr 346 if Thearch.Sudoaddable(a, n, &addr) { 347 if res.Op == OREGISTER { 348 p1 := Thearch.Gins(a, nil, res) 349 p1.From = addr 350 } else { 351 var n2 Node 352 Regalloc(&n2, n.Type, nil) 353 p1 := Thearch.Gins(a, nil, &n2) 354 p1.From = addr 355 Thearch.Gins(a, &n2, res) 356 Regfree(&n2) 357 } 358 359 Thearch.Sudoclean() 360 return 361 } 362 } 363 364 var a int 365 switch n.Op { 366 default: 367 Dump("cgen", n) 368 Dump("cgen-res", res) 369 Fatal("cgen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign)) 370 371 case OOROR, OANDAND, 372 OEQ, ONE, 373 OLT, OLE, 374 OGE, OGT, 375 ONOT: 376 Bvgen(n, res, true) 377 return 378 379 case OPLUS: 380 Cgen(nl, res) 381 return 382 383 // unary 384 case OCOM: 385 a := Thearch.Optoas(OXOR, nl.Type) 386 387 var n1 Node 388 Regalloc(&n1, nl.Type, nil) 389 Cgen(nl, &n1) 390 var n2 Node 391 Nodconst(&n2, nl.Type, -1) 392 Thearch.Gins(a, &n2, &n1) 393 cgen_norm(n, &n1, res) 394 return 395 396 case OMINUS: 397 if Isfloat[nl.Type.Etype] { 398 nr = Nodintconst(-1) 399 Convlit(&nr, n.Type) 400 a = Thearch.Optoas(OMUL, nl.Type) 401 goto sbop 402 } 403 404 a := Thearch.Optoas(int(n.Op), nl.Type) 405 // unary 406 var n1 Node 407 Regalloc(&n1, nl.Type, res) 408 409 Cgen(nl, &n1) 410 if Ctxt.Arch.Thechar == '5' { 411 var n2 Node 412 Nodconst(&n2, nl.Type, 0) 413 Thearch.Gins(a, &n2, &n1) 414 } else if Ctxt.Arch.Thechar == '7' { 415 Thearch.Gins(a, &n1, &n1) 416 } else { 417 Thearch.Gins(a, nil, &n1) 418 } 419 cgen_norm(n, &n1, res) 420 return 421 422 case OSQRT: 423 var n1 Node 424 Regalloc(&n1, nl.Type, res) 425 Cgen(n.Left, &n1) 426 Thearch.Gins(Thearch.Optoas(OSQRT, nl.Type), &n1, &n1) 427 Thearch.Gmove(&n1, res) 428 Regfree(&n1) 429 return 430 431 case OGETG: 432 Thearch.Getg(res) 433 return 434 435 // symmetric binary 436 case OAND, 437 OOR, 438 OXOR, 439 OADD, 440 OMUL: 441 if n.Op == OMUL && Thearch.Cgen_bmul != nil && Thearch.Cgen_bmul(int(n.Op), nl, nr, res) { 442 break 443 } 444 a = Thearch.Optoas(int(n.Op), nl.Type) 445 goto sbop 446 447 // asymmetric binary 448 case OSUB: 449 a = Thearch.Optoas(int(n.Op), nl.Type) 450 goto abop 451 452 case OHMUL: 453 Thearch.Cgen_hmul(nl, nr, res) 454 455 case OCONV: 456 if Eqtype(n.Type, nl.Type) || Noconv(n.Type, nl.Type) { 457 Cgen(nl, res) 458 return 459 } 460 461 if Ctxt.Arch.Thechar == '8' { 462 var n1 Node 463 var n2 Node 464 Tempname(&n2, n.Type) 465 Mgen(nl, &n1, res) 466 Thearch.Gmove(&n1, &n2) 467 Thearch.Gmove(&n2, res) 468 Mfree(&n1) 469 break 470 } 471 472 var n1 Node 473 var n2 Node 474 if Ctxt.Arch.Thechar == '5' { 475 if nl.Addable && !Is64(nl.Type) { 476 Regalloc(&n1, nl.Type, res) 477 Thearch.Gmove(nl, &n1) 478 } else { 479 if n.Type.Width > int64(Widthptr) || Is64(nl.Type) || Isfloat[nl.Type.Etype] { 480 Tempname(&n1, nl.Type) 481 } else { 482 Regalloc(&n1, nl.Type, res) 483 } 484 Cgen(nl, &n1) 485 } 486 if n.Type.Width > int64(Widthptr) || Is64(n.Type) || Isfloat[n.Type.Etype] { 487 Tempname(&n2, n.Type) 488 } else { 489 Regalloc(&n2, n.Type, nil) 490 } 491 } else { 492 if n.Type.Width > nl.Type.Width { 493 // If loading from memory, do conversion during load, 494 // so as to avoid use of 8-bit register in, say, int(*byteptr). 495 switch nl.Op { 496 case ODOT, ODOTPTR, OINDEX, OIND, ONAME: 497 Igen(nl, &n1, res) 498 Regalloc(&n2, n.Type, res) 499 Thearch.Gmove(&n1, &n2) 500 Thearch.Gmove(&n2, res) 501 Regfree(&n2) 502 Regfree(&n1) 503 return 504 } 505 } 506 Regalloc(&n1, nl.Type, res) 507 Regalloc(&n2, n.Type, &n1) 508 Cgen(nl, &n1) 509 } 510 511 // if we do the conversion n1 -> n2 here 512 // reusing the register, then gmove won't 513 // have to allocate its own register. 514 Thearch.Gmove(&n1, &n2) 515 Thearch.Gmove(&n2, res) 516 if n2.Op == OREGISTER { 517 Regfree(&n2) 518 } 519 if n1.Op == OREGISTER { 520 Regfree(&n1) 521 } 522 523 case ODOT, 524 ODOTPTR, 525 OINDEX, 526 OIND, 527 ONAME: // PHEAP or PPARAMREF var 528 var n1 Node 529 Igen(n, &n1, res) 530 531 Thearch.Gmove(&n1, res) 532 Regfree(&n1) 533 534 // interface table is first word of interface value 535 case OITAB: 536 var n1 Node 537 Igen(nl, &n1, res) 538 539 n1.Type = n.Type 540 Thearch.Gmove(&n1, res) 541 Regfree(&n1) 542 543 case OSPTR: 544 // pointer is the first word of string or slice. 545 if Isconst(nl, CTSTR) { 546 var n1 Node 547 Regalloc(&n1, Types[Tptr], res) 548 p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1) 549 Datastring(nl.Val.U.Sval, &p1.From) 550 p1.From.Type = obj.TYPE_ADDR 551 Thearch.Gmove(&n1, res) 552 Regfree(&n1) 553 break 554 } 555 556 var n1 Node 557 Igen(nl, &n1, res) 558 n1.Type = n.Type 559 Thearch.Gmove(&n1, res) 560 Regfree(&n1) 561 562 case OLEN: 563 if Istype(nl.Type, TMAP) || Istype(nl.Type, TCHAN) { 564 // map and chan have len in the first int-sized word. 565 // a zero pointer means zero length 566 var n1 Node 567 Regalloc(&n1, Types[Tptr], res) 568 569 Cgen(nl, &n1) 570 571 var n2 Node 572 Nodconst(&n2, Types[Tptr], 0) 573 Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2) 574 p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0) 575 576 n2 = n1 577 n2.Op = OINDREG 578 n2.Type = Types[Simtype[TINT]] 579 Thearch.Gmove(&n2, &n1) 580 581 Patch(p1, Pc) 582 583 Thearch.Gmove(&n1, res) 584 Regfree(&n1) 585 break 586 } 587 588 if Istype(nl.Type, TSTRING) || Isslice(nl.Type) { 589 // both slice and string have len one pointer into the struct. 590 // a zero pointer means zero length 591 var n1 Node 592 Igen(nl, &n1, res) 593 594 n1.Type = Types[Simtype[TUINT]] 595 n1.Xoffset += int64(Array_nel) 596 Thearch.Gmove(&n1, res) 597 Regfree(&n1) 598 break 599 } 600 601 Fatal("cgen: OLEN: unknown type %v", Tconv(nl.Type, obj.FmtLong)) 602 603 case OCAP: 604 if Istype(nl.Type, TCHAN) { 605 // chan has cap in the second int-sized word. 606 // a zero pointer means zero length 607 var n1 Node 608 Regalloc(&n1, Types[Tptr], res) 609 610 Cgen(nl, &n1) 611 612 var n2 Node 613 Nodconst(&n2, Types[Tptr], 0) 614 Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n1, &n2) 615 p1 := Gbranch(Thearch.Optoas(OEQ, Types[Tptr]), nil, 0) 616 617 n2 = n1 618 n2.Op = OINDREG 619 n2.Xoffset = int64(Widthint) 620 n2.Type = Types[Simtype[TINT]] 621 Thearch.Gmove(&n2, &n1) 622 623 Patch(p1, Pc) 624 625 Thearch.Gmove(&n1, res) 626 Regfree(&n1) 627 break 628 } 629 630 if Isslice(nl.Type) { 631 var n1 Node 632 Igen(nl, &n1, res) 633 n1.Type = Types[Simtype[TUINT]] 634 n1.Xoffset += int64(Array_cap) 635 Thearch.Gmove(&n1, res) 636 Regfree(&n1) 637 break 638 } 639 640 Fatal("cgen: OCAP: unknown type %v", Tconv(nl.Type, obj.FmtLong)) 641 642 case OADDR: 643 if n.Bounded { // let race detector avoid nil checks 644 Disable_checknil++ 645 } 646 Agen(nl, res) 647 if n.Bounded { 648 Disable_checknil-- 649 } 650 651 case OCALLMETH: 652 cgen_callmeth(n, 0) 653 cgen_callret(n, res) 654 655 case OCALLINTER: 656 cgen_callinter(n, res, 0) 657 cgen_callret(n, res) 658 659 case OCALLFUNC: 660 cgen_call(n, 0) 661 cgen_callret(n, res) 662 663 case OMOD, ODIV: 664 if Isfloat[n.Type.Etype] || Thearch.Dodiv == nil { 665 a = Thearch.Optoas(int(n.Op), nl.Type) 666 goto abop 667 } 668 669 if nl.Ullman >= nr.Ullman { 670 var n1 Node 671 Regalloc(&n1, nl.Type, res) 672 Cgen(nl, &n1) 673 cgen_div(int(n.Op), &n1, nr, res) 674 Regfree(&n1) 675 } else { 676 var n2 Node 677 if !Smallintconst(nr) { 678 Regalloc(&n2, nr.Type, res) 679 Cgen(nr, &n2) 680 } else { 681 n2 = *nr 682 } 683 684 cgen_div(int(n.Op), nl, &n2, res) 685 if n2.Op != OLITERAL { 686 Regfree(&n2) 687 } 688 } 689 690 case OLSH, ORSH, OLROT: 691 Thearch.Cgen_shift(int(n.Op), n.Bounded, nl, nr, res) 692 } 693 694 return 695 696 /* 697 * put simplest on right - we'll generate into left 698 * and then adjust it using the computation of right. 699 * constants and variables have the same ullman 700 * count, so look for constants specially. 701 * 702 * an integer constant we can use as an immediate 703 * is simpler than a variable - we can use the immediate 704 * in the adjustment instruction directly - so it goes 705 * on the right. 706 * 707 * other constants, like big integers or floating point 708 * constants, require a mov into a register, so those 709 * might as well go on the left, so we can reuse that 710 * register for the computation. 711 */ 712 sbop: // symmetric binary 713 if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (Smallintconst(nl) || (nr.Op == OLITERAL && !Smallintconst(nr)))) { 714 r := nl 715 nl = nr 716 nr = r 717 } 718 719 abop: // asymmetric binary 720 var n1 Node 721 var n2 Node 722 if Ctxt.Arch.Thechar == '8' { 723 // no registers, sigh 724 if Smallintconst(nr) { 725 var n1 Node 726 Mgen(nl, &n1, res) 727 var n2 Node 728 Regalloc(&n2, nl.Type, &n1) 729 Thearch.Gmove(&n1, &n2) 730 Thearch.Gins(a, nr, &n2) 731 Thearch.Gmove(&n2, res) 732 Regfree(&n2) 733 Mfree(&n1) 734 } else if nl.Ullman >= nr.Ullman { 735 var nt Node 736 Tempname(&nt, nl.Type) 737 Cgen(nl, &nt) 738 var n2 Node 739 Mgen(nr, &n2, nil) 740 var n1 Node 741 Regalloc(&n1, nl.Type, res) 742 Thearch.Gmove(&nt, &n1) 743 Thearch.Gins(a, &n2, &n1) 744 Thearch.Gmove(&n1, res) 745 Regfree(&n1) 746 Mfree(&n2) 747 } else { 748 var n2 Node 749 Regalloc(&n2, nr.Type, res) 750 Cgen(nr, &n2) 751 var n1 Node 752 Regalloc(&n1, nl.Type, nil) 753 Cgen(nl, &n1) 754 Thearch.Gins(a, &n2, &n1) 755 Regfree(&n2) 756 Thearch.Gmove(&n1, res) 757 Regfree(&n1) 758 } 759 return 760 } 761 762 if nl.Ullman >= nr.Ullman { 763 Regalloc(&n1, nl.Type, res) 764 Cgen(nl, &n1) 765 766 if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm 767 n2 = *nr 768 } else { 769 Regalloc(&n2, nr.Type, nil) 770 Cgen(nr, &n2) 771 } 772 } else { 773 if Smallintconst(nr) && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm 774 n2 = *nr 775 } else { 776 Regalloc(&n2, nr.Type, res) 777 Cgen(nr, &n2) 778 } 779 780 Regalloc(&n1, nl.Type, nil) 781 Cgen(nl, &n1) 782 } 783 784 Thearch.Gins(a, &n2, &n1) 785 if n2.Op != OLITERAL { 786 Regfree(&n2) 787 } 788 cgen_norm(n, &n1, res) 789 } 790 791 var sys_wbptr *Node 792 793 func cgen_wbptr(n, res *Node) { 794 if Debug_wb > 0 { 795 Warn("write barrier") 796 } 797 var dst, src Node 798 Agenr(res, &dst, nil) 799 Cgenr(n, &src, nil) 800 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &dst, nil) 801 a := &p.To 802 a.Type = obj.TYPE_MEM 803 a.Reg = int16(Thearch.REGSP) 804 a.Offset = 0 805 if HasLinkRegister() { 806 a.Offset += int64(Widthptr) 807 } 808 p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil) 809 p2.To = p.To 810 p2.To.Offset += int64(Widthptr) 811 Regfree(&dst) 812 Regfree(&src) 813 if sys_wbptr == nil { 814 sys_wbptr = writebarrierfn("writebarrierptr", Types[Tptr], Types[Tptr]) 815 } 816 Ginscall(sys_wbptr, 0) 817 } 818 819 func cgen_wbfat(n, res *Node) { 820 if Debug_wb > 0 { 821 Warn("write barrier") 822 } 823 needType := true 824 funcName := "typedmemmove" 825 var dst, src Node 826 if n.Ullman >= res.Ullman { 827 Agenr(n, &src, nil) 828 Agenr(res, &dst, nil) 829 } else { 830 Agenr(res, &dst, nil) 831 Agenr(n, &src, nil) 832 } 833 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &dst, nil) 834 a := &p.To 835 a.Type = obj.TYPE_MEM 836 a.Reg = int16(Thearch.REGSP) 837 a.Offset = 0 838 if HasLinkRegister() { 839 a.Offset += int64(Widthptr) 840 } 841 if needType { 842 a.Offset += int64(Widthptr) 843 } 844 p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil) 845 p2.To = p.To 846 p2.To.Offset += int64(Widthptr) 847 Regfree(&dst) 848 Regfree(&src) 849 if needType { 850 p3 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), typename(n.Type), nil) 851 p3.To = p2.To 852 p3.To.Offset -= 2 * int64(Widthptr) 853 Regfree(&src) 854 } 855 Ginscall(writebarrierfn(funcName, Types[Tptr], Types[Tptr]), 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.Addable { 1517 if n.Op == OREGISTER { 1518 Fatal("agen OREGISTER") 1519 } 1520 var n1 Node 1521 n1.Op = OADDR 1522 n1.Left = n 1523 var n2 Node 1524 Regalloc(&n2, Types[Tptr], res) 1525 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n1, &n2) 1526 Thearch.Gmove(&n2, res) 1527 Regfree(&n2) 1528 return 1529 } 1530 1531 nl := n.Left 1532 1533 switch n.Op { 1534 default: 1535 Fatal("agen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign)) 1536 1537 case OCALLMETH: 1538 cgen_callmeth(n, 0) 1539 cgen_aret(n, res) 1540 1541 case OCALLINTER: 1542 cgen_callinter(n, res, 0) 1543 cgen_aret(n, res) 1544 1545 case OCALLFUNC: 1546 cgen_call(n, 0) 1547 cgen_aret(n, res) 1548 1549 case OEFACE, ODOTTYPE, OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: 1550 var n1 Node 1551 Tempname(&n1, n.Type) 1552 Cgen(n, &n1) 1553 Agen(&n1, res) 1554 1555 case OINDEX: 1556 var n1 Node 1557 Agenr(n, &n1, res) 1558 Thearch.Gmove(&n1, res) 1559 Regfree(&n1) 1560 1561 case ONAME: 1562 // should only get here with names in this func. 1563 if n.Funcdepth > 0 && n.Funcdepth != Funcdepth { 1564 Dump("bad agen", n) 1565 Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, Funcdepth) 1566 } 1567 1568 // should only get here for heap vars or paramref 1569 if n.Class&PHEAP == 0 && n.Class != PPARAMREF { 1570 Dump("bad agen", n) 1571 Fatal("agen: bad ONAME class %#x", n.Class) 1572 } 1573 1574 Cgen(n.Heapaddr, res) 1575 if n.Xoffset != 0 { 1576 addOffset(res, n.Xoffset) 1577 } 1578 1579 case OIND: 1580 Cgen(nl, res) 1581 Cgen_checknil(res) 1582 1583 case ODOT: 1584 Agen(nl, res) 1585 if n.Xoffset != 0 { 1586 addOffset(res, n.Xoffset) 1587 } 1588 1589 case ODOTPTR: 1590 Cgen(nl, res) 1591 Cgen_checknil(res) 1592 if n.Xoffset != 0 { 1593 addOffset(res, n.Xoffset) 1594 } 1595 } 1596 } 1597 1598 func addOffset(res *Node, offset int64) { 1599 if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' { 1600 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res) 1601 return 1602 } 1603 1604 var n1, n2 Node 1605 Regalloc(&n1, Types[Tptr], nil) 1606 Thearch.Gmove(res, &n1) 1607 Regalloc(&n2, Types[Tptr], nil) 1608 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), Nodintconst(offset), &n2) 1609 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n1) 1610 Thearch.Gmove(&n1, res) 1611 Regfree(&n1) 1612 Regfree(&n2) 1613 } 1614 1615 // Igen computes the address &n, stores it in a register r, 1616 // and rewrites a to refer to *r. The chosen r may be the 1617 // stack pointer, it may be borrowed from res, or it may 1618 // be a newly allocated register. The caller must call Regfree(a) 1619 // to free r when the address is no longer needed. 1620 // The generated code ensures that &n is not nil. 1621 func Igen(n *Node, a *Node, res *Node) { 1622 if Debug['g'] != 0 { 1623 Dump("\nigen-n", n) 1624 } 1625 1626 switch n.Op { 1627 case ONAME: 1628 if (n.Class&PHEAP != 0) || n.Class == PPARAMREF { 1629 break 1630 } 1631 *a = *n 1632 return 1633 1634 case OINDREG: 1635 // Increase the refcount of the register so that igen's caller 1636 // has to call Regfree. 1637 if n.Reg != int16(Thearch.REGSP) { 1638 reg[n.Reg-int16(Thearch.REGMIN)]++ 1639 } 1640 *a = *n 1641 return 1642 1643 case ODOT: 1644 Igen(n.Left, a, res) 1645 a.Xoffset += n.Xoffset 1646 a.Type = n.Type 1647 Fixlargeoffset(a) 1648 return 1649 1650 case ODOTPTR: 1651 Cgenr(n.Left, a, res) 1652 Cgen_checknil(a) 1653 a.Op = OINDREG 1654 a.Xoffset += n.Xoffset 1655 a.Type = n.Type 1656 Fixlargeoffset(a) 1657 return 1658 1659 case OCALLFUNC, OCALLMETH, OCALLINTER: 1660 switch n.Op { 1661 case OCALLFUNC: 1662 cgen_call(n, 0) 1663 1664 case OCALLMETH: 1665 cgen_callmeth(n, 0) 1666 1667 case OCALLINTER: 1668 cgen_callinter(n, nil, 0) 1669 } 1670 1671 var flist Iter 1672 fp := Structfirst(&flist, Getoutarg(n.Left.Type)) 1673 *a = Node{} 1674 a.Op = OINDREG 1675 a.Reg = int16(Thearch.REGSP) 1676 a.Addable = true 1677 a.Xoffset = fp.Width 1678 if HasLinkRegister() { 1679 a.Xoffset += int64(Ctxt.Arch.Ptrsize) 1680 } 1681 a.Type = n.Type 1682 return 1683 1684 // Index of fixed-size array by constant can 1685 // put the offset in the addressing. 1686 // Could do the same for slice except that we need 1687 // to use the real index for the bounds checking. 1688 case OINDEX: 1689 if Isfixedarray(n.Left.Type) || (Isptr[n.Left.Type.Etype] && Isfixedarray(n.Left.Left.Type)) { 1690 if Isconst(n.Right, CTINT) { 1691 // Compute &a. 1692 if !Isptr[n.Left.Type.Etype] { 1693 Igen(n.Left, a, res) 1694 } else { 1695 var n1 Node 1696 Igen(n.Left, &n1, res) 1697 Cgen_checknil(&n1) 1698 Regalloc(a, Types[Tptr], res) 1699 Thearch.Gmove(&n1, a) 1700 Regfree(&n1) 1701 a.Op = OINDREG 1702 } 1703 1704 // Compute &a[i] as &a + i*width. 1705 a.Type = n.Type 1706 1707 a.Xoffset += Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width 1708 Fixlargeoffset(a) 1709 return 1710 } 1711 } 1712 } 1713 1714 Agenr(n, a, res) 1715 a.Op = OINDREG 1716 a.Type = n.Type 1717 } 1718 1719 // Bgen generates code for branches: 1720 // 1721 // if n == wantTrue { 1722 // goto to 1723 // } 1724 func Bgen(n *Node, wantTrue bool, likely int, to *obj.Prog) { 1725 bgenx(n, nil, wantTrue, likely, to) 1726 } 1727 1728 // Bvgen generates code for calculating boolean values: 1729 // res = n == wantTrue 1730 func Bvgen(n, res *Node, wantTrue bool) { 1731 if Thearch.Ginsboolval == nil { 1732 // Direct value generation not implemented for this architecture. 1733 // Implement using jumps. 1734 bvgenjump(n, res, wantTrue, true) 1735 return 1736 } 1737 bgenx(n, res, wantTrue, 0, nil) 1738 } 1739 1740 // bvgenjump implements boolean value generation using jumps: 1741 // if n == wantTrue { 1742 // res = 1 1743 // } else { 1744 // res = 0 1745 // } 1746 // geninit controls whether n's Ninit is generated. 1747 func bvgenjump(n, res *Node, wantTrue, geninit bool) { 1748 init := n.Ninit 1749 if !geninit { 1750 n.Ninit = nil 1751 } 1752 p1 := Gbranch(obj.AJMP, nil, 0) 1753 p2 := Pc 1754 Thearch.Gmove(Nodbool(true), res) 1755 p3 := Gbranch(obj.AJMP, nil, 0) 1756 Patch(p1, Pc) 1757 Bgen(n, wantTrue, 0, p2) 1758 Thearch.Gmove(Nodbool(false), res) 1759 Patch(p3, Pc) 1760 n.Ninit = init 1761 } 1762 1763 // bgenx is the backend for Bgen and Bvgen. 1764 // If res is nil, it generates a branch. 1765 // Otherwise, it generates a boolean value. 1766 func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { 1767 if Debug['g'] != 0 { 1768 fmt.Printf("\nbgenx wantTrue=%t likely=%d to=%v\n", wantTrue, likely, to) 1769 Dump("n", n) 1770 Dump("res", res) 1771 } 1772 1773 genval := res != nil 1774 1775 if n == nil { 1776 n = Nodbool(true) 1777 } 1778 1779 Genlist(n.Ninit) 1780 1781 if n.Type == nil { 1782 Convlit(&n, Types[TBOOL]) 1783 if n.Type == nil { 1784 return 1785 } 1786 } 1787 1788 if n.Type.Etype != TBOOL { 1789 Fatal("bgen: bad type %v for %v", n.Type, Oconv(int(n.Op), 0)) 1790 } 1791 1792 for n.Op == OCONVNOP { 1793 n = n.Left 1794 Genlist(n.Ninit) 1795 } 1796 1797 if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] { 1798 if genval { 1799 bvgenjump(n, res, wantTrue, false) 1800 return 1801 } 1802 Thearch.Bgen_float(n, wantTrue, likely, to) 1803 return 1804 } 1805 1806 switch n.Op { 1807 default: 1808 if genval { 1809 Cgen(n, res) 1810 if !wantTrue { 1811 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) 1812 } 1813 return 1814 } 1815 1816 var tmp Node 1817 Regalloc(&tmp, n.Type, nil) 1818 Cgen(n, &tmp) 1819 bgenNonZero(&tmp, nil, wantTrue, likely, to) 1820 Regfree(&tmp) 1821 return 1822 1823 case ONAME: 1824 if genval { 1825 // 5g, 7g, and 9g might need a temporary or other help here, 1826 // but they don't support direct generation of a bool value yet. 1827 // We can fix that as we go. 1828 switch Ctxt.Arch.Thechar { 1829 case '5', '7', '9': 1830 Fatal("genval 5g, 7g, 9g ONAMES not fully implemented") 1831 } 1832 Cgen(n, res) 1833 if !wantTrue { 1834 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) 1835 } 1836 return 1837 } 1838 1839 if n.Addable && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { 1840 // no need for a temporary 1841 bgenNonZero(n, nil, wantTrue, likely, to) 1842 return 1843 } 1844 var tmp Node 1845 Regalloc(&tmp, n.Type, nil) 1846 Cgen(n, &tmp) 1847 bgenNonZero(&tmp, nil, wantTrue, likely, to) 1848 Regfree(&tmp) 1849 return 1850 1851 case OLITERAL: 1852 // n is a constant. 1853 if !Isconst(n, CTBOOL) { 1854 Fatal("bgen: non-bool const %v\n", Nconv(n, obj.FmtLong)) 1855 } 1856 if genval { 1857 Cgen(Nodbool(wantTrue == n.Val.U.Bval), res) 1858 return 1859 } 1860 // If n == wantTrue, jump; otherwise do nothing. 1861 if wantTrue == n.Val.U.Bval { 1862 Patch(Gbranch(obj.AJMP, nil, likely), to) 1863 } 1864 return 1865 1866 case OANDAND, OOROR: 1867 and := (n.Op == OANDAND) == wantTrue 1868 if genval { 1869 p1 := Gbranch(obj.AJMP, nil, 0) 1870 p2 := Gbranch(obj.AJMP, nil, 0) 1871 Patch(p2, Pc) 1872 Cgen(Nodbool(!and), res) 1873 p3 := Gbranch(obj.AJMP, nil, 0) 1874 Patch(p1, Pc) 1875 Bgen(n.Left, wantTrue != and, 0, p2) 1876 Bvgen(n.Right, res, wantTrue) 1877 Patch(p3, Pc) 1878 return 1879 } 1880 1881 if and { 1882 p1 := Gbranch(obj.AJMP, nil, 0) 1883 p2 := Gbranch(obj.AJMP, nil, 0) 1884 Patch(p1, Pc) 1885 Bgen(n.Left, !wantTrue, -likely, p2) 1886 Bgen(n.Right, !wantTrue, -likely, p2) 1887 p1 = Gbranch(obj.AJMP, nil, 0) 1888 Patch(p1, to) 1889 Patch(p2, Pc) 1890 } else { 1891 Bgen(n.Left, wantTrue, likely, to) 1892 Bgen(n.Right, wantTrue, likely, to) 1893 } 1894 return 1895 1896 case ONOT: // unary 1897 if n.Left == nil || n.Left.Type == nil { 1898 return 1899 } 1900 bgenx(n.Left, res, !wantTrue, likely, to) 1901 return 1902 1903 case OEQ, ONE, OLT, OGT, OLE, OGE: 1904 if n.Left == nil || n.Left.Type == nil || n.Right == nil || n.Right.Type == nil { 1905 return 1906 } 1907 } 1908 1909 // n.Op is one of OEQ, ONE, OLT, OGT, OLE, OGE 1910 nl := n.Left 1911 nr := n.Right 1912 a := int(n.Op) 1913 1914 if !wantTrue { 1915 if Isfloat[nr.Type.Etype] { 1916 // Brcom is not valid on floats when NaN is involved. 1917 ll := n.Ninit // avoid re-genning Ninit 1918 n.Ninit = nil 1919 if genval { 1920 bgenx(n, res, true, likely, to) 1921 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) // res = !res 1922 n.Ninit = ll 1923 return 1924 } 1925 p1 := Gbranch(obj.AJMP, nil, 0) 1926 p2 := Gbranch(obj.AJMP, nil, 0) 1927 Patch(p1, Pc) 1928 bgenx(n, res, true, -likely, p2) 1929 Patch(Gbranch(obj.AJMP, nil, 0), to) 1930 Patch(p2, Pc) 1931 n.Ninit = ll 1932 return 1933 } 1934 1935 a = Brcom(a) 1936 } 1937 wantTrue = true 1938 1939 // make simplest on right 1940 if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) { 1941 a = Brrev(a) 1942 nl, nr = nr, nl 1943 } 1944 1945 if Isslice(nl.Type) || Isinter(nl.Type) { 1946 // front end should only leave cmp to literal nil 1947 if (a != OEQ && a != ONE) || nr.Op != OLITERAL { 1948 if Isslice(nl.Type) { 1949 Yyerror("illegal slice comparison") 1950 } else { 1951 Yyerror("illegal interface comparison") 1952 } 1953 return 1954 } 1955 1956 var ptr Node 1957 Igen(nl, &ptr, nil) 1958 if Isslice(nl.Type) { 1959 ptr.Xoffset += int64(Array_array) 1960 } 1961 ptr.Type = Types[Tptr] 1962 var tmp Node 1963 Regalloc(&tmp, ptr.Type, &ptr) 1964 Cgen(&ptr, &tmp) 1965 Regfree(&ptr) 1966 bgenNonZero(&tmp, res, a == OEQ != wantTrue, likely, to) 1967 Regfree(&tmp) 1968 return 1969 } 1970 1971 if Iscomplex[nl.Type.Etype] { 1972 complexbool(a, nl, nr, res, wantTrue, likely, to) 1973 return 1974 } 1975 1976 if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) { 1977 if genval { 1978 // TODO: Teach Cmp64 to generate boolean values and remove this. 1979 bvgenjump(n, res, wantTrue, false) 1980 return 1981 } 1982 if !nl.Addable || Isconst(nl, CTINT) { 1983 nl = CgenTemp(nl) 1984 } 1985 if !nr.Addable { 1986 nr = CgenTemp(nr) 1987 } 1988 Thearch.Cmp64(nl, nr, a, likely, to) 1989 return 1990 } 1991 1992 if nr.Ullman >= UINF { 1993 var n1 Node 1994 Regalloc(&n1, nl.Type, nil) 1995 Cgen(nl, &n1) 1996 1997 var tmp Node 1998 Tempname(&tmp, nl.Type) 1999 Thearch.Gmove(&n1, &tmp) 2000 Regfree(&n1) 2001 2002 var n2 Node 2003 Regalloc(&n2, nr.Type, nil) 2004 Cgen(nr, &n2) 2005 Regfree(&n2) 2006 2007 Regalloc(&n1, nl.Type, nil) 2008 Cgen(&tmp, &n1) 2009 Regfree(&n1) 2010 } else { 2011 var n1 Node 2012 if !nl.Addable && Ctxt.Arch.Thechar == '8' { 2013 Tempname(&n1, nl.Type) 2014 } else { 2015 Regalloc(&n1, nl.Type, nil) 2016 defer Regfree(&n1) 2017 } 2018 Cgen(nl, &n1) 2019 nl = &n1 2020 2021 if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' { 2022 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr) 2023 bins(nr.Type, res, a, likely, to) 2024 return 2025 } 2026 2027 if !nr.Addable && Ctxt.Arch.Thechar == '8' { 2028 nr = CgenTemp(nr) 2029 } 2030 2031 var n2 Node 2032 Regalloc(&n2, nr.Type, nil) 2033 Cgen(nr, &n2) 2034 nr = &n2 2035 Regfree(&n2) 2036 } 2037 2038 l, r := nl, nr 2039 2040 // On x86, only < and <= work right with NaN; reverse if needed 2041 if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) { 2042 l, r = r, l 2043 a = Brrev(a) 2044 } 2045 2046 // Do the comparison. 2047 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r) 2048 2049 // Handle floating point special cases. 2050 // Note that 8g has Bgen_float and is handled above. 2051 if Isfloat[nl.Type.Etype] { 2052 switch Ctxt.Arch.Thechar { 2053 case '5': 2054 if genval { 2055 Fatal("genval 5g Isfloat special cases not implemented") 2056 } 2057 switch n.Op { 2058 case ONE: 2059 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to) 2060 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 2061 default: 2062 p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely) 2063 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 2064 Patch(p, Pc) 2065 } 2066 return 2067 case '6': 2068 switch n.Op { 2069 case OEQ: 2070 // neither NE nor P 2071 if genval { 2072 var reg Node 2073 Regalloc(®, Types[TBOOL], nil) 2074 Thearch.Ginsboolval(Thearch.Optoas(OEQ, nr.Type), ®) 2075 Thearch.Ginsboolval(Thearch.Optoas(OPC, nr.Type), res) 2076 Thearch.Gins(Thearch.Optoas(OAND, Types[TBOOL]), ®, res) 2077 Regfree(®) 2078 } else { 2079 p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely) 2080 p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely) 2081 Patch(Gbranch(obj.AJMP, nil, 0), to) 2082 Patch(p1, Pc) 2083 Patch(p2, Pc) 2084 } 2085 return 2086 case ONE: 2087 // either NE or P 2088 if genval { 2089 var reg Node 2090 Regalloc(®, Types[TBOOL], nil) 2091 Thearch.Ginsboolval(Thearch.Optoas(ONE, nr.Type), ®) 2092 Thearch.Ginsboolval(Thearch.Optoas(OPS, nr.Type), res) 2093 Thearch.Gins(Thearch.Optoas(OOR, Types[TBOOL]), ®, res) 2094 Regfree(®) 2095 } else { 2096 Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to) 2097 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to) 2098 } 2099 return 2100 } 2101 case '7', '9': 2102 if genval { 2103 Fatal("genval 7g, 9g Isfloat special cases not implemented") 2104 } 2105 switch n.Op { 2106 // On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =. 2107 // TODO(josh): Convert a <= b to b > a instead? 2108 case OLE, OGE: 2109 if a == OLE { 2110 a = OLT 2111 } else { 2112 a = OGT 2113 } 2114 Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) 2115 Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to) 2116 return 2117 } 2118 } 2119 } 2120 2121 // Not a special case. Insert the conditional jump or value gen. 2122 bins(nr.Type, res, a, likely, to) 2123 } 2124 2125 func bgenNonZero(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { 2126 // TODO: Optimize on systems that can compare to zero easily. 2127 a := ONE 2128 if !wantTrue { 2129 a = OEQ 2130 } 2131 var zero Node 2132 Nodconst(&zero, n.Type, 0) 2133 Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &zero) 2134 bins(n.Type, res, a, likely, to) 2135 } 2136 2137 // bins inserts an instruction to handle the result of a compare. 2138 // If res is non-nil, it inserts appropriate value generation instructions. 2139 // If res is nil, it inserts a branch to to. 2140 func bins(typ *Type, res *Node, a, likely int, to *obj.Prog) { 2141 a = Thearch.Optoas(a, typ) 2142 if res != nil { 2143 // value gen 2144 Thearch.Ginsboolval(a, res) 2145 } else { 2146 // jump 2147 Patch(Gbranch(a, typ, likely), to) 2148 } 2149 } 2150 2151 /* 2152 * n is on stack, either local variable 2153 * or return value from function call. 2154 * return n's offset from SP. 2155 */ 2156 func stkof(n *Node) int64 { 2157 switch n.Op { 2158 case OINDREG: 2159 return n.Xoffset 2160 2161 case ODOT: 2162 t := n.Left.Type 2163 if Isptr[t.Etype] { 2164 break 2165 } 2166 off := stkof(n.Left) 2167 if off == -1000 || off == 1000 { 2168 return off 2169 } 2170 return off + n.Xoffset 2171 2172 case OINDEX: 2173 t := n.Left.Type 2174 if !Isfixedarray(t) { 2175 break 2176 } 2177 off := stkof(n.Left) 2178 if off == -1000 || off == 1000 { 2179 return off 2180 } 2181 if Isconst(n.Right, CTINT) { 2182 return off + t.Type.Width*Mpgetfix(n.Right.Val.U.Xval) 2183 } 2184 return 1000 2185 2186 case OCALLMETH, OCALLINTER, OCALLFUNC: 2187 t := n.Left.Type 2188 if Isptr[t.Etype] { 2189 t = t.Type 2190 } 2191 2192 var flist Iter 2193 t = Structfirst(&flist, Getoutarg(t)) 2194 if t != nil { 2195 w := t.Width 2196 if HasLinkRegister() { 2197 w += int64(Ctxt.Arch.Ptrsize) 2198 } 2199 return w 2200 } 2201 } 2202 2203 // botch - probably failing to recognize address 2204 // arithmetic on the above. eg INDEX and DOT 2205 return -1000 2206 } 2207 2208 /* 2209 * block copy: 2210 * memmove(&ns, &n, w); 2211 * if wb is true, needs write barrier. 2212 */ 2213 func sgen_wb(n *Node, ns *Node, w int64, wb bool) { 2214 if Debug['g'] != 0 { 2215 op := "sgen" 2216 if wb { 2217 op = "sgen-wb" 2218 } 2219 fmt.Printf("\n%s w=%d\n", op, w) 2220 Dump("r", n) 2221 Dump("res", ns) 2222 } 2223 2224 if n.Ullman >= UINF && ns.Ullman >= UINF { 2225 Fatal("sgen UINF") 2226 } 2227 2228 if w < 0 { 2229 Fatal("sgen copy %d", w) 2230 } 2231 2232 // If copying .args, that's all the results, so record definition sites 2233 // for them for the liveness analysis. 2234 if ns.Op == ONAME && ns.Sym.Name == ".args" { 2235 for l := Curfn.Func.Dcl; l != nil; l = l.Next { 2236 if l.N.Class == PPARAMOUT { 2237 Gvardef(l.N) 2238 } 2239 } 2240 } 2241 2242 // Avoid taking the address for simple enough types. 2243 if componentgen_wb(n, ns, wb) { 2244 return 2245 } 2246 2247 if w == 0 { 2248 // evaluate side effects only 2249 var nodr Node 2250 Regalloc(&nodr, Types[Tptr], nil) 2251 Agen(ns, &nodr) 2252 Agen(n, &nodr) 2253 Regfree(&nodr) 2254 return 2255 } 2256 2257 // offset on the stack 2258 osrc := stkof(n) 2259 odst := stkof(ns) 2260 2261 if odst != -1000 { 2262 // on stack, write barrier not needed after all 2263 wb = false 2264 } 2265 2266 if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) || wb && osrc != -1000 { 2267 // osrc and odst both on stack, and at least one is in 2268 // an unknown position. Could generate code to test 2269 // for forward/backward copy, but instead just copy 2270 // to a temporary location first. 2271 // 2272 // OR: write barrier needed and source is on stack. 2273 // Invoking the write barrier will use the stack to prepare its call. 2274 // Copy to temporary. 2275 var tmp Node 2276 Tempname(&tmp, n.Type) 2277 sgen_wb(n, &tmp, w, false) 2278 sgen_wb(&tmp, ns, w, wb) 2279 return 2280 } 2281 2282 if wb { 2283 cgen_wbfat(n, ns) 2284 return 2285 } 2286 2287 Thearch.Stackcopy(n, ns, osrc, odst, w) 2288 } 2289 2290 /* 2291 * generate: 2292 * call f 2293 * proc=-1 normal call but no return 2294 * proc=0 normal call 2295 * proc=1 goroutine run in new proc 2296 * proc=2 defer call save away stack 2297 * proc=3 normal call to C pointer (not Go func value) 2298 */ 2299 func Ginscall(f *Node, proc int) { 2300 if f.Type != nil { 2301 extra := int32(0) 2302 if proc == 1 || proc == 2 { 2303 extra = 2 * int32(Widthptr) 2304 } 2305 Setmaxarg(f.Type, extra) 2306 } 2307 2308 switch proc { 2309 default: 2310 Fatal("Ginscall: bad proc %d", proc) 2311 2312 case 0, // normal call 2313 -1: // normal call but no return 2314 if f.Op == ONAME && f.Class == PFUNC { 2315 if f == Deferreturn { 2316 // Deferred calls will appear to be returning to 2317 // the CALL deferreturn(SB) that we are about to emit. 2318 // However, the stack trace code will show the line 2319 // of the instruction byte before the return PC. 2320 // To avoid that being an unrelated instruction, 2321 // insert an actual hardware NOP that will have the right line number. 2322 // This is different from obj.ANOP, which is a virtual no-op 2323 // that doesn't make it into the instruction stream. 2324 Thearch.Ginsnop() 2325 } 2326 2327 p := Thearch.Gins(obj.ACALL, nil, f) 2328 Afunclit(&p.To, f) 2329 if proc == -1 || Noreturn(p) { 2330 Thearch.Gins(obj.AUNDEF, nil, nil) 2331 } 2332 break 2333 } 2334 2335 var reg Node 2336 Nodreg(®, Types[Tptr], Thearch.REGCTXT) 2337 var r1 Node 2338 Nodreg(&r1, Types[Tptr], Thearch.REGCALLX) 2339 Thearch.Gmove(f, ®) 2340 reg.Op = OINDREG 2341 Thearch.Gmove(®, &r1) 2342 reg.Op = OREGISTER 2343 Thearch.Gins(obj.ACALL, ®, &r1) 2344 2345 case 3: // normal call of c function pointer 2346 Thearch.Gins(obj.ACALL, nil, f) 2347 2348 case 1, // call in new proc (go) 2349 2: // deferred call (defer) 2350 var stk Node 2351 2352 // size of arguments at 0(SP) 2353 stk.Op = OINDREG 2354 stk.Reg = int16(Thearch.REGSP) 2355 stk.Xoffset = 0 2356 if HasLinkRegister() { 2357 stk.Xoffset += int64(Ctxt.Arch.Ptrsize) 2358 } 2359 Thearch.Ginscon(Thearch.Optoas(OAS, Types[Tptr]), int64(Argsize(f.Type)), &stk) 2360 2361 // FuncVal* at 8(SP) 2362 stk.Xoffset = int64(Widthptr) 2363 if HasLinkRegister() { 2364 stk.Xoffset += int64(Ctxt.Arch.Ptrsize) 2365 } 2366 2367 var reg Node 2368 Nodreg(®, Types[Tptr], Thearch.REGCALLX2) 2369 Thearch.Gmove(f, ®) 2370 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), ®, &stk) 2371 2372 if proc == 1 { 2373 Ginscall(Newproc, 0) 2374 } else { 2375 if Hasdefer == 0 { 2376 Fatal("hasdefer=0 but has defer") 2377 } 2378 Ginscall(Deferproc, 0) 2379 } 2380 2381 if proc == 2 { 2382 Nodreg(®, Types[TINT32], Thearch.REGRETURN) 2383 Thearch.Gins(Thearch.Optoas(OCMP, Types[TINT32]), ®, Nodintconst(0)) 2384 p := Gbranch(Thearch.Optoas(OEQ, Types[TINT32]), nil, +1) 2385 cgen_ret(nil) 2386 Patch(p, Pc) 2387 } 2388 } 2389 } 2390 2391 /* 2392 * n is call to interface method. 2393 * generate res = n. 2394 */ 2395 func cgen_callinter(n *Node, res *Node, proc int) { 2396 i := n.Left 2397 if i.Op != ODOTINTER { 2398 Fatal("cgen_callinter: not ODOTINTER %v", Oconv(int(i.Op), 0)) 2399 } 2400 2401 f := i.Right // field 2402 if f.Op != ONAME { 2403 Fatal("cgen_callinter: not ONAME %v", Oconv(int(f.Op), 0)) 2404 } 2405 2406 i = i.Left // interface 2407 2408 if !i.Addable { 2409 var tmpi Node 2410 Tempname(&tmpi, i.Type) 2411 Cgen(i, &tmpi) 2412 i = &tmpi 2413 } 2414 2415 Genlist(n.List) // assign the args 2416 2417 // i is now addable, prepare an indirected 2418 // register to hold its address. 2419 var nodi Node 2420 Igen(i, &nodi, res) // REG = &inter 2421 2422 var nodsp Node 2423 Nodindreg(&nodsp, Types[Tptr], Thearch.REGSP) 2424 nodsp.Xoffset = 0 2425 if HasLinkRegister() { 2426 nodsp.Xoffset += int64(Ctxt.Arch.Ptrsize) 2427 } 2428 if proc != 0 { 2429 nodsp.Xoffset += 2 * int64(Widthptr) // leave room for size & fn 2430 } 2431 nodi.Type = Types[Tptr] 2432 nodi.Xoffset += int64(Widthptr) 2433 Cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data 2434 2435 var nodo Node 2436 Regalloc(&nodo, Types[Tptr], res) 2437 2438 nodi.Type = Types[Tptr] 2439 nodi.Xoffset -= int64(Widthptr) 2440 Cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab 2441 Regfree(&nodi) 2442 2443 var nodr Node 2444 Regalloc(&nodr, Types[Tptr], &nodo) 2445 if n.Left.Xoffset == BADWIDTH { 2446 Fatal("cgen_callinter: badwidth") 2447 } 2448 Cgen_checknil(&nodo) // in case offset is huge 2449 nodo.Op = OINDREG 2450 nodo.Xoffset = n.Left.Xoffset + 3*int64(Widthptr) + 8 2451 if proc == 0 { 2452 // plain call: use direct c function pointer - more efficient 2453 Cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f] 2454 proc = 3 2455 } else { 2456 // go/defer. generate go func value. 2457 Agen(&nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f] 2458 } 2459 2460 nodr.Type = n.Left.Type 2461 Ginscall(&nodr, proc) 2462 2463 Regfree(&nodr) 2464 Regfree(&nodo) 2465 } 2466 2467 /* 2468 * generate function call; 2469 * proc=0 normal call 2470 * proc=1 goroutine run in new proc 2471 * proc=2 defer call save away stack 2472 */ 2473 func cgen_call(n *Node, proc int) { 2474 if n == nil { 2475 return 2476 } 2477 2478 var afun Node 2479 if n.Left.Ullman >= UINF { 2480 // if name involves a fn call 2481 // precompute the address of the fn 2482 Tempname(&afun, Types[Tptr]) 2483 2484 Cgen(n.Left, &afun) 2485 } 2486 2487 Genlist(n.List) // assign the args 2488 t := n.Left.Type 2489 2490 // call tempname pointer 2491 if n.Left.Ullman >= UINF { 2492 var nod Node 2493 Regalloc(&nod, Types[Tptr], nil) 2494 Cgen_as(&nod, &afun) 2495 nod.Type = t 2496 Ginscall(&nod, proc) 2497 Regfree(&nod) 2498 return 2499 } 2500 2501 // call pointer 2502 if n.Left.Op != ONAME || n.Left.Class != PFUNC { 2503 var nod Node 2504 Regalloc(&nod, Types[Tptr], nil) 2505 Cgen_as(&nod, n.Left) 2506 nod.Type = t 2507 Ginscall(&nod, proc) 2508 Regfree(&nod) 2509 return 2510 } 2511 2512 // call direct 2513 n.Left.Method = true 2514 2515 Ginscall(n.Left, proc) 2516 } 2517 2518 func HasLinkRegister() bool { 2519 c := Ctxt.Arch.Thechar 2520 return c != '6' && c != '8' 2521 } 2522 2523 /* 2524 * call to n has already been generated. 2525 * generate: 2526 * res = return value from call. 2527 */ 2528 func cgen_callret(n *Node, res *Node) { 2529 t := n.Left.Type 2530 if t.Etype == TPTR32 || t.Etype == TPTR64 { 2531 t = t.Type 2532 } 2533 2534 var flist Iter 2535 fp := Structfirst(&flist, Getoutarg(t)) 2536 if fp == nil { 2537 Fatal("cgen_callret: nil") 2538 } 2539 2540 var nod Node 2541 nod.Op = OINDREG 2542 nod.Reg = int16(Thearch.REGSP) 2543 nod.Addable = true 2544 2545 nod.Xoffset = fp.Width 2546 if HasLinkRegister() { 2547 nod.Xoffset += int64(Ctxt.Arch.Ptrsize) 2548 } 2549 nod.Type = fp.Type 2550 Cgen_as(res, &nod) 2551 } 2552 2553 /* 2554 * call to n has already been generated. 2555 * generate: 2556 * res = &return value from call. 2557 */ 2558 func cgen_aret(n *Node, res *Node) { 2559 t := n.Left.Type 2560 if Isptr[t.Etype] { 2561 t = t.Type 2562 } 2563 2564 var flist Iter 2565 fp := Structfirst(&flist, Getoutarg(t)) 2566 if fp == nil { 2567 Fatal("cgen_aret: nil") 2568 } 2569 2570 var nod1 Node 2571 nod1.Op = OINDREG 2572 nod1.Reg = int16(Thearch.REGSP) 2573 nod1.Addable = true 2574 nod1.Xoffset = fp.Width 2575 if HasLinkRegister() { 2576 nod1.Xoffset += int64(Ctxt.Arch.Ptrsize) 2577 } 2578 nod1.Type = fp.Type 2579 2580 if res.Op != OREGISTER { 2581 var nod2 Node 2582 Regalloc(&nod2, Types[Tptr], res) 2583 Agen(&nod1, &nod2) 2584 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &nod2, res) 2585 Regfree(&nod2) 2586 } else { 2587 Agen(&nod1, res) 2588 } 2589 } 2590 2591 /* 2592 * generate return. 2593 * n->left is assignments to return values. 2594 */ 2595 func cgen_ret(n *Node) { 2596 if n != nil { 2597 Genlist(n.List) // copy out args 2598 } 2599 if Hasdefer != 0 { 2600 Ginscall(Deferreturn, 0) 2601 } 2602 Genlist(Curfn.Func.Exit) 2603 p := Thearch.Gins(obj.ARET, nil, nil) 2604 if n != nil && n.Op == ORETJMP { 2605 p.To.Type = obj.TYPE_MEM 2606 p.To.Name = obj.NAME_EXTERN 2607 p.To.Sym = Linksym(n.Left.Sym) 2608 } 2609 } 2610 2611 /* 2612 * generate division according to op, one of: 2613 * res = nl / nr 2614 * res = nl % nr 2615 */ 2616 func cgen_div(op int, nl *Node, nr *Node, res *Node) { 2617 var w int 2618 2619 // TODO(rsc): arm64 needs to support the relevant instructions 2620 // in peep and optoas in order to enable this. 2621 // TODO(rsc): ppc64 needs to support the relevant instructions 2622 // in peep and optoas in order to enable this. 2623 if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { 2624 goto longdiv 2625 } 2626 w = int(nl.Type.Width * 8) 2627 2628 // Front end handled 32-bit division. We only need to handle 64-bit. 2629 // try to do division by multiply by (2^w)/d 2630 // see hacker's delight chapter 10 2631 switch Simtype[nl.Type.Etype] { 2632 default: 2633 goto longdiv 2634 2635 case TUINT64: 2636 var m Magic 2637 m.W = w 2638 m.Ud = uint64(Mpgetfix(nr.Val.U.Xval)) 2639 Umagic(&m) 2640 if m.Bad != 0 { 2641 break 2642 } 2643 if op == OMOD { 2644 goto longmod 2645 } 2646 2647 var n1 Node 2648 Cgenr(nl, &n1, nil) 2649 var n2 Node 2650 Nodconst(&n2, nl.Type, int64(m.Um)) 2651 var n3 Node 2652 Regalloc(&n3, nl.Type, res) 2653 Thearch.Cgen_hmul(&n1, &n2, &n3) 2654 2655 if m.Ua != 0 { 2656 // need to add numerator accounting for overflow 2657 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3) 2658 2659 Nodconst(&n2, nl.Type, 1) 2660 Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3) 2661 Nodconst(&n2, nl.Type, int64(m.S)-1) 2662 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) 2663 } else { 2664 Nodconst(&n2, nl.Type, int64(m.S)) 2665 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift dx 2666 } 2667 2668 Thearch.Gmove(&n3, res) 2669 Regfree(&n1) 2670 Regfree(&n3) 2671 return 2672 2673 case TINT64: 2674 var m Magic 2675 m.W = w 2676 m.Sd = Mpgetfix(nr.Val.U.Xval) 2677 Smagic(&m) 2678 if m.Bad != 0 { 2679 break 2680 } 2681 if op == OMOD { 2682 goto longmod 2683 } 2684 2685 var n1 Node 2686 Cgenr(nl, &n1, res) 2687 var n2 Node 2688 Nodconst(&n2, nl.Type, m.Sm) 2689 var n3 Node 2690 Regalloc(&n3, nl.Type, nil) 2691 Thearch.Cgen_hmul(&n1, &n2, &n3) 2692 2693 if m.Sm < 0 { 2694 // need to add numerator 2695 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3) 2696 } 2697 2698 Nodconst(&n2, nl.Type, int64(m.S)) 2699 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift n3 2700 2701 Nodconst(&n2, nl.Type, int64(w)-1) 2702 2703 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n1) // -1 iff num is neg 2704 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n1, &n3) // added 2705 2706 if m.Sd < 0 { 2707 // this could probably be removed 2708 // by factoring it into the multiplier 2709 Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3) 2710 } 2711 2712 Thearch.Gmove(&n3, res) 2713 Regfree(&n1) 2714 Regfree(&n3) 2715 return 2716 } 2717 2718 goto longdiv 2719 2720 // division and mod using (slow) hardware instruction 2721 longdiv: 2722 Thearch.Dodiv(op, nl, nr, res) 2723 2724 return 2725 2726 // mod using formula A%B = A-(A/B*B) but 2727 // we know that there is a fast algorithm for A/B 2728 longmod: 2729 var n1 Node 2730 Regalloc(&n1, nl.Type, res) 2731 2732 Cgen(nl, &n1) 2733 var n2 Node 2734 Regalloc(&n2, nl.Type, nil) 2735 cgen_div(ODIV, &n1, nr, &n2) 2736 a := Thearch.Optoas(OMUL, nl.Type) 2737 if w == 8 { 2738 // use 2-operand 16-bit multiply 2739 // because there is no 2-operand 8-bit multiply 2740 a = Thearch.Optoas(OMUL, Types[TINT16]) // XXX was IMULW 2741 } 2742 2743 if !Smallintconst(nr) { 2744 var n3 Node 2745 Regalloc(&n3, nl.Type, nil) 2746 Cgen(nr, &n3) 2747 Thearch.Gins(a, &n3, &n2) 2748 Regfree(&n3) 2749 } else { 2750 Thearch.Gins(a, nr, &n2) 2751 } 2752 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n2, &n1) 2753 Thearch.Gmove(&n1, res) 2754 Regfree(&n1) 2755 Regfree(&n2) 2756 } 2757 2758 func Fixlargeoffset(n *Node) { 2759 if n == nil { 2760 return 2761 } 2762 if n.Op != OINDREG { 2763 return 2764 } 2765 if n.Reg == int16(Thearch.REGSP) { // stack offset cannot be large 2766 return 2767 } 2768 if n.Xoffset != int64(int32(n.Xoffset)) { 2769 // offset too large, add to register instead. 2770 a := *n 2771 2772 a.Op = OREGISTER 2773 a.Type = Types[Tptr] 2774 a.Xoffset = 0 2775 Cgen_checknil(&a) 2776 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), n.Xoffset, &a) 2777 n.Xoffset = 0 2778 } 2779 }