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