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