github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/cmd/compile/internal/ssa/decompose.go (about)

     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 "cmd/compile/internal/types"
     8  
     9  // decompose converts phi ops on compound builtin types into phi
    10  // ops on simple types.
    11  // (The remaining compound ops are decomposed with rewrite rules.)
    12  func decomposeBuiltIn(f *Func) {
    13  	for _, b := range f.Blocks {
    14  		for _, v := range b.Values {
    15  			if v.Op != OpPhi {
    16  				continue
    17  			}
    18  			decomposeBuiltInPhi(v)
    19  		}
    20  	}
    21  
    22  	// Split up named values into their components.
    23  	// NOTE: the component values we are making are dead at this point.
    24  	// We must do the opt pass before any deadcode elimination or we will
    25  	// lose the name->value correspondence.
    26  	var newNames []LocalSlot
    27  	for _, name := range f.Names {
    28  		t := name.Type
    29  		switch {
    30  		case t.IsInteger() && t.Size() > f.Config.RegSize:
    31  			var elemType *types.Type
    32  			if t.IsSigned() {
    33  				elemType = f.Config.Types.Int32
    34  			} else {
    35  				elemType = f.Config.Types.UInt32
    36  			}
    37  			hiName, loName := f.fe.SplitInt64(name)
    38  			newNames = append(newNames, hiName, loName)
    39  			for _, v := range f.NamedValues[name] {
    40  				hi := v.Block.NewValue1(v.Pos, OpInt64Hi, elemType, v)
    41  				lo := v.Block.NewValue1(v.Pos, OpInt64Lo, f.Config.Types.UInt32, v)
    42  				f.NamedValues[hiName] = append(f.NamedValues[hiName], hi)
    43  				f.NamedValues[loName] = append(f.NamedValues[loName], lo)
    44  			}
    45  			delete(f.NamedValues, name)
    46  		case t.IsComplex():
    47  			var elemType *types.Type
    48  			if t.Size() == 16 {
    49  				elemType = f.Config.Types.Float64
    50  			} else {
    51  				elemType = f.Config.Types.Float32
    52  			}
    53  			rName, iName := f.fe.SplitComplex(name)
    54  			newNames = append(newNames, rName, iName)
    55  			for _, v := range f.NamedValues[name] {
    56  				r := v.Block.NewValue1(v.Pos, OpComplexReal, elemType, v)
    57  				i := v.Block.NewValue1(v.Pos, OpComplexImag, elemType, v)
    58  				f.NamedValues[rName] = append(f.NamedValues[rName], r)
    59  				f.NamedValues[iName] = append(f.NamedValues[iName], i)
    60  			}
    61  			delete(f.NamedValues, name)
    62  		case t.IsString():
    63  			ptrType := f.Config.Types.BytePtr
    64  			lenType := f.Config.Types.Int
    65  			ptrName, lenName := f.fe.SplitString(name)
    66  			newNames = append(newNames, ptrName, lenName)
    67  			for _, v := range f.NamedValues[name] {
    68  				ptr := v.Block.NewValue1(v.Pos, OpStringPtr, ptrType, v)
    69  				len := v.Block.NewValue1(v.Pos, OpStringLen, lenType, v)
    70  				f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
    71  				f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
    72  			}
    73  			delete(f.NamedValues, name)
    74  		case t.IsSlice():
    75  			ptrType := f.Config.Types.BytePtr
    76  			lenType := f.Config.Types.Int
    77  			ptrName, lenName, capName := f.fe.SplitSlice(name)
    78  			newNames = append(newNames, ptrName, lenName, capName)
    79  			for _, v := range f.NamedValues[name] {
    80  				ptr := v.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, v)
    81  				len := v.Block.NewValue1(v.Pos, OpSliceLen, lenType, v)
    82  				cap := v.Block.NewValue1(v.Pos, OpSliceCap, lenType, v)
    83  				f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
    84  				f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
    85  				f.NamedValues[capName] = append(f.NamedValues[capName], cap)
    86  			}
    87  			delete(f.NamedValues, name)
    88  		case t.IsInterface():
    89  			ptrType := f.Config.Types.BytePtr
    90  			typeName, dataName := f.fe.SplitInterface(name)
    91  			newNames = append(newNames, typeName, dataName)
    92  			for _, v := range f.NamedValues[name] {
    93  				typ := v.Block.NewValue1(v.Pos, OpITab, ptrType, v)
    94  				data := v.Block.NewValue1(v.Pos, OpIData, ptrType, v)
    95  				f.NamedValues[typeName] = append(f.NamedValues[typeName], typ)
    96  				f.NamedValues[dataName] = append(f.NamedValues[dataName], data)
    97  			}
    98  			delete(f.NamedValues, name)
    99  		case t.IsFloat():
   100  			// floats are never decomposed, even ones bigger than RegSize
   101  			newNames = append(newNames, name)
   102  		case t.Size() > f.Config.RegSize:
   103  			f.Fatalf("undecomposed named type %s %v", name, t)
   104  		default:
   105  			newNames = append(newNames, name)
   106  		}
   107  	}
   108  	f.Names = newNames
   109  }
   110  
   111  func decomposeBuiltInPhi(v *Value) {
   112  	switch {
   113  	case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize:
   114  		decomposeInt64Phi(v)
   115  	case v.Type.IsComplex():
   116  		decomposeComplexPhi(v)
   117  	case v.Type.IsString():
   118  		decomposeStringPhi(v)
   119  	case v.Type.IsSlice():
   120  		decomposeSlicePhi(v)
   121  	case v.Type.IsInterface():
   122  		decomposeInterfacePhi(v)
   123  	case v.Type.IsFloat():
   124  		// floats are never decomposed, even ones bigger than RegSize
   125  	case v.Type.Size() > v.Block.Func.Config.RegSize:
   126  		v.Fatalf("undecomposed type %s", v.Type)
   127  	}
   128  }
   129  
   130  func decomposeStringPhi(v *Value) {
   131  	types := &v.Block.Func.Config.Types
   132  	ptrType := types.BytePtr
   133  	lenType := types.Int
   134  
   135  	ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
   136  	len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
   137  	for _, a := range v.Args {
   138  		ptr.AddArg(a.Block.NewValue1(v.Pos, OpStringPtr, ptrType, a))
   139  		len.AddArg(a.Block.NewValue1(v.Pos, OpStringLen, lenType, a))
   140  	}
   141  	v.reset(OpStringMake)
   142  	v.AddArg(ptr)
   143  	v.AddArg(len)
   144  }
   145  
   146  func decomposeSlicePhi(v *Value) {
   147  	types := &v.Block.Func.Config.Types
   148  	ptrType := types.BytePtr
   149  	lenType := types.Int
   150  
   151  	ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
   152  	len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
   153  	cap := v.Block.NewValue0(v.Pos, OpPhi, lenType)
   154  	for _, a := range v.Args {
   155  		ptr.AddArg(a.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, a))
   156  		len.AddArg(a.Block.NewValue1(v.Pos, OpSliceLen, lenType, a))
   157  		cap.AddArg(a.Block.NewValue1(v.Pos, OpSliceCap, lenType, a))
   158  	}
   159  	v.reset(OpSliceMake)
   160  	v.AddArg(ptr)
   161  	v.AddArg(len)
   162  	v.AddArg(cap)
   163  }
   164  
   165  func decomposeInt64Phi(v *Value) {
   166  	cfgtypes := &v.Block.Func.Config.Types
   167  	var partType *types.Type
   168  	if v.Type.IsSigned() {
   169  		partType = cfgtypes.Int32
   170  	} else {
   171  		partType = cfgtypes.UInt32
   172  	}
   173  
   174  	hi := v.Block.NewValue0(v.Pos, OpPhi, partType)
   175  	lo := v.Block.NewValue0(v.Pos, OpPhi, cfgtypes.UInt32)
   176  	for _, a := range v.Args {
   177  		hi.AddArg(a.Block.NewValue1(v.Pos, OpInt64Hi, partType, a))
   178  		lo.AddArg(a.Block.NewValue1(v.Pos, OpInt64Lo, cfgtypes.UInt32, a))
   179  	}
   180  	v.reset(OpInt64Make)
   181  	v.AddArg(hi)
   182  	v.AddArg(lo)
   183  }
   184  
   185  func decomposeComplexPhi(v *Value) {
   186  	cfgtypes := &v.Block.Func.Config.Types
   187  	var partType *types.Type
   188  	switch z := v.Type.Size(); z {
   189  	case 8:
   190  		partType = cfgtypes.Float32
   191  	case 16:
   192  		partType = cfgtypes.Float64
   193  	default:
   194  		v.Fatalf("decomposeComplexPhi: bad complex size %d", z)
   195  	}
   196  
   197  	real := v.Block.NewValue0(v.Pos, OpPhi, partType)
   198  	imag := v.Block.NewValue0(v.Pos, OpPhi, partType)
   199  	for _, a := range v.Args {
   200  		real.AddArg(a.Block.NewValue1(v.Pos, OpComplexReal, partType, a))
   201  		imag.AddArg(a.Block.NewValue1(v.Pos, OpComplexImag, partType, a))
   202  	}
   203  	v.reset(OpComplexMake)
   204  	v.AddArg(real)
   205  	v.AddArg(imag)
   206  }
   207  
   208  func decomposeInterfacePhi(v *Value) {
   209  	ptrType := v.Block.Func.Config.Types.BytePtr
   210  
   211  	itab := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
   212  	data := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
   213  	for _, a := range v.Args {
   214  		itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, ptrType, 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 decomposeUser(f *Func) {
   223  	for _, b := range f.Blocks {
   224  		for _, v := range b.Values {
   225  			if v.Op != OpPhi {
   226  				continue
   227  			}
   228  			decomposeUserPhi(v)
   229  		}
   230  	}
   231  	// Split up named values into their components.
   232  	// NOTE: the component values we are making are dead at this point.
   233  	// We must do the opt pass before any deadcode elimination or we will
   234  	// lose the name->value correspondence.
   235  	i := 0
   236  	var fnames []LocalSlot
   237  	var newNames []LocalSlot
   238  	for _, name := range f.Names {
   239  		t := name.Type
   240  		switch {
   241  		case t.IsStruct():
   242  			n := t.NumFields()
   243  			fnames = fnames[:0]
   244  			for i := 0; i < n; i++ {
   245  				fnames = append(fnames, f.fe.SplitStruct(name, i))
   246  			}
   247  			for _, v := range f.NamedValues[name] {
   248  				for i := 0; i < n; i++ {
   249  					x := v.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), v)
   250  					f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], x)
   251  				}
   252  			}
   253  			delete(f.NamedValues, name)
   254  			newNames = append(newNames, fnames...)
   255  		case t.IsArray():
   256  			if t.NumElem() == 0 {
   257  				// TODO(khr): Not sure what to do here.  Probably nothing.
   258  				// Names for empty arrays aren't important.
   259  				break
   260  			}
   261  			if t.NumElem() != 1 {
   262  				f.Fatalf("array not of size 1")
   263  			}
   264  			elemName := f.fe.SplitArray(name)
   265  			for _, v := range f.NamedValues[name] {
   266  				e := v.Block.NewValue1I(v.Pos, OpArraySelect, t.ElemType(), 0, v)
   267  				f.NamedValues[elemName] = append(f.NamedValues[elemName], e)
   268  			}
   269  
   270  		default:
   271  			f.Names[i] = name
   272  			i++
   273  		}
   274  	}
   275  	f.Names = f.Names[:i]
   276  	f.Names = append(f.Names, newNames...)
   277  }
   278  
   279  func decomposeUserPhi(v *Value) {
   280  	switch {
   281  	case v.Type.IsStruct():
   282  		decomposeStructPhi(v)
   283  	case v.Type.IsArray():
   284  		decomposeArrayPhi(v)
   285  	}
   286  }
   287  
   288  // decomposeStructPhi replaces phi-of-struct with structmake(phi-for-each-field),
   289  // and then recursively decomposes the phis for each field.
   290  func decomposeStructPhi(v *Value) {
   291  	t := v.Type
   292  	n := t.NumFields()
   293  	var fields [MaxStruct]*Value
   294  	for i := 0; i < n; i++ {
   295  		fields[i] = v.Block.NewValue0(v.Pos, OpPhi, t.FieldType(i))
   296  	}
   297  	for _, a := range v.Args {
   298  		for i := 0; i < n; i++ {
   299  			fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a))
   300  		}
   301  	}
   302  	v.reset(StructMakeOp(n))
   303  	v.AddArgs(fields[:n]...)
   304  
   305  	// Recursively decompose phis for each field.
   306  	for _, f := range fields[:n] {
   307  		decomposeUserPhi(f)
   308  	}
   309  }
   310  
   311  // decomposeArrayPhi replaces phi-of-array with arraymake(phi-of-array-element),
   312  // and then recursively decomposes the element phi.
   313  func decomposeArrayPhi(v *Value) {
   314  	t := v.Type
   315  	if t.NumElem() == 0 {
   316  		v.reset(OpArrayMake0)
   317  		return
   318  	}
   319  	if t.NumElem() != 1 {
   320  		v.Fatalf("SSAable array must have no more than 1 element")
   321  	}
   322  	elem := v.Block.NewValue0(v.Pos, OpPhi, t.ElemType())
   323  	for _, a := range v.Args {
   324  		elem.AddArg(a.Block.NewValue1I(v.Pos, OpArraySelect, t.ElemType(), 0, a))
   325  	}
   326  	v.reset(OpArrayMake1)
   327  	v.AddArg(elem)
   328  
   329  	// Recursively decompose elem phi.
   330  	decomposeUserPhi(elem)
   331  }
   332  
   333  // MaxStruct is the maximum number of fields a struct
   334  // can have and still be SSAable.
   335  const MaxStruct = 4
   336  
   337  // StructMakeOp returns the opcode to construct a struct with the
   338  // given number of fields.
   339  func StructMakeOp(nf int) Op {
   340  	switch nf {
   341  	case 0:
   342  		return OpStructMake0
   343  	case 1:
   344  		return OpStructMake1
   345  	case 2:
   346  		return OpStructMake2
   347  	case 3:
   348  		return OpStructMake3
   349  	case 4:
   350  		return OpStructMake4
   351  	}
   352  	panic("too many fields in an SSAable struct")
   353  }