1
2
3
4
5 package ssacompile
6
7 import (
8 "fmt"
9 "math"
10
11 "cmd/compile/internal/ssa"
12 "cmd/compile/internal/ssa/ssaop"
13 "cmd/internal/src"
14 )
15
16
17 func applyRewrite(f *ssa.Func, rb ssa.BlockRewriter, rv ssa.ValueRewriter, deadcode ssa.DeadValueChoice) {
18
19 pendingLines := f.CachedLineStarts
20 pendingLines.Clear()
21 debug := f.Pass.Debug
22 if debug > 1 {
23 fmt.Printf("%s: rewriting for %s\n", f.Pass.Name, f.Name)
24 }
25
26
27
28
29 itersLimit := f.NumBlocks()
30 if itersLimit < 20 {
31 itersLimit = 20
32 }
33 var iters int
34 var states map[string]bool
35 for {
36 if debug > 1 {
37 fmt.Printf("%s: iter %d\n", f.Pass.Name, iters)
38 }
39 change := false
40 deadChange := false
41 for _, b := range f.Blocks {
42 var b0 *ssa.Block
43 if debug > 1 {
44 fmt.Printf("%s: start block\n", f.Pass.Name)
45 b0 = new(ssa.Block)
46 *b0 = *b
47 b0.Succs = append([]ssa.Edge{}, b.Succs...)
48 }
49 for i, c := range b.ControlValues() {
50 for c.Op == ssaop.OpCopy {
51 c = c.Args[0]
52 b.ReplaceControl(i, c)
53 }
54 }
55 if rb(b) {
56 change = true
57 if debug > 1 {
58 fmt.Printf("rewriting %s -> %s\n", b0.LongString(), b.LongString())
59 }
60 }
61 for j, v := range b.Values {
62 if debug > 1 {
63 fmt.Printf("%s: consider %v\n", f.Pass.Name, v.LongString())
64 }
65 var v0 *ssa.Value
66 if debug > 1 {
67 v0 = new(ssa.Value)
68 *v0 = *v
69 v0.Args = append([]*ssa.Value{}, v.Args...)
70 }
71 if v.Uses == 0 && v.Removeable() {
72 if v.Op != ssaop.OpInvalid && deadcode == ssa.RemoveDeadValues {
73
74
75
76
77 v.Reset(ssaop.OpInvalid)
78 deadChange = true
79 }
80
81 continue
82 }
83
84 vchange := ssa.PhiElimValue(v)
85 if vchange && debug > 1 {
86 fmt.Printf("rewriting %s -> %s\n", v0.LongString(), v.LongString())
87 }
88
89
90
91
92
93
94
95
96 for i, a := range v.Args {
97 if a.Op != ssaop.OpCopy {
98 continue
99 }
100 aa := copySource(a)
101 v.SetArg(i, aa)
102
103
104
105
106
107 if a.Pos.IsStmt() == src.PosIsStmt {
108 if aa.Block == a.Block && aa.Pos.Line() == a.Pos.Line() && aa.Pos.IsStmt() != src.PosNotStmt {
109 aa.Pos = aa.Pos.WithIsStmt()
110 } else if v.Block == a.Block && v.Pos.Line() == a.Pos.Line() && v.Pos.IsStmt() != src.PosNotStmt {
111 v.Pos = v.Pos.WithIsStmt()
112 } else {
113
114
115
116
117 pendingLines.Set(a.Pos, int32(a.Block.ID))
118 }
119 a.Pos = a.Pos.WithNotStmt()
120 }
121 vchange = true
122 for a.Uses == 0 {
123 b := a.Args[0]
124 a.Reset(ssaop.OpInvalid)
125 a = b
126 }
127 }
128 if vchange && debug > 1 {
129 fmt.Printf("rewriting %s -> %s\n", v0.LongString(), v.LongString())
130 }
131
132
133 if rv(v) {
134 vchange = true
135
136 if v.Pos.IsStmt() == src.PosIsStmt {
137 if k := nextGoodStatementIndex(v, j, b); k != j {
138 v.Pos = v.Pos.WithNotStmt()
139 b.Values[k].Pos = b.Values[k].Pos.WithIsStmt()
140 }
141 }
142 }
143
144 change = change || vchange
145 if vchange && debug > 1 {
146 fmt.Printf("rewriting %s -> %s\n", v0.LongString(), v.LongString())
147 }
148 }
149 }
150 if !change && !deadChange {
151 break
152 }
153 iters++
154 if (iters > itersLimit || debug >= 2) && change {
155
156
157
158
159
160 if states == nil {
161 states = make(map[string]bool)
162 }
163 h := f.RewriteHash()
164 if _, ok := states[h]; ok {
165
166
167
168
169 if debug < 2 {
170 debug = 2
171 states = make(map[string]bool)
172 } else {
173 f.Fatalf("rewrite cycle detected")
174 }
175 }
176 states[h] = true
177 }
178 }
179
180 for _, b := range f.Blocks {
181 j := 0
182 for i, v := range b.Values {
183 vl := v.Pos
184 if v.Op == ssaop.OpInvalid {
185 if v.Pos.IsStmt() == src.PosIsStmt {
186 pendingLines.Set(vl, int32(b.ID))
187 }
188 f.FreeValue(v)
189 continue
190 }
191 if v.Pos.IsStmt() != src.PosNotStmt && !ssa.NotStmtBoundary(v.Op) {
192 if pl, ok := pendingLines.Get(vl); ok && pl == int32(b.ID) {
193 pendingLines.Remove(vl)
194 v.Pos = v.Pos.WithIsStmt()
195 }
196 }
197 if i != j {
198 b.Values[j] = v
199 }
200 j++
201 }
202 if pl, ok := pendingLines.Get(b.Pos); ok && pl == int32(b.ID) {
203 b.Pos = b.Pos.WithIsStmt()
204 pendingLines.Remove(b.Pos)
205 }
206 b.TruncateValues(j)
207 }
208 }
209
210
211
212 func truncate64Fto32F(f float64) float32 {
213 if !isExactFloat32(f) {
214 panic("truncate64Fto32F: truncation is not exact")
215 }
216 if !math.IsNaN(f) {
217 return float32(f)
218 }
219
220
221 b := math.Float64bits(f)
222 m := b & ((1 << 52) - 1)
223
224 r := uint32(((b >> 32) & (1 << 31)) | 0x7f800000 | (m >> (52 - 23)))
225 return math.Float32frombits(r)
226 }
227
228
229 func auxTo32F(i int64) float32 {
230 return truncate64Fto32F(math.Float64frombits(uint64(i)))
231 }
232
233
234
235
236 func mergePoint(b *ssa.Block, a ...*ssa.Value) *ssa.Block {
237
238
239
240 d := 100
241
242 for d > 0 {
243 for _, x := range a {
244 if b == x.Block {
245 goto found
246 }
247 }
248 if len(b.Preds) > 1 {
249
250 return nil
251 }
252 b = b.Preds[0].B
253 d--
254 }
255 return nil
256 found:
257
258
259 r := b
260
261
262 na := 0
263 for d > 0 {
264 for _, x := range a {
265 if b == x.Block {
266 na++
267 }
268 }
269 if na == len(a) {
270
271 return r
272 }
273 if len(b.Preds) > 1 {
274 return nil
275 }
276 b = b.Preds[0].B
277 d--
278
279 }
280 return nil
281 }
282
283
284 func arm64ConditionalParamsAuxInt(cond ssaop.Op, nzcv uint8) ssa.Arm64ConditionalParams {
285 if cond < ssaop.OpARM64Equal || cond > ssaop.OpARM64GreaterEqualU {
286 panic("Wrong conditional operation")
287 }
288 if nzcv&0x0f != nzcv {
289 panic("Wrong value of NZCV flag")
290 }
291 return ssa.Arm64ConditionalParams{Cond: cond, NzcvVal: nzcv, ConstVal: 0, Ind: false}
292 }
293
294
295 func arm64ConditionalParamsAuxIntWithValue(cond ssaop.Op, nzcv uint8, value uint8) ssa.Arm64ConditionalParams {
296 if value&0x1f != value {
297 panic("Wrong value of constant")
298 }
299 params := arm64ConditionalParamsAuxInt(cond, nzcv)
300 params.ConstVal = value
301 params.Ind = true
302 return params
303 }
304
View as plain text