]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/obj/util.go
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
[gostls13.git] / src / cmd / internal / obj / util.go
1 // Copyright 2015 The Go Authors.  All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package obj
6
7 import (
8         "bufio"
9         "bytes"
10         "fmt"
11         "io"
12         "log"
13         "os"
14         "strings"
15         "time"
16 )
17
18 const REG_NONE = 0
19
20 var start time.Time
21
22 func Cputime() float64 {
23         if start.IsZero() {
24                 start = time.Now()
25         }
26         return time.Since(start).Seconds()
27 }
28
29 type Biobuf struct {
30         f       *os.File
31         r       *bufio.Reader
32         w       *bufio.Writer
33         linelen int
34 }
35
36 func Bopenw(name string) (*Biobuf, error) {
37         f, err := os.Create(name)
38         if err != nil {
39                 return nil, err
40         }
41         return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
42 }
43
44 func Bopenr(name string) (*Biobuf, error) {
45         f, err := os.Open(name)
46         if err != nil {
47                 return nil, err
48         }
49         return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
50 }
51
52 func Binitw(w io.Writer) *Biobuf {
53         return &Biobuf{w: bufio.NewWriter(w)}
54 }
55
56 func Binitr(r io.Reader) *Biobuf {
57         return &Biobuf{r: bufio.NewReader(r)}
58 }
59
60 func (b *Biobuf) Write(p []byte) (int, error) {
61         return b.w.Write(p)
62 }
63
64 func Bwritestring(b *Biobuf, p string) (int, error) {
65         return b.w.WriteString(p)
66 }
67
68 func Bseek(b *Biobuf, offset int64, whence int) int64 {
69         if b.w != nil {
70                 if err := b.w.Flush(); err != nil {
71                         log.Fatalf("writing output: %v", err)
72                 }
73         } else if b.r != nil {
74                 if whence == 1 {
75                         offset -= int64(b.r.Buffered())
76                 }
77         }
78         off, err := b.f.Seek(offset, whence)
79         if err != nil {
80                 log.Fatalf("seeking in output: %v", err)
81         }
82         if b.r != nil {
83                 b.r.Reset(b.f)
84         }
85         return off
86 }
87
88 func Boffset(b *Biobuf) int64 {
89         if b.w != nil {
90                 if err := b.w.Flush(); err != nil {
91                         log.Fatalf("writing output: %v", err)
92                 }
93         }
94         off, err := b.f.Seek(0, 1)
95         if err != nil {
96                 log.Fatalf("seeking in output [0, 1]: %v", err)
97         }
98         if b.r != nil {
99                 off -= int64(b.r.Buffered())
100         }
101         return off
102 }
103
104 func (b *Biobuf) Flush() error {
105         return b.w.Flush()
106 }
107
108 func Bputc(b *Biobuf, c byte) {
109         b.w.WriteByte(c)
110 }
111
112 const Beof = -1
113
114 func Bread(b *Biobuf, p []byte) int {
115         n, err := io.ReadFull(b.r, p)
116         if n == 0 {
117                 if err != nil && err != io.EOF {
118                         n = -1
119                 }
120         }
121         return n
122 }
123
124 func Bgetc(b *Biobuf) int {
125         c, err := b.r.ReadByte()
126         if err != nil {
127                 return -1
128         }
129         return int(c)
130 }
131
132 func Bgetrune(b *Biobuf) int {
133         r, _, err := b.r.ReadRune()
134         if err != nil {
135                 return -1
136         }
137         return int(r)
138 }
139
140 func Bungetrune(b *Biobuf) {
141         b.r.UnreadRune()
142 }
143
144 func (b *Biobuf) Read(p []byte) (int, error) {
145         return b.r.Read(p)
146 }
147
148 func (b *Biobuf) Peek(n int) ([]byte, error) {
149         return b.r.Peek(n)
150 }
151
152 func Brdline(b *Biobuf, delim int) string {
153         s, err := b.r.ReadBytes(byte(delim))
154         if err != nil {
155                 log.Fatalf("reading input: %v", err)
156         }
157         b.linelen = len(s)
158         return string(s)
159 }
160
161 func Brdstr(b *Biobuf, delim int, cut int) string {
162         s, err := b.r.ReadString(byte(delim))
163         if err != nil {
164                 log.Fatalf("reading input: %v", err)
165         }
166         if len(s) > 0 && cut > 0 {
167                 s = s[:len(s)-1]
168         }
169         return s
170 }
171
172 func Blinelen(b *Biobuf) int {
173         return b.linelen
174 }
175
176 func Bterm(b *Biobuf) error {
177         var err error
178         if b.w != nil {
179                 err = b.w.Flush()
180         }
181         err1 := b.f.Close()
182         if err == nil {
183                 err = err1
184         }
185         return err
186 }
187
188 func envOr(key, value string) string {
189         if x := os.Getenv(key); x != "" {
190                 return x
191         }
192         return value
193 }
194
195 func Getgoroot() string {
196         return envOr("GOROOT", defaultGOROOT)
197 }
198
199 func Getgoarch() string {
200         return envOr("GOARCH", defaultGOARCH)
201 }
202
203 func Getgoos() string {
204         return envOr("GOOS", defaultGOOS)
205 }
206
207 func Getgoarm() int32 {
208         switch v := envOr("GOARM", defaultGOARM); v {
209         case "5":
210                 return 5
211         case "6":
212                 return 6
213         case "7":
214                 return 7
215         }
216         // Fail here, rather than validate at multiple call sites.
217         log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
218         panic("unreachable")
219 }
220
221 func Getgo386() string {
222         // Validated by cmd/compile.
223         return envOr("GO386", defaultGO386)
224 }
225
226 func Getgoextlinkenabled() string {
227         return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
228 }
229
230 func Getgoversion() string {
231         return version
232 }
233
234 func (p *Prog) Line() string {
235         return p.Ctxt.LineHist.LineString(int(p.Lineno))
236 }
237
238 var armCondCode = []string{
239         ".EQ",
240         ".NE",
241         ".CS",
242         ".CC",
243         ".MI",
244         ".PL",
245         ".VS",
246         ".VC",
247         ".HI",
248         ".LS",
249         ".GE",
250         ".LT",
251         ".GT",
252         ".LE",
253         "",
254         ".NV",
255 }
256
257 /* ARM scond byte */
258 const (
259         C_SCOND     = (1 << 4) - 1
260         C_SBIT      = 1 << 4
261         C_PBIT      = 1 << 5
262         C_WBIT      = 1 << 6
263         C_FBIT      = 1 << 7
264         C_UBIT      = 1 << 7
265         C_SCOND_XOR = 14
266 )
267
268 // CConv formats ARM condition codes.
269 func CConv(s uint8) string {
270         if s == 0 {
271                 return ""
272         }
273         sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
274         if s&C_SBIT != 0 {
275                 sc += ".S"
276         }
277         if s&C_PBIT != 0 {
278                 sc += ".P"
279         }
280         if s&C_WBIT != 0 {
281                 sc += ".W"
282         }
283         if s&C_UBIT != 0 { /* ambiguous with FBIT */
284                 sc += ".U"
285         }
286         return sc
287 }
288
289 func (p *Prog) String() string {
290         if p.Ctxt == nil {
291                 return "<Prog without ctxt>"
292         }
293
294         sc := CConv(p.Scond)
295
296         var buf bytes.Buffer
297
298         fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(int(p.As)), sc)
299         sep := "\t"
300         if p.From.Type != TYPE_NONE {
301                 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
302                 sep = ", "
303         }
304         if p.Reg != REG_NONE {
305                 // Should not happen but might as well show it if it does.
306                 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
307                 sep = ", "
308         }
309         if p.From3Type() != TYPE_NONE {
310                 if p.From3.Type == TYPE_CONST && (p.As == ADATA || p.As == ATEXT || p.As == AGLOBL) {
311                         // Special case - omit $.
312                         fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
313                 } else {
314                         fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
315                 }
316                 sep = ", "
317         }
318         if p.To.Type != TYPE_NONE {
319                 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
320         }
321         if p.RegTo2 != REG_NONE {
322                 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
323         }
324         return buf.String()
325 }
326
327 func (ctxt *Link) NewProg() *Prog {
328         p := new(Prog) // should be the only call to this; all others should use ctxt.NewProg
329         p.Ctxt = ctxt
330         return p
331 }
332
333 func (ctxt *Link) Line(n int) string {
334         return ctxt.LineHist.LineString(n)
335 }
336
337 func Getcallerpc(interface{}) uintptr {
338         return 1
339 }
340
341 func (ctxt *Link) Dconv(a *Addr) string {
342         return Dconv(nil, a)
343 }
344
345 func Dconv(p *Prog, a *Addr) string {
346         var str string
347
348         switch a.Type {
349         default:
350                 str = fmt.Sprintf("type=%d", a.Type)
351
352         case TYPE_NONE:
353                 str = ""
354                 if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
355                         str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
356                 }
357
358         case TYPE_REG:
359                 // TODO(rsc): This special case is for x86 instructions like
360                 //      PINSRQ  CX,$1,X6
361                 // where the $1 is included in the p->to Addr.
362                 // Move into a new field.
363                 if a.Offset != 0 {
364                         str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
365                         break
366                 }
367
368                 str = Rconv(int(a.Reg))
369                 if a.Name != TYPE_NONE || a.Sym != nil {
370                         str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
371                 }
372
373         case TYPE_BRANCH:
374                 if a.Sym != nil {
375                         str = fmt.Sprintf("%s(SB)", a.Sym.Name)
376                 } else if p != nil && p.Pcond != nil {
377                         str = fmt.Sprint(p.Pcond.Pc)
378                 } else if a.Val != nil {
379                         str = fmt.Sprint(a.Val.(*Prog).Pc)
380                 } else {
381                         str = fmt.Sprintf("%d(PC)", a.Offset)
382                 }
383
384         case TYPE_INDIR:
385                 str = fmt.Sprintf("*%s", Mconv(a))
386
387         case TYPE_MEM:
388                 str = Mconv(a)
389                 if a.Index != REG_NONE {
390                         str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
391                 }
392                 if p.As == ATYPE && a.Gotype != nil {
393                         str += fmt.Sprintf("%s", a.Gotype.Name)
394                 }
395
396         case TYPE_CONST:
397                 if a.Reg != 0 {
398                         str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
399                 } else {
400                         str = fmt.Sprintf("$%v", Mconv(a))
401                 }
402
403         case TYPE_TEXTSIZE:
404                 if a.Val.(int32) == ArgsSizeUnknown {
405                         str = fmt.Sprintf("$%d", a.Offset)
406                 } else {
407                         str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
408                 }
409
410         case TYPE_FCONST:
411                 str = fmt.Sprintf("%.17g", a.Val.(float64))
412                 // Make sure 1 prints as 1.0
413                 if !strings.ContainsAny(str, ".e") {
414                         str += ".0"
415                 }
416                 str = fmt.Sprintf("$(%s)", str)
417
418         case TYPE_SCONST:
419                 str = fmt.Sprintf("$%q", a.Val.(string))
420
421         case TYPE_ADDR:
422                 str = fmt.Sprintf("$%s", Mconv(a))
423
424         case TYPE_SHIFT:
425                 v := int(a.Offset)
426                 op := string("<<>>->@>"[((v>>5)&3)<<1:])
427                 if v&(1<<4) != 0 {
428                         str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
429                 } else {
430                         str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
431                 }
432                 if a.Reg != 0 {
433                         str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
434                 }
435
436         case TYPE_REGREG:
437                 str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
438
439         case TYPE_REGREG2:
440                 str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
441
442         case TYPE_REGLIST:
443                 str = regListConv(int(a.Offset))
444         }
445
446         return str
447 }
448
449 func Mconv(a *Addr) string {
450         var str string
451
452         switch a.Name {
453         default:
454                 str = fmt.Sprintf("name=%d", a.Name)
455
456         case NAME_NONE:
457                 switch {
458                 case a.Reg == REG_NONE:
459                         str = fmt.Sprint(a.Offset)
460                 case a.Offset == 0:
461                         str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
462                 case a.Offset != 0:
463                         str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
464                 }
465
466         case NAME_EXTERN:
467                 if a.Sym != nil {
468                         str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
469                 } else {
470                         str = fmt.Sprintf("%s(SB)", offConv(a.Offset))
471                 }
472
473         case NAME_GOTREF:
474                 if a.Sym != nil {
475                         str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
476                 } else {
477                         str = fmt.Sprintf("%s@GOT(SB)", offConv(a.Offset))
478                 }
479
480         case NAME_STATIC:
481                 if a.Sym != nil {
482                         str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
483                 } else {
484                         str = fmt.Sprintf("<>%s(SB)", offConv(a.Offset))
485                 }
486
487         case NAME_AUTO:
488                 if a.Sym != nil {
489                         str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
490                 } else {
491                         str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
492                 }
493
494         case NAME_PARAM:
495                 if a.Sym != nil {
496                         str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
497                 } else {
498                         str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
499                 }
500         }
501         return str
502 }
503
504 func offConv(off int64) string {
505         if off == 0 {
506                 return ""
507         }
508         return fmt.Sprintf("%+d", off)
509 }
510
511 type regSet struct {
512         lo    int
513         hi    int
514         Rconv func(int) string
515 }
516
517 // Few enough architectures that a linear scan is fastest.
518 // Not even worth sorting.
519 var regSpace []regSet
520
521 /*
522         Each architecture defines a register space as a unique
523         integer range.
524         Here is the list of architectures and the base of their register spaces.
525 */
526
527 const (
528         // Because of masking operations in the encodings, each register
529         // space should start at 0 modulo some power of 2.
530         RBase386    = 1 * 1024
531         RBaseAMD64  = 2 * 1024
532         RBaseARM    = 3 * 1024
533         RBasePPC64  = 4 * 1024  // range [4k, 8k)
534         RBaseARM64  = 8 * 1024  // range [8k, 13k)
535         RBaseMIPS64 = 13 * 1024 // range [13k, 14k)
536 )
537
538 // RegisterRegister binds a pretty-printer (Rconv) for register
539 // numbers to a given register number range.  Lo is inclusive,
540 // hi exclusive (valid registers are lo through hi-1).
541 func RegisterRegister(lo, hi int, Rconv func(int) string) {
542         regSpace = append(regSpace, regSet{lo, hi, Rconv})
543 }
544
545 func Rconv(reg int) string {
546         if reg == REG_NONE {
547                 return "NONE"
548         }
549         for i := range regSpace {
550                 rs := &regSpace[i]
551                 if rs.lo <= reg && reg < rs.hi {
552                         return rs.Rconv(reg)
553                 }
554         }
555         return fmt.Sprintf("R???%d", reg)
556 }
557
558 func regListConv(list int) string {
559         str := ""
560
561         for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
562                 if list&(1<<uint(i)) != 0 {
563                         if str == "" {
564                                 str += "["
565                         } else {
566                                 str += ","
567                         }
568                         // This is ARM-specific; R10 is g.
569                         if i == 10 {
570                                 str += "g"
571                         } else {
572                                 str += fmt.Sprintf("R%d", i)
573                         }
574                 }
575         }
576
577         str += "]"
578         return str
579 }
580
581 /*
582         Each architecture defines an instruction (A*) space as a unique
583         integer range.
584         Global opcodes like CALL start at 0; the architecture-specific ones
585         start at a distinct, big-maskable offsets.
586         Here is the list of architectures and the base of their opcode spaces.
587 */
588
589 const (
590         ABase386 = (1 + iota) << 12
591         ABaseARM
592         ABaseAMD64
593         ABasePPC64
594         ABaseARM64
595         ABaseMIPS64
596         AMask = 1<<12 - 1 // AND with this to use the opcode as an array index.
597 )
598
599 type opSet struct {
600         lo    int
601         names []string
602 }
603
604 // Not even worth sorting
605 var aSpace []opSet
606
607 // RegisterOpcode binds a list of instruction names
608 // to a given instruction number range.
609 func RegisterOpcode(lo int, Anames []string) {
610         aSpace = append(aSpace, opSet{lo, Anames})
611 }
612
613 func Aconv(a int) string {
614         if 0 <= a && a < len(Anames) {
615                 return Anames[a]
616         }
617         for i := range aSpace {
618                 as := &aSpace[i]
619                 if as.lo <= a && a < as.lo+len(as.names) {
620                         return as.names[a-as.lo]
621                 }
622         }
623         return fmt.Sprintf("A???%d", a)
624 }
625
626 var Anames = []string{
627         "XXX",
628         "CALL",
629         "CHECKNIL",
630         "DATA",
631         "DUFFCOPY",
632         "DUFFZERO",
633         "END",
634         "FUNCDATA",
635         "GLOBL",
636         "JMP",
637         "NOP",
638         "PCDATA",
639         "RET",
640         "TEXT",
641         "TYPE",
642         "UNDEF",
643         "USEFIELD",
644         "VARDEF",
645         "VARKILL",
646         "VARLIVE",
647 }
648
649 func Bool2int(b bool) int {
650         if b {
651                 return 1
652         }
653         return 0
654 }