1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ssa
6
7import (
8	"cmd/compile/internal/types"
9	"sort"
10)
11
12// decompose converts phi ops on compound builtin types into phi
13// ops on simple types, then invokes rewrite rules to decompose
14// other ops on those types.
15func decomposeBuiltIn(f *Func) {
16	// Decompose phis
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	// Decompose other values
27	// Note: Leave dead values because we need to keep the original
28	// values around so the name component resolution below can still work.
29	applyRewrite(f, rewriteBlockdec, rewriteValuedec, leaveDeadValues)
30	if f.Config.RegSize == 4 {
31		applyRewrite(f, rewriteBlockdec64, rewriteValuedec64, leaveDeadValues)
32	}
33
34	// Split up named values into their components.
35	// accumulate old names for aggregates (that are decomposed) in toDelete for efficient bulk deletion,
36	// accumulate new LocalSlots in newNames for addition after the iteration.  This decomposition is for
37	// builtin types with leaf components, and thus there is no need to reprocess the newly create LocalSlots.
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			// floats are never decomposed, even ones bigger than RegSize
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
111func 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
119func maybeAppend2(f *Func, ss []*LocalSlot, s1, s2 *LocalSlot) []*LocalSlot {
120	return maybeAppend(f, maybeAppend(f, ss, s1), s2)
121}
122
123func 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		// floats are never decomposed, even ones bigger than RegSize
137	case v.Type.Size() > v.Block.Func.Config.RegSize:
138		v.Fatalf("%v undecomposed type %v", v, v.Type)
139	}
140}
141
142func 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
158func 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
177func 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
197func 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
220func 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
235func 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	// Split up named values into their components.
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// decomposeUserArrayInto creates names for the element(s) of arrays referenced
264// by name where possible, and appends those new names to slots, which is then
265// returned.
266func decomposeUserArrayInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
267	t := name.Type
268	if t.NumElem() == 0 {
269		// TODO(khr): Not sure what to do here.  Probably nothing.
270		// Names for empty arrays aren't important.
271		return slots
272	}
273	if t.NumElem() != 1 {
274		// shouldn't get here due to CanSSA
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		// delete the name for the array as a whole
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// decomposeUserStructInto creates names for the fields(s) of structs referenced
303// by name where possible, and appends those new names to slots, which is then
304// returned.
305func decomposeUserStructInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot {
306	fnames := []*LocalSlot{} // slots for struct in name
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		// arrays and structs will be decomposed further, so
314		// there's no need to record a name
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	// create named values for each struct field
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		// delete the name for the struct as a whole
334		delete(f.NamedValues, *name)
335	} else {
336		f.NamedValues[*name] = keep
337	}
338
339	// now that this f.NamedValues contains values for the struct
340	// fields, recurse into nested structs
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}
352func 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// decomposeStructPhi replaces phi-of-struct with structmake(phi-for-each-field),
362// and then recursively decomposes the phis for each field.
363func 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	// Recursively decompose phis for each field.
379	for _, f := range fields[:n] {
380		decomposeUserPhi(f)
381	}
382}
383
384// decomposeArrayPhi replaces phi-of-array with arraymake(phi-of-array-element),
385// and then recursively decomposes the element phi.
386func 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	// Recursively decompose elem phi.
403	decomposeUserPhi(elem)
404}
405
406// MaxStruct is the maximum number of fields a struct
407// can have and still be SSAable.
408const MaxStruct = 4
409
410// StructMakeOp returns the opcode to construct a struct with the
411// given number of fields.
412func 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
428type namedVal struct {
429	locIndex, valIndex int // f.NamedValues[f.Names[locIndex]][valIndex] = key
430}
431
432// deleteNamedVals removes particular values with debugger names from f's naming data structures,
433// removes all values with OpInvalid, and re-sorts the list of Names.
434func deleteNamedVals(f *Func, toDelete []namedVal) {
435	// Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalidate pending indices.
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	// Get rid of obsolete names
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	// Delete locations with no values attached.
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