]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/obj/pass.go
[dev.ssa] Merge remote-tracking branch 'origin/master' into ssamerge
[gostls13.git] / src / cmd / internal / obj / pass.go
1 // Inferno utils/6l/pass.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.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 obj
32
33 // Code and data passes.
34
35 func Brchain(ctxt *Link, p *Prog) *Prog {
36         for i := 0; i < 20; i++ {
37                 if p == nil || p.As != AJMP || p.Pcond == nil {
38                         return p
39                 }
40                 p = p.Pcond
41         }
42
43         return nil
44 }
45
46 func brloop(ctxt *Link, p *Prog) *Prog {
47         var q *Prog
48
49         c := 0
50         for q = p; q != nil; q = q.Pcond {
51                 if q.As != AJMP || q.Pcond == nil {
52                         break
53                 }
54                 c++
55                 if c >= 5000 {
56                         return nil
57                 }
58         }
59
60         return q
61 }
62
63 func checkaddr(ctxt *Link, p *Prog, a *Addr) {
64         // Check expected encoding, especially TYPE_CONST vs TYPE_ADDR.
65         switch a.Type {
66         case TYPE_NONE:
67                 return
68
69         case TYPE_BRANCH:
70                 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 {
71                         break
72                 }
73                 return
74
75         case TYPE_TEXTSIZE:
76                 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 {
77                         break
78                 }
79                 return
80
81                 //if(a->u.bits != 0)
82         //      break;
83         case TYPE_MEM:
84                 return
85
86                 // TODO(rsc): After fixing SHRQ, check a->index != 0 too.
87         case TYPE_CONST:
88                 if a.Name != 0 || a.Sym != nil || a.Reg != 0 {
89                         ctxt.Diag("argument is TYPE_CONST, should be TYPE_ADDR, in %v", p)
90                         return
91                 }
92
93                 if a.Reg != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
94                         break
95                 }
96                 return
97
98         case TYPE_FCONST, TYPE_SCONST:
99                 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Offset != 0 || a.Sym != nil {
100                         break
101                 }
102                 return
103
104         // TODO(rsc): After fixing PINSRQ, check a->offset != 0 too.
105         // TODO(rsc): After fixing SHRQ, check a->index != 0 too.
106         case TYPE_REG:
107                 if a.Scale != 0 || a.Name != 0 || a.Sym != nil {
108                         break
109                 }
110                 return
111
112         case TYPE_ADDR:
113                 if a.Val != nil {
114                         break
115                 }
116                 if a.Reg == 0 && a.Index == 0 && a.Scale == 0 && a.Name == 0 && a.Sym == nil {
117                         ctxt.Diag("argument is TYPE_ADDR, should be TYPE_CONST, in %v", p)
118                 }
119                 return
120
121         case TYPE_SHIFT:
122                 if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
123                         break
124                 }
125                 return
126
127         case TYPE_REGREG:
128                 if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
129                         break
130                 }
131                 return
132
133         case TYPE_REGREG2:
134                 return
135
136         case TYPE_REGLIST:
137                 return
138
139         // Expect sym and name to be set, nothing else.
140         // Technically more is allowed, but this is only used for *name(SB).
141         case TYPE_INDIR:
142                 if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name == 0 || a.Offset != 0 || a.Sym == nil || a.Val != nil {
143                         break
144                 }
145                 return
146         }
147
148         ctxt.Diag("invalid encoding for argument %v", p)
149 }
150
151 func linkpatch(ctxt *Link, sym *LSym) {
152         var c int32
153         var name string
154         var q *Prog
155
156         ctxt.Cursym = sym
157
158         for p := sym.Text; p != nil; p = p.Link {
159                 checkaddr(ctxt, p, &p.From)
160                 if p.From3 != nil {
161                         checkaddr(ctxt, p, p.From3)
162                 }
163                 checkaddr(ctxt, p, &p.To)
164
165                 if ctxt.Arch.Progedit != nil {
166                         ctxt.Arch.Progedit(ctxt, p)
167                 }
168                 if p.To.Type != TYPE_BRANCH {
169                         continue
170                 }
171                 if p.To.Val != nil {
172                         // TODO: Remove To.Val.(*Prog) in favor of p->pcond.
173                         p.Pcond = p.To.Val.(*Prog)
174                         continue
175                 }
176
177                 if p.To.Sym != nil {
178                         continue
179                 }
180                 c = int32(p.To.Offset)
181                 for q = sym.Text; q != nil; {
182                         if int64(c) == q.Pc {
183                                 break
184                         }
185                         if q.Forwd != nil && int64(c) >= q.Forwd.Pc {
186                                 q = q.Forwd
187                         } else {
188                                 q = q.Link
189                         }
190                 }
191
192                 if q == nil {
193                         name = "<nil>"
194                         if p.To.Sym != nil {
195                                 name = p.To.Sym.Name
196                         }
197                         ctxt.Diag("branch out of range (%#x)\n%v [%s]", uint32(c), p, name)
198                         p.To.Type = TYPE_NONE
199                 }
200
201                 p.To.Val = q
202                 p.Pcond = q
203         }
204
205         if ctxt.Flag_optimize {
206                 for p := sym.Text; p != nil; p = p.Link {
207                         if p.Pcond != nil {
208                                 p.Pcond = brloop(ctxt, p.Pcond)
209                                 if p.Pcond != nil {
210                                         if p.To.Type == TYPE_BRANCH {
211                                                 p.To.Offset = p.Pcond.Pc
212                                         }
213                                 }
214                         }
215                 }
216         }
217 }