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