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