1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "sort"
10 )
11
12
13
14
15 func decomposeBuiltIn(f *Func) {
16
17 for _, b := range f.Blocks {
18 for _, v := range b.Values {
19 if v.Op != OpPhi {
20 continue
21 }
22 decomposeBuiltInPhi(v)
23 }
24 }
25
26
27
28
29 applyRewrite(f, rewriteBlockdec, rewriteValuedec, leaveDeadValues)
30 if f.Config.RegSize == 4 {
31 applyRewrite(f, rewriteBlockdec64, rewriteValuedec64, leaveDeadValues)
32 }
33
34
35
36
37
38 var toDelete []namedVal
39 var newNames []*LocalSlot
40 for i, name := range f.Names {
41 t := name.Type
42 switch {
43 case t.IsInteger() && t.Size() > f.Config.RegSize:
44 hiName, loName := f.SplitInt64(name)
45 newNames = maybeAppend2(f, newNames, hiName, loName)
46 for j, v := range f.NamedValues[*name] {
47 if v.Op != OpInt64Make {
48 continue
49 }
50 f.NamedValues[*hiName] = append(f.NamedValues[*hiName], v.Args[0])
51 f.NamedValues[*loName] = append(f.NamedValues[*loName], v.Args[1])
52 toDelete = append(toDelete, namedVal{i, j})
53 }
54 case t.IsComplex():
55 rName, iName := f.SplitComplex(name)
56 newNames = maybeAppend2(f, newNames, rName, iName)
57 for j, v := range f.NamedValues[*name] {
58 if v.Op != OpComplexMake {
59 continue
60 }
61 f.NamedValues[*rName] = append(f.NamedValues[*rName], v.Args[0])
62 f.NamedValues[*iName] = append(f.NamedValues[*iName], v.Args[1])
63 toDelete = append(toDelete, namedVal{i, j})
64 }
65 case t.IsString():
66 ptrName, lenName := f.SplitString(name)
67 newNames = maybeAppend2(f, newNames, ptrName, lenName)
68 for j, v := range f.NamedValues[*name] {
69 if v.Op != OpStringMake {
70 continue
71 }
72 f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0])
73 f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1])
74 toDelete = append(toDelete, namedVal{i, j})
75 }
76 case t.IsSlice():
77 ptrName, lenName, capName := f.SplitSlice(name)
78 newNames = maybeAppend2(f, newNames, ptrName, lenName)
79 newNames = maybeAppend(f, newNames, capName)
80 for j, v := range f.NamedValues[*name] {
81 if v.Op != OpSliceMake {
82 continue
83 }
84 f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0])
85 f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1])
86 f.NamedValues[*capName] = append(f.NamedValues[*capName], v.Args[2])
87 toDelete = append(toDelete, namedVal{i, j})
88 }
89 case t.IsInterface():
90 typeName, dataName := f.SplitInterface(name)
91 newNames = maybeAppend2(f, newNames, typeName, dataName)
92 for j, v := range f.NamedValues[*name] {
93 if v.Op != OpIMake {
94 continue
95 }
96 f.NamedValues[*typeName] = append(f.NamedValues[*typeName], v.Args[0])
97 f.NamedValues[*dataName] = append(f.NamedValues[*dataName], v.Args[1])
98 toDelete = append(toDelete, namedVal{i, j})
99 }
100 case t.IsFloat():
101
102 case t.Size() > f.Config.RegSize:
103 f.Fatalf("undecomposed named type %s %v", name, t)
104 }
105 }
106
107 deleteNamedVals(f, toDelete)
108 f.Names = append(f.Names, newNames...)
109 }
110
111 func maybeAppend(f *Func, ss []*LocalSlot, s *LocalSlot) []*LocalSlot {
112 if _, ok := f.NamedValues[*s]; !ok {
113 f.NamedValues[*s] = nil
114 return append(ss, s)
115 }
116 return ss
117 }
118
119 func maybeAppend2(f *Func, ss []*LocalSlot, s1, s2 *LocalSlot) []*LocalSlot {
120 return maybeAppend(f, maybeAppend(f, ss, s1), s2)
121 }
122
123 func decomposeBuiltInPhi(v *Value) {
124 switch {
125 case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize:
126 decomposeInt64Phi(v)
127 case v.Type.IsComplex():
128 decomposeComplexPhi(v)
129 case v.Type.IsString():
130 decomposeStringPhi(v)
131 case v.Type.IsSlice():
132 decomposeSlicePhi(v)
133 case v.Type.IsInterface():
134 decomposeInterfacePhi(v)
135 case v.Type.IsFloat():
136
137 case v.Type.Size() > v.Block.Func.Config.RegSize:
138 v.Fatalf("undecomposed type %s", v.Type)
139 }
140 }
141
142 func decomposeStringPhi(v *Value) {
143 types := &v.Block.Func.Config.Types
144 ptrType := types.BytePtr
145 lenType := types.Int
146
147 ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
148 len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
149 for _, a := range v.Args {
150 ptr.AddArg(a.Block.NewValue1(v.Pos, OpStringPtr, ptrType, a))
151 len.AddArg(a.Block.NewValue1(v.Pos, OpStringLen, lenType, a))
152 }
153 v.reset(OpStringMake)
154 v.AddArg(ptr)
155 v.AddArg(len)
156 }
157
158 func decomposeSlicePhi(v *Value) {
159 types := &v.Block.Func.Config.Types
160 ptrType := v.Type.Elem().PtrTo()
161 lenType := types.Int
162
163 ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
164 len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
165 cap := v.Block.NewValue0(v.Pos, OpPhi, lenType)
166 for _, a := range v.Args {
167 ptr.AddArg(a.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, a))
168 len.AddArg(a.Block.NewValue1(v.Pos, OpSliceLen, lenType, a))
169 cap.AddArg(a.Block.NewValue1(v.Pos, OpSliceCap, lenType, a))
170 }
171 v.reset(OpSliceMake)
172 v.AddArg(ptr)
173 v.AddArg(len)
174 v.AddArg(cap)
175 }
176
177 func decomposeInt64Phi(v *Value) {
178 cfgtypes := &v.Block.Func.Config.Types
179 var partType *types.Type
180 if v.Type.IsSigned() {
181 partType = cfgtypes.Int32
182 } else {
183 partType = cfgtypes.UInt32
184 }
185
186 hi := v.Block.NewValue0(v.Pos, OpPhi, partType)
187 lo := v.Block.NewValue0(v.Pos, OpPhi, cfgtypes.UInt32)
188 for _, a := range v.Args {
189 hi.AddArg(a.Block.NewValue1(v.Pos, OpInt64Hi, partType, a))
190 lo.AddArg(a.Block.NewValue1(v.Pos, OpInt64Lo, cfgtypes.UInt32, a))
191 }
192 v.reset(OpInt64Make)
193 v.AddArg(hi)
194 v.AddArg(lo)
195 }
196
197 func decomposeComplexPhi(v *Value) {
198 cfgtypes := &v.Block.Func.Config.Types
199 var partType *types.Type
200 switch z := v.Type.Size(); z {
201 case 8:
202 partType = cfgtypes.Float32
203 case 16:
204 partType = cfgtypes.Float64
205 default:
206 v.Fatalf("decomposeComplexPhi: bad complex size %d", z)
207 }
208
209 real := v.Block.NewValue0(v.Pos, OpPhi, partType)
210 imag := v.Block.NewValue0(v.Pos, OpPhi, partType)
211 for _, a := range v.Args {
212 real.AddArg(a.Block.NewValue1(v.Pos, OpComplexReal, partType, a))
213 imag.AddArg(a.Block.NewValue1(v.Pos, OpComplexImag, partType, a))
214 }
215 v.reset(OpComplexMake)
216 v.AddArg(real)
217 v.AddArg(imag)
218 }
219
220 func decomposeInterfacePhi(v *Value) {
221 uintptrType := v.Block.Func.Config.Types.Uintptr
222 ptrType := v.Block.Func.Config.Types.BytePtr
223
224 itab := v.Block.NewValue0(v.Pos, OpPhi, uintptrType)
225 data := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
226 for _, a := range v.Args {
227 itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, uintptrType, a))
228 data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a))
229 }
230 v.reset(OpIMake)
231 v.AddArg(itab)
232 v.AddArg(data)
233 }
234
235 func decomposeUser(f *Func) {
236 for _, b := range f.Blocks {
237 for _, v := range b.Values {
238 if v.Op != OpPhi {
239 continue
240 }
241 decomposeUserPhi(v)
242 }
243 }
244
245 i := 0
246 var newNames []*LocalSlot
247 for _, name := range f.Names {
248 t := name.Type
249 switch {
250 case t.IsStruct():
251 newNames = decomposeUserStructInto(f, name, newNames)
252 case t.IsArray():
253 newNames = decomposeUserArrayInto(f, name, newNames)
254 default:
255 f.Names[i] = name
256 i++
257 }
258 }
259 f.Names = f.Names[:i]
260 f.Names = append(f.Names, newNames...)
261 }
262
263
264
265
266 func decomposeUserArrayInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
267 t := name.Type
268 if t.NumElem() == 0 {
269
270
271 return slots
272 }
273 if t.NumElem() != 1 {
274
275 f.Fatalf("array not of size 1")
276 }
277 elemName := f.SplitArray(name)
278 var keep []*Value
279 for _, v := range f.NamedValues[*name] {
280 if v.Op != OpArrayMake1 {
281 keep = append(keep, v)
282 continue
283 }
284 f.NamedValues[*elemName] = append(f.NamedValues[*elemName], v.Args[0])
285 }
286 if len(keep) == 0 {
287
288 delete(f.NamedValues, *name)
289 } else {
290 f.NamedValues[*name] = keep
291 }
292
293 if t.Elem().IsArray() {
294 return decomposeUserArrayInto(f, elemName, slots)
295 } else if t.Elem().IsStruct() {
296 return decomposeUserStructInto(f, elemName, slots)
297 }
298
299 return append(slots, elemName)
300 }
301
302
303
304
305 func decomposeUserStructInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
306 fnames := []*LocalSlot{}
307 t := name.Type
308 n := t.NumFields()
309
310 for i := 0; i < n; i++ {
311 fs := f.SplitStruct(name, i)
312 fnames = append(fnames, fs)
313
314
315 if !fs.Type.IsArray() && !fs.Type.IsStruct() {
316 slots = maybeAppend(f, slots, fs)
317 }
318 }
319
320 makeOp := StructMakeOp(n)
321 var keep []*Value
322
323 for _, v := range f.NamedValues[*name] {
324 if v.Op != makeOp {
325 keep = append(keep, v)
326 continue
327 }
328 for i := 0; i < len(fnames); i++ {
329 f.NamedValues[*fnames[i]] = append(f.NamedValues[*fnames[i]], v.Args[i])
330 }
331 }
332 if len(keep) == 0 {
333
334 delete(f.NamedValues, *name)
335 } else {
336 f.NamedValues[*name] = keep
337 }
338
339
340
341 for i := 0; i < n; i++ {
342 if name.Type.FieldType(i).IsStruct() {
343 slots = decomposeUserStructInto(f, fnames[i], slots)
344 delete(f.NamedValues, *fnames[i])
345 } else if name.Type.FieldType(i).IsArray() {
346 slots = decomposeUserArrayInto(f, fnames[i], slots)
347 delete(f.NamedValues, *fnames[i])
348 }
349 }
350 return slots
351 }
352 func decomposeUserPhi(v *Value) {
353 switch {
354 case v.Type.IsStruct():
355 decomposeStructPhi(v)
356 case v.Type.IsArray():
357 decomposeArrayPhi(v)
358 }
359 }
360
361
362
363 func decomposeStructPhi(v *Value) {
364 t := v.Type
365 n := t.NumFields()
366 var fields [MaxStruct]*Value
367 for i := 0; i < n; i++ {
368 fields[i] = v.Block.NewValue0(v.Pos, OpPhi, t.FieldType(i))
369 }
370 for _, a := range v.Args {
371 for i := 0; i < n; i++ {
372 fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a))
373 }
374 }
375 v.reset(StructMakeOp(n))
376 v.AddArgs(fields[:n]...)
377
378
379 for _, f := range fields[:n] {
380 decomposeUserPhi(f)
381 }
382 }
383
384
385
386 func decomposeArrayPhi(v *Value) {
387 t := v.Type
388 if t.NumElem() == 0 {
389 v.reset(OpArrayMake0)
390 return
391 }
392 if t.NumElem() != 1 {
393 v.Fatalf("SSAable array must have no more than 1 element")
394 }
395 elem := v.Block.NewValue0(v.Pos, OpPhi, t.Elem())
396 for _, a := range v.Args {
397 elem.AddArg(a.Block.NewValue1I(v.Pos, OpArraySelect, t.Elem(), 0, a))
398 }
399 v.reset(OpArrayMake1)
400 v.AddArg(elem)
401
402
403 decomposeUserPhi(elem)
404 }
405
406
407
408 const MaxStruct = 4
409
410
411
412 func StructMakeOp(nf int) Op {
413 switch nf {
414 case 0:
415 return OpStructMake0
416 case 1:
417 return OpStructMake1
418 case 2:
419 return OpStructMake2
420 case 3:
421 return OpStructMake3
422 case 4:
423 return OpStructMake4
424 }
425 panic("too many fields in an SSAable struct")
426 }
427
428 type namedVal struct {
429 locIndex, valIndex int
430 }
431
432
433
434 func deleteNamedVals(f *Func, toDelete []namedVal) {
435
436 sort.Slice(toDelete, func(i, j int) bool {
437 if toDelete[i].locIndex != toDelete[j].locIndex {
438 return toDelete[i].locIndex > toDelete[j].locIndex
439 }
440 return toDelete[i].valIndex > toDelete[j].valIndex
441
442 })
443
444
445 for _, d := range toDelete {
446 loc := f.Names[d.locIndex]
447 vals := f.NamedValues[*loc]
448 l := len(vals) - 1
449 if l > 0 {
450 vals[d.valIndex] = vals[l]
451 }
452 vals[l] = nil
453 f.NamedValues[*loc] = vals[:l]
454 }
455
456 end := len(f.Names)
457 for i := len(f.Names) - 1; i >= 0; i-- {
458 loc := f.Names[i]
459 vals := f.NamedValues[*loc]
460 last := len(vals)
461 for j := len(vals) - 1; j >= 0; j-- {
462 if vals[j].Op == OpInvalid {
463 last--
464 vals[j] = vals[last]
465 vals[last] = nil
466 }
467 }
468 if last < len(vals) {
469 f.NamedValues[*loc] = vals[:last]
470 }
471 if len(vals) == 0 {
472 delete(f.NamedValues, *loc)
473 end--
474 f.Names[i] = f.Names[end]
475 f.Names[end] = nil
476 }
477 }
478 f.Names = f.Names[:end]
479 }
480
View as plain text