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