github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/src/cmd/compile/internal/gc/gsubr.go (about)

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