github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/gc/cgen.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gc 6 7 import ( 8 "cmd/internal/obj" 9 "cmd/internal/obj/ppc64" 10 "fmt" 11 ) 12 13 // generate: 14 // res = n; 15 // simplifies and calls Thearch.Gmove. 16 // if wb is true, need to emit write barriers. 17 func Cgen(n, res *Node) { 18 cgen_wb(n, res, false) 19 } 20 21 func cgen_wb(n, res *Node, wb bool) { 22 if Debug['g'] != 0 { 23 op := "cgen" 24 if wb { 25 op = "cgen_wb" 26 } 27 Dump("\n"+op+"-n", n) 28 Dump(op+"-res", res) 29 } 30 31 if n == nil || n.Type == nil { 32 return 33 } 34 35 if res == nil || res.Type == nil { 36 Fatalf("cgen: res nil") 37 } 38 39 for n.Op == OCONVNOP { 40 n = n.Left 41 } 42 43 switch n.Op { 44 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: 45 cgen_slice(n, res, wb) 46 return 47 48 case OEFACE: 49 if res.Op != ONAME || !res.Addable || wb { 50 var n1 Node 51 Tempname(&n1, n.Type) 52 Cgen_eface(n, &n1) 53 cgen_wb(&n1, res, wb) 54 } else { 55 Cgen_eface(n, res) 56 } 57 return 58 59 case ODOTTYPE: 60 cgen_dottype(n, res, nil, wb) 61 return 62 63 case OAPPEND: 64 cgen_append(n, res) 65 return 66 } 67 68 if n.Ullman >= UINF { 69 if n.Op == OINDREG { 70 Fatalf("cgen: this is going to miscompile") 71 } 72 if res.Ullman >= UINF { 73 var n1 Node 74 Tempname(&n1, n.Type) 75 Cgen(n, &n1) 76 cgen_wb(&n1, res, wb) 77 return 78 } 79 } 80 81 if Isfat(n.Type) { 82 if n.Type.Width < 0 { 83 Fatalf("forgot to compute width for %v", n.Type) 84 } 85 sgen_wb(n, res, n.Type.Width, wb) 86 return 87 } 88 89 if !res.Addable { 90 if n.Ullman > res.Ullman { 91 if Ctxt.Arch.Regsize == 4 && Is64(n.Type) { 92 var n1 Node 93 Tempname(&n1, n.Type) 94 Cgen(n, &n1) 95 cgen_wb(&n1, res, wb) 96 return 97 } 98 99 var n1 Node 100 Regalloc(&n1, n.Type, res) 101 Cgen(n, &n1) 102 if n1.Ullman > res.Ullman { 103 Dump("n1", &n1) 104 Dump("res", res) 105 Fatalf("loop in cgen") 106 } 107 108 cgen_wb(&n1, res, wb) 109 Regfree(&n1) 110 return 111 } 112 113 if res.Ullman < UINF { 114 if Complexop(n, res) { 115 Complexgen(n, res) 116 return 117 } 118 119 f := true // gen through register 120 switch n.Op { 121 case OLITERAL: 122 if Smallintconst(n) { 123 f = false 124 } 125 126 case OREGISTER: 127 f = false 128 } 129 130 if !n.Type.IsComplex() && Ctxt.Arch.Regsize == 8 && !wb { 131 a := Thearch.Optoas(OAS, res.Type) 132 var addr obj.Addr 133 if Thearch.Sudoaddable(a, res, &addr) { 134 var p1 *obj.Prog 135 if f { 136 var n2 Node 137 Regalloc(&n2, res.Type, nil) 138 Cgen(n, &n2) 139 p1 = Thearch.Gins(a, &n2, nil) 140 Regfree(&n2) 141 } else { 142 p1 = Thearch.Gins(a, n, nil) 143 } 144 p1.To = addr 145 if Debug['g'] != 0 { 146 fmt.Printf("%v [ignore previous line]\n", p1) 147 } 148 Thearch.Sudoclean() 149 return 150 } 151 } 152 } 153 154 if Ctxt.Arch.Thechar == '8' { 155 // no registers to speak of 156 var n1, n2 Node 157 Tempname(&n1, n.Type) 158 Cgen(n, &n1) 159 Igen(res, &n2, nil) 160 cgen_wb(&n1, &n2, wb) 161 Regfree(&n2) 162 return 163 } 164 165 var n1 Node 166 Igen(res, &n1, nil) 167 cgen_wb(n, &n1, wb) 168 Regfree(&n1) 169 return 170 } 171 172 // update addressability for string, slice 173 // can't do in walk because n->left->addable 174 // changes if n->left is an escaping local variable. 175 switch n.Op { 176 case OSPTR, OLEN: 177 if n.Left.Type.IsSlice() || n.Left.Type.IsString() { 178 n.Addable = n.Left.Addable 179 } 180 181 case OCAP: 182 if n.Left.Type.IsSlice() { 183 n.Addable = n.Left.Addable 184 } 185 186 case OITAB: 187 n.Addable = n.Left.Addable 188 } 189 190 if wb { 191 if Simtype[res.Type.Etype] != Tptr { 192 Fatalf("cgen_wb of type %v", res.Type) 193 } 194 if n.Ullman >= UINF { 195 var n1 Node 196 Tempname(&n1, n.Type) 197 Cgen(n, &n1) 198 n = &n1 199 } 200 cgen_wbptr(n, res) 201 return 202 } 203 204 // Write barrier now handled. Code below this line can ignore wb. 205 206 if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often? 207 // if both are addressable, move 208 if n.Addable && res.Addable { 209 if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || n.Type.IsComplex() || res.Type.IsComplex() { 210 Thearch.Gmove(n, res) 211 } else { 212 var n1 Node 213 Regalloc(&n1, n.Type, nil) 214 Thearch.Gmove(n, &n1) 215 Cgen(&n1, res) 216 Regfree(&n1) 217 } 218 219 return 220 } 221 222 // if both are not addressable, use a temporary. 223 if !n.Addable && !res.Addable { 224 // could use regalloc here sometimes, 225 // but have to check for ullman >= UINF. 226 var n1 Node 227 Tempname(&n1, n.Type) 228 Cgen(n, &n1) 229 Cgen(&n1, res) 230 return 231 } 232 233 // if result is not addressable directly but n is, 234 // compute its address and then store via the address. 235 if !res.Addable { 236 var n1 Node 237 Igen(res, &n1, nil) 238 Cgen(n, &n1) 239 Regfree(&n1) 240 return 241 } 242 } 243 244 if Complexop(n, res) { 245 Complexgen(n, res) 246 return 247 } 248 249 if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable { 250 Thearch.Gmove(n, res) 251 return 252 } 253 254 if Ctxt.Arch.Thechar == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { 255 // if both are addressable, move 256 if n.Addable { 257 if n.Op == OREGISTER || res.Op == OREGISTER { 258 Thearch.Gmove(n, res) 259 } else { 260 var n1 Node 261 Regalloc(&n1, n.Type, nil) 262 Thearch.Gmove(n, &n1) 263 Cgen(&n1, res) 264 Regfree(&n1) 265 } 266 return 267 } 268 } 269 270 // if n is sudoaddable generate addr and move 271 if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() { 272 a := Thearch.Optoas(OAS, n.Type) 273 var addr obj.Addr 274 if Thearch.Sudoaddable(a, n, &addr) { 275 if res.Op != OREGISTER { 276 var n2 Node 277 Regalloc(&n2, res.Type, nil) 278 p1 := Thearch.Gins(a, nil, &n2) 279 p1.From = addr 280 if Debug['g'] != 0 { 281 fmt.Printf("%v [ignore previous line]\n", p1) 282 } 283 Thearch.Gmove(&n2, res) 284 Regfree(&n2) 285 } else { 286 p1 := Thearch.Gins(a, nil, res) 287 p1.From = addr 288 if Debug['g'] != 0 { 289 fmt.Printf("%v [ignore previous line]\n", p1) 290 } 291 } 292 Thearch.Sudoclean() 293 return 294 } 295 } 296 297 nl := n.Left 298 nr := n.Right 299 300 if nl != nil && nl.Ullman >= UINF { 301 if nr != nil && nr.Ullman >= UINF { 302 var n1 Node 303 Tempname(&n1, nl.Type) 304 Cgen(nl, &n1) 305 n2 := *n 306 n2.Left = &n1 307 Cgen(&n2, res) 308 return 309 } 310 } 311 312 // 64-bit ops are hard on 32-bit machine. 313 if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) { 314 switch n.Op { 315 // math goes to cgen64. 316 case OMINUS, 317 OCOM, 318 OADD, 319 OSUB, 320 OMUL, 321 OLROT, 322 OLSH, 323 ORSH, 324 OAND, 325 OOR, 326 OXOR: 327 Thearch.Cgen64(n, res) 328 return 329 } 330 } 331 332 if Thearch.Cgen_float != nil && nl != nil && n.Type.IsFloat() && nl.Type.IsFloat() { 333 Thearch.Cgen_float(n, res) 334 return 335 } 336 337 if !n.Type.IsComplex() && Ctxt.Arch.Regsize == 8 { 338 a := Thearch.Optoas(OAS, n.Type) 339 var addr obj.Addr 340 if Thearch.Sudoaddable(a, n, &addr) { 341 if res.Op == OREGISTER { 342 p1 := Thearch.Gins(a, nil, res) 343 p1.From = addr 344 } else { 345 var n2 Node 346 Regalloc(&n2, n.Type, nil) 347 p1 := Thearch.Gins(a, nil, &n2) 348 p1.From = addr 349 Thearch.Gins(a, &n2, res) 350 Regfree(&n2) 351 } 352 353 Thearch.Sudoclean() 354 return 355 } 356 } 357 358 var a obj.As 359 switch n.Op { 360 default: 361 Dump("cgen", n) 362 Dump("cgen-res", res) 363 Fatalf("cgen: unknown op %v", Nconv(n, FmtShort|FmtSign)) 364 365 case OOROR, OANDAND, 366 OEQ, ONE, 367 OLT, OLE, 368 OGE, OGT, 369 ONOT: 370 Bvgen(n, res, true) 371 return 372 373 case OPLUS: 374 Cgen(nl, res) 375 return 376 377 // unary 378 case OCOM: 379 a := Thearch.Optoas(OXOR, nl.Type) 380 381 var n1 Node 382 Regalloc(&n1, nl.Type, nil) 383 Cgen(nl, &n1) 384 var n2 Node 385 Nodconst(&n2, nl.Type, -1) 386 Thearch.Gins(a, &n2, &n1) 387 cgen_norm(n, &n1, res) 388 return 389 390 case OMINUS: 391 if nl.Type.IsFloat() { 392 nr = Nodintconst(-1) 393 nr = convlit(nr, n.Type) 394 a = Thearch.Optoas(OMUL, nl.Type) 395 goto sbop 396 } 397 398 a := Thearch.Optoas(n.Op, nl.Type) 399 // unary 400 var n1 Node 401 Regalloc(&n1, nl.Type, res) 402 403 Cgen(nl, &n1) 404 if Ctxt.Arch.Thechar == '5' { 405 var n2 Node 406 Nodconst(&n2, nl.Type, 0) 407 Thearch.Gins(a, &n2, &n1) 408 } else if Ctxt.Arch.Thechar == '7' { 409 Thearch.Gins(a, &n1, &n1) 410 } else { 411 Thearch.Gins(a, nil, &n1) 412 } 413 cgen_norm(n, &n1, res) 414 return 415 416 case OSQRT: 417 var n1 Node 418 Regalloc(&n1, nl.Type, res) 419 Cgen(n.Left, &n1) 420 Thearch.Gins(Thearch.Optoas(OSQRT, nl.Type), &n1, &n1) 421 Thearch.Gmove(&n1, res) 422 Regfree(&n1) 423 return 424 425 case OGETG: 426 Thearch.Getg(res) 427 return 428 429 // symmetric binary 430 case OAND, 431 OOR, 432 OXOR, 433 OADD, 434 OMUL: 435 if n.Op == OMUL && Thearch.Cgen_bmul != nil && Thearch.Cgen_bmul(n.Op, nl, nr, res) { 436 break 437 } 438 a = Thearch.Optoas(n.Op, nl.Type) 439 goto sbop 440 441 // asymmetric binary 442 case OSUB: 443 a = Thearch.Optoas(n.Op, nl.Type) 444 goto abop 445 446 case OHMUL: 447 Thearch.Cgen_hmul(nl, nr, res) 448 449 case OCONV: 450 if Eqtype(n.Type, nl.Type) || Noconv(n.Type, nl.Type) { 451 Cgen(nl, res) 452 return 453 } 454 455 if Ctxt.Arch.Thechar == '8' { 456 var n1 Node 457 var n2 Node 458 Tempname(&n2, n.Type) 459 Mgen(nl, &n1, res) 460 Thearch.Gmove(&n1, &n2) 461 Thearch.Gmove(&n2, res) 462 Mfree(&n1) 463 break 464 } 465 466 var n1 Node 467 var n2 Node 468 if Ctxt.Arch.Thechar == '5' { 469 if nl.Addable && !Is64(nl.Type) { 470 Regalloc(&n1, nl.Type, res) 471 Thearch.Gmove(nl, &n1) 472 } else { 473 if n.Type.Width > int64(Widthptr) || Is64(nl.Type) || nl.Type.IsFloat() { 474 Tempname(&n1, nl.Type) 475 } else { 476 Regalloc(&n1, nl.Type, res) 477 } 478 Cgen(nl, &n1) 479 } 480 if n.Type.Width > int64(Widthptr) || Is64(n.Type) || n.Type.IsFloat() { 481 Tempname(&n2, n.Type) 482 } else { 483 Regalloc(&n2, n.Type, nil) 484 } 485 } else { 486 if n.Type.Width > nl.Type.Width { 487 // If loading from memory, do conversion during load, 488 // so as to avoid use of 8-bit register in, say, int(*byteptr). 489 switch nl.Op { 490 case ODOT, ODOTPTR, OINDEX, OIND, ONAME: 491 Igen(nl, &n1, res) 492 Regalloc(&n2, n.Type, res) 493 Thearch.Gmove(&n1, &n2) 494 Thearch.Gmove(&n2, res) 495 Regfree(&n2) 496 Regfree(&n1) 497 return 498 } 499 } 500 Regalloc(&n1, nl.Type, res) 501 Regalloc(&n2, n.Type, &n1) 502 Cgen(nl, &n1) 503 } 504 505 // if we do the conversion n1 -> n2 here 506 // reusing the register, then gmove won't 507 // have to allocate its own register. 508 Thearch.Gmove(&n1, &n2) 509 Thearch.Gmove(&n2, res) 510 if n2.Op == OREGISTER { 511 Regfree(&n2) 512 } 513 if n1.Op == OREGISTER { 514 Regfree(&n1) 515 } 516 517 case ODOT, 518 ODOTPTR, 519 OINDEX, 520 OIND, 521 ONAME: // PHEAP or PPARAMREF var 522 var n1 Node 523 Igen(n, &n1, res) 524 525 Thearch.Gmove(&n1, res) 526 Regfree(&n1) 527 528 // interface table is first word of interface value 529 case OITAB: 530 var n1 Node 531 Igen(nl, &n1, res) 532 533 n1.Type = n.Type 534 Thearch.Gmove(&n1, res) 535 Regfree(&n1) 536 537 case OSPTR: 538 // pointer is the first word of string or slice. 539 if Isconst(nl, CTSTR) { 540 var n1 Node 541 Regalloc(&n1, Types[Tptr], res) 542 p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1) 543 Datastring(nl.Val().U.(string), &p1.From) 544 p1.From.Type = obj.TYPE_ADDR 545 Thearch.Gmove(&n1, res) 546 Regfree(&n1) 547 break 548 } 549 550 var n1 Node 551 Igen(nl, &n1, res) 552 n1.Type = n.Type 553 Thearch.Gmove(&n1, res) 554 Regfree(&n1) 555 556 case OLEN: 557 if nl.Type.IsMap() || nl.Type.IsChan() { 558 // map and chan have len in the first int-sized word. 559 // a zero pointer means zero length 560 var n1 Node 561 Regalloc(&n1, Types[Tptr], res) 562 563 Cgen(nl, &n1) 564 565 var n2 Node 566 Nodconst(&n2, Types[Tptr], 0) 567 p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 0) 568 569 n2 = n1 570 n2.Op = OINDREG 571 n2.Type = Types[Simtype[TINT]] 572 Thearch.Gmove(&n2, &n1) 573 574 Patch(p1, Pc) 575 576 Thearch.Gmove(&n1, res) 577 Regfree(&n1) 578 break 579 } 580 581 if nl.Type.IsString() || nl.Type.IsSlice() { 582 // both slice and string have len one pointer into the struct. 583 // a zero pointer means zero length 584 var n1 Node 585 Igen(nl, &n1, res) 586 587 n1.Type = Types[Simtype[TUINT]] 588 n1.Xoffset += int64(Array_nel) 589 Thearch.Gmove(&n1, res) 590 Regfree(&n1) 591 break 592 } 593 594 Fatalf("cgen: OLEN: unknown type %v", Tconv(nl.Type, FmtLong)) 595 596 case OCAP: 597 if nl.Type.IsChan() { 598 // chan has cap in the second int-sized word. 599 // a zero pointer means zero length 600 var n1 Node 601 Regalloc(&n1, Types[Tptr], res) 602 603 Cgen(nl, &n1) 604 605 var n2 Node 606 Nodconst(&n2, Types[Tptr], 0) 607 p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 0) 608 609 n2 = n1 610 n2.Op = OINDREG 611 n2.Xoffset = int64(Widthint) 612 n2.Type = Types[Simtype[TINT]] 613 Thearch.Gmove(&n2, &n1) 614 615 Patch(p1, Pc) 616 617 Thearch.Gmove(&n1, res) 618 Regfree(&n1) 619 break 620 } 621 622 if nl.Type.IsSlice() { 623 var n1 Node 624 Igen(nl, &n1, res) 625 n1.Type = Types[Simtype[TUINT]] 626 n1.Xoffset += int64(Array_cap) 627 Thearch.Gmove(&n1, res) 628 Regfree(&n1) 629 break 630 } 631 632 Fatalf("cgen: OCAP: unknown type %v", Tconv(nl.Type, FmtLong)) 633 634 case OADDR: 635 if n.Bounded { // let race detector avoid nil checks 636 Disable_checknil++ 637 } 638 Agen(nl, res) 639 if n.Bounded { 640 Disable_checknil-- 641 } 642 643 case OCALLMETH: 644 cgen_callmeth(n, 0) 645 cgen_callret(n, res) 646 647 case OCALLINTER: 648 cgen_callinter(n, res, 0) 649 cgen_callret(n, res) 650 651 case OCALLFUNC: 652 cgen_call(n, 0) 653 cgen_callret(n, res) 654 655 case OMOD, ODIV: 656 if n.Type.IsFloat() || Thearch.Dodiv == nil { 657 a = Thearch.Optoas(n.Op, nl.Type) 658 goto abop 659 } 660 661 if nl.Ullman >= nr.Ullman { 662 var n1 Node 663 Regalloc(&n1, nl.Type, res) 664 Cgen(nl, &n1) 665 cgen_div(n.Op, &n1, nr, res) 666 Regfree(&n1) 667 } else { 668 var n2 Node 669 if !Smallintconst(nr) { 670 Regalloc(&n2, nr.Type, res) 671 Cgen(nr, &n2) 672 } else { 673 n2 = *nr 674 } 675 676 cgen_div(n.Op, nl, &n2, res) 677 if n2.Op != OLITERAL { 678 Regfree(&n2) 679 } 680 } 681 682 case OLSH, ORSH, OLROT: 683 Thearch.Cgen_shift(n.Op, n.Bounded, nl, nr, res) 684 } 685 686 return 687 688 // put simplest on right - we'll generate into left 689 // and then adjust it using the computation of right. 690 // constants and variables have the same ullman 691 // count, so look for constants specially. 692 // 693 // an integer constant we can use as an immediate 694 // is simpler than a variable - we can use the immediate 695 // in the adjustment instruction directly - so it goes 696 // on the right. 697 // 698 // other constants, like big integers or floating point 699 // constants, require a mov into a register, so those 700 // might as well go on the left, so we can reuse that 701 // register for the computation. 702 sbop: // symmetric binary 703 if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (Smallintconst(nl) || (nr.Op == OLITERAL && !Smallintconst(nr)))) { 704 nl, nr = nr, nl 705 } 706 707 abop: // asymmetric binary 708 var n1 Node 709 var n2 Node 710 if Ctxt.Arch.Thechar == '8' { 711 // no registers, sigh 712 if Smallintconst(nr) { 713 var n1 Node 714 Mgen(nl, &n1, res) 715 var n2 Node 716 Regalloc(&n2, nl.Type, &n1) 717 Thearch.Gmove(&n1, &n2) 718 Thearch.Gins(a, nr, &n2) 719 Thearch.Gmove(&n2, res) 720 Regfree(&n2) 721 Mfree(&n1) 722 } else if nl.Ullman >= nr.Ullman { 723 var nt Node 724 Tempname(&nt, nl.Type) 725 Cgen(nl, &nt) 726 var n2 Node 727 Mgen(nr, &n2, nil) 728 var n1 Node 729 Regalloc(&n1, nl.Type, res) 730 Thearch.Gmove(&nt, &n1) 731 Thearch.Gins(a, &n2, &n1) 732 Thearch.Gmove(&n1, res) 733 Regfree(&n1) 734 Mfree(&n2) 735 } else { 736 var n2 Node 737 Regalloc(&n2, nr.Type, res) 738 Cgen(nr, &n2) 739 var n1 Node 740 Regalloc(&n1, nl.Type, nil) 741 Cgen(nl, &n1) 742 Thearch.Gins(a, &n2, &n1) 743 Regfree(&n2) 744 Thearch.Gmove(&n1, res) 745 Regfree(&n1) 746 } 747 return 748 } 749 750 if nl.Ullman >= nr.Ullman { 751 Regalloc(&n1, nl.Type, res) 752 Cgen(nl, &n1) 753 754 if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm 755 n2 = *nr 756 } else { 757 Regalloc(&n2, nr.Type, nil) 758 Cgen(nr, &n2) 759 } 760 } else { 761 if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm 762 n2 = *nr 763 } else { 764 Regalloc(&n2, nr.Type, res) 765 Cgen(nr, &n2) 766 } 767 768 Regalloc(&n1, nl.Type, nil) 769 Cgen(nl, &n1) 770 } 771 772 Thearch.Gins(a, &n2, &n1) 773 if n2.Op != OLITERAL { 774 Regfree(&n2) 775 } 776 cgen_norm(n, &n1, res) 777 } 778 779 var sys_wbptr *Node 780 781 func cgen_wbptr(n, res *Node) { 782 if Curfn != nil { 783 if Curfn.Func.Pragma&Nowritebarrier != 0 { 784 Yyerror("write barrier prohibited") 785 } 786 if Curfn.Func.WBLineno == 0 { 787 Curfn.Func.WBLineno = lineno 788 } 789 } 790 if Debug_wb > 0 { 791 Warn("write barrier") 792 } 793 794 var dst, src Node 795 Igen(res, &dst, nil) 796 if n.Op == OREGISTER { 797 src = *n 798 Regrealloc(&src) 799 } else { 800 Cgenr(n, &src, nil) 801 } 802 803 wbVar := syslook("writeBarrier") 804 wbEnabled := NodSym(ODOT, wbVar, wbVar.Type.Field(0).Sym) 805 wbEnabled = typecheck(wbEnabled, Erv) 806 pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1) 807 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst) 808 pjmp := Gbranch(obj.AJMP, nil, 0) 809 Patch(pbr, Pc) 810 var adst Node 811 Agenr(&dst, &adst, &dst) 812 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &adst, nil) 813 a := &p.To 814 a.Type = obj.TYPE_MEM 815 a.Reg = int16(Thearch.REGSP) 816 a.Offset = Ctxt.FixedFrameSize() 817 p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil) 818 p2.To = p.To 819 p2.To.Offset += int64(Widthptr) 820 Regfree(&adst) 821 if sys_wbptr == nil { 822 sys_wbptr = writebarrierfn("writebarrierptr", Types[Tptr], Types[Tptr]) 823 } 824 Ginscall(sys_wbptr, 0) 825 Patch(pjmp, Pc) 826 827 Regfree(&dst) 828 Regfree(&src) 829 } 830 831 func cgen_wbfat(n, res *Node) { 832 if Curfn != nil { 833 if Curfn.Func.Pragma&Nowritebarrier != 0 { 834 Yyerror("write barrier prohibited") 835 } 836 if Curfn.Func.WBLineno == 0 { 837 Curfn.Func.WBLineno = lineno 838 } 839 } 840 if Debug_wb > 0 { 841 Warn("write barrier") 842 } 843 needType := true 844 funcName := "typedmemmove" 845 var dst, src Node 846 if n.Ullman >= res.Ullman { 847 Agenr(n, &src, nil) 848 Agenr(res, &dst, nil) 849 } else { 850 Agenr(res, &dst, nil) 851 Agenr(n, &src, nil) 852 } 853 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &dst, nil) 854 a := &p.To 855 a.Type = obj.TYPE_MEM 856 a.Reg = int16(Thearch.REGSP) 857 a.Offset = Ctxt.FixedFrameSize() 858 if needType { 859 a.Offset += int64(Widthptr) 860 } 861 p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil) 862 p2.To = p.To 863 p2.To.Offset += int64(Widthptr) 864 Regfree(&dst) 865 if needType { 866 src.Type = Types[Tptr] 867 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), typename(n.Type), &src) 868 p3 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil) 869 p3.To = p2.To 870 p3.To.Offset -= 2 * int64(Widthptr) 871 } 872 Regfree(&src) 873 Ginscall(writebarrierfn(funcName, Types[Tptr], Types[Tptr]), 0) 874 } 875 876 // cgen_norm moves n1 to res, truncating to expected type if necessary. 877 // n1 is a register, and cgen_norm frees it. 878 func cgen_norm(n, n1, res *Node) { 879 switch Ctxt.Arch.Thechar { 880 case '6', '8': 881 // We use sized math, so the result is already truncated. 882 default: 883 switch n.Op { 884 case OADD, OSUB, OMUL, ODIV, OCOM, OMINUS: 885 // TODO(rsc): What about left shift? 886 Thearch.Gins(Thearch.Optoas(OAS, n.Type), n1, n1) 887 } 888 } 889 890 Thearch.Gmove(n1, res) 891 Regfree(n1) 892 } 893 894 func Mgen(n *Node, n1 *Node, rg *Node) { 895 n1.Op = OEMPTY 896 897 if n.Addable { 898 *n1 = *n 899 if n1.Op == OREGISTER || n1.Op == OINDREG { 900 reg[n.Reg-int16(Thearch.REGMIN)]++ 901 } 902 return 903 } 904 905 Tempname(n1, n.Type) 906 Cgen(n, n1) 907 if n.Type.Width <= int64(Widthptr) || n.Type.IsFloat() { 908 n2 := *n1 909 Regalloc(n1, n.Type, rg) 910 Thearch.Gmove(&n2, n1) 911 } 912 } 913 914 func Mfree(n *Node) { 915 if n.Op == OREGISTER { 916 Regfree(n) 917 } 918 } 919 920 // allocate a register (reusing res if possible) and generate 921 // a = n 922 // The caller must call Regfree(a). 923 func Cgenr(n *Node, a *Node, res *Node) { 924 if Debug['g'] != 0 { 925 Dump("cgenr-n", n) 926 } 927 928 if Isfat(n.Type) { 929 Fatalf("cgenr on fat node") 930 } 931 932 if n.Addable { 933 Regalloc(a, n.Type, res) 934 Thearch.Gmove(n, a) 935 return 936 } 937 938 switch n.Op { 939 case ONAME, 940 ODOT, 941 ODOTPTR, 942 OINDEX, 943 OCALLFUNC, 944 OCALLMETH, 945 OCALLINTER: 946 var n1 Node 947 Igen(n, &n1, res) 948 Regalloc(a, Types[Tptr], &n1) 949 Thearch.Gmove(&n1, a) 950 Regfree(&n1) 951 952 default: 953 Regalloc(a, n.Type, res) 954 Cgen(n, a) 955 } 956 } 957 958 // allocate a register (reusing res if possible) and generate 959 // a = &n 960 // The caller must call Regfree(a). 961 // The generated code checks that the result is not nil. 962 func Agenr(n *Node, a *Node, res *Node) { 963 if Debug['g'] != 0 { 964 Dump("\nagenr-n", n) 965 } 966 967 nl := n.Left 968 nr := n.Right 969 970 switch n.Op { 971 case ODOT, ODOTPTR, OCALLFUNC, OCALLMETH, OCALLINTER: 972 var n1 Node 973 Igen(n, &n1, res) 974 Regalloc(a, Types[Tptr], &n1) 975 Agen(&n1, a) 976 Regfree(&n1) 977 978 case OIND: 979 Cgenr(n.Left, a, res) 980 Cgen_checknil(a) 981 982 case OINDEX: 983 if Ctxt.Arch.Thechar == '5' { 984 var p2 *obj.Prog // to be patched to panicindex. 985 w := uint32(n.Type.Width) 986 bounded := Debug['B'] != 0 || n.Bounded 987 var n1 Node 988 var n3 Node 989 if nr.Addable { 990 var tmp Node 991 if !Isconst(nr, CTINT) { 992 Tempname(&tmp, Types[TINT32]) 993 } 994 if !Isconst(nl, CTSTR) { 995 Agenr(nl, &n3, res) 996 } 997 if !Isconst(nr, CTINT) { 998 p2 = Thearch.Cgenindex(nr, &tmp, bounded) 999 Regalloc(&n1, tmp.Type, nil) 1000 Thearch.Gmove(&tmp, &n1) 1001 } 1002 } else if nl.Addable { 1003 if !Isconst(nr, CTINT) { 1004 var tmp Node 1005 Tempname(&tmp, Types[TINT32]) 1006 p2 = Thearch.Cgenindex(nr, &tmp, bounded) 1007 Regalloc(&n1, tmp.Type, nil) 1008 Thearch.Gmove(&tmp, &n1) 1009 } 1010 1011 if !Isconst(nl, CTSTR) { 1012 Agenr(nl, &n3, res) 1013 } 1014 } else { 1015 var tmp Node 1016 Tempname(&tmp, Types[TINT32]) 1017 p2 = Thearch.Cgenindex(nr, &tmp, bounded) 1018 nr = &tmp 1019 if !Isconst(nl, CTSTR) { 1020 Agenr(nl, &n3, res) 1021 } 1022 Regalloc(&n1, tmp.Type, nil) 1023 Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1) 1024 } 1025 1026 // &a is in &n3 (allocated in res) 1027 // i is in &n1 (if not constant) 1028 // w is width 1029 1030 // constant index 1031 if Isconst(nr, CTINT) { 1032 if Isconst(nl, CTSTR) { 1033 Fatalf("constant string constant index") 1034 } 1035 v := uint64(nr.Int64()) 1036 var n2 Node 1037 if nl.Type.IsSlice() || nl.Type.IsString() { 1038 if Debug['B'] == 0 && !n.Bounded { 1039 n1 = n3 1040 n1.Op = OINDREG 1041 n1.Type = Types[Tptr] 1042 n1.Xoffset = int64(Array_nel) 1043 Nodconst(&n2, Types[TUINT32], int64(v)) 1044 p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &n1, &n2, +1) 1045 Ginscall(Panicindex, -1) 1046 Patch(p1, Pc) 1047 } 1048 1049 n1 = n3 1050 n1.Op = OINDREG 1051 n1.Type = Types[Tptr] 1052 n1.Xoffset = int64(Array_array) 1053 Thearch.Gmove(&n1, &n3) 1054 } 1055 1056 Nodconst(&n2, Types[Tptr], int64(v*uint64(w))) 1057 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1058 *a = n3 1059 break 1060 } 1061 1062 var n2 Node 1063 Regalloc(&n2, Types[TINT32], &n1) // i 1064 Thearch.Gmove(&n1, &n2) 1065 Regfree(&n1) 1066 1067 var n4 Node 1068 if Debug['B'] == 0 && !n.Bounded { 1069 // check bounds 1070 if Isconst(nl, CTSTR) { 1071 Nodconst(&n4, Types[TUINT32], int64(len(nl.Val().U.(string)))) 1072 } else if nl.Type.IsSlice() || nl.Type.IsString() { 1073 n1 = n3 1074 n1.Op = OINDREG 1075 n1.Type = Types[Tptr] 1076 n1.Xoffset = int64(Array_nel) 1077 Regalloc(&n4, Types[TUINT32], nil) 1078 Thearch.Gmove(&n1, &n4) 1079 } else { 1080 Nodconst(&n4, Types[TUINT32], nl.Type.NumElem()) 1081 } 1082 p1 := Thearch.Ginscmp(OLT, Types[TUINT32], &n2, &n4, +1) 1083 if n4.Op == OREGISTER { 1084 Regfree(&n4) 1085 } 1086 if p2 != nil { 1087 Patch(p2, Pc) 1088 } 1089 Ginscall(Panicindex, -1) 1090 Patch(p1, Pc) 1091 } 1092 1093 if Isconst(nl, CTSTR) { 1094 Regalloc(&n3, Types[Tptr], res) 1095 p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3) 1096 Datastring(nl.Val().U.(string), &p1.From) 1097 p1.From.Type = obj.TYPE_ADDR 1098 } else if nl.Type.IsSlice() || nl.Type.IsString() { 1099 n1 = n3 1100 n1.Op = OINDREG 1101 n1.Type = Types[Tptr] 1102 n1.Xoffset = int64(Array_array) 1103 Thearch.Gmove(&n1, &n3) 1104 } 1105 1106 if w == 0 { 1107 // nothing to do 1108 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) { 1109 // done by back end 1110 } else if w == 1 { 1111 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1112 } else { 1113 if w&(w-1) == 0 { 1114 // Power of 2. Use shift. 1115 Thearch.Ginscon(Thearch.Optoas(OLSH, Types[TUINT32]), int64(log2(uint64(w))), &n2) 1116 } else { 1117 // Not a power of 2. Use multiply. 1118 Regalloc(&n4, Types[TUINT32], nil) 1119 Nodconst(&n1, Types[TUINT32], int64(w)) 1120 Thearch.Gmove(&n1, &n4) 1121 Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2) 1122 Regfree(&n4) 1123 } 1124 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1125 } 1126 *a = n3 1127 Regfree(&n2) 1128 break 1129 } 1130 if Ctxt.Arch.Thechar == '8' { 1131 var p2 *obj.Prog // to be patched to panicindex. 1132 w := uint32(n.Type.Width) 1133 bounded := Debug['B'] != 0 || n.Bounded 1134 var n3 Node 1135 var tmp Node 1136 var n1 Node 1137 if nr.Addable { 1138 // Generate &nl first, and move nr into register. 1139 if !Isconst(nl, CTSTR) { 1140 Igen(nl, &n3, res) 1141 } 1142 if !Isconst(nr, CTINT) { 1143 p2 = Thearch.Igenindex(nr, &tmp, bounded) 1144 Regalloc(&n1, tmp.Type, nil) 1145 Thearch.Gmove(&tmp, &n1) 1146 } 1147 } else if nl.Addable { 1148 // Generate nr first, and move &nl into register. 1149 if !Isconst(nr, CTINT) { 1150 p2 = Thearch.Igenindex(nr, &tmp, bounded) 1151 Regalloc(&n1, tmp.Type, nil) 1152 Thearch.Gmove(&tmp, &n1) 1153 } 1154 1155 if !Isconst(nl, CTSTR) { 1156 Igen(nl, &n3, res) 1157 } 1158 } else { 1159 p2 = Thearch.Igenindex(nr, &tmp, bounded) 1160 nr = &tmp 1161 if !Isconst(nl, CTSTR) { 1162 Igen(nl, &n3, res) 1163 } 1164 Regalloc(&n1, tmp.Type, nil) 1165 Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1) 1166 } 1167 1168 // For fixed array we really want the pointer in n3. 1169 var n2 Node 1170 if nl.Type.IsArray() { 1171 Regalloc(&n2, Types[Tptr], &n3) 1172 Agen(&n3, &n2) 1173 Regfree(&n3) 1174 n3 = n2 1175 } 1176 1177 // &a[0] is in n3 (allocated in res) 1178 // i is in n1 (if not constant) 1179 // len(a) is in nlen (if needed) 1180 // w is width 1181 1182 // constant index 1183 if Isconst(nr, CTINT) { 1184 if Isconst(nl, CTSTR) { 1185 Fatalf("constant string constant index") // front end should handle 1186 } 1187 v := uint64(nr.Int64()) 1188 if nl.Type.IsSlice() || nl.Type.IsString() { 1189 if Debug['B'] == 0 && !n.Bounded { 1190 nlen := n3 1191 nlen.Type = Types[TUINT32] 1192 nlen.Xoffset += int64(Array_nel) 1193 Nodconst(&n2, Types[TUINT32], int64(v)) 1194 p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &nlen, &n2, +1) 1195 Ginscall(Panicindex, -1) 1196 Patch(p1, Pc) 1197 } 1198 } 1199 1200 // Load base pointer in n2 = n3. 1201 Regalloc(&n2, Types[Tptr], &n3) 1202 1203 n3.Type = Types[Tptr] 1204 n3.Xoffset += int64(Array_array) 1205 Thearch.Gmove(&n3, &n2) 1206 Regfree(&n3) 1207 if v*uint64(w) != 0 { 1208 Nodconst(&n1, Types[Tptr], int64(v*uint64(w))) 1209 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n1, &n2) 1210 } 1211 *a = n2 1212 break 1213 } 1214 1215 // i is in register n1, extend to 32 bits. 1216 t := Types[TUINT32] 1217 1218 if n1.Type.IsSigned() { 1219 t = Types[TINT32] 1220 } 1221 1222 Regalloc(&n2, t, &n1) // i 1223 Thearch.Gmove(&n1, &n2) 1224 Regfree(&n1) 1225 1226 if Debug['B'] == 0 && !n.Bounded { 1227 // check bounds 1228 t := Types[TUINT32] 1229 1230 var nlen Node 1231 if Isconst(nl, CTSTR) { 1232 Nodconst(&nlen, t, int64(len(nl.Val().U.(string)))) 1233 } else if nl.Type.IsSlice() || nl.Type.IsString() { 1234 nlen = n3 1235 nlen.Type = t 1236 nlen.Xoffset += int64(Array_nel) 1237 } else { 1238 Nodconst(&nlen, t, nl.Type.NumElem()) 1239 } 1240 1241 p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1) 1242 if p2 != nil { 1243 Patch(p2, Pc) 1244 } 1245 Ginscall(Panicindex, -1) 1246 Patch(p1, Pc) 1247 } 1248 1249 if Isconst(nl, CTSTR) { 1250 Regalloc(&n3, Types[Tptr], res) 1251 p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3) 1252 Datastring(nl.Val().U.(string), &p1.From) 1253 p1.From.Type = obj.TYPE_ADDR 1254 Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3) 1255 goto indexdone1 1256 } 1257 1258 // Load base pointer in n3. 1259 Regalloc(&tmp, Types[Tptr], &n3) 1260 1261 if nl.Type.IsSlice() || nl.Type.IsString() { 1262 n3.Type = Types[Tptr] 1263 n3.Xoffset += int64(Array_array) 1264 Thearch.Gmove(&n3, &tmp) 1265 } 1266 1267 Regfree(&n3) 1268 n3 = tmp 1269 1270 if w == 0 { 1271 // nothing to do 1272 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) { 1273 // done by back end 1274 } else if w == 1 { 1275 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1276 } else { 1277 if w&(w-1) == 0 { 1278 // Power of 2. Use shift. 1279 Thearch.Ginscon(Thearch.Optoas(OLSH, Types[TUINT32]), int64(log2(uint64(w))), &n2) 1280 } else { 1281 // Not a power of 2. Use multiply. 1282 Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT32]), int64(w), &n2) 1283 } 1284 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1285 } 1286 1287 indexdone1: 1288 *a = n3 1289 Regfree(&n2) 1290 break 1291 } 1292 1293 freelen := 0 1294 w := uint64(n.Type.Width) 1295 1296 // Generate the non-addressable child first. 1297 var n3 Node 1298 var nlen Node 1299 var tmp Node 1300 var n1 Node 1301 if nr.Addable { 1302 goto irad 1303 } 1304 if nl.Addable { 1305 Cgenr(nr, &n1, nil) 1306 if !Isconst(nl, CTSTR) { 1307 if nl.Type.IsArray() { 1308 Agenr(nl, &n3, res) 1309 } else { 1310 Igen(nl, &nlen, res) 1311 freelen = 1 1312 nlen.Type = Types[Tptr] 1313 nlen.Xoffset += int64(Array_array) 1314 Regalloc(&n3, Types[Tptr], res) 1315 Thearch.Gmove(&nlen, &n3) 1316 nlen.Type = Types[Simtype[TUINT]] 1317 nlen.Xoffset += int64(Array_nel) - int64(Array_array) 1318 } 1319 } 1320 1321 goto index 1322 } 1323 1324 Tempname(&tmp, nr.Type) 1325 Cgen(nr, &tmp) 1326 nr = &tmp 1327 1328 irad: 1329 if !Isconst(nl, CTSTR) { 1330 if nl.Type.IsArray() { 1331 Agenr(nl, &n3, res) 1332 } else { 1333 if !nl.Addable { 1334 if res != nil && res.Op == OREGISTER { // give up res, which we don't need yet. 1335 Regfree(res) 1336 } 1337 1338 // igen will need an addressable node. 1339 var tmp2 Node 1340 Tempname(&tmp2, nl.Type) 1341 Cgen(nl, &tmp2) 1342 nl = &tmp2 1343 1344 if res != nil && res.Op == OREGISTER { // reacquire res 1345 Regrealloc(res) 1346 } 1347 } 1348 1349 Igen(nl, &nlen, res) 1350 freelen = 1 1351 nlen.Type = Types[Tptr] 1352 nlen.Xoffset += int64(Array_array) 1353 Regalloc(&n3, Types[Tptr], res) 1354 Thearch.Gmove(&nlen, &n3) 1355 nlen.Type = Types[Simtype[TUINT]] 1356 nlen.Xoffset += int64(Array_nel) - int64(Array_array) 1357 } 1358 } 1359 1360 if !Isconst(nr, CTINT) { 1361 Cgenr(nr, &n1, nil) 1362 } 1363 1364 goto index 1365 1366 // &a is in &n3 (allocated in res) 1367 // i is in &n1 (if not constant) 1368 // len(a) is in nlen (if needed) 1369 // w is width 1370 1371 // constant index 1372 index: 1373 if Isconst(nr, CTINT) { 1374 if Isconst(nl, CTSTR) { 1375 Fatalf("constant string constant index") // front end should handle 1376 } 1377 v := uint64(nr.Int64()) 1378 if nl.Type.IsSlice() || nl.Type.IsString() { 1379 if Debug['B'] == 0 && !n.Bounded { 1380 p1 := Thearch.Ginscmp(OGT, Types[Simtype[TUINT]], &nlen, Nodintconst(int64(v)), +1) 1381 Ginscall(Panicindex, -1) 1382 Patch(p1, Pc) 1383 } 1384 1385 Regfree(&nlen) 1386 } 1387 1388 if v*w != 0 { 1389 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), int64(v*w), &n3) 1390 } 1391 *a = n3 1392 break 1393 } 1394 1395 // type of the index 1396 t := Types[TUINT64] 1397 1398 if n1.Type.IsSigned() { 1399 t = Types[TINT64] 1400 } 1401 1402 var n2 Node 1403 Regalloc(&n2, t, &n1) // i 1404 Thearch.Gmove(&n1, &n2) 1405 Regfree(&n1) 1406 1407 if Debug['B'] == 0 && !n.Bounded { 1408 // check bounds 1409 t = Types[Simtype[TUINT]] 1410 1411 if Is64(nr.Type) { 1412 t = Types[TUINT64] 1413 } 1414 if Isconst(nl, CTSTR) { 1415 Nodconst(&nlen, t, int64(len(nl.Val().U.(string)))) 1416 } else if nl.Type.IsSlice() || nl.Type.IsString() { 1417 // nlen already initialized 1418 } else { 1419 Nodconst(&nlen, t, nl.Type.NumElem()) 1420 } 1421 1422 p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1) 1423 Ginscall(Panicindex, -1) 1424 Patch(p1, Pc) 1425 } 1426 1427 if Isconst(nl, CTSTR) { 1428 Regalloc(&n3, Types[Tptr], res) 1429 p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ! 1430 Datastring(nl.Val().U.(string), &p1.From) 1431 p1.From.Type = obj.TYPE_ADDR 1432 Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3) 1433 goto indexdone 1434 } 1435 1436 if w == 0 { 1437 // nothing to do 1438 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) { 1439 // done by back end 1440 } else if w == 1 { 1441 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1442 } else { 1443 if w&(w-1) == 0 { 1444 // Power of 2. Use shift. 1445 Thearch.Ginscon(Thearch.Optoas(OLSH, t), int64(log2(w)), &n2) 1446 } else { 1447 // Not a power of 2. Use multiply. 1448 Thearch.Ginscon(Thearch.Optoas(OMUL, t), int64(w), &n2) 1449 } 1450 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3) 1451 } 1452 1453 indexdone: 1454 *a = n3 1455 Regfree(&n2) 1456 if freelen != 0 { 1457 Regfree(&nlen) 1458 } 1459 1460 default: 1461 Regalloc(a, Types[Tptr], res) 1462 Agen(n, a) 1463 } 1464 } 1465 1466 // log2 returns the logarithm base 2 of n. n must be a power of 2. 1467 func log2(n uint64) int { 1468 x := 0 1469 for n>>uint(x) != 1 { 1470 x++ 1471 } 1472 return x 1473 } 1474 1475 // generate: 1476 // res = &n; 1477 // The generated code checks that the result is not nil. 1478 func Agen(n *Node, res *Node) { 1479 if Debug['g'] != 0 { 1480 Dump("\nagen-res", res) 1481 Dump("agen-r", n) 1482 } 1483 1484 if n == nil || n.Type == nil { 1485 return 1486 } 1487 1488 for n.Op == OCONVNOP { 1489 n = n.Left 1490 } 1491 1492 if Isconst(n, CTNIL) && n.Type.Width > int64(Widthptr) { 1493 // Use of a nil interface or nil slice. 1494 // Create a temporary we can take the address of and read. 1495 // The generated code is just going to panic, so it need not 1496 // be terribly efficient. See issue 3670. 1497 var n1 Node 1498 Tempname(&n1, n.Type) 1499 1500 Gvardef(&n1) 1501 Thearch.Clearfat(&n1) 1502 var n2 Node 1503 Regalloc(&n2, Types[Tptr], res) 1504 var n3 Node 1505 n3.Op = OADDR 1506 n3.Left = &n1 1507 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n3, &n2) 1508 Thearch.Gmove(&n2, res) 1509 Regfree(&n2) 1510 return 1511 } 1512 1513 if n.Op == OINDREG && n.Xoffset == 0 { 1514 // Generate MOVW R0, R1 instead of MOVW $0(R0), R1. 1515 // This allows better move propagation in the back ends 1516 // (and maybe it helps the processor). 1517 n1 := *n 1518 n1.Op = OREGISTER 1519 n1.Type = res.Type 1520 Thearch.Gmove(&n1, res) 1521 return 1522 } 1523 1524 if n.Addable { 1525 if n.Op == OREGISTER { 1526 Fatalf("agen OREGISTER") 1527 } 1528 var n1 Node 1529 n1.Op = OADDR 1530 n1.Left = n 1531 var n2 Node 1532 Regalloc(&n2, Types[Tptr], res) 1533 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n1, &n2) 1534 Thearch.Gmove(&n2, res) 1535 Regfree(&n2) 1536 return 1537 } 1538 1539 nl := n.Left 1540 1541 switch n.Op { 1542 default: 1543 Fatalf("agen: unknown op %v", Nconv(n, FmtShort|FmtSign)) 1544 1545 case OCALLMETH: 1546 cgen_callmeth(n, 0) 1547 cgen_aret(n, res) 1548 1549 case OCALLINTER: 1550 cgen_callinter(n, res, 0) 1551 cgen_aret(n, res) 1552 1553 case OCALLFUNC: 1554 cgen_call(n, 0) 1555 cgen_aret(n, res) 1556 1557 case OEFACE, ODOTTYPE, OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: 1558 var n1 Node 1559 Tempname(&n1, n.Type) 1560 Cgen(n, &n1) 1561 Agen(&n1, res) 1562 1563 case OINDEX: 1564 var n1 Node 1565 Agenr(n, &n1, res) 1566 Thearch.Gmove(&n1, res) 1567 Regfree(&n1) 1568 1569 case ONAME: 1570 // should only get here with names in this func. 1571 if n.Name.Funcdepth > 0 && n.Name.Funcdepth != Funcdepth { 1572 Dump("bad agen", n) 1573 Fatalf("agen: bad ONAME funcdepth %d != %d", n.Name.Funcdepth, Funcdepth) 1574 } 1575 1576 // should only get here for heap vars or paramref 1577 if n.Class&PHEAP == 0 && n.Class != PPARAMREF { 1578 Dump("bad agen", n) 1579 Fatalf("agen: bad ONAME class %#x", n.Class) 1580 } 1581 1582 Cgen(n.Name.Heapaddr, res) 1583 if n.Xoffset != 0 { 1584 addOffset(res, n.Xoffset) 1585 } 1586 1587 case OIND: 1588 Cgen(nl, res) 1589 Cgen_checknil(res) 1590 1591 case ODOT: 1592 Agen(nl, res) 1593 if n.Xoffset != 0 { 1594 addOffset(res, n.Xoffset) 1595 } 1596 1597 case ODOTPTR: 1598 Cgen(nl, res) 1599 Cgen_checknil(res) 1600 if n.Xoffset != 0 { 1601 addOffset(res, n.Xoffset) 1602 } 1603 } 1604 } 1605 1606 func addOffset(res *Node, offset int64) { 1607 if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' { 1608 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res) 1609 return 1610 } 1611 1612 var n1, n2 Node 1613 Regalloc(&n1, Types[Tptr], nil) 1614 Thearch.Gmove(res, &n1) 1615 Regalloc(&n2, Types[Tptr], nil) 1616 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), Nodintconst(offset), &n2) 1617 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n1) 1618 Thearch.Gmove(&n1, res) 1619 Regfree(&n1) 1620 Regfree(&n2) 1621 } 1622 1623 // Igen computes the address &n, stores it in a register r, 1624 // and rewrites a to refer to *r. The chosen r may be the 1625 // stack pointer, it may be borrowed from res, or it may 1626 // be a newly allocated register. The caller must call Regfree(a) 1627 // to free r when the address is no longer needed. 1628 // The generated code ensures that &n is not nil. 1629 func Igen(n *Node, a *Node, res *Node) { 1630 if Debug['g'] != 0 { 1631 Dump("\nigen-n", n) 1632 } 1633 1634 switch n.Op { 1635 case ONAME: 1636 if (n.Class&PHEAP != 0) || n.Class == PPARAMREF { 1637 break 1638 } 1639 *a = *n 1640 return 1641 1642 case OINDREG: 1643 // Increase the refcount of the register so that igen's caller 1644 // has to call Regfree. 1645 if n.Reg != int16(Thearch.REGSP) { 1646 reg[n.Reg-int16(Thearch.REGMIN)]++ 1647 } 1648 *a = *n 1649 return 1650 1651 case ODOT: 1652 Igen(n.Left, a, res) 1653 a.Xoffset += n.Xoffset 1654 a.Type = n.Type 1655 Fixlargeoffset(a) 1656 return 1657 1658 case ODOTPTR: 1659 Cgenr(n.Left, a, res) 1660 Cgen_checknil(a) 1661 a.Op = OINDREG 1662 a.Xoffset += n.Xoffset 1663 a.Type = n.Type 1664 Fixlargeoffset(a) 1665 return 1666 1667 case OCALLFUNC, OCALLMETH, OCALLINTER: 1668 switch n.Op { 1669 case OCALLFUNC: 1670 cgen_call(n, 0) 1671 1672 case OCALLMETH: 1673 cgen_callmeth(n, 0) 1674 1675 case OCALLINTER: 1676 cgen_callinter(n, nil, 0) 1677 } 1678 1679 fp := n.Left.Type.Results().Field(0) 1680 *a = Node{} 1681 a.Op = OINDREG 1682 a.Reg = int16(Thearch.REGSP) 1683 a.Addable = true 1684 a.Xoffset = fp.Offset + Ctxt.FixedFrameSize() 1685 a.Type = n.Type 1686 return 1687 1688 // Index of fixed-size array by constant can 1689 // put the offset in the addressing. 1690 // Could do the same for slice except that we need 1691 // to use the real index for the bounds checking. 1692 case OINDEX: 1693 if n.Left.Type.IsArray() || (n.Left.Type.IsPtr() && n.Left.Left.Type.IsArray()) { 1694 if Isconst(n.Right, CTINT) { 1695 // Compute &a. 1696 if !n.Left.Type.IsPtr() { 1697 Igen(n.Left, a, res) 1698 } else { 1699 var n1 Node 1700 Igen(n.Left, &n1, res) 1701 Cgen_checknil(&n1) 1702 Regalloc(a, Types[Tptr], res) 1703 Thearch.Gmove(&n1, a) 1704 Regfree(&n1) 1705 a.Op = OINDREG 1706 } 1707 1708 // Compute &a[i] as &a + i*width. 1709 a.Type = n.Type 1710 1711 a.Xoffset += n.Right.Int64() * n.Type.Width 1712 Fixlargeoffset(a) 1713 return 1714 } 1715 } 1716 } 1717 1718 Agenr(n, a, res) 1719 a.Op = OINDREG 1720 a.Type = n.Type 1721 } 1722 1723 // Bgen generates code for branches: 1724 // 1725 // if n == wantTrue { 1726 // goto to 1727 // } 1728 func Bgen(n *Node, wantTrue bool, likely int, to *obj.Prog) { 1729 bgenx(n, nil, wantTrue, likely, to) 1730 } 1731 1732 // Bvgen generates code for calculating boolean values: 1733 // res = n == wantTrue 1734 func Bvgen(n, res *Node, wantTrue bool) { 1735 if Thearch.Ginsboolval == nil { 1736 // Direct value generation not implemented for this architecture. 1737 // Implement using jumps. 1738 bvgenjump(n, res, wantTrue, true) 1739 return 1740 } 1741 bgenx(n, res, wantTrue, 0, nil) 1742 } 1743 1744 // bvgenjump implements boolean value generation using jumps: 1745 // if n == wantTrue { 1746 // res = 1 1747 // } else { 1748 // res = 0 1749 // } 1750 // geninit controls whether n's Ninit is generated. 1751 func bvgenjump(n, res *Node, wantTrue, geninit bool) { 1752 init := n.Ninit 1753 if !geninit { 1754 n.Ninit.Set(nil) 1755 } 1756 p1 := Gbranch(obj.AJMP, nil, 0) 1757 p2 := Pc 1758 Thearch.Gmove(Nodbool(true), res) 1759 p3 := Gbranch(obj.AJMP, nil, 0) 1760 Patch(p1, Pc) 1761 Bgen(n, wantTrue, 0, p2) 1762 Thearch.Gmove(Nodbool(false), res) 1763 Patch(p3, Pc) 1764 n.Ninit.MoveNodes(&init) 1765 } 1766 1767 // bgenx is the backend for Bgen and Bvgen. 1768 // If res is nil, it generates a branch. 1769 // Otherwise, it generates a boolean value. 1770 func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { 1771 if Debug['g'] != 0 { 1772 fmt.Printf("\nbgenx wantTrue=%t likely=%d to=%v\n", wantTrue, likely, to) 1773 Dump("n", n) 1774 Dump("res", res) 1775 } 1776 1777 genval := res != nil 1778 1779 if n == nil { 1780 n = Nodbool(true) 1781 } 1782 1783 Genlist(n.Ninit) 1784 1785 if n.Type == nil { 1786 n = convlit(n, Types[TBOOL]) 1787 if n.Type == nil { 1788 return 1789 } 1790 } 1791 1792 if !n.Type.IsBoolean() { 1793 Fatalf("bgen: bad type %v for %v", n.Type, Oconv(n.Op, 0)) 1794 } 1795 1796 for n.Op == OCONVNOP { 1797 n = n.Left 1798 Genlist(n.Ninit) 1799 } 1800 1801 if Thearch.Bgen_float != nil && n.Left != nil && n.Left.Type.IsFloat() { 1802 if genval { 1803 bvgenjump(n, res, wantTrue, false) 1804 return 1805 } 1806 Thearch.Bgen_float(n, wantTrue, likely, to) 1807 return 1808 } 1809 1810 switch n.Op { 1811 default: 1812 if genval { 1813 Cgen(n, res) 1814 if !wantTrue { 1815 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) 1816 } 1817 return 1818 } 1819 1820 var tmp Node 1821 Regalloc(&tmp, n.Type, nil) 1822 Cgen(n, &tmp) 1823 bgenNonZero(&tmp, nil, wantTrue, likely, to) 1824 Regfree(&tmp) 1825 return 1826 1827 case ONAME: 1828 if genval { 1829 // 5g, 7g, and 9g might need a temporary or other help here, 1830 // but they don't support direct generation of a bool value yet. 1831 // We can fix that as we go. 1832 switch Ctxt.Arch.Thechar { 1833 case '0', '5', '7', '9': 1834 Fatalf("genval 0g, 5g, 7g, 9g ONAMES not fully implemented") 1835 } 1836 Cgen(n, res) 1837 if !wantTrue { 1838 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) 1839 } 1840 return 1841 } 1842 1843 if n.Addable && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { 1844 // no need for a temporary 1845 bgenNonZero(n, nil, wantTrue, likely, to) 1846 return 1847 } 1848 var tmp Node 1849 Regalloc(&tmp, n.Type, nil) 1850 Cgen(n, &tmp) 1851 bgenNonZero(&tmp, nil, wantTrue, likely, to) 1852 Regfree(&tmp) 1853 return 1854 1855 case OLITERAL: 1856 // n is a constant. 1857 if !Isconst(n, CTBOOL) { 1858 Fatalf("bgen: non-bool const %v\n", Nconv(n, FmtLong)) 1859 } 1860 if genval { 1861 Cgen(Nodbool(wantTrue == n.Val().U.(bool)), res) 1862 return 1863 } 1864 // If n == wantTrue, jump; otherwise do nothing. 1865 if wantTrue == n.Val().U.(bool) { 1866 Patch(Gbranch(obj.AJMP, nil, likely), to) 1867 } 1868 return 1869 1870 case OANDAND, OOROR: 1871 and := (n.Op == OANDAND) == wantTrue 1872 if genval { 1873 p1 := Gbranch(obj.AJMP, nil, 0) 1874 p2 := Gbranch(obj.AJMP, nil, 0) 1875 Patch(p2, Pc) 1876 Cgen(Nodbool(!and), res) 1877 p3 := Gbranch(obj.AJMP, nil, 0) 1878 Patch(p1, Pc) 1879 Bgen(n.Left, wantTrue != and, 0, p2) 1880 Bvgen(n.Right, res, wantTrue) 1881 Patch(p3, Pc) 1882 return 1883 } 1884 1885 if and { 1886 p1 := Gbranch(obj.AJMP, nil, 0) 1887 p2 := Gbranch(obj.AJMP, nil, 0) 1888 Patch(p1, Pc) 1889 Bgen(n.Left, !wantTrue, -likely, p2) 1890 Bgen(n.Right, !wantTrue, -likely, p2) 1891 p1 = Gbranch(obj.AJMP, nil, 0) 1892 Patch(p1, to) 1893 Patch(p2, Pc) 1894 } else { 1895 Bgen(n.Left, wantTrue, likely, to) 1896 Bgen(n.Right, wantTrue, likely, to) 1897 } 1898 return 1899 1900 case ONOT: // unary 1901 if n.Left == nil || n.Left.Type == nil { 1902 return 1903 } 1904 bgenx(n.Left, res, !wantTrue, likely, to) 1905 return 1906 1907 case OEQ, ONE, OLT, OGT, OLE, OGE: 1908 if n.Left == nil || n.Left.Type == nil || n.Right == nil || n.Right.Type == nil { 1909 return 1910 } 1911 } 1912 1913 // n.Op is one of OEQ, ONE, OLT, OGT, OLE, OGE 1914 nl := n.Left 1915 nr := n.Right 1916 op := n.Op 1917 1918 if !wantTrue { 1919 if nr.Type.IsFloat() { 1920 // Brcom is not valid on floats when NaN is involved. 1921 ll := n.Ninit // avoid re-genning Ninit 1922 n.Ninit.Set(nil) 1923 if genval { 1924 bgenx(n, res, true, likely, to) 1925 Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) // res = !res 1926 n.Ninit.Set(ll.Slice()) 1927 return 1928 } 1929 p1 := Gbranch(obj.AJMP, nil, 0) 1930 p2 := Gbranch(obj.AJMP, nil, 0) 1931 Patch(p1, Pc) 1932 bgenx(n, res, true, -likely, p2) 1933 Patch(Gbranch(obj.AJMP, nil, 0), to) 1934 Patch(p2, Pc) 1935 n.Ninit.Set(ll.Slice()) 1936 return 1937 } 1938 1939 op = Brcom(op) 1940 } 1941 wantTrue = true 1942 1943 // make simplest on right 1944 if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) { 1945 op = Brrev(op) 1946 nl, nr = nr, nl 1947 } 1948 1949 if nl.Type.IsSlice() || nl.Type.IsInterface() { 1950 // front end should only leave cmp to literal nil 1951 if (op != OEQ && op != ONE) || nr.Op != OLITERAL { 1952 if nl.Type.IsSlice() { 1953 Yyerror("illegal slice comparison") 1954 } else { 1955 Yyerror("illegal interface comparison") 1956 } 1957 return 1958 } 1959 1960 var ptr Node 1961 Igen(nl, &ptr, nil) 1962 if nl.Type.IsSlice() { 1963 ptr.Xoffset += int64(Array_array) 1964 } 1965 ptr.Type = Types[Tptr] 1966 var tmp Node 1967 Regalloc(&tmp, ptr.Type, &ptr) 1968 Cgen(&ptr, &tmp) 1969 Regfree(&ptr) 1970 bgenNonZero(&tmp, res, op == OEQ != wantTrue, likely, to) 1971 Regfree(&tmp) 1972 return 1973 } 1974 1975 if nl.Type.IsComplex() { 1976 complexbool(op, nl, nr, res, wantTrue, likely, to) 1977 return 1978 } 1979 1980 if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) { 1981 if genval { 1982 // TODO: Teach Cmp64 to generate boolean values and remove this. 1983 bvgenjump(n, res, wantTrue, false) 1984 return 1985 } 1986 if !nl.Addable || Isconst(nl, CTINT) { 1987 nl = CgenTemp(nl) 1988 } 1989 if !nr.Addable { 1990 nr = CgenTemp(nr) 1991 } 1992 Thearch.Cmp64(nl, nr, op, likely, to) 1993 return 1994 } 1995 1996 if nr.Ullman >= UINF { 1997 var n1 Node 1998 Regalloc(&n1, nl.Type, nil) 1999 Cgen(nl, &n1) 2000 nl = &n1 2001 2002 var tmp Node 2003 Tempname(&tmp, nl.Type) 2004 Thearch.Gmove(&n1, &tmp) 2005 Regfree(&n1) 2006 2007 var n2 Node 2008 Regalloc(&n2, nr.Type, nil) 2009 Cgen(nr, &n2) 2010 nr = &n2 2011 2012 Regalloc(&n1, nl.Type, nil) 2013 Cgen(&tmp, &n1) 2014 Regfree(&n1) 2015 Regfree(&n2) 2016 } else { 2017 var n1 Node 2018 if !nl.Addable && Ctxt.Arch.Thechar == '8' { 2019 Tempname(&n1, nl.Type) 2020 } else { 2021 Regalloc(&n1, nl.Type, nil) 2022 defer Regfree(&n1) 2023 } 2024 Cgen(nl, &n1) 2025 nl = &n1 2026 2027 if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '9' { 2028 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr) 2029 bins(nr.Type, res, op, likely, to) 2030 return 2031 } 2032 2033 if !nr.Addable && Ctxt.Arch.Thechar == '8' { 2034 nr = CgenTemp(nr) 2035 } 2036 2037 var n2 Node 2038 Regalloc(&n2, nr.Type, nil) 2039 Cgen(nr, &n2) 2040 nr = &n2 2041 Regfree(&n2) 2042 } 2043 2044 l, r := nl, nr 2045 2046 // On x86, only < and <= work right with NaN; reverse if needed 2047 if Ctxt.Arch.Thechar == '6' && nl.Type.IsFloat() && (op == OGT || op == OGE) { 2048 l, r = r, l 2049 op = Brrev(op) 2050 } 2051 2052 // MIPS does not have CMP instruction 2053 if Ctxt.Arch.Thechar == '0' { 2054 p := Thearch.Ginscmp(op, nr.Type, l, r, likely) 2055 Patch(p, to) 2056 return 2057 } 2058 2059 // Do the comparison. 2060 Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r) 2061 2062 // Handle floating point special cases. 2063 // Note that 8g has Bgen_float and is handled above. 2064 if nl.Type.IsFloat() { 2065 switch Ctxt.Arch.Thechar { 2066 case '5': 2067 if genval { 2068 Fatalf("genval 5g Isfloat special cases not implemented") 2069 } 2070 switch n.Op { 2071 case ONE: 2072 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to) 2073 Patch(Gbranch(Thearch.Optoas(op, nr.Type), nr.Type, likely), to) 2074 default: 2075 p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely) 2076 Patch(Gbranch(Thearch.Optoas(op, nr.Type), nr.Type, likely), to) 2077 Patch(p, Pc) 2078 } 2079 return 2080 case '6': 2081 switch n.Op { 2082 case OEQ: 2083 // neither NE nor P 2084 if genval { 2085 var reg Node 2086 Regalloc(®, Types[TBOOL], nil) 2087 Thearch.Ginsboolval(Thearch.Optoas(OEQ, nr.Type), ®) 2088 Thearch.Ginsboolval(Thearch.Optoas(OPC, nr.Type), res) 2089 Thearch.Gins(Thearch.Optoas(OAND, Types[TBOOL]), ®, res) 2090 Regfree(®) 2091 } else { 2092 p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely) 2093 p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely) 2094 Patch(Gbranch(obj.AJMP, nil, 0), to) 2095 Patch(p1, Pc) 2096 Patch(p2, Pc) 2097 } 2098 return 2099 case ONE: 2100 // either NE or P 2101 if genval { 2102 var reg Node 2103 Regalloc(®, Types[TBOOL], nil) 2104 Thearch.Ginsboolval(Thearch.Optoas(ONE, nr.Type), ®) 2105 Thearch.Ginsboolval(Thearch.Optoas(OPS, nr.Type), res) 2106 Thearch.Gins(Thearch.Optoas(OOR, Types[TBOOL]), ®, res) 2107 Regfree(®) 2108 } else { 2109 Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to) 2110 Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to) 2111 } 2112 return 2113 } 2114 case '7', '9': 2115 if genval { 2116 Fatalf("genval 7g, 9g Isfloat special cases not implemented") 2117 } 2118 switch n.Op { 2119 // On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =. 2120 // TODO(josh): Convert a <= b to b > a instead? 2121 case OLE, OGE: 2122 if op == OLE { 2123 op = OLT 2124 } else { 2125 op = OGT 2126 } 2127 Patch(Gbranch(Thearch.Optoas(op, nr.Type), nr.Type, likely), to) 2128 Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to) 2129 return 2130 } 2131 } 2132 } 2133 2134 // Not a special case. Insert the conditional jump or value gen. 2135 bins(nr.Type, res, op, likely, to) 2136 } 2137 2138 func bgenNonZero(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { 2139 // TODO: Optimize on systems that can compare to zero easily. 2140 var op Op = ONE 2141 if !wantTrue { 2142 op = OEQ 2143 } 2144 2145 // MIPS does not have CMP instruction 2146 if Thearch.Thechar == '0' { 2147 p := Gbranch(Thearch.Optoas(op, n.Type), n.Type, likely) 2148 Naddr(&p.From, n) 2149 Patch(p, to) 2150 return 2151 } 2152 2153 var zero Node 2154 Nodconst(&zero, n.Type, 0) 2155 Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &zero) 2156 bins(n.Type, res, op, likely, to) 2157 } 2158 2159 // bins inserts an instruction to handle the result of a compare. 2160 // If res is non-nil, it inserts appropriate value generation instructions. 2161 // If res is nil, it inserts a branch to to. 2162 func bins(typ *Type, res *Node, op Op, likely int, to *obj.Prog) { 2163 a := Thearch.Optoas(op, typ) 2164 if res != nil { 2165 // value gen 2166 Thearch.Ginsboolval(a, res) 2167 } else { 2168 // jump 2169 Patch(Gbranch(a, typ, likely), to) 2170 } 2171 } 2172 2173 // stkof returns n's offset from SP if n is on the stack 2174 // (either a local variable or the return value from a function call 2175 // or the arguments to a function call). 2176 // If n is not on the stack, stkof returns -1000. 2177 // If n is on the stack but in an unknown location 2178 // (due to array index arithmetic), stkof returns +1000. 2179 // 2180 // NOTE(rsc): It is possible that the ODOT and OINDEX cases 2181 // are not relevant here, since it shouldn't be possible for them 2182 // to be involved in an overlapping copy. Only function results 2183 // from one call and the arguments to the next can overlap in 2184 // any non-trivial way. If they can be dropped, then this function 2185 // becomes much simpler and also more trustworthy. 2186 // The fact that it works at all today is probably due to the fact 2187 // that ODOT and OINDEX are irrelevant. 2188 func stkof(n *Node) int64 { 2189 switch n.Op { 2190 case OINDREG: 2191 if n.Reg != int16(Thearch.REGSP) { 2192 return -1000 // not on stack 2193 } 2194 return n.Xoffset 2195 2196 case ODOT: 2197 t := n.Left.Type 2198 if t.IsPtr() { 2199 break 2200 } 2201 off := stkof(n.Left) 2202 if off == -1000 || off == +1000 { 2203 return off 2204 } 2205 return off + n.Xoffset 2206 2207 case OINDEX: 2208 t := n.Left.Type 2209 if !t.IsArray() { 2210 break 2211 } 2212 off := stkof(n.Left) 2213 if off == -1000 || off == +1000 { 2214 return off 2215 } 2216 if Isconst(n.Right, CTINT) { 2217 return off + t.Elem().Width*n.Right.Int64() 2218 } 2219 return +1000 // on stack but not sure exactly where 2220 2221 case OCALLMETH, OCALLINTER, OCALLFUNC: 2222 t := n.Left.Type 2223 if t.IsPtr() { 2224 t = t.Elem() 2225 } 2226 2227 f := t.Results().Field(0) 2228 if f != nil { 2229 return f.Offset + Ctxt.FixedFrameSize() 2230 } 2231 } 2232 2233 // botch - probably failing to recognize address 2234 // arithmetic on the above. eg INDEX and DOT 2235 return -1000 // not on stack 2236 } 2237 2238 // block copy: 2239 // memmove(&ns, &n, w); 2240 // if wb is true, needs write barrier. 2241 func sgen_wb(n *Node, ns *Node, w int64, wb bool) { 2242 if Debug['g'] != 0 { 2243 op := "sgen" 2244 if wb { 2245 op = "sgen-wb" 2246 } 2247 fmt.Printf("\n%s w=%d\n", op, w) 2248 Dump("r", n) 2249 Dump("res", ns) 2250 } 2251 2252 if n.Ullman >= UINF && ns.Ullman >= UINF { 2253 Fatalf("sgen UINF") 2254 } 2255 2256 if w < 0 { 2257 Fatalf("sgen copy %d", w) 2258 } 2259 2260 // If copying .args, that's all the results, so record definition sites 2261 // for them for the liveness analysis. 2262 if ns.Op == ONAME && ns.Sym.Name == ".args" { 2263 for _, ln := range Curfn.Func.Dcl { 2264 if ln.Class == PPARAMOUT { 2265 Gvardef(ln) 2266 } 2267 } 2268 } 2269 2270 // Avoid taking the address for simple enough types. 2271 if componentgen_wb(n, ns, wb) { 2272 return 2273 } 2274 2275 if w == 0 { 2276 // evaluate side effects only 2277 var nodr Node 2278 Regalloc(&nodr, Types[Tptr], nil) 2279 Agen(ns, &nodr) 2280 Agen(n, &nodr) 2281 Regfree(&nodr) 2282 return 2283 } 2284 2285 // offset on the stack 2286 osrc := stkof(n) 2287 odst := stkof(ns) 2288 2289 if odst != -1000 { 2290 // on stack, write barrier not needed after all 2291 wb = false 2292 } 2293 2294 if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) || wb && osrc != -1000 { 2295 // osrc and odst both on stack, and at least one is in 2296 // an unknown position. Could generate code to test 2297 // for forward/backward copy, but instead just copy 2298 // to a temporary location first. 2299 // 2300 // OR: write barrier needed and source is on stack. 2301 // Invoking the write barrier will use the stack to prepare its call. 2302 // Copy to temporary. 2303 var tmp Node 2304 Tempname(&tmp, n.Type) 2305 sgen_wb(n, &tmp, w, false) 2306 sgen_wb(&tmp, ns, w, wb) 2307 return 2308 } 2309 2310 if wb { 2311 cgen_wbfat(n, ns) 2312 return 2313 } 2314 2315 Thearch.Blockcopy(n, ns, osrc, odst, w) 2316 } 2317 2318 // generate: 2319 // call f 2320 // proc=-1 normal call but no return 2321 // proc=0 normal call 2322 // proc=1 goroutine run in new proc 2323 // proc=2 defer call save away stack 2324 // proc=3 normal call to C pointer (not Go func value) 2325 func Ginscall(f *Node, proc int) { 2326 if f.Type != nil { 2327 extra := int32(0) 2328 if proc == 1 || proc == 2 { 2329 extra = 2 * int32(Widthptr) 2330 } 2331 Setmaxarg(f.Type, extra) 2332 } 2333 2334 switch proc { 2335 default: 2336 Fatalf("Ginscall: bad proc %d", proc) 2337 2338 case 0, // normal call 2339 -1: // normal call but no return 2340 if f.Op == ONAME && f.Class == PFUNC { 2341 if f == Deferreturn { 2342 // Deferred calls will appear to be returning to the CALL 2343 // deferreturn(SB) that we are about to emit. However, the 2344 // stack scanning code will think that the instruction 2345 // before the CALL is executing. To avoid the scanning 2346 // code making bad assumptions (both cosmetic such as 2347 // showing the wrong line number and fatal, such as being 2348 // confused over whether a stack slot contains a pointer 2349 // or a scalar) insert an actual hardware NOP that will 2350 // have the right line number. This is different from 2351 // obj.ANOP, which is a virtual no-op that doesn't make it 2352 // into the instruction stream. 2353 Thearch.Ginsnop() 2354 2355 if Thearch.Thechar == '9' { 2356 // On ppc64, when compiling Go into position 2357 // independent code on ppc64le we insert an 2358 // instruction to reload the TOC pointer from the 2359 // stack as well. See the long comment near 2360 // jmpdefer in runtime/asm_ppc64.s for why. 2361 // If the MOVD is not needed, insert a hardware NOP 2362 // so that the same number of instructions are used 2363 // on ppc64 in both shared and non-shared modes. 2364 if Ctxt.Flag_shared != 0 { 2365 p := Thearch.Gins(ppc64.AMOVD, nil, nil) 2366 p.From.Type = obj.TYPE_MEM 2367 p.From.Offset = 24 2368 p.From.Reg = ppc64.REGSP 2369 p.To.Type = obj.TYPE_REG 2370 p.To.Reg = ppc64.REG_R2 2371 } else { 2372 Thearch.Ginsnop() 2373 } 2374 } 2375 } 2376 2377 p := Thearch.Gins(obj.ACALL, nil, f) 2378 Afunclit(&p.To, f) 2379 if proc == -1 || Noreturn(p) { 2380 Thearch.Gins(obj.AUNDEF, nil, nil) 2381 } 2382 break 2383 } 2384 2385 var reg Node 2386 Nodreg(®, Types[Tptr], Thearch.REGCTXT) 2387 var r1 Node 2388 Nodreg(&r1, Types[Tptr], Thearch.REGCALLX) 2389 Thearch.Gmove(f, ®) 2390 reg.Op = OINDREG 2391 Thearch.Gmove(®, &r1) 2392 reg.Op = OREGISTER 2393 Thearch.Gins(obj.ACALL, ®, &r1) 2394 2395 case 3: // normal call of c function pointer 2396 Thearch.Gins(obj.ACALL, nil, f) 2397 2398 case 1, // call in new proc (go) 2399 2: // deferred call (defer) 2400 var stk Node 2401 2402 // size of arguments at 0(SP) 2403 stk.Op = OINDREG 2404 stk.Reg = int16(Thearch.REGSP) 2405 stk.Xoffset = Ctxt.FixedFrameSize() 2406 Thearch.Ginscon(Thearch.Optoas(OAS, Types[TINT32]), int64(Argsize(f.Type)), &stk) 2407 2408 // FuncVal* at 8(SP) 2409 stk.Xoffset = int64(Widthptr) + Ctxt.FixedFrameSize() 2410 2411 var reg Node 2412 Nodreg(®, Types[Tptr], Thearch.REGCALLX2) 2413 Thearch.Gmove(f, ®) 2414 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), ®, &stk) 2415 2416 if proc == 1 { 2417 Ginscall(Newproc, 0) 2418 } else { 2419 if !hasdefer { 2420 Fatalf("hasdefer=0 but has defer") 2421 } 2422 Ginscall(Deferproc, 0) 2423 } 2424 2425 if proc == 2 { 2426 Nodreg(®, Types[TINT32], Thearch.REGRETURN) 2427 p := Thearch.Ginscmp(OEQ, Types[TINT32], ®, Nodintconst(0), +1) 2428 cgen_ret(nil) 2429 Patch(p, Pc) 2430 } 2431 } 2432 } 2433 2434 // n is call to interface method. 2435 // generate res = n. 2436 func cgen_callinter(n *Node, res *Node, proc int) { 2437 i := n.Left 2438 if i.Op != ODOTINTER { 2439 Fatalf("cgen_callinter: not ODOTINTER %v", Oconv(i.Op, 0)) 2440 } 2441 2442 i = i.Left // interface 2443 2444 if !i.Addable { 2445 var tmpi Node 2446 Tempname(&tmpi, i.Type) 2447 Cgen(i, &tmpi) 2448 i = &tmpi 2449 } 2450 2451 Genlist(n.List) // assign the args 2452 2453 // i is now addable, prepare an indirected 2454 // register to hold its address. 2455 var nodi Node 2456 Igen(i, &nodi, res) // REG = &inter 2457 2458 var nodsp Node 2459 Nodindreg(&nodsp, Types[Tptr], Thearch.REGSP) 2460 nodsp.Xoffset = Ctxt.FixedFrameSize() 2461 if proc != 0 { 2462 nodsp.Xoffset += 2 * int64(Widthptr) // leave room for size & fn 2463 } 2464 nodi.Type = Types[Tptr] 2465 nodi.Xoffset += int64(Widthptr) 2466 Cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data 2467 2468 var nodo Node 2469 Regalloc(&nodo, Types[Tptr], res) 2470 2471 nodi.Type = Types[Tptr] 2472 nodi.Xoffset -= int64(Widthptr) 2473 Cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab 2474 Regfree(&nodi) 2475 2476 var nodr Node 2477 Regalloc(&nodr, Types[Tptr], &nodo) 2478 if n.Left.Xoffset == BADWIDTH { 2479 Fatalf("cgen_callinter: badwidth") 2480 } 2481 Cgen_checknil(&nodo) // in case offset is huge 2482 nodo.Op = OINDREG 2483 nodo.Xoffset = n.Left.Xoffset + 3*int64(Widthptr) + 8 2484 if proc == 0 { 2485 // plain call: use direct c function pointer - more efficient 2486 Cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f] 2487 proc = 3 2488 } else { 2489 // go/defer. generate go func value. 2490 Agen(&nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f] 2491 } 2492 2493 nodr.Type = n.Left.Type 2494 Ginscall(&nodr, proc) 2495 2496 Regfree(&nodr) 2497 Regfree(&nodo) 2498 } 2499 2500 // generate function call; 2501 // proc=0 normal call 2502 // proc=1 goroutine run in new proc 2503 // proc=2 defer call save away stack 2504 func cgen_call(n *Node, proc int) { 2505 if n == nil { 2506 return 2507 } 2508 2509 var afun Node 2510 if n.Left.Ullman >= UINF { 2511 // if name involves a fn call 2512 // precompute the address of the fn 2513 Tempname(&afun, Types[Tptr]) 2514 2515 Cgen(n.Left, &afun) 2516 } 2517 2518 Genlist(n.List) // assign the args 2519 t := n.Left.Type 2520 2521 // call tempname pointer 2522 if n.Left.Ullman >= UINF { 2523 var nod Node 2524 Regalloc(&nod, Types[Tptr], nil) 2525 Cgen_as(&nod, &afun) 2526 nod.Type = t 2527 Ginscall(&nod, proc) 2528 Regfree(&nod) 2529 return 2530 } 2531 2532 // call pointer 2533 if n.Left.Op != ONAME || n.Left.Class != PFUNC { 2534 var nod Node 2535 Regalloc(&nod, Types[Tptr], nil) 2536 Cgen_as(&nod, n.Left) 2537 nod.Type = t 2538 Ginscall(&nod, proc) 2539 Regfree(&nod) 2540 return 2541 } 2542 2543 // call direct 2544 n.Left.Name.Method = true 2545 2546 Ginscall(n.Left, proc) 2547 } 2548 2549 // call to n has already been generated. 2550 // generate: 2551 // res = return value from call. 2552 func cgen_callret(n *Node, res *Node) { 2553 t := n.Left.Type 2554 if t.Etype == TPTR32 || t.Etype == TPTR64 { 2555 t = t.Elem() 2556 } 2557 2558 fp := t.Results().Field(0) 2559 if fp == nil { 2560 Fatalf("cgen_callret: nil") 2561 } 2562 2563 var nod Node 2564 nod.Op = OINDREG 2565 nod.Reg = int16(Thearch.REGSP) 2566 nod.Addable = true 2567 2568 nod.Xoffset = fp.Offset + Ctxt.FixedFrameSize() 2569 nod.Type = fp.Type 2570 Cgen_as(res, &nod) 2571 } 2572 2573 // call to n has already been generated. 2574 // generate: 2575 // res = &return value from call. 2576 func cgen_aret(n *Node, res *Node) { 2577 t := n.Left.Type 2578 if t.IsPtr() { 2579 t = t.Elem() 2580 } 2581 2582 fp := t.Results().Field(0) 2583 if fp == nil { 2584 Fatalf("cgen_aret: nil") 2585 } 2586 2587 var nod1 Node 2588 nod1.Op = OINDREG 2589 nod1.Reg = int16(Thearch.REGSP) 2590 nod1.Addable = true 2591 nod1.Xoffset = fp.Offset + Ctxt.FixedFrameSize() 2592 nod1.Type = fp.Type 2593 2594 if res.Op != OREGISTER { 2595 var nod2 Node 2596 Regalloc(&nod2, Types[Tptr], res) 2597 Agen(&nod1, &nod2) 2598 Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &nod2, res) 2599 Regfree(&nod2) 2600 } else { 2601 Agen(&nod1, res) 2602 } 2603 } 2604 2605 // generate return. 2606 // n->left is assignments to return values. 2607 func cgen_ret(n *Node) { 2608 if n != nil { 2609 Genlist(n.List) // copy out args 2610 } 2611 if hasdefer { 2612 Ginscall(Deferreturn, 0) 2613 } 2614 Genlist(Curfn.Func.Exit) 2615 p := Thearch.Gins(obj.ARET, nil, nil) 2616 if n != nil && n.Op == ORETJMP { 2617 p.To.Type = obj.TYPE_MEM 2618 p.To.Name = obj.NAME_EXTERN 2619 p.To.Sym = Linksym(n.Left.Sym) 2620 } 2621 } 2622 2623 // generate division according to op, one of: 2624 // res = nl / nr 2625 // res = nl % nr 2626 func cgen_div(op Op, nl *Node, nr *Node, res *Node) { 2627 var w int 2628 2629 // TODO(rsc): arm64 needs to support the relevant instructions 2630 // in peep and optoas in order to enable this. 2631 // TODO(rsc): ppc64 needs to support the relevant instructions 2632 // in peep and optoas in order to enable this. 2633 if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { 2634 goto longdiv 2635 } 2636 w = int(nl.Type.Width * 8) 2637 2638 // Front end handled 32-bit division. We only need to handle 64-bit. 2639 // try to do division by multiply by (2^w)/d 2640 // see hacker's delight chapter 10 2641 switch Simtype[nl.Type.Etype] { 2642 default: 2643 goto longdiv 2644 2645 case TUINT64: 2646 var m Magic 2647 m.W = w 2648 m.Ud = uint64(nr.Int64()) 2649 Umagic(&m) 2650 if m.Bad != 0 { 2651 break 2652 } 2653 if op == OMOD { 2654 goto longmod 2655 } 2656 2657 var n1 Node 2658 Cgenr(nl, &n1, nil) 2659 var n2 Node 2660 Nodconst(&n2, nl.Type, int64(m.Um)) 2661 var n3 Node 2662 Regalloc(&n3, nl.Type, res) 2663 Thearch.Cgen_hmul(&n1, &n2, &n3) 2664 2665 if m.Ua != 0 { 2666 // need to add numerator accounting for overflow 2667 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3) 2668 2669 Nodconst(&n2, nl.Type, 1) 2670 Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3) 2671 Nodconst(&n2, nl.Type, int64(m.S)-1) 2672 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) 2673 } else { 2674 Nodconst(&n2, nl.Type, int64(m.S)) 2675 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift dx 2676 } 2677 2678 Thearch.Gmove(&n3, res) 2679 Regfree(&n1) 2680 Regfree(&n3) 2681 return 2682 2683 case TINT64: 2684 var m Magic 2685 m.W = w 2686 m.Sd = nr.Int64() 2687 Smagic(&m) 2688 if m.Bad != 0 { 2689 break 2690 } 2691 if op == OMOD { 2692 goto longmod 2693 } 2694 2695 var n1 Node 2696 Cgenr(nl, &n1, res) 2697 var n2 Node 2698 Nodconst(&n2, nl.Type, m.Sm) 2699 var n3 Node 2700 Regalloc(&n3, nl.Type, nil) 2701 Thearch.Cgen_hmul(&n1, &n2, &n3) 2702 2703 if m.Sm < 0 { 2704 // need to add numerator 2705 Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3) 2706 } 2707 2708 Nodconst(&n2, nl.Type, int64(m.S)) 2709 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift n3 2710 2711 Nodconst(&n2, nl.Type, int64(w)-1) 2712 2713 Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n1) // -1 iff num is neg 2714 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n1, &n3) // added 2715 2716 if m.Sd < 0 { 2717 // this could probably be removed 2718 // by factoring it into the multiplier 2719 Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3) 2720 } 2721 2722 Thearch.Gmove(&n3, res) 2723 Regfree(&n1) 2724 Regfree(&n3) 2725 return 2726 } 2727 2728 goto longdiv 2729 2730 // division and mod using (slow) hardware instruction 2731 longdiv: 2732 Thearch.Dodiv(op, nl, nr, res) 2733 2734 return 2735 2736 // mod using formula A%B = A-(A/B*B) but 2737 // we know that there is a fast algorithm for A/B 2738 longmod: 2739 var n1 Node 2740 Regalloc(&n1, nl.Type, res) 2741 2742 Cgen(nl, &n1) 2743 var n2 Node 2744 Regalloc(&n2, nl.Type, nil) 2745 cgen_div(ODIV, &n1, nr, &n2) 2746 a := Thearch.Optoas(OMUL, nl.Type) 2747 if w == 8 { 2748 // use 2-operand 16-bit multiply 2749 // because there is no 2-operand 8-bit multiply 2750 a = Thearch.Optoas(OMUL, Types[TINT16]) // XXX was IMULW 2751 } 2752 2753 if !Smallintconst(nr) { 2754 var n3 Node 2755 Regalloc(&n3, nl.Type, nil) 2756 Cgen(nr, &n3) 2757 Thearch.Gins(a, &n3, &n2) 2758 Regfree(&n3) 2759 } else { 2760 Thearch.Gins(a, nr, &n2) 2761 } 2762 Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n2, &n1) 2763 Thearch.Gmove(&n1, res) 2764 Regfree(&n1) 2765 Regfree(&n2) 2766 } 2767 2768 func Fixlargeoffset(n *Node) { 2769 if n == nil { 2770 return 2771 } 2772 if n.Op != OINDREG { 2773 return 2774 } 2775 if n.Reg == int16(Thearch.REGSP) { // stack offset cannot be large 2776 return 2777 } 2778 if n.Xoffset != int64(int32(n.Xoffset)) { 2779 // offset too large, add to register instead. 2780 a := *n 2781 2782 a.Op = OREGISTER 2783 a.Type = Types[Tptr] 2784 a.Xoffset = 0 2785 Cgen_checknil(&a) 2786 Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), n.Xoffset, &a) 2787 n.Xoffset = 0 2788 } 2789 } 2790 2791 func cgen_append(n, res *Node) { 2792 if Debug['g'] != 0 { 2793 Dump("cgen_append-n", n) 2794 Dump("cgen_append-res", res) 2795 } 2796 if res.Op != ONAME && !samesafeexpr(res, n.List.First()) { 2797 Dump("cgen_append-n", n) 2798 Dump("cgen_append-res", res) 2799 Fatalf("append not lowered") 2800 } 2801 for _, n1 := range n.List.Slice() { 2802 if n1.Ullman >= UINF { 2803 Fatalf("append with function call arguments") 2804 } 2805 } 2806 2807 // res = append(src, x, y, z) 2808 // 2809 // If res and src are the same, we can avoid writing to base and cap 2810 // unless we grow the underlying array. 2811 needFullUpdate := !samesafeexpr(res, n.List.First()) 2812 2813 // Copy src triple into base, len, cap. 2814 base := temp(Types[Tptr]) 2815 len := temp(Types[TUINT]) 2816 cap := temp(Types[TUINT]) 2817 2818 var src Node 2819 Igen(n.List.First(), &src, nil) 2820 src.Type = Types[Tptr] 2821 Thearch.Gmove(&src, base) 2822 src.Type = Types[TUINT] 2823 src.Xoffset += int64(Widthptr) 2824 Thearch.Gmove(&src, len) 2825 src.Xoffset += int64(Widthptr) 2826 Thearch.Gmove(&src, cap) 2827 2828 // if len+argc <= cap goto L1 2829 var rlen Node 2830 Regalloc(&rlen, Types[TUINT], nil) 2831 Thearch.Gmove(len, &rlen) 2832 Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(n.List.Len()-1), &rlen) 2833 p := Thearch.Ginscmp(OLE, Types[TUINT], &rlen, cap, +1) 2834 // Note: rlen and src are Regrealloc'ed below at the target of the 2835 // branch we just emitted; do not reuse these Go variables for 2836 // other purposes. They need to still describe the same things 2837 // below that they describe right here. 2838 Regfree(&src) 2839 2840 // base, len, cap = growslice(type, base, len, cap, newlen) 2841 var arg Node 2842 arg.Op = OINDREG 2843 arg.Reg = int16(Thearch.REGSP) 2844 arg.Addable = true 2845 arg.Xoffset = Ctxt.FixedFrameSize() 2846 arg.Type = Ptrto(Types[TUINT8]) 2847 Cgen(typename(res.Type), &arg) 2848 arg.Xoffset += int64(Widthptr) 2849 2850 arg.Type = Types[Tptr] 2851 Cgen(base, &arg) 2852 arg.Xoffset += int64(Widthptr) 2853 2854 arg.Type = Types[TUINT] 2855 Cgen(len, &arg) 2856 arg.Xoffset += int64(Widthptr) 2857 2858 arg.Type = Types[TUINT] 2859 Cgen(cap, &arg) 2860 arg.Xoffset += int64(Widthptr) 2861 2862 arg.Type = Types[TUINT] 2863 Cgen(&rlen, &arg) 2864 arg.Xoffset += int64(Widthptr) 2865 Regfree(&rlen) 2866 2867 fn := syslook("growslice") 2868 fn = substArgTypes(fn, res.Type.Elem(), res.Type.Elem()) 2869 Ginscall(fn, 0) 2870 2871 if Widthptr == 4 && Widthreg == 8 { 2872 arg.Xoffset += 4 2873 } 2874 2875 arg.Type = Types[Tptr] 2876 Cgen(&arg, base) 2877 arg.Xoffset += int64(Widthptr) 2878 2879 arg.Type = Types[TUINT] 2880 Cgen(&arg, len) 2881 arg.Xoffset += int64(Widthptr) 2882 2883 arg.Type = Types[TUINT] 2884 Cgen(&arg, cap) 2885 2886 // Update res with base, len+argc, cap. 2887 if needFullUpdate { 2888 if Debug_append > 0 { 2889 Warn("append: full update") 2890 } 2891 Patch(p, Pc) 2892 } 2893 if res.Op == ONAME { 2894 Gvardef(res) 2895 } 2896 var dst, r1 Node 2897 Igen(res, &dst, nil) 2898 dst.Type = Types[TUINT] 2899 dst.Xoffset += int64(Widthptr) 2900 Regalloc(&r1, Types[TUINT], nil) 2901 Thearch.Gmove(len, &r1) 2902 Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(n.List.Len()-1), &r1) 2903 Thearch.Gmove(&r1, &dst) 2904 Regfree(&r1) 2905 dst.Xoffset += int64(Widthptr) 2906 Thearch.Gmove(cap, &dst) 2907 dst.Type = Types[Tptr] 2908 dst.Xoffset -= 2 * int64(Widthptr) 2909 cgen_wb(base, &dst, needwritebarrier(&dst, base)) 2910 Regfree(&dst) 2911 2912 if !needFullUpdate { 2913 if Debug_append > 0 { 2914 Warn("append: len-only update") 2915 } 2916 // goto L2; 2917 // L1: 2918 // update len only 2919 // L2: 2920 q := Gbranch(obj.AJMP, nil, 0) 2921 Patch(p, Pc) 2922 // At the goto above, src refers to cap and rlen holds the new len 2923 if src.Op == OREGISTER || src.Op == OINDREG { 2924 Regrealloc(&src) 2925 } 2926 Regrealloc(&rlen) 2927 src.Xoffset -= int64(Widthptr) 2928 Thearch.Gmove(&rlen, &src) 2929 Regfree(&src) 2930 Regfree(&rlen) 2931 Patch(q, Pc) 2932 } 2933 2934 // Copy data into place. 2935 // Could do write barrier check around entire copy instead of each element. 2936 // Could avoid reloading registers on each iteration if we know the cgen_wb 2937 // is not going to use a write barrier. 2938 i := 0 2939 var r2 Node 2940 for _, n2 := range n.List.Slice()[1:] { 2941 Regalloc(&r1, Types[Tptr], nil) 2942 Thearch.Gmove(base, &r1) 2943 Regalloc(&r2, Types[TUINT], nil) 2944 Thearch.Gmove(len, &r2) 2945 if i > 0 { 2946 Thearch.Gins(Thearch.Optoas(OADD, Types[TUINT]), Nodintconst(int64(i)), &r2) 2947 } 2948 w := res.Type.Elem().Width 2949 if Thearch.AddIndex != nil && Thearch.AddIndex(&r2, w, &r1) { 2950 // r1 updated by back end 2951 } else if w == 1 { 2952 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1) 2953 } else { 2954 Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT]), w, &r2) 2955 Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1) 2956 } 2957 Regfree(&r2) 2958 2959 r1.Op = OINDREG 2960 r1.Type = res.Type.Elem() 2961 cgen_wb(n2, &r1, needwritebarrier(&r1, n2)) 2962 Regfree(&r1) 2963 i++ 2964 } 2965 } 2966 2967 // Generate res = n, where n is x[i:j] or x[i:j:k]. 2968 // If wb is true, need write barrier updating res's base pointer. 2969 // On systems with 32-bit ints, i, j, k are guaranteed to be 32-bit values. 2970 func cgen_slice(n, res *Node, wb bool) { 2971 if Debug['g'] != 0 { 2972 Dump("cgen_slice-n", n) 2973 Dump("cgen_slice-res", res) 2974 } 2975 2976 needFullUpdate := !samesafeexpr(n.Left, res) 2977 2978 // orderexpr has made sure that x is safe (but possibly expensive) 2979 // and i, j, k are cheap. On a system with registers (anything but 386) 2980 // we can evaluate x first and then know we have enough registers 2981 // for i, j, k as well. 2982 var x, xbase, xlen, xcap, i, j, k Node 2983 if n.Op != OSLICEARR && n.Op != OSLICE3ARR { 2984 Igen(n.Left, &x, nil) 2985 } 2986 2987 indexRegType := Types[TUINT] 2988 if Widthreg > Widthptr { // amd64p32 2989 indexRegType = Types[TUINT64] 2990 } 2991 2992 // On most systems, we use registers. 2993 // The 386 has basically no registers, so substitute functions 2994 // that can work with temporaries instead. 2995 regalloc := Regalloc 2996 ginscon := Thearch.Ginscon 2997 gins := Thearch.Gins 2998 if Thearch.Thechar == '8' { 2999 regalloc = func(n *Node, t *Type, reuse *Node) { 3000 Tempname(n, t) 3001 } 3002 ginscon = func(as obj.As, c int64, n *Node) { 3003 var n1 Node 3004 Regalloc(&n1, n.Type, n) 3005 Thearch.Gmove(n, &n1) 3006 Thearch.Ginscon(as, c, &n1) 3007 Thearch.Gmove(&n1, n) 3008 Regfree(&n1) 3009 } 3010 gins = func(as obj.As, f, t *Node) *obj.Prog { 3011 var n1 Node 3012 Regalloc(&n1, t.Type, t) 3013 Thearch.Gmove(t, &n1) 3014 Thearch.Gins(as, f, &n1) 3015 Thearch.Gmove(&n1, t) 3016 Regfree(&n1) 3017 return nil 3018 } 3019 } 3020 3021 panics := make([]*obj.Prog, 0, 6) // 3 loads + 3 checks 3022 3023 loadlen := func() { 3024 if xlen.Op != 0 { 3025 return 3026 } 3027 if n.Op == OSLICEARR || n.Op == OSLICE3ARR { 3028 Nodconst(&xlen, indexRegType, n.Left.Type.Elem().NumElem()) 3029 return 3030 } 3031 if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) { 3032 Nodconst(&xlen, indexRegType, int64(len(n.Left.Val().U.(string)))) 3033 return 3034 } 3035 regalloc(&xlen, indexRegType, nil) 3036 x.Xoffset += int64(Widthptr) 3037 x.Type = Types[TUINT] 3038 Thearch.Gmove(&x, &xlen) 3039 x.Xoffset -= int64(Widthptr) 3040 } 3041 3042 loadcap := func() { 3043 if xcap.Op != 0 { 3044 return 3045 } 3046 if n.Op == OSLICEARR || n.Op == OSLICE3ARR || n.Op == OSLICESTR { 3047 loadlen() 3048 xcap = xlen 3049 if xcap.Op == OREGISTER { 3050 Regrealloc(&xcap) 3051 } 3052 return 3053 } 3054 regalloc(&xcap, indexRegType, nil) 3055 x.Xoffset += 2 * int64(Widthptr) 3056 x.Type = Types[TUINT] 3057 Thearch.Gmove(&x, &xcap) 3058 x.Xoffset -= 2 * int64(Widthptr) 3059 } 3060 3061 var x1, x2, x3 *Node // unevaluated index arguments 3062 x1 = n.Right.Left 3063 switch n.Op { 3064 default: 3065 x2 = n.Right.Right 3066 case OSLICE3, OSLICE3ARR: 3067 x2 = n.Right.Right.Left 3068 x3 = n.Right.Right.Right 3069 } 3070 3071 // load computes src into targ, but if src refers to the len or cap of n.Left, 3072 // load copies those from xlen, xcap, loading xlen if needed. 3073 // If targ.Op == OREGISTER on return, it must be Regfreed, 3074 // but it should not be modified without first checking whether it is 3075 // xlen or xcap's register. 3076 load := func(src, targ *Node) { 3077 if src == nil { 3078 return 3079 } 3080 switch src.Op { 3081 case OLITERAL: 3082 *targ = *src 3083 return 3084 case OLEN: 3085 // NOTE(rsc): This doesn't actually trigger, because order.go 3086 // has pulled all the len and cap calls into separate assignments 3087 // to temporaries. There are tests in test/sliceopt.go that could 3088 // be enabled if this is fixed. 3089 if samesafeexpr(n.Left, src.Left) { 3090 if Debug_slice > 0 { 3091 Warn("slice: reuse len") 3092 } 3093 loadlen() 3094 *targ = xlen 3095 if targ.Op == OREGISTER { 3096 Regrealloc(targ) 3097 } 3098 return 3099 } 3100 case OCAP: 3101 // NOTE(rsc): This doesn't actually trigger; see note in case OLEN above. 3102 if samesafeexpr(n.Left, src.Left) { 3103 if Debug_slice > 0 { 3104 Warn("slice: reuse cap") 3105 } 3106 loadcap() 3107 *targ = xcap 3108 if targ.Op == OREGISTER { 3109 Regrealloc(targ) 3110 } 3111 return 3112 } 3113 } 3114 if i.Op != 0 && samesafeexpr(x1, src) { 3115 if Debug_slice > 0 { 3116 Warn("slice: reuse 1st index") 3117 } 3118 *targ = i 3119 if targ.Op == OREGISTER { 3120 Regrealloc(targ) 3121 } 3122 return 3123 } 3124 if j.Op != 0 && samesafeexpr(x2, src) { 3125 if Debug_slice > 0 { 3126 Warn("slice: reuse 2nd index") 3127 } 3128 *targ = j 3129 if targ.Op == OREGISTER { 3130 Regrealloc(targ) 3131 } 3132 return 3133 } 3134 if Thearch.Cgenindex != nil { 3135 regalloc(targ, indexRegType, nil) 3136 p := Thearch.Cgenindex(src, targ, false) 3137 if p != nil { 3138 panics = append(panics, p) 3139 } 3140 } else if Thearch.Igenindex != nil { 3141 p := Thearch.Igenindex(src, targ, false) 3142 if p != nil { 3143 panics = append(panics, p) 3144 } 3145 } else { 3146 regalloc(targ, indexRegType, nil) 3147 var tmp Node 3148 Cgenr(src, &tmp, targ) 3149 Thearch.Gmove(&tmp, targ) 3150 Regfree(&tmp) 3151 } 3152 } 3153 3154 load(x1, &i) 3155 load(x2, &j) 3156 load(x3, &k) 3157 3158 // i defaults to 0. 3159 if i.Op == 0 { 3160 Nodconst(&i, indexRegType, 0) 3161 } 3162 3163 // j defaults to len(x) 3164 if j.Op == 0 { 3165 loadlen() 3166 j = xlen 3167 if j.Op == OREGISTER { 3168 Regrealloc(&j) 3169 } 3170 } 3171 3172 // k defaults to cap(x) 3173 // Only need to load it if we're recalculating cap or doing a full update. 3174 if k.Op == 0 && n.Op != OSLICESTR && (!iszero(&i) || needFullUpdate) { 3175 loadcap() 3176 k = xcap 3177 if k.Op == OREGISTER { 3178 Regrealloc(&k) 3179 } 3180 } 3181 3182 // Check constant indexes for negative values, and against constant length if known. 3183 // The func obvious below checks for out-of-order constant indexes. 3184 var bound int64 = -1 3185 if n.Op == OSLICEARR || n.Op == OSLICE3ARR { 3186 bound = n.Left.Type.Elem().NumElem() 3187 } else if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) { 3188 bound = int64(len(n.Left.Val().U.(string))) 3189 } 3190 if Isconst(&i, CTINT) { 3191 if i.Val().U.(*Mpint).CmpInt64(0) < 0 || bound >= 0 && i.Val().U.(*Mpint).CmpInt64(bound) > 0 { 3192 Yyerror("slice index out of bounds") 3193 } 3194 } 3195 if Isconst(&j, CTINT) { 3196 if j.Val().U.(*Mpint).CmpInt64(0) < 0 || bound >= 0 && j.Val().U.(*Mpint).CmpInt64(bound) > 0 { 3197 Yyerror("slice index out of bounds") 3198 } 3199 } 3200 if Isconst(&k, CTINT) { 3201 if k.Val().U.(*Mpint).CmpInt64(0) < 0 || bound >= 0 && k.Val().U.(*Mpint).CmpInt64(bound) > 0 { 3202 Yyerror("slice index out of bounds") 3203 } 3204 } 3205 3206 // same reports whether n1 and n2 are the same register or constant. 3207 same := func(n1, n2 *Node) bool { 3208 return n1.Op == OREGISTER && n2.Op == OREGISTER && n1.Reg == n2.Reg || 3209 n1.Op == ONAME && n2.Op == ONAME && n1.Orig == n2.Orig && n1.Type == n2.Type && n1.Xoffset == n2.Xoffset || 3210 n1.Op == OLITERAL && n2.Op == OLITERAL && n1.Val().U.(*Mpint).Cmp(n2.Val().U.(*Mpint)) == 0 3211 } 3212 3213 // obvious reports whether n1 <= n2 is obviously true, 3214 // and it calls Yyerror if n1 <= n2 is obviously false. 3215 obvious := func(n1, n2 *Node) bool { 3216 if Debug['B'] != 0 { // -B disables bounds checks 3217 return true 3218 } 3219 if same(n1, n2) { 3220 return true // n1 == n2 3221 } 3222 if iszero(n1) { 3223 return true // using unsigned compare, so 0 <= n2 always true 3224 } 3225 if xlen.Op != 0 && same(n1, &xlen) && xcap.Op != 0 && same(n2, &xcap) { 3226 return true // len(x) <= cap(x) always true 3227 } 3228 if Isconst(n1, CTINT) && Isconst(n2, CTINT) { 3229 if n1.Val().U.(*Mpint).Cmp(n2.Val().U.(*Mpint)) <= 0 { 3230 return true // n1, n2 constants such that n1 <= n2 3231 } 3232 Yyerror("slice index out of bounds") 3233 return true 3234 } 3235 return false 3236 } 3237 3238 compare := func(n1, n2 *Node) { 3239 // n1 might be a 64-bit constant, even on 32-bit architectures, 3240 // but it will be represented in 32 bits. 3241 if Ctxt.Arch.Regsize == 4 && Is64(n1.Type) { 3242 if n1.Val().U.(*Mpint).CmpInt64(1<<31) >= 0 { 3243 Fatalf("missed slice out of bounds check") 3244 } 3245 var tmp Node 3246 Nodconst(&tmp, indexRegType, n1.Int64()) 3247 n1 = &tmp 3248 } 3249 p := Thearch.Ginscmp(OGT, indexRegType, n1, n2, -1) 3250 panics = append(panics, p) 3251 } 3252 3253 loadcap() 3254 max := &xcap 3255 if k.Op != 0 && (n.Op == OSLICE3 || n.Op == OSLICE3ARR) { 3256 if obvious(&k, max) { 3257 if Debug_slice > 0 { 3258 Warn("slice: omit check for 3rd index") 3259 } 3260 } else { 3261 compare(&k, max) 3262 } 3263 max = &k 3264 } 3265 if j.Op != 0 { 3266 if obvious(&j, max) { 3267 if Debug_slice > 0 { 3268 Warn("slice: omit check for 2nd index") 3269 } 3270 } else { 3271 compare(&j, max) 3272 } 3273 max = &j 3274 } 3275 if i.Op != 0 { 3276 if obvious(&i, max) { 3277 if Debug_slice > 0 { 3278 Warn("slice: omit check for 1st index") 3279 } 3280 } else { 3281 compare(&i, max) 3282 } 3283 max = &i 3284 } 3285 if k.Op != 0 && i.Op != 0 { 3286 obvious(&i, &k) // emit compile-time error for x[3:n:2] 3287 } 3288 3289 if len(panics) > 0 { 3290 p := Gbranch(obj.AJMP, nil, 0) 3291 for _, q := range panics { 3292 Patch(q, Pc) 3293 } 3294 Ginscall(panicslice, -1) 3295 Patch(p, Pc) 3296 } 3297 3298 // Checks are done. 3299 // Compute new len as j-i, cap as k-i. 3300 // If i and j are same register, len is constant 0. 3301 // If i and k are same register, cap is constant 0. 3302 // If j and k are same register, len and cap are same. 3303 3304 // Done with xlen and xcap. 3305 // Now safe to modify j and k even if they alias xlen, xcap. 3306 if xlen.Op == OREGISTER { 3307 Regfree(&xlen) 3308 } 3309 if xcap.Op == OREGISTER { 3310 Regfree(&xcap) 3311 } 3312 3313 // are j and k the same value? 3314 sameJK := same(&j, &k) 3315 3316 if i.Op != 0 { 3317 // j -= i 3318 if same(&i, &j) { 3319 if Debug_slice > 0 { 3320 Warn("slice: result len == 0") 3321 } 3322 if j.Op == OREGISTER { 3323 Regfree(&j) 3324 } 3325 Nodconst(&j, indexRegType, 0) 3326 } else { 3327 switch j.Op { 3328 case OLITERAL: 3329 if Isconst(&i, CTINT) { 3330 Nodconst(&j, indexRegType, j.Int64()-i.Int64()) 3331 if Debug_slice > 0 { 3332 Warn("slice: result len == %d", j.Int64()) 3333 } 3334 break 3335 } 3336 fallthrough 3337 case ONAME: 3338 if !istemp(&j) { 3339 var r Node 3340 regalloc(&r, indexRegType, nil) 3341 Thearch.Gmove(&j, &r) 3342 j = r 3343 } 3344 fallthrough 3345 case OREGISTER: 3346 if i.Op == OLITERAL { 3347 v := i.Int64() 3348 if v != 0 { 3349 ginscon(Thearch.Optoas(OSUB, indexRegType), v, &j) 3350 } 3351 } else { 3352 gins(Thearch.Optoas(OSUB, indexRegType), &i, &j) 3353 } 3354 } 3355 } 3356 3357 // k -= i if k different from j and cap is needed.j 3358 // (The modifications to j above cannot affect i: if j and i were aliased, 3359 // we replace j with a constant 0 instead of doing a subtraction, 3360 // leaving i unmodified.) 3361 if k.Op == 0 { 3362 if Debug_slice > 0 && n.Op != OSLICESTR { 3363 Warn("slice: result cap not computed") 3364 } 3365 // no need 3366 } else if same(&i, &k) { 3367 if k.Op == OREGISTER { 3368 Regfree(&k) 3369 } 3370 Nodconst(&k, indexRegType, 0) 3371 if Debug_slice > 0 { 3372 Warn("slice: result cap == 0") 3373 } 3374 } else if sameJK { 3375 if Debug_slice > 0 { 3376 Warn("slice: result cap == result len") 3377 } 3378 // k and j were the same value; make k-i the same as j-i. 3379 if k.Op == OREGISTER { 3380 Regfree(&k) 3381 } 3382 k = j 3383 if k.Op == OREGISTER { 3384 Regrealloc(&k) 3385 } 3386 } else { 3387 switch k.Op { 3388 case OLITERAL: 3389 if Isconst(&i, CTINT) { 3390 Nodconst(&k, indexRegType, k.Int64()-i.Int64()) 3391 if Debug_slice > 0 { 3392 Warn("slice: result cap == %d", k.Int64()) 3393 } 3394 break 3395 } 3396 fallthrough 3397 case ONAME: 3398 if !istemp(&k) { 3399 var r Node 3400 regalloc(&r, indexRegType, nil) 3401 Thearch.Gmove(&k, &r) 3402 k = r 3403 } 3404 fallthrough 3405 case OREGISTER: 3406 if same(&i, &k) { 3407 Regfree(&k) 3408 Nodconst(&k, indexRegType, 0) 3409 if Debug_slice > 0 { 3410 Warn("slice: result cap == 0") 3411 } 3412 } else if i.Op == OLITERAL { 3413 v := i.Int64() 3414 if v != 0 { 3415 ginscon(Thearch.Optoas(OSUB, indexRegType), v, &k) 3416 } 3417 } else { 3418 gins(Thearch.Optoas(OSUB, indexRegType), &i, &k) 3419 } 3420 } 3421 } 3422 } 3423 3424 adjustBase := true 3425 if i.Op == 0 || iszero(&i) { 3426 if Debug_slice > 0 { 3427 Warn("slice: skip base adjustment for 1st index 0") 3428 } 3429 adjustBase = false 3430 } else if k.Op != 0 && iszero(&k) || k.Op == 0 && iszero(&j) { 3431 if Debug_slice > 0 { 3432 if n.Op == OSLICESTR { 3433 Warn("slice: skip base adjustment for string len == 0") 3434 } else { 3435 Warn("slice: skip base adjustment for cap == 0") 3436 } 3437 } 3438 adjustBase = false 3439 } 3440 3441 if !adjustBase && !needFullUpdate { 3442 if Debug_slice > 0 { 3443 if k.Op != 0 { 3444 Warn("slice: len/cap-only update") 3445 } else { 3446 Warn("slice: len-only update") 3447 } 3448 } 3449 if i.Op == OREGISTER { 3450 Regfree(&i) 3451 } 3452 // Write len (and cap if needed) back to x. 3453 x.Xoffset += int64(Widthptr) 3454 x.Type = Types[TUINT] 3455 Thearch.Gmove(&j, &x) 3456 x.Xoffset -= int64(Widthptr) 3457 if k.Op != 0 { 3458 x.Xoffset += 2 * int64(Widthptr) 3459 x.Type = Types[TUINT] 3460 Thearch.Gmove(&k, &x) 3461 x.Xoffset -= 2 * int64(Widthptr) 3462 } 3463 Regfree(&x) 3464 } else { 3465 // Compute new base. May smash i. 3466 if n.Op == OSLICEARR || n.Op == OSLICE3ARR { 3467 Cgenr(n.Left, &xbase, nil) 3468 Cgen_checknil(&xbase) 3469 } else { 3470 var ptr *Type 3471 if n.Op == OSLICESTR { 3472 ptr = ptrToUint8 3473 } else { 3474 ptr = Ptrto(n.Type.Elem()) 3475 } 3476 regalloc(&xbase, ptr, nil) 3477 x.Type = xbase.Type 3478 Thearch.Gmove(&x, &xbase) 3479 Regfree(&x) 3480 } 3481 if i.Op != 0 && adjustBase { 3482 // Branch around the base adjustment if the resulting cap will be 0. 3483 var p *obj.Prog 3484 size := &k 3485 if k.Op == 0 { 3486 size = &j 3487 } 3488 if Isconst(size, CTINT) { 3489 // zero was checked above, must be non-zero. 3490 } else { 3491 var tmp Node 3492 Nodconst(&tmp, indexRegType, 0) 3493 p = Thearch.Ginscmp(OEQ, indexRegType, size, &tmp, -1) 3494 } 3495 var w int64 3496 if n.Op == OSLICESTR { 3497 w = 1 // res is string, elem size is 1 (byte) 3498 } else { 3499 w = res.Type.Elem().Width // res is []T, elem size is T.width 3500 } 3501 if Isconst(&i, CTINT) { 3502 ginscon(Thearch.Optoas(OADD, xbase.Type), i.Int64()*w, &xbase) 3503 } else if Thearch.AddIndex != nil && Thearch.AddIndex(&i, w, &xbase) { 3504 // done by back end 3505 } else if w == 1 { 3506 gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase) 3507 } else { 3508 if i.Op == ONAME && !istemp(&i) { 3509 var tmp Node 3510 Tempname(&tmp, i.Type) 3511 Thearch.Gmove(&i, &tmp) 3512 i = tmp 3513 } 3514 ginscon(Thearch.Optoas(OMUL, i.Type), w, &i) 3515 gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase) 3516 } 3517 if p != nil { 3518 Patch(p, Pc) 3519 } 3520 } 3521 if i.Op == OREGISTER { 3522 Regfree(&i) 3523 } 3524 3525 // Write len, cap, base to result. 3526 if res.Op == ONAME { 3527 Gvardef(res) 3528 } 3529 Igen(res, &x, nil) 3530 x.Xoffset += int64(Widthptr) 3531 x.Type = Types[TUINT] 3532 Thearch.Gmove(&j, &x) 3533 x.Xoffset -= int64(Widthptr) 3534 if k.Op != 0 { 3535 x.Xoffset += 2 * int64(Widthptr) 3536 Thearch.Gmove(&k, &x) 3537 x.Xoffset -= 2 * int64(Widthptr) 3538 } 3539 x.Type = xbase.Type 3540 cgen_wb(&xbase, &x, wb) 3541 Regfree(&xbase) 3542 Regfree(&x) 3543 } 3544 3545 if j.Op == OREGISTER { 3546 Regfree(&j) 3547 } 3548 if k.Op == OREGISTER { 3549 Regfree(&k) 3550 } 3551 }