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