github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/gc/gsubr.go (about) 1 // Derived from Inferno utils/6c/txt.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package gc 32 33 import ( 34 "cmd/internal/obj" 35 "fmt" 36 "runtime" 37 "strings" 38 ) 39 40 var ( 41 ddumped bool 42 dfirst *obj.Prog 43 dpc *obj.Prog 44 ) 45 46 // Is this node a memory operand? 47 func Ismem(n *Node) bool { 48 switch n.Op { 49 case OITAB, 50 OSPTR, 51 OLEN, 52 OCAP, 53 OINDREG, 54 ONAME, 55 OPARAM, 56 OCLOSUREVAR: 57 return true 58 59 case OADDR: 60 return Thearch.Thechar == '6' || Thearch.Thechar == '9' // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too 61 } 62 63 return false 64 } 65 66 func Samereg(a *Node, b *Node) bool { 67 if a == nil || b == nil { 68 return false 69 } 70 if a.Op != OREGISTER { 71 return false 72 } 73 if b.Op != OREGISTER { 74 return false 75 } 76 if a.Reg != b.Reg { 77 return false 78 } 79 return true 80 } 81 82 func Gbranch(as obj.As, t *Type, likely int) *obj.Prog { 83 p := Prog(as) 84 p.To.Type = obj.TYPE_BRANCH 85 p.To.Val = nil 86 if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' && Thearch.Thechar != '7' && Thearch.Thechar != '0' { 87 p.From.Type = obj.TYPE_CONST 88 if likely > 0 { 89 p.From.Offset = 1 90 } 91 } 92 93 if Debug['g'] != 0 { 94 fmt.Printf("%v\n", p) 95 } 96 97 return p 98 } 99 100 func Prog(as obj.As) *obj.Prog { 101 var p *obj.Prog 102 103 if as == obj.AGLOBL { 104 if ddumped { 105 Fatalf("already dumped data") 106 } 107 if dpc == nil { 108 dpc = Ctxt.NewProg() 109 dfirst = dpc 110 } 111 112 p = dpc 113 dpc = Ctxt.NewProg() 114 p.Link = dpc 115 } else { 116 p = Pc 117 Pc = Ctxt.NewProg() 118 Clearp(Pc) 119 p.Link = Pc 120 } 121 122 if lineno == 0 && Debug['K'] != 0 { 123 Warn("prog: line 0") 124 } 125 126 p.As = as 127 p.Lineno = lineno 128 return p 129 } 130 131 func Nodreg(n *Node, t *Type, r int) { 132 if t == nil { 133 Fatalf("nodreg: t nil") 134 } 135 136 *n = Node{} 137 n.Op = OREGISTER 138 n.Addable = true 139 ullmancalc(n) 140 n.Reg = int16(r) 141 n.Type = t 142 } 143 144 func Nodindreg(n *Node, t *Type, r int) { 145 Nodreg(n, t, r) 146 n.Op = OINDREG 147 } 148 149 func Afunclit(a *obj.Addr, n *Node) { 150 if a.Type == obj.TYPE_ADDR && a.Name == obj.NAME_EXTERN { 151 a.Type = obj.TYPE_MEM 152 a.Sym = Linksym(n.Sym) 153 } 154 } 155 156 func Clearp(p *obj.Prog) { 157 obj.Nopout(p) 158 p.As = obj.AEND 159 p.Pc = int64(pcloc) 160 pcloc++ 161 } 162 163 func dumpdata() { 164 ddumped = true 165 if dfirst == nil { 166 return 167 } 168 newplist() 169 *Pc = *dfirst 170 Pc = dpc 171 Clearp(Pc) 172 } 173 174 func flushdata() { 175 if dfirst == nil { 176 return 177 } 178 newplist() 179 *Pc = *dfirst 180 Pc = dpc 181 Clearp(Pc) 182 dfirst = nil 183 dpc = nil 184 } 185 186 // Fixup instructions after allocauto (formerly compactframe) has moved all autos around. 187 func fixautoused(p *obj.Prog) { 188 for lp := &p; ; { 189 p = *lp 190 if p == nil { 191 break 192 } 193 if p.As == obj.ATYPE && p.From.Node != nil && p.From.Name == obj.NAME_AUTO && !((p.From.Node).(*Node)).Used { 194 *lp = p.Link 195 continue 196 } 197 198 if (p.As == obj.AVARDEF || p.As == obj.AVARKILL || p.As == obj.AVARLIVE) && p.To.Node != nil && !((p.To.Node).(*Node)).Used { 199 // Cannot remove VARDEF instruction, because - unlike TYPE handled above - 200 // VARDEFs are interspersed with other code, and a jump might be using the 201 // VARDEF as a target. Replace with a no-op instead. A later pass will remove 202 // the no-ops. 203 obj.Nopout(p) 204 205 continue 206 } 207 208 if p.From.Name == obj.NAME_AUTO && p.From.Node != nil { 209 p.From.Offset += stkdelta[p.From.Node.(*Node)] 210 } 211 212 if p.To.Name == obj.NAME_AUTO && p.To.Node != nil { 213 p.To.Offset += stkdelta[p.To.Node.(*Node)] 214 } 215 216 lp = &p.Link 217 } 218 } 219 220 func ggloblnod(nam *Node) { 221 p := Thearch.Gins(obj.AGLOBL, nam, nil) 222 p.Lineno = nam.Lineno 223 p.From.Sym.Gotype = Linksym(ngotype(nam)) 224 p.To.Sym = nil 225 p.To.Type = obj.TYPE_CONST 226 p.To.Offset = nam.Type.Width 227 p.From3 = new(obj.Addr) 228 if nam.Name.Readonly { 229 p.From3.Offset = obj.RODATA 230 } 231 if nam.Type != nil && !haspointers(nam.Type) { 232 p.From3.Offset |= obj.NOPTR 233 } 234 } 235 236 func ggloblsym(s *Sym, width int32, flags int16) { 237 ggloblLSym(Linksym(s), width, flags) 238 } 239 240 func ggloblLSym(s *obj.LSym, width int32, flags int16) { 241 p := Thearch.Gins(obj.AGLOBL, nil, nil) 242 p.From.Type = obj.TYPE_MEM 243 p.From.Name = obj.NAME_EXTERN 244 p.From.Sym = s 245 if flags&obj.LOCAL != 0 { 246 p.From.Sym.Local = true 247 flags &^= obj.LOCAL 248 } 249 p.To.Type = obj.TYPE_CONST 250 p.To.Offset = int64(width) 251 p.From3 = new(obj.Addr) 252 p.From3.Offset = int64(flags) 253 } 254 255 func gjmp(to *obj.Prog) *obj.Prog { 256 p := Gbranch(obj.AJMP, nil, 0) 257 if to != nil { 258 Patch(p, to) 259 } 260 return p 261 } 262 263 func gtrack(s *Sym) { 264 p := Thearch.Gins(obj.AUSEFIELD, nil, nil) 265 p.From.Type = obj.TYPE_MEM 266 p.From.Name = obj.NAME_EXTERN 267 p.From.Sym = Linksym(s) 268 } 269 270 func gused(n *Node) { 271 Thearch.Gins(obj.ANOP, n, nil) // used 272 } 273 274 func Isfat(t *Type) bool { 275 if t != nil { 276 switch t.Etype { 277 case TSTRUCT, TARRAY, TSTRING, 278 TINTER: // maybe remove later 279 return true 280 } 281 } 282 283 return false 284 } 285 286 // Sweep the prog list to mark any used nodes. 287 func markautoused(p *obj.Prog) { 288 for ; p != nil; p = p.Link { 289 if p.As == obj.ATYPE || p.As == obj.AVARDEF || p.As == obj.AVARKILL { 290 continue 291 } 292 293 if p.From.Node != nil { 294 ((p.From.Node).(*Node)).Used = true 295 } 296 297 if p.To.Node != nil { 298 ((p.To.Node).(*Node)).Used = true 299 } 300 } 301 } 302 303 // Naddr rewrites a to refer to n. 304 // It assumes that a is zeroed on entry. 305 func Naddr(a *obj.Addr, n *Node) { 306 if n == nil { 307 return 308 } 309 310 if n.Type != nil && n.Type.Etype != TIDEAL { 311 // TODO(rsc): This is undone by the selective clearing of width below, 312 // to match architectures that were not as aggressive in setting width 313 // during naddr. Those widths must be cleared to avoid triggering 314 // failures in gins when it detects real but heretofore latent (and one 315 // hopes innocuous) type mismatches. 316 // The type mismatches should be fixed and the clearing below removed. 317 dowidth(n.Type) 318 319 a.Width = n.Type.Width 320 } 321 322 switch n.Op { 323 default: 324 a := a // copy to let escape into Ctxt.Dconv 325 Debug['h'] = 1 326 Dump("naddr", n) 327 Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a)) 328 329 case OREGISTER: 330 a.Type = obj.TYPE_REG 331 a.Reg = n.Reg 332 a.Sym = nil 333 if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width. 334 a.Width = 0 335 } 336 337 case OINDREG: 338 a.Type = obj.TYPE_MEM 339 a.Reg = n.Reg 340 a.Sym = Linksym(n.Sym) 341 a.Offset = n.Xoffset 342 if a.Offset != int64(int32(a.Offset)) { 343 Yyerror("offset %d too large for OINDREG", a.Offset) 344 } 345 if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width. 346 a.Width = 0 347 } 348 349 // n->left is PHEAP ONAME for stack parameter. 350 // compute address of actual parameter on stack. 351 case OPARAM: 352 a.Etype = uint8(Simtype[n.Left.Type.Etype]) 353 354 a.Width = n.Left.Type.Width 355 a.Offset = n.Xoffset 356 a.Sym = Linksym(n.Left.Sym) 357 a.Type = obj.TYPE_MEM 358 a.Name = obj.NAME_PARAM 359 a.Node = n.Left.Orig 360 361 case OCLOSUREVAR: 362 if !Curfn.Func.Needctxt { 363 Fatalf("closurevar without needctxt") 364 } 365 a.Type = obj.TYPE_MEM 366 a.Reg = int16(Thearch.REGCTXT) 367 a.Sym = nil 368 a.Offset = n.Xoffset 369 370 case OCFUNC: 371 Naddr(a, n.Left) 372 a.Sym = Linksym(n.Left.Sym) 373 374 case ONAME: 375 a.Etype = 0 376 if n.Type != nil { 377 a.Etype = uint8(Simtype[n.Type.Etype]) 378 } 379 a.Offset = n.Xoffset 380 s := n.Sym 381 a.Node = n.Orig 382 383 //if(a->node >= (Node*)&n) 384 // fatal("stack node"); 385 if s == nil { 386 s = Lookup(".noname") 387 } 388 if n.Name.Method && n.Type != nil && n.Type.Sym != nil && n.Type.Sym.Pkg != nil { 389 s = Pkglookup(s.Name, n.Type.Sym.Pkg) 390 } 391 392 a.Type = obj.TYPE_MEM 393 switch n.Class { 394 default: 395 Fatalf("naddr: ONAME class %v %d\n", n.Sym, n.Class) 396 397 case PEXTERN: 398 a.Name = obj.NAME_EXTERN 399 400 case PAUTO: 401 a.Name = obj.NAME_AUTO 402 403 case PPARAM, PPARAMOUT: 404 a.Name = obj.NAME_PARAM 405 406 case PFUNC: 407 a.Name = obj.NAME_EXTERN 408 a.Type = obj.TYPE_ADDR 409 a.Width = int64(Widthptr) 410 s = funcsym(s) 411 } 412 413 a.Sym = Linksym(s) 414 415 case ODOT: 416 // A special case to make write barriers more efficient. 417 // Taking the address of the first field of a named struct 418 // is the same as taking the address of the struct. 419 if !n.Left.Type.IsStruct() || n.Left.Type.Field(0).Sym != n.Sym { 420 Debug['h'] = 1 421 Dump("naddr", n) 422 Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a)) 423 } 424 Naddr(a, n.Left) 425 426 case OLITERAL: 427 if Thearch.Thechar == '8' { 428 a.Width = 0 429 } 430 switch n.Val().Ctype() { 431 default: 432 Fatalf("naddr: const %v", Tconv(n.Type, FmtLong)) 433 434 case CTFLT: 435 a.Type = obj.TYPE_FCONST 436 a.Val = n.Val().U.(*Mpflt).Float64() 437 438 case CTINT, CTRUNE: 439 a.Sym = nil 440 a.Type = obj.TYPE_CONST 441 a.Offset = n.Int64() 442 443 case CTSTR: 444 datagostring(n.Val().U.(string), a) 445 446 case CTBOOL: 447 a.Sym = nil 448 a.Type = obj.TYPE_CONST 449 a.Offset = int64(obj.Bool2int(n.Val().U.(bool))) 450 451 case CTNIL: 452 a.Sym = nil 453 a.Type = obj.TYPE_CONST 454 a.Offset = 0 455 } 456 457 case OADDR: 458 Naddr(a, n.Left) 459 a.Etype = uint8(Tptr) 460 if Thearch.Thechar != '0' && Thearch.Thechar != '5' && Thearch.Thechar != '7' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64. 461 a.Width = int64(Widthptr) 462 } 463 if a.Type != obj.TYPE_MEM { 464 a := a // copy to let escape into Ctxt.Dconv 465 Fatalf("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), Oconv(n.Left.Op, 0)) 466 } 467 a.Type = obj.TYPE_ADDR 468 469 // itable of interface value 470 case OITAB: 471 Naddr(a, n.Left) 472 473 if a.Type == obj.TYPE_CONST && a.Offset == 0 { 474 break // itab(nil) 475 } 476 a.Etype = uint8(Tptr) 477 a.Width = int64(Widthptr) 478 479 // pointer in a string or slice 480 case OSPTR: 481 Naddr(a, n.Left) 482 483 if a.Type == obj.TYPE_CONST && a.Offset == 0 { 484 break // ptr(nil) 485 } 486 a.Etype = uint8(Simtype[Tptr]) 487 a.Offset += int64(Array_array) 488 a.Width = int64(Widthptr) 489 490 // len of string or slice 491 case OLEN: 492 Naddr(a, n.Left) 493 494 if a.Type == obj.TYPE_CONST && a.Offset == 0 { 495 break // len(nil) 496 } 497 a.Etype = uint8(Simtype[TUINT]) 498 a.Offset += int64(Array_nel) 499 if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm. 500 a.Width = int64(Widthint) 501 } 502 503 // cap of string or slice 504 case OCAP: 505 Naddr(a, n.Left) 506 507 if a.Type == obj.TYPE_CONST && a.Offset == 0 { 508 break // cap(nil) 509 } 510 a.Etype = uint8(Simtype[TUINT]) 511 a.Offset += int64(Array_cap) 512 if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm. 513 a.Width = int64(Widthint) 514 } 515 } 516 } 517 518 func newplist() *obj.Plist { 519 pl := obj.Linknewplist(Ctxt) 520 521 Pc = Ctxt.NewProg() 522 Clearp(Pc) 523 pl.Firstpc = Pc 524 525 return pl 526 } 527 528 // nodarg does something that depends on the value of 529 // fp (this was previously completely undocumented). 530 // 531 // fp=1 corresponds to input args 532 // fp=0 corresponds to output args 533 // fp=-1 is a special case of output args for a 534 // specific call from walk that previously (and 535 // incorrectly) passed a 1; the behavior is exactly 536 // the same as it is for 1, except that PARAMOUT is 537 // generated instead of PARAM. 538 func nodarg(t interface{}, fp int) *Node { 539 var n *Node 540 541 switch t := t.(type) { 542 case *Type: 543 // entire argument struct, not just one arg 544 if !t.IsStruct() || !t.Funarg { 545 Fatalf("nodarg: bad type %v", t) 546 } 547 n = Nod(ONAME, nil, nil) 548 n.Sym = Lookup(".args") 549 n.Type = t 550 first := t.Field(0) 551 if first == nil { 552 Fatalf("nodarg: bad struct") 553 } 554 if first.Offset == BADWIDTH { 555 Fatalf("nodarg: offset not computed for %v", t) 556 } 557 n.Xoffset = first.Offset 558 n.Addable = true 559 case *Field: 560 if fp == 1 || fp == -1 { 561 for _, n := range Curfn.Func.Dcl { 562 if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym { 563 return n 564 } 565 } 566 } 567 568 n = Nod(ONAME, nil, nil) 569 n.Type = t.Type 570 n.Sym = t.Sym 571 if t.Offset == BADWIDTH { 572 Fatalf("nodarg: offset not computed for %v", t) 573 } 574 n.Xoffset = t.Offset 575 n.Addable = true 576 n.Orig = t.Nname 577 default: 578 panic("unreachable") 579 } 580 581 // Rewrite argument named _ to __, 582 // or else the assignment to _ will be 583 // discarded during code generation. 584 if isblank(n) { 585 n.Sym = Lookup("__") 586 } 587 588 switch fp { 589 case 0: // output arg 590 n.Op = OINDREG 591 592 n.Reg = int16(Thearch.REGSP) 593 n.Xoffset += Ctxt.FixedFrameSize() 594 595 case 1: // input arg 596 n.Class = PPARAM 597 598 case -1: // output arg from paramstoheap 599 n.Class = PPARAMOUT 600 601 case 2: // offset output arg 602 Fatalf("shouldn't be used") 603 } 604 605 n.Typecheck = 1 606 return n 607 } 608 609 func Patch(p *obj.Prog, to *obj.Prog) { 610 if p.To.Type != obj.TYPE_BRANCH { 611 Fatalf("patch: not a branch") 612 } 613 p.To.Val = to 614 p.To.Offset = to.Pc 615 } 616 617 func unpatch(p *obj.Prog) *obj.Prog { 618 if p.To.Type != obj.TYPE_BRANCH { 619 Fatalf("unpatch: not a branch") 620 } 621 q, _ := p.To.Val.(*obj.Prog) 622 p.To.Val = nil 623 p.To.Offset = 0 624 return q 625 } 626 627 var reg [100]int // count of references to reg 628 var regstk [100][]byte // allocation sites, when -v is given 629 630 func GetReg(r int) int { 631 return reg[r-Thearch.REGMIN] 632 } 633 func SetReg(r, v int) { 634 reg[r-Thearch.REGMIN] = v 635 } 636 637 func ginit() { 638 for r := range reg { 639 reg[r] = 1 640 } 641 642 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 643 reg[r-Thearch.REGMIN] = 0 644 } 645 for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { 646 reg[r-Thearch.REGMIN] = 0 647 } 648 649 for _, r := range Thearch.ReservedRegs { 650 reg[r-Thearch.REGMIN] = 1 651 } 652 } 653 654 func gclean() { 655 for _, r := range Thearch.ReservedRegs { 656 reg[r-Thearch.REGMIN]-- 657 } 658 659 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 660 n := reg[r-Thearch.REGMIN] 661 if n != 0 { 662 if Debug['v'] != 0 { 663 Regdump() 664 } 665 Yyerror("reg %v left allocated", obj.Rconv(r)) 666 } 667 } 668 669 for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { 670 n := reg[r-Thearch.REGMIN] 671 if n != 0 { 672 if Debug['v'] != 0 { 673 Regdump() 674 } 675 Yyerror("reg %v left allocated", obj.Rconv(r)) 676 } 677 } 678 } 679 680 func Anyregalloc() bool { 681 n := 0 682 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 683 if reg[r-Thearch.REGMIN] == 0 { 684 n++ 685 } 686 } 687 return n > len(Thearch.ReservedRegs) 688 } 689 690 // allocate register of type t, leave in n. 691 // if o != N, o may be reusable register. 692 // caller must Regfree(n). 693 func Regalloc(n *Node, t *Type, o *Node) { 694 if t == nil { 695 Fatalf("regalloc: t nil") 696 } 697 et := Simtype[t.Etype] 698 if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) { 699 Fatalf("regalloc 64bit") 700 } 701 702 var i int 703 Switch: 704 switch et { 705 default: 706 Fatalf("regalloc: unknown type %v", t) 707 708 case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TPTR32, TPTR64, TBOOL: 709 if o != nil && o.Op == OREGISTER { 710 i = int(o.Reg) 711 if Thearch.REGMIN <= i && i <= Thearch.REGMAX { 712 break Switch 713 } 714 } 715 for i = Thearch.REGMIN; i <= Thearch.REGMAX; i++ { 716 if reg[i-Thearch.REGMIN] == 0 { 717 break Switch 718 } 719 } 720 Flusherrors() 721 Regdump() 722 Fatalf("out of fixed registers") 723 724 case TFLOAT32, TFLOAT64: 725 if Thearch.Use387 { 726 i = Thearch.FREGMIN // x86.REG_F0 727 break Switch 728 } 729 if o != nil && o.Op == OREGISTER { 730 i = int(o.Reg) 731 if Thearch.FREGMIN <= i && i <= Thearch.FREGMAX { 732 break Switch 733 } 734 } 735 for i = Thearch.FREGMIN; i <= Thearch.FREGMAX; i++ { 736 if reg[i-Thearch.REGMIN] == 0 { // note: REGMIN, not FREGMIN 737 break Switch 738 } 739 } 740 Flusherrors() 741 Regdump() 742 Fatalf("out of floating registers") 743 744 case TCOMPLEX64, TCOMPLEX128: 745 Tempname(n, t) 746 return 747 } 748 749 ix := i - Thearch.REGMIN 750 if reg[ix] == 0 && Debug['v'] > 0 { 751 if regstk[ix] == nil { 752 regstk[ix] = make([]byte, 4096) 753 } 754 stk := regstk[ix] 755 n := runtime.Stack(stk[:cap(stk)], false) 756 regstk[ix] = stk[:n] 757 } 758 reg[ix]++ 759 Nodreg(n, t, i) 760 } 761 762 func Regfree(n *Node) { 763 if n.Op == ONAME { 764 return 765 } 766 if n.Op != OREGISTER && n.Op != OINDREG { 767 Fatalf("regfree: not a register") 768 } 769 i := int(n.Reg) 770 if i == Thearch.REGSP { 771 return 772 } 773 switch { 774 case Thearch.REGMIN <= i && i <= Thearch.REGMAX, 775 Thearch.FREGMIN <= i && i <= Thearch.FREGMAX: 776 // ok 777 default: 778 Fatalf("regfree: reg out of range") 779 } 780 781 i -= Thearch.REGMIN 782 if reg[i] <= 0 { 783 Fatalf("regfree: reg not allocated") 784 } 785 reg[i]-- 786 if reg[i] == 0 { 787 regstk[i] = regstk[i][:0] 788 } 789 } 790 791 // Reginuse reports whether r is in use. 792 func Reginuse(r int) bool { 793 switch { 794 case Thearch.REGMIN <= r && r <= Thearch.REGMAX, 795 Thearch.FREGMIN <= r && r <= Thearch.FREGMAX: 796 // ok 797 default: 798 Fatalf("reginuse: reg out of range") 799 } 800 801 return reg[r-Thearch.REGMIN] > 0 802 } 803 804 // Regrealloc(n) undoes the effect of Regfree(n), 805 // so that a register can be given up but then reclaimed. 806 func Regrealloc(n *Node) { 807 if n.Op != OREGISTER && n.Op != OINDREG { 808 Fatalf("regrealloc: not a register") 809 } 810 i := int(n.Reg) 811 if i == Thearch.REGSP { 812 return 813 } 814 switch { 815 case Thearch.REGMIN <= i && i <= Thearch.REGMAX, 816 Thearch.FREGMIN <= i && i <= Thearch.FREGMAX: 817 // ok 818 default: 819 Fatalf("regrealloc: reg out of range") 820 } 821 822 i -= Thearch.REGMIN 823 if reg[i] == 0 && Debug['v'] > 0 { 824 if regstk[i] == nil { 825 regstk[i] = make([]byte, 4096) 826 } 827 stk := regstk[i] 828 n := runtime.Stack(stk[:cap(stk)], false) 829 regstk[i] = stk[:n] 830 } 831 reg[i]++ 832 } 833 834 func Regdump() { 835 if Debug['v'] == 0 { 836 fmt.Printf("run compiler with -v for register allocation sites\n") 837 return 838 } 839 840 dump := func(r int) { 841 stk := regstk[r-Thearch.REGMIN] 842 if len(stk) == 0 { 843 return 844 } 845 fmt.Printf("reg %v allocated at:\n", obj.Rconv(r)) 846 fmt.Printf("\t%s\n", strings.Replace(strings.TrimSpace(string(stk)), "\n", "\n\t", -1)) 847 } 848 849 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 850 if reg[r-Thearch.REGMIN] != 0 { 851 dump(r) 852 } 853 } 854 for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { 855 if reg[r-Thearch.REGMIN] == 0 { 856 dump(r) 857 } 858 } 859 }