Black Lives Matter. Support the Equal Justice Initiative.

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: deadcode is false 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.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  			// floats are never decomposed, even ones bigger than RegSize
   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  		// floats are never decomposed, even ones bigger than RegSize
   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  	// Split up named values into their components.
   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  // decomposeUserArrayInto creates names for the element(s) of arrays referenced
   255  // by name where possible, and appends those new names to slots, which is then
   256  // returned.
   257  func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot {
   258  	t := name.Type
   259  	if t.NumElem() == 0 {
   260  		// TODO(khr): Not sure what to do here.  Probably nothing.
   261  		// Names for empty arrays aren't important.
   262  		return slots
   263  	}
   264  	if t.NumElem() != 1 {
   265  		// shouldn't get here due to CanSSA
   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  		// delete the name for the array as a whole
   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  // decomposeUserStructInto creates names for the fields(s) of structs referenced
   294  // by name where possible, and appends those new names to slots, which is then
   295  // returned.
   296  func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot {
   297  	fnames := []LocalSlot{} // slots for struct in name
   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  		// arrays and structs will be decomposed further, so
   305  		// there's no need to record a name
   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  	// create named values for each struct field
   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  		// delete the name for the struct as a whole
   325  		delete(f.NamedValues, name)
   326  	} else {
   327  		f.NamedValues[name] = keep
   328  	}
   329  
   330  	// now that this f.NamedValues contains values for the struct
   331  	// fields, recurse into nested structs
   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  // decomposeStructPhi replaces phi-of-struct with structmake(phi-for-each-field),
   353  // and then recursively decomposes the phis for each field.
   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  	// Recursively decompose phis for each field.
   370  	for _, f := range fields[:n] {
   371  		decomposeUserPhi(f)
   372  	}
   373  }
   374  
   375  // decomposeArrayPhi replaces phi-of-array with arraymake(phi-of-array-element),
   376  // and then recursively decomposes the element phi.
   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  	// Recursively decompose elem phi.
   394  	decomposeUserPhi(elem)
   395  }
   396  
   397  // MaxStruct is the maximum number of fields a struct
   398  // can have and still be SSAable.
   399  const MaxStruct = 4
   400  
   401  // StructMakeOp returns the opcode to construct a struct with the
   402  // given number of fields.
   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 // f.NamedValues[f.Names[locIndex]][valIndex] = key
   421  }
   422  
   423  // deleteNamedVals removes particular values with debugger names from f's naming data structures
   424  func deleteNamedVals(f *Func, toDelete []namedVal) {
   425  	// Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalid pending indices.
   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  	// Get rid of obsolete names
   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