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