github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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 ddumped int 41 42 var dfirst *obj.Prog 43 44 var dpc *obj.Prog 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 int, 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' { 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 int) *obj.Prog { 101 var p *obj.Prog 102 103 if as == obj.ADATA || as == obj.AGLOBL { 104 if ddumped != 0 { 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 { 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 Fatalf("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 Fatalf("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 = uint8(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 Fatalf("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 = uint8(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 Fatalf("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 Fatalf("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 Fatalf("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 = uint8(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 = uint8(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 = uint8(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 { 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 Fatalf("nodarg: bad struct") 522 } 523 if first.Width == BADWIDTH { 524 Fatalf("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 Fatalf("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 Fatalf("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 n.Xoffset += Ctxt.FixedFrameSize() 570 571 case 1: // input arg 572 n.Class = PPARAM 573 574 case 2: // offset output arg 575 Fatalf("shouldn't be used") 576 } 577 578 n.Typecheck = 1 579 return n 580 } 581 582 func Patch(p *obj.Prog, to *obj.Prog) { 583 if p.To.Type != obj.TYPE_BRANCH { 584 Fatalf("patch: not a branch") 585 } 586 p.To.Val = to 587 p.To.Offset = to.Pc 588 } 589 590 func unpatch(p *obj.Prog) *obj.Prog { 591 if p.To.Type != obj.TYPE_BRANCH { 592 Fatalf("unpatch: not a branch") 593 } 594 q, _ := p.To.Val.(*obj.Prog) 595 p.To.Val = nil 596 p.To.Offset = 0 597 return q 598 } 599 600 var reg [100]int // count of references to reg 601 var regstk [100][]byte // allocation sites, when -v is given 602 603 func GetReg(r int) int { 604 return reg[r-Thearch.REGMIN] 605 } 606 func SetReg(r, v int) { 607 reg[r-Thearch.REGMIN] = v 608 } 609 610 func ginit() { 611 for r := range reg { 612 reg[r] = 1 613 } 614 615 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 616 reg[r-Thearch.REGMIN] = 0 617 } 618 for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { 619 reg[r-Thearch.REGMIN] = 0 620 } 621 622 for _, r := range Thearch.ReservedRegs { 623 reg[r-Thearch.REGMIN] = 1 624 } 625 } 626 627 func gclean() { 628 for _, r := range Thearch.ReservedRegs { 629 reg[r-Thearch.REGMIN]-- 630 } 631 632 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 633 n := reg[r-Thearch.REGMIN] 634 if n != 0 { 635 if Debug['v'] != 0 { 636 Regdump() 637 } 638 Yyerror("reg %v left allocated", obj.Rconv(r)) 639 } 640 } 641 642 for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { 643 n := reg[r-Thearch.REGMIN] 644 if n != 0 { 645 if Debug['v'] != 0 { 646 Regdump() 647 } 648 Yyerror("reg %v left allocated", obj.Rconv(r)) 649 } 650 } 651 } 652 653 func Anyregalloc() bool { 654 n := 0 655 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 656 if reg[r-Thearch.REGMIN] == 0 { 657 n++ 658 } 659 } 660 return n > len(Thearch.ReservedRegs) 661 } 662 663 // allocate register of type t, leave in n. 664 // if o != N, o may be reusable register. 665 // caller must Regfree(n). 666 func Regalloc(n *Node, t *Type, o *Node) { 667 if t == nil { 668 Fatalf("regalloc: t nil") 669 } 670 et := Simtype[t.Etype] 671 if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) { 672 Fatalf("regalloc 64bit") 673 } 674 675 var i int 676 Switch: 677 switch et { 678 default: 679 Fatalf("regalloc: unknown type %v", t) 680 681 case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TPTR32, TPTR64, TBOOL: 682 if o != nil && o.Op == OREGISTER { 683 i = int(o.Reg) 684 if Thearch.REGMIN <= i && i <= Thearch.REGMAX { 685 break Switch 686 } 687 } 688 for i = Thearch.REGMIN; i <= Thearch.REGMAX; i++ { 689 if reg[i-Thearch.REGMIN] == 0 { 690 break Switch 691 } 692 } 693 Flusherrors() 694 Regdump() 695 Fatalf("out of fixed registers") 696 697 case TFLOAT32, TFLOAT64: 698 if Thearch.Use387 { 699 i = Thearch.FREGMIN // x86.REG_F0 700 break Switch 701 } 702 if o != nil && o.Op == OREGISTER { 703 i = int(o.Reg) 704 if Thearch.FREGMIN <= i && i <= Thearch.FREGMAX { 705 break Switch 706 } 707 } 708 for i = Thearch.FREGMIN; i <= Thearch.FREGMAX; i++ { 709 if reg[i-Thearch.REGMIN] == 0 { // note: REGMIN, not FREGMIN 710 break Switch 711 } 712 } 713 Flusherrors() 714 Regdump() 715 Fatalf("out of floating registers") 716 717 case TCOMPLEX64, TCOMPLEX128: 718 Tempname(n, t) 719 return 720 } 721 722 ix := i - Thearch.REGMIN 723 if reg[ix] == 0 && Debug['v'] > 0 { 724 if regstk[ix] == nil { 725 regstk[ix] = make([]byte, 4096) 726 } 727 stk := regstk[ix] 728 n := runtime.Stack(stk[:cap(stk)], false) 729 regstk[ix] = stk[:n] 730 } 731 reg[ix]++ 732 Nodreg(n, t, i) 733 } 734 735 func Regfree(n *Node) { 736 if n.Op == ONAME { 737 return 738 } 739 if n.Op != OREGISTER && n.Op != OINDREG { 740 Fatalf("regfree: not a register") 741 } 742 i := int(n.Reg) 743 if i == Thearch.REGSP { 744 return 745 } 746 switch { 747 case Thearch.REGMIN <= i && i <= Thearch.REGMAX, 748 Thearch.FREGMIN <= i && i <= Thearch.FREGMAX: 749 // ok 750 default: 751 Fatalf("regfree: reg out of range") 752 } 753 754 i -= Thearch.REGMIN 755 if reg[i] <= 0 { 756 Fatalf("regfree: reg not allocated") 757 } 758 reg[i]-- 759 if reg[i] == 0 { 760 regstk[i] = regstk[i][:0] 761 } 762 } 763 764 // Reginuse reports whether r is in use. 765 func Reginuse(r int) bool { 766 switch { 767 case Thearch.REGMIN <= r && r <= Thearch.REGMAX, 768 Thearch.FREGMIN <= r && r <= Thearch.FREGMAX: 769 // ok 770 default: 771 Fatalf("reginuse: reg out of range") 772 } 773 774 return reg[r-Thearch.REGMIN] > 0 775 } 776 777 // Regrealloc(n) undoes the effect of Regfree(n), 778 // so that a register can be given up but then reclaimed. 779 func Regrealloc(n *Node) { 780 if n.Op != OREGISTER && n.Op != OINDREG { 781 Fatalf("regrealloc: not a register") 782 } 783 i := int(n.Reg) 784 if i == Thearch.REGSP { 785 return 786 } 787 switch { 788 case Thearch.REGMIN <= i && i <= Thearch.REGMAX, 789 Thearch.FREGMIN <= i && i <= Thearch.FREGMAX: 790 // ok 791 default: 792 Fatalf("regrealloc: reg out of range") 793 } 794 795 i -= Thearch.REGMIN 796 if reg[i] == 0 && Debug['v'] > 0 { 797 if regstk[i] == nil { 798 regstk[i] = make([]byte, 4096) 799 } 800 stk := regstk[i] 801 n := runtime.Stack(stk[:cap(stk)], false) 802 regstk[i] = stk[:n] 803 } 804 reg[i]++ 805 } 806 807 func Regdump() { 808 if Debug['v'] == 0 { 809 fmt.Printf("run compiler with -v for register allocation sites\n") 810 return 811 } 812 813 dump := func(r int) { 814 stk := regstk[r-Thearch.REGMIN] 815 if len(stk) == 0 { 816 return 817 } 818 fmt.Printf("reg %v allocated at:\n", obj.Rconv(r)) 819 fmt.Printf("\t%s\n", strings.Replace(strings.TrimSpace(string(stk)), "\n", "\n\t", -1)) 820 } 821 822 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 823 if reg[r-Thearch.REGMIN] != 0 { 824 dump(r) 825 } 826 } 827 for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { 828 if reg[r-Thearch.REGMIN] == 0 { 829 dump(r) 830 } 831 } 832 }