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