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