1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "cmp"
10 "slices"
11 )
12
13
14
15
16 func decomposeBuiltIn(f *Func) {
17
18 for _, b := range f.Blocks {
19 for _, v := range b.Values {
20 if v.Op != OpPhi {
21 continue
22 }
23 decomposeBuiltInPhi(v)
24 }
25 }
26
27
28
29
30 applyRewrite(f, rewriteBlockdec, rewriteValuedec, leaveDeadValues)
31 if f.Config.RegSize == 4 {
32 applyRewrite(f, rewriteBlockdec64, rewriteValuedec64, leaveDeadValues)
33 }
34
35
36
37
38
39 var toDelete []namedVal
40 var newNames []*LocalSlot
41 for i, name := range f.Names {
42 t := name.Type
43 switch {
44 case t.IsInteger() && t.Size() > f.Config.RegSize:
45 hiName, loName := f.SplitInt64(name)
46 newNames = maybeAppend2(f, newNames, hiName, loName)
47 for j, v := range f.NamedValues[*name] {
48 if v.Op != OpInt64Make {
49 continue
50 }
51 f.NamedValues[*hiName] = append(f.NamedValues[*hiName], v.Args[0])
52 f.NamedValues[*loName] = append(f.NamedValues[*loName], v.Args[1])
53 toDelete = append(toDelete, namedVal{i, j})
54 }
55 case t.IsComplex():
56 rName, iName := f.SplitComplex(name)
57 newNames = maybeAppend2(f, newNames, rName, iName)
58 for j, v := range f.NamedValues[*name] {
59 if v.Op != OpComplexMake {
60 continue
61 }
62 f.NamedValues[*rName] = append(f.NamedValues[*rName], v.Args[0])
63 f.NamedValues[*iName] = append(f.NamedValues[*iName], v.Args[1])
64 toDelete = append(toDelete, namedVal{i, j})
65 }
66 case t.IsString():
67 ptrName, lenName := f.SplitString(name)
68 newNames = maybeAppend2(f, newNames, ptrName, lenName)
69 for j, v := range f.NamedValues[*name] {
70 if v.Op != OpStringMake {
71 continue
72 }
73 f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0])
74 f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1])
75 toDelete = append(toDelete, namedVal{i, j})
76 }
77 case t.IsSlice():
78 ptrName, lenName, capName := f.SplitSlice(name)
79 newNames = maybeAppend2(f, newNames, ptrName, lenName)
80 newNames = maybeAppend(f, newNames, capName)
81 for j, v := range f.NamedValues[*name] {
82 if v.Op != OpSliceMake {
83 continue
84 }
85 f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0])
86 f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1])
87 f.NamedValues[*capName] = append(f.NamedValues[*capName], v.Args[2])
88 toDelete = append(toDelete, namedVal{i, j})
89 }
90 case t.IsInterface():
91 typeName, dataName := f.SplitInterface(name)
92 newNames = maybeAppend2(f, newNames, typeName, dataName)
93 for j, v := range f.NamedValues[*name] {
94 if v.Op != OpIMake {
95 continue
96 }
97 f.NamedValues[*typeName] = append(f.NamedValues[*typeName], v.Args[0])
98 f.NamedValues[*dataName] = append(f.NamedValues[*dataName], v.Args[1])
99 toDelete = append(toDelete, namedVal{i, j})
100 }
101 case t.IsFloat():
102
103 case t.Size() > f.Config.RegSize:
104 f.Fatalf("undecomposed named type %s %v", name, t)
105 }
106 }
107
108 deleteNamedVals(f, toDelete)
109 f.Names = append(f.Names, newNames...)
110 }
111
112 func maybeAppend(f *Func, ss []*LocalSlot, s *LocalSlot) []*LocalSlot {
113 if _, ok := f.NamedValues[*s]; !ok {
114 f.NamedValues[*s] = nil
115 return append(ss, s)
116 }
117 return ss
118 }
119
120 func maybeAppend2(f *Func, ss []*LocalSlot, s1, s2 *LocalSlot) []*LocalSlot {
121 return maybeAppend(f, maybeAppend(f, ss, s1), s2)
122 }
123
124 func decomposeBuiltInPhi(v *Value) {
125 switch {
126 case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize:
127 decomposeInt64Phi(v)
128 case v.Type.IsComplex():
129 decomposeComplexPhi(v)
130 case v.Type.IsString():
131 decomposeStringPhi(v)
132 case v.Type.IsSlice():
133 decomposeSlicePhi(v)
134 case v.Type.IsInterface():
135 decomposeInterfacePhi(v)
136 case v.Type.IsFloat():
137
138 case v.Type.Size() > v.Block.Func.Config.RegSize:
139 v.Fatalf("%v undecomposed type %v", v, v.Type)
140 }
141 }
142
143 func decomposeStringPhi(v *Value) {
144 types := &v.Block.Func.Config.Types
145 ptrType := types.BytePtr
146 lenType := types.Int
147
148 ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
149 len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
150 for _, a := range v.Args {
151 ptr.AddArg(a.Block.NewValue1(v.Pos, OpStringPtr, ptrType, a))
152 len.AddArg(a.Block.NewValue1(v.Pos, OpStringLen, lenType, a))
153 }
154 v.reset(OpStringMake)
155 v.AddArg(ptr)
156 v.AddArg(len)
157 }
158
159 func decomposeSlicePhi(v *Value) {
160 types := &v.Block.Func.Config.Types
161 ptrType := v.Type.Elem().PtrTo()
162 lenType := types.Int
163
164 ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
165 len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
166 cap := v.Block.NewValue0(v.Pos, OpPhi, lenType)
167 for _, a := range v.Args {
168 ptr.AddArg(a.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, a))
169 len.AddArg(a.Block.NewValue1(v.Pos, OpSliceLen, lenType, a))
170 cap.AddArg(a.Block.NewValue1(v.Pos, OpSliceCap, lenType, a))
171 }
172 v.reset(OpSliceMake)
173 v.AddArg(ptr)
174 v.AddArg(len)
175 v.AddArg(cap)
176 }
177
178 func decomposeInt64Phi(v *Value) {
179 cfgtypes := &v.Block.Func.Config.Types
180 var partType *types.Type
181 if v.Type.IsSigned() {
182 partType = cfgtypes.Int32
183 } else {
184 partType = cfgtypes.UInt32
185 }
186
187 hi := v.Block.NewValue0(v.Pos, OpPhi, partType)
188 lo := v.Block.NewValue0(v.Pos, OpPhi, cfgtypes.UInt32)
189 for _, a := range v.Args {
190 hi.AddArg(a.Block.NewValue1(v.Pos, OpInt64Hi, partType, a))
191 lo.AddArg(a.Block.NewValue1(v.Pos, OpInt64Lo, cfgtypes.UInt32, a))
192 }
193 v.reset(OpInt64Make)
194 v.AddArg(hi)
195 v.AddArg(lo)
196 }
197
198 func decomposeComplexPhi(v *Value) {
199 cfgtypes := &v.Block.Func.Config.Types
200 var partType *types.Type
201 switch z := v.Type.Size(); z {
202 case 8:
203 partType = cfgtypes.Float32
204 case 16:
205 partType = cfgtypes.Float64
206 default:
207 v.Fatalf("decomposeComplexPhi: bad complex size %d", z)
208 }
209
210 real := v.Block.NewValue0(v.Pos, OpPhi, partType)
211 imag := v.Block.NewValue0(v.Pos, OpPhi, partType)
212 for _, a := range v.Args {
213 real.AddArg(a.Block.NewValue1(v.Pos, OpComplexReal, partType, a))
214 imag.AddArg(a.Block.NewValue1(v.Pos, OpComplexImag, partType, a))
215 }
216 v.reset(OpComplexMake)
217 v.AddArg(real)
218 v.AddArg(imag)
219 }
220
221 func decomposeInterfacePhi(v *Value) {
222 uintptrType := v.Block.Func.Config.Types.Uintptr
223 ptrType := v.Block.Func.Config.Types.BytePtr
224
225 itab := v.Block.NewValue0(v.Pos, OpPhi, uintptrType)
226 data := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
227 for _, a := range v.Args {
228 itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, uintptrType, a))
229 data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a))
230 }
231 v.reset(OpIMake)
232 v.AddArg(itab)
233 v.AddArg(data)
234 }
235
236 func decomposeUser(f *Func) {
237 for _, b := range f.Blocks {
238 for _, v := range b.Values {
239 if v.Op != OpPhi {
240 continue
241 }
242 decomposeUserPhi(v)
243 }
244 }
245
246 i := 0
247 var newNames []*LocalSlot
248 for _, name := range f.Names {
249 t := name.Type
250 switch {
251 case t.IsStruct():
252 newNames = decomposeUserStructInto(f, name, newNames)
253 case t.IsArray():
254 newNames = decomposeUserArrayInto(f, name, newNames)
255 default:
256 f.Names[i] = name
257 i++
258 }
259 }
260 f.Names = f.Names[:i]
261 f.Names = append(f.Names, newNames...)
262 }
263
264
265
266
267 func decomposeUserArrayInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
268 t := name.Type
269 if t.NumElem() == 0 {
270
271
272 return slots
273 }
274 if t.NumElem() != 1 {
275
276 f.Fatalf("array not of size 1")
277 }
278 elemName := f.SplitArray(name)
279 var keep []*Value
280 for _, v := range f.NamedValues[*name] {
281 if v.Op != OpArrayMake1 {
282 keep = append(keep, v)
283 continue
284 }
285 f.NamedValues[*elemName] = append(f.NamedValues[*elemName], v.Args[0])
286 }
287 if len(keep) == 0 {
288
289 delete(f.NamedValues, *name)
290 } else {
291 f.NamedValues[*name] = keep
292 }
293
294 if t.Elem().IsArray() {
295 return decomposeUserArrayInto(f, elemName, slots)
296 } else if t.Elem().IsStruct() {
297 return decomposeUserStructInto(f, elemName, slots)
298 }
299
300 return append(slots, elemName)
301 }
302
303
304
305
306 func decomposeUserStructInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
307 fnames := []*LocalSlot{}
308 t := name.Type
309 n := t.NumFields()
310
311 for i := 0; i < n; i++ {
312 fs := f.SplitStruct(name, i)
313 fnames = append(fnames, fs)
314
315
316 if !fs.Type.IsArray() && !fs.Type.IsStruct() {
317 slots = maybeAppend(f, slots, fs)
318 }
319 }
320
321 var keep []*Value
322
323 for _, v := range f.NamedValues[*name] {
324 if v.Op != OpStructMake || len(v.Args) != n {
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(OpStructMake)
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 type namedVal struct {
411 locIndex, valIndex int
412 }
413
414
415
416 func deleteNamedVals(f *Func, toDelete []namedVal) {
417
418 slices.SortFunc(toDelete, func(a, b namedVal) int {
419 if a.locIndex != b.locIndex {
420 return cmp.Compare(b.locIndex, a.locIndex)
421 }
422 return cmp.Compare(b.valIndex, a.valIndex)
423 })
424
425
426 for _, d := range toDelete {
427 loc := f.Names[d.locIndex]
428 vals := f.NamedValues[*loc]
429 l := len(vals) - 1
430 if l > 0 {
431 vals[d.valIndex] = vals[l]
432 }
433 vals[l] = nil
434 f.NamedValues[*loc] = vals[:l]
435 }
436
437 end := len(f.Names)
438 for i := len(f.Names) - 1; i >= 0; i-- {
439 loc := f.Names[i]
440 vals := f.NamedValues[*loc]
441 last := len(vals)
442 for j := len(vals) - 1; j >= 0; j-- {
443 if vals[j].Op == OpInvalid {
444 last--
445 vals[j] = vals[last]
446 vals[last] = nil
447 }
448 }
449 if last < len(vals) {
450 f.NamedValues[*loc] = vals[:last]
451 }
452 if len(vals) == 0 {
453 delete(f.NamedValues, *loc)
454 end--
455 f.Names[i] = f.Names[end]
456 f.Names[end] = nil
457 }
458 }
459 f.Names = f.Names[:end]
460 }
461
View as plain text