...

Source file src/cmd/compile/internal/ssa/decompose.go

Documentation: cmd/compile/internal/ssa

     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  
     5  package ssa
     6  
     7  import (
     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.
    15  func 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  
   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  		// 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  
   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  	// 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.
   266  func 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.
   305  func 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  }
   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  // decomposeStructPhi replaces phi-of-struct with structmake(phi-for-each-field),
   362  // and then recursively decomposes the phis for each field.
   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  	// 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.
   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  	// 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.
   408  const MaxStruct = 4
   409  
   410  // StructMakeOp returns the opcode to construct a struct with the
   411  // given number of fields.
   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 // 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.
   434  func 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  

View as plain text