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