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