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