]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/gc/gsubr.go
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
[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 /*
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 // nodarg does something that depends on the value of
513 // fp (this was previously completely undocumented).
514 //
515 // fp=1 corresponds to input args
516 // fp=0 corresponds to output args
517 // fp=-1 is a special case of output args for a
518 // specific call from walk that previously (and
519 // incorrectly) passed a 1; the behavior is exactly
520 // the same as it is for 1, except that PARAMOUT is
521 // generated instead of PARAM.
522 func nodarg(t *Type, fp int) *Node {
523         var n *Node
524
525         // entire argument struct, not just one arg
526         if t.Etype == TSTRUCT && t.Funarg {
527                 n = Nod(ONAME, nil, nil)
528                 n.Sym = Lookup(".args")
529                 n.Type = t
530                 var savet Iter
531                 first := Structfirst(&savet, &t)
532                 if first == nil {
533                         Fatalf("nodarg: bad struct")
534                 }
535                 if first.Width == BADWIDTH {
536                         Fatalf("nodarg: offset not computed for %v", t)
537                 }
538                 n.Xoffset = first.Width
539                 n.Addable = true
540                 goto fp
541         }
542
543         if t.Etype != TFIELD {
544                 Fatalf("nodarg: not field %v", t)
545         }
546
547         if fp == 1 || fp == -1 {
548                 var n *Node
549                 for l := Curfn.Func.Dcl; l != nil; l = l.Next {
550                         n = l.N
551                         if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
552                                 return n
553                         }
554                 }
555         }
556
557         n = Nod(ONAME, nil, nil)
558         n.Type = t.Type
559         n.Sym = t.Sym
560
561         if t.Width == BADWIDTH {
562                 Fatalf("nodarg: offset not computed for %v", t)
563         }
564         n.Xoffset = t.Width
565         n.Addable = true
566         n.Orig = t.Nname
567
568         // Rewrite argument named _ to __,
569         // or else the assignment to _ will be
570         // discarded during code generation.
571 fp:
572         if isblank(n) {
573                 n.Sym = Lookup("__")
574         }
575
576         switch fp {
577         case 0: // output arg
578                 n.Op = OINDREG
579
580                 n.Reg = int16(Thearch.REGSP)
581                 n.Xoffset += Ctxt.FixedFrameSize()
582
583         case 1: // input arg
584                 n.Class = PPARAM
585
586         case -1: // output arg from paramstoheap
587                 n.Class = PPARAMOUT
588
589         case 2: // offset output arg
590                 Fatalf("shouldn't be used")
591         }
592
593         n.Typecheck = 1
594         return n
595 }
596
597 func Patch(p *obj.Prog, to *obj.Prog) {
598         if p.To.Type != obj.TYPE_BRANCH {
599                 Fatalf("patch: not a branch")
600         }
601         p.To.Val = to
602         p.To.Offset = to.Pc
603 }
604
605 func unpatch(p *obj.Prog) *obj.Prog {
606         if p.To.Type != obj.TYPE_BRANCH {
607                 Fatalf("unpatch: not a branch")
608         }
609         q, _ := p.To.Val.(*obj.Prog)
610         p.To.Val = nil
611         p.To.Offset = 0
612         return q
613 }
614
615 var reg [100]int       // count of references to reg
616 var regstk [100][]byte // allocation sites, when -v is given
617
618 func GetReg(r int) int {
619         return reg[r-Thearch.REGMIN]
620 }
621 func SetReg(r, v int) {
622         reg[r-Thearch.REGMIN] = v
623 }
624
625 func ginit() {
626         for r := range reg {
627                 reg[r] = 1
628         }
629
630         for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
631                 reg[r-Thearch.REGMIN] = 0
632         }
633         for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
634                 reg[r-Thearch.REGMIN] = 0
635         }
636
637         for _, r := range Thearch.ReservedRegs {
638                 reg[r-Thearch.REGMIN] = 1
639         }
640 }
641
642 func gclean() {
643         for _, r := range Thearch.ReservedRegs {
644                 reg[r-Thearch.REGMIN]--
645         }
646
647         for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
648                 n := reg[r-Thearch.REGMIN]
649                 if n != 0 {
650                         if Debug['v'] != 0 {
651                                 Regdump()
652                         }
653                         Yyerror("reg %v left allocated", obj.Rconv(r))
654                 }
655         }
656
657         for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
658                 n := reg[r-Thearch.REGMIN]
659                 if n != 0 {
660                         if Debug['v'] != 0 {
661                                 Regdump()
662                         }
663                         Yyerror("reg %v left allocated", obj.Rconv(r))
664                 }
665         }
666 }
667
668 func Anyregalloc() bool {
669         n := 0
670         for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
671                 if reg[r-Thearch.REGMIN] == 0 {
672                         n++
673                 }
674         }
675         return n > len(Thearch.ReservedRegs)
676 }
677
678 /*
679  * allocate register of type t, leave in n.
680  * if o != N, o may be reusable register.
681  * caller must Regfree(n).
682  */
683 func Regalloc(n *Node, t *Type, o *Node) {
684         if t == nil {
685                 Fatalf("regalloc: t nil")
686         }
687         et := int(Simtype[t.Etype])
688         if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) {
689                 Fatalf("regalloc 64bit")
690         }
691
692         var i int
693 Switch:
694         switch et {
695         default:
696                 Fatalf("regalloc: unknown type %v", t)
697
698         case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TPTR32, TPTR64, TBOOL:
699                 if o != nil && o.Op == OREGISTER {
700                         i = int(o.Reg)
701                         if Thearch.REGMIN <= i && i <= Thearch.REGMAX {
702                                 break Switch
703                         }
704                 }
705                 for i = Thearch.REGMIN; i <= Thearch.REGMAX; i++ {
706                         if reg[i-Thearch.REGMIN] == 0 {
707                                 break Switch
708                         }
709                 }
710                 Flusherrors()
711                 Regdump()
712                 Fatalf("out of fixed registers")
713
714         case TFLOAT32, TFLOAT64:
715                 if Thearch.Use387 {
716                         i = Thearch.FREGMIN // x86.REG_F0
717                         break Switch
718                 }
719                 if o != nil && o.Op == OREGISTER {
720                         i = int(o.Reg)
721                         if Thearch.FREGMIN <= i && i <= Thearch.FREGMAX {
722                                 break Switch
723                         }
724                 }
725                 for i = Thearch.FREGMIN; i <= Thearch.FREGMAX; i++ {
726                         if reg[i-Thearch.REGMIN] == 0 { // note: REGMIN, not FREGMIN
727                                 break Switch
728                         }
729                 }
730                 Flusherrors()
731                 Regdump()
732                 Fatalf("out of floating registers")
733
734         case TCOMPLEX64, TCOMPLEX128:
735                 Tempname(n, t)
736                 return
737         }
738
739         ix := i - Thearch.REGMIN
740         if reg[ix] == 0 && Debug['v'] > 0 {
741                 if regstk[ix] == nil {
742                         regstk[ix] = make([]byte, 4096)
743                 }
744                 stk := regstk[ix]
745                 n := runtime.Stack(stk[:cap(stk)], false)
746                 regstk[ix] = stk[:n]
747         }
748         reg[ix]++
749         Nodreg(n, t, i)
750 }
751
752 func Regfree(n *Node) {
753         if n.Op == ONAME {
754                 return
755         }
756         if n.Op != OREGISTER && n.Op != OINDREG {
757                 Fatalf("regfree: not a register")
758         }
759         i := int(n.Reg)
760         if i == Thearch.REGSP {
761                 return
762         }
763         switch {
764         case Thearch.REGMIN <= i && i <= Thearch.REGMAX,
765                 Thearch.FREGMIN <= i && i <= Thearch.FREGMAX:
766                 // ok
767         default:
768                 Fatalf("regfree: reg out of range")
769         }
770
771         i -= Thearch.REGMIN
772         if reg[i] <= 0 {
773                 Fatalf("regfree: reg not allocated")
774         }
775         reg[i]--
776         if reg[i] == 0 {
777                 regstk[i] = regstk[i][:0]
778         }
779 }
780
781 // Reginuse reports whether r is in use.
782 func Reginuse(r int) bool {
783         switch {
784         case Thearch.REGMIN <= r && r <= Thearch.REGMAX,
785                 Thearch.FREGMIN <= r && r <= Thearch.FREGMAX:
786                 // ok
787         default:
788                 Fatalf("reginuse: reg out of range")
789         }
790
791         return reg[r-Thearch.REGMIN] > 0
792 }
793
794 // Regrealloc(n) undoes the effect of Regfree(n),
795 // so that a register can be given up but then reclaimed.
796 func Regrealloc(n *Node) {
797         if n.Op != OREGISTER && n.Op != OINDREG {
798                 Fatalf("regrealloc: not a register")
799         }
800         i := int(n.Reg)
801         if i == Thearch.REGSP {
802                 return
803         }
804         switch {
805         case Thearch.REGMIN <= i && i <= Thearch.REGMAX,
806                 Thearch.FREGMIN <= i && i <= Thearch.FREGMAX:
807                 // ok
808         default:
809                 Fatalf("regrealloc: reg out of range")
810         }
811
812         i -= Thearch.REGMIN
813         if reg[i] == 0 && Debug['v'] > 0 {
814                 if regstk[i] == nil {
815                         regstk[i] = make([]byte, 4096)
816                 }
817                 stk := regstk[i]
818                 n := runtime.Stack(stk[:cap(stk)], false)
819                 regstk[i] = stk[:n]
820         }
821         reg[i]++
822 }
823
824 func Regdump() {
825         if Debug['v'] == 0 {
826                 fmt.Printf("run compiler with -v for register allocation sites\n")
827                 return
828         }
829
830         dump := func(r int) {
831                 stk := regstk[r-Thearch.REGMIN]
832                 if len(stk) == 0 {
833                         return
834                 }
835                 fmt.Printf("reg %v allocated at:\n", obj.Rconv(r))
836                 fmt.Printf("\t%s\n", strings.Replace(strings.TrimSpace(string(stk)), "\n", "\n\t", -1))
837         }
838
839         for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
840                 if reg[r-Thearch.REGMIN] != 0 {
841                         dump(r)
842                 }
843         }
844         for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
845                 if reg[r-Thearch.REGMIN] == 0 {
846                         dump(r)
847                 }
848         }
849 }