github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/gsubr.go (about)

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