github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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' && Thearch.Thechar != '0' { 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 ODOT: 408 // A special case to make write barriers more efficient. 409 // Taking the address of the first field of a named struct 410 // is the same as taking the address of the struct. 411 if n.Left.Type.Etype != TSTRUCT || n.Left.Type.Type.Sym != n.Right.Sym { 412 Debug['h'] = 1 413 Dump("naddr", n) 414 Fatalf("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(a)) 415 } 416 Naddr(a, n.Left) 417 418 case OLITERAL: 419 if Thearch.Thechar == '8' { 420 a.Width = 0 421 } 422 switch n.Val().Ctype() { 423 default: 424 Fatalf("naddr: const %v", Tconv(n.Type, obj.FmtLong)) 425 426 case CTFLT: 427 a.Type = obj.TYPE_FCONST 428 a.Val = mpgetflt(n.Val().U.(*Mpflt)) 429 430 case CTINT, CTRUNE: 431 a.Sym = nil 432 a.Type = obj.TYPE_CONST 433 a.Offset = Mpgetfix(n.Val().U.(*Mpint)) 434 435 case CTSTR: 436 datagostring(n.Val().U.(string), a) 437 438 case CTBOOL: 439 a.Sym = nil 440 a.Type = obj.TYPE_CONST 441 a.Offset = int64(obj.Bool2int(n.Val().U.(bool))) 442 443 case CTNIL: 444 a.Sym = nil 445 a.Type = obj.TYPE_CONST 446 a.Offset = 0 447 } 448 449 case OADDR: 450 Naddr(a, n.Left) 451 a.Etype = uint8(Tptr) 452 if Thearch.Thechar != '0' && Thearch.Thechar != '5' && Thearch.Thechar != '7' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64. 453 a.Width = int64(Widthptr) 454 } 455 if a.Type != obj.TYPE_MEM { 456 a := a // copy to let escape into Ctxt.Dconv 457 Fatalf("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), Oconv(int(n.Left.Op), 0)) 458 } 459 a.Type = obj.TYPE_ADDR 460 461 // itable of interface value 462 case OITAB: 463 Naddr(a, n.Left) 464 465 if a.Type == obj.TYPE_CONST && a.Offset == 0 { 466 break // itab(nil) 467 } 468 a.Etype = uint8(Tptr) 469 a.Width = int64(Widthptr) 470 471 // pointer in a string or slice 472 case OSPTR: 473 Naddr(a, n.Left) 474 475 if a.Type == obj.TYPE_CONST && a.Offset == 0 { 476 break // ptr(nil) 477 } 478 a.Etype = uint8(Simtype[Tptr]) 479 a.Offset += int64(Array_array) 480 a.Width = int64(Widthptr) 481 482 // len of string or slice 483 case OLEN: 484 Naddr(a, n.Left) 485 486 if a.Type == obj.TYPE_CONST && a.Offset == 0 { 487 break // len(nil) 488 } 489 a.Etype = uint8(Simtype[TUINT]) 490 a.Offset += int64(Array_nel) 491 if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm. 492 a.Width = int64(Widthint) 493 } 494 495 // cap of string or slice 496 case OCAP: 497 Naddr(a, n.Left) 498 499 if a.Type == obj.TYPE_CONST && a.Offset == 0 { 500 break // cap(nil) 501 } 502 a.Etype = uint8(Simtype[TUINT]) 503 a.Offset += int64(Array_cap) 504 if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm. 505 a.Width = int64(Widthint) 506 } 507 } 508 return 509 } 510 511 func newplist() *obj.Plist { 512 pl := obj.Linknewplist(Ctxt) 513 514 Pc = Ctxt.NewProg() 515 Clearp(Pc) 516 pl.Firstpc = Pc 517 518 return pl 519 } 520 521 func nodarg(t *Type, fp int) *Node { 522 var n *Node 523 524 // entire argument struct, not just one arg 525 if t.Etype == TSTRUCT && t.Funarg { 526 n = Nod(ONAME, nil, nil) 527 n.Sym = Lookup(".args") 528 n.Type = t 529 var savet Iter 530 first := Structfirst(&savet, &t) 531 if first == nil { 532 Fatalf("nodarg: bad struct") 533 } 534 if first.Width == BADWIDTH { 535 Fatalf("nodarg: offset not computed for %v", t) 536 } 537 n.Xoffset = first.Width 538 n.Addable = true 539 goto fp 540 } 541 542 if t.Etype != TFIELD { 543 Fatalf("nodarg: not field %v", t) 544 } 545 546 if fp == 1 { 547 var n *Node 548 for l := Curfn.Func.Dcl; l != nil; l = l.Next { 549 n = l.N 550 if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym { 551 return n 552 } 553 } 554 } 555 556 n = Nod(ONAME, nil, nil) 557 n.Type = t.Type 558 n.Sym = t.Sym 559 560 if t.Width == BADWIDTH { 561 Fatalf("nodarg: offset not computed for %v", t) 562 } 563 n.Xoffset = t.Width 564 n.Addable = true 565 n.Orig = t.Nname 566 567 // Rewrite argument named _ to __, 568 // or else the assignment to _ will be 569 // discarded during code generation. 570 fp: 571 if isblank(n) { 572 n.Sym = Lookup("__") 573 } 574 575 switch fp { 576 case 0: // output arg 577 n.Op = OINDREG 578 579 n.Reg = int16(Thearch.REGSP) 580 n.Xoffset += Ctxt.FixedFrameSize() 581 582 case 1: // input arg 583 n.Class = PPARAM 584 585 case 2: // offset output arg 586 Fatalf("shouldn't be used") 587 } 588 589 n.Typecheck = 1 590 return n 591 } 592 593 func Patch(p *obj.Prog, to *obj.Prog) { 594 if p.To.Type != obj.TYPE_BRANCH { 595 Fatalf("patch: not a branch") 596 } 597 p.To.Val = to 598 p.To.Offset = to.Pc 599 } 600 601 func unpatch(p *obj.Prog) *obj.Prog { 602 if p.To.Type != obj.TYPE_BRANCH { 603 Fatalf("unpatch: not a branch") 604 } 605 q, _ := p.To.Val.(*obj.Prog) 606 p.To.Val = nil 607 p.To.Offset = 0 608 return q 609 } 610 611 var reg [100]int // count of references to reg 612 var regstk [100][]byte // allocation sites, when -v is given 613 614 func GetReg(r int) int { 615 return reg[r-Thearch.REGMIN] 616 } 617 func SetReg(r, v int) { 618 reg[r-Thearch.REGMIN] = v 619 } 620 621 func ginit() { 622 for r := range reg { 623 reg[r] = 1 624 } 625 626 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 627 reg[r-Thearch.REGMIN] = 0 628 } 629 for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { 630 reg[r-Thearch.REGMIN] = 0 631 } 632 633 for _, r := range Thearch.ReservedRegs { 634 reg[r-Thearch.REGMIN] = 1 635 } 636 } 637 638 func gclean() { 639 for _, r := range Thearch.ReservedRegs { 640 reg[r-Thearch.REGMIN]-- 641 } 642 643 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 644 n := reg[r-Thearch.REGMIN] 645 if n != 0 { 646 if Debug['v'] != 0 { 647 Regdump() 648 } 649 Yyerror("reg %v left allocated", obj.Rconv(r)) 650 } 651 } 652 653 for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { 654 n := reg[r-Thearch.REGMIN] 655 if n != 0 { 656 if Debug['v'] != 0 { 657 Regdump() 658 } 659 Yyerror("reg %v left allocated", obj.Rconv(r)) 660 } 661 } 662 } 663 664 func Anyregalloc() bool { 665 n := 0 666 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 667 if reg[r-Thearch.REGMIN] == 0 { 668 n++ 669 } 670 } 671 return n > len(Thearch.ReservedRegs) 672 } 673 674 // allocate register of type t, leave in n. 675 // if o != N, o may be reusable register. 676 // caller must Regfree(n). 677 func Regalloc(n *Node, t *Type, o *Node) { 678 if t == nil { 679 Fatalf("regalloc: t nil") 680 } 681 et := Simtype[t.Etype] 682 if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) { 683 Fatalf("regalloc 64bit") 684 } 685 686 var i int 687 Switch: 688 switch et { 689 default: 690 Fatalf("regalloc: unknown type %v", t) 691 692 case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TPTR32, TPTR64, TBOOL: 693 if o != nil && o.Op == OREGISTER { 694 i = int(o.Reg) 695 if Thearch.REGMIN <= i && i <= Thearch.REGMAX { 696 break Switch 697 } 698 } 699 for i = Thearch.REGMIN; i <= Thearch.REGMAX; i++ { 700 if reg[i-Thearch.REGMIN] == 0 { 701 break Switch 702 } 703 } 704 Flusherrors() 705 Regdump() 706 Fatalf("out of fixed registers") 707 708 case TFLOAT32, TFLOAT64: 709 if Thearch.Use387 { 710 i = Thearch.FREGMIN // x86.REG_F0 711 break Switch 712 } 713 if o != nil && o.Op == OREGISTER { 714 i = int(o.Reg) 715 if Thearch.FREGMIN <= i && i <= Thearch.FREGMAX { 716 break Switch 717 } 718 } 719 for i = Thearch.FREGMIN; i <= Thearch.FREGMAX; i++ { 720 if reg[i-Thearch.REGMIN] == 0 { // note: REGMIN, not FREGMIN 721 break Switch 722 } 723 } 724 Flusherrors() 725 Regdump() 726 Fatalf("out of floating registers") 727 728 case TCOMPLEX64, TCOMPLEX128: 729 Tempname(n, t) 730 return 731 } 732 733 ix := i - Thearch.REGMIN 734 if reg[ix] == 0 && Debug['v'] > 0 { 735 if regstk[ix] == nil { 736 regstk[ix] = make([]byte, 4096) 737 } 738 stk := regstk[ix] 739 n := runtime.Stack(stk[:cap(stk)], false) 740 regstk[ix] = stk[:n] 741 } 742 reg[ix]++ 743 Nodreg(n, t, i) 744 } 745 746 func Regfree(n *Node) { 747 if n.Op == ONAME { 748 return 749 } 750 if n.Op != OREGISTER && n.Op != OINDREG { 751 Fatalf("regfree: not a register") 752 } 753 i := int(n.Reg) 754 if i == Thearch.REGSP { 755 return 756 } 757 switch { 758 case Thearch.REGMIN <= i && i <= Thearch.REGMAX, 759 Thearch.FREGMIN <= i && i <= Thearch.FREGMAX: 760 // ok 761 default: 762 Fatalf("regfree: reg out of range") 763 } 764 765 i -= Thearch.REGMIN 766 if reg[i] <= 0 { 767 Fatalf("regfree: reg not allocated") 768 } 769 reg[i]-- 770 if reg[i] == 0 { 771 regstk[i] = regstk[i][:0] 772 } 773 } 774 775 // Reginuse reports whether r is in use. 776 func Reginuse(r int) bool { 777 switch { 778 case Thearch.REGMIN <= r && r <= Thearch.REGMAX, 779 Thearch.FREGMIN <= r && r <= Thearch.FREGMAX: 780 // ok 781 default: 782 Fatalf("reginuse: reg out of range") 783 } 784 785 return reg[r-Thearch.REGMIN] > 0 786 } 787 788 // Regrealloc(n) undoes the effect of Regfree(n), 789 // so that a register can be given up but then reclaimed. 790 func Regrealloc(n *Node) { 791 if n.Op != OREGISTER && n.Op != OINDREG { 792 Fatalf("regrealloc: not a register") 793 } 794 i := int(n.Reg) 795 if i == Thearch.REGSP { 796 return 797 } 798 switch { 799 case Thearch.REGMIN <= i && i <= Thearch.REGMAX, 800 Thearch.FREGMIN <= i && i <= Thearch.FREGMAX: 801 // ok 802 default: 803 Fatalf("regrealloc: reg out of range") 804 } 805 806 i -= Thearch.REGMIN 807 if reg[i] == 0 && Debug['v'] > 0 { 808 if regstk[i] == nil { 809 regstk[i] = make([]byte, 4096) 810 } 811 stk := regstk[i] 812 n := runtime.Stack(stk[:cap(stk)], false) 813 regstk[i] = stk[:n] 814 } 815 reg[i]++ 816 } 817 818 func Regdump() { 819 if Debug['v'] == 0 { 820 fmt.Printf("run compiler with -v for register allocation sites\n") 821 return 822 } 823 824 dump := func(r int) { 825 stk := regstk[r-Thearch.REGMIN] 826 if len(stk) == 0 { 827 return 828 } 829 fmt.Printf("reg %v allocated at:\n", obj.Rconv(r)) 830 fmt.Printf("\t%s\n", strings.Replace(strings.TrimSpace(string(stk)), "\n", "\n\t", -1)) 831 } 832 833 for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ { 834 if reg[r-Thearch.REGMIN] != 0 { 835 dump(r) 836 } 837 } 838 for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ { 839 if reg[r-Thearch.REGMIN] == 0 { 840 dump(r) 841 } 842 } 843 }