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