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