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