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