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  }