github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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  	for _, name := range f.Names {
    25  		t := name.Type
    26  		switch {
    27  		case t.IsComplex():
    28  			var elemType Type
    29  			if t.Size() == 16 {
    30  				elemType = f.Config.fe.TypeFloat64()
    31  			} else {
    32  				elemType = f.Config.fe.TypeFloat32()
    33  			}
    34  			rName, iName := f.Config.fe.SplitComplex(name)
    35  			f.Names = append(f.Names, rName, iName)
    36  			for _, v := range f.NamedValues[name] {
    37  				r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v)
    38  				i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v)
    39  				f.NamedValues[rName] = append(f.NamedValues[rName], r)
    40  				f.NamedValues[iName] = append(f.NamedValues[iName], i)
    41  			}
    42  		case t.IsString():
    43  			ptrType := f.Config.fe.TypeBytePtr()
    44  			lenType := f.Config.fe.TypeInt()
    45  			ptrName, lenName := f.Config.fe.SplitString(name)
    46  			f.Names = append(f.Names, ptrName, lenName)
    47  			for _, v := range f.NamedValues[name] {
    48  				ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v)
    49  				len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v)
    50  				f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
    51  				f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
    52  			}
    53  		case t.IsSlice():
    54  			ptrType := f.Config.fe.TypeBytePtr()
    55  			lenType := f.Config.fe.TypeInt()
    56  			ptrName, lenName, capName := f.Config.fe.SplitSlice(name)
    57  			f.Names = append(f.Names, ptrName, lenName, capName)
    58  			for _, v := range f.NamedValues[name] {
    59  				ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v)
    60  				len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v)
    61  				cap := v.Block.NewValue1(v.Line, OpSliceCap, lenType, v)
    62  				f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
    63  				f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
    64  				f.NamedValues[capName] = append(f.NamedValues[capName], cap)
    65  			}
    66  		case t.IsInterface():
    67  			ptrType := f.Config.fe.TypeBytePtr()
    68  			typeName, dataName := f.Config.fe.SplitInterface(name)
    69  			f.Names = append(f.Names, typeName, dataName)
    70  			for _, v := range f.NamedValues[name] {
    71  				typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v)
    72  				data := v.Block.NewValue1(v.Line, OpIData, ptrType, v)
    73  				f.NamedValues[typeName] = append(f.NamedValues[typeName], typ)
    74  				f.NamedValues[dataName] = append(f.NamedValues[dataName], data)
    75  			}
    76  		case t.Size() > f.Config.IntSize:
    77  			f.Unimplementedf("undecomposed named type %s", t)
    78  		}
    79  	}
    80  }
    81  
    82  func decomposeBuiltInPhi(v *Value) {
    83  	// TODO: decompose 64-bit ops on 32-bit archs?
    84  	switch {
    85  	case v.Type.IsComplex():
    86  		decomposeComplexPhi(v)
    87  	case v.Type.IsString():
    88  		decomposeStringPhi(v)
    89  	case v.Type.IsSlice():
    90  		decomposeSlicePhi(v)
    91  	case v.Type.IsInterface():
    92  		decomposeInterfacePhi(v)
    93  	case v.Type.Size() > v.Block.Func.Config.IntSize:
    94  		v.Unimplementedf("undecomposed type %s", v.Type)
    95  	}
    96  }
    97  
    98  func decomposeStringPhi(v *Value) {
    99  	fe := v.Block.Func.Config.fe
   100  	ptrType := fe.TypeBytePtr()
   101  	lenType := fe.TypeInt()
   102  
   103  	ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType)
   104  	len := v.Block.NewValue0(v.Line, OpPhi, lenType)
   105  	for _, a := range v.Args {
   106  		ptr.AddArg(a.Block.NewValue1(v.Line, OpStringPtr, ptrType, a))
   107  		len.AddArg(a.Block.NewValue1(v.Line, OpStringLen, lenType, a))
   108  	}
   109  	v.reset(OpStringMake)
   110  	v.AddArg(ptr)
   111  	v.AddArg(len)
   112  }
   113  
   114  func decomposeSlicePhi(v *Value) {
   115  	fe := v.Block.Func.Config.fe
   116  	ptrType := fe.TypeBytePtr()
   117  	lenType := fe.TypeInt()
   118  
   119  	ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType)
   120  	len := v.Block.NewValue0(v.Line, OpPhi, lenType)
   121  	cap := v.Block.NewValue0(v.Line, OpPhi, lenType)
   122  	for _, a := range v.Args {
   123  		ptr.AddArg(a.Block.NewValue1(v.Line, OpSlicePtr, ptrType, a))
   124  		len.AddArg(a.Block.NewValue1(v.Line, OpSliceLen, lenType, a))
   125  		cap.AddArg(a.Block.NewValue1(v.Line, OpSliceCap, lenType, a))
   126  	}
   127  	v.reset(OpSliceMake)
   128  	v.AddArg(ptr)
   129  	v.AddArg(len)
   130  	v.AddArg(cap)
   131  }
   132  
   133  func decomposeComplexPhi(v *Value) {
   134  	fe := v.Block.Func.Config.fe
   135  	var partType Type
   136  	switch z := v.Type.Size(); z {
   137  	case 8:
   138  		partType = fe.TypeFloat32()
   139  	case 16:
   140  		partType = fe.TypeFloat64()
   141  	default:
   142  		v.Fatalf("decomposeComplexPhi: bad complex size %d", z)
   143  	}
   144  
   145  	real := v.Block.NewValue0(v.Line, OpPhi, partType)
   146  	imag := v.Block.NewValue0(v.Line, OpPhi, partType)
   147  	for _, a := range v.Args {
   148  		real.AddArg(a.Block.NewValue1(v.Line, OpComplexReal, partType, a))
   149  		imag.AddArg(a.Block.NewValue1(v.Line, OpComplexImag, partType, a))
   150  	}
   151  	v.reset(OpComplexMake)
   152  	v.AddArg(real)
   153  	v.AddArg(imag)
   154  }
   155  
   156  func decomposeInterfacePhi(v *Value) {
   157  	ptrType := v.Block.Func.Config.fe.TypeBytePtr()
   158  
   159  	itab := v.Block.NewValue0(v.Line, OpPhi, ptrType)
   160  	data := v.Block.NewValue0(v.Line, OpPhi, ptrType)
   161  	for _, a := range v.Args {
   162  		itab.AddArg(a.Block.NewValue1(v.Line, OpITab, ptrType, a))
   163  		data.AddArg(a.Block.NewValue1(v.Line, OpIData, ptrType, a))
   164  	}
   165  	v.reset(OpIMake)
   166  	v.AddArg(itab)
   167  	v.AddArg(data)
   168  }
   169  
   170  func decomposeUser(f *Func) {
   171  	for _, b := range f.Blocks {
   172  		for _, v := range b.Values {
   173  			if v.Op != OpPhi {
   174  				continue
   175  			}
   176  			decomposeUserPhi(v)
   177  		}
   178  	}
   179  	// Split up named values into their components.
   180  	// NOTE: the component values we are making are dead at this point.
   181  	// We must do the opt pass before any deadcode elimination or we will
   182  	// lose the name->value correspondence.
   183  	i := 0
   184  	for _, name := range f.Names {
   185  		t := name.Type
   186  		switch {
   187  		case t.IsStruct():
   188  			n := t.NumFields()
   189  			for _, v := range f.NamedValues[name] {
   190  				for i := 0; i < n; i++ {
   191  					fname := LocalSlot{name.N, t.FieldType(i), name.Off + t.FieldOff(i)} // TODO: use actual field name?
   192  					x := v.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), v)
   193  					f.NamedValues[fname] = append(f.NamedValues[fname], x)
   194  				}
   195  			}
   196  			delete(f.NamedValues, name)
   197  		default:
   198  			f.Names[i] = name
   199  			i++
   200  		}
   201  	}
   202  	f.Names = f.Names[:i]
   203  }
   204  
   205  func decomposeUserPhi(v *Value) {
   206  	switch {
   207  	case v.Type.IsStruct():
   208  		decomposeStructPhi(v)
   209  	}
   210  	// TODO: Arrays of length 1?
   211  }
   212  
   213  func decomposeStructPhi(v *Value) {
   214  	t := v.Type
   215  	n := t.NumFields()
   216  	var fields [MaxStruct]*Value
   217  	for i := 0; i < n; i++ {
   218  		fields[i] = v.Block.NewValue0(v.Line, OpPhi, t.FieldType(i))
   219  	}
   220  	for _, a := range v.Args {
   221  		for i := 0; i < n; i++ {
   222  			fields[i].AddArg(a.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), a))
   223  		}
   224  	}
   225  	v.reset(StructMakeOp(n))
   226  	v.AddArgs(fields[:n]...)
   227  
   228  	// Recursively decompose phis for each field.
   229  	for _, f := range fields[:n] {
   230  		if f.Type.IsStruct() {
   231  			decomposeStructPhi(f)
   232  		}
   233  	}
   234  }
   235  
   236  // MaxStruct is the maximum number of fields a struct
   237  // can have and still be SSAable.
   238  const MaxStruct = 4
   239  
   240  // StructMakeOp returns the opcode to construct a struct with the
   241  // given number of fields.
   242  func StructMakeOp(nf int) Op {
   243  	switch nf {
   244  	case 0:
   245  		return OpStructMake0
   246  	case 1:
   247  		return OpStructMake1
   248  	case 2:
   249  		return OpStructMake2
   250  	case 3:
   251  		return OpStructMake3
   252  	case 4:
   253  		return OpStructMake4
   254  	}
   255  	panic("too many fields in an SSAable struct")
   256  }