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 // 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.Fatalf("undecomposed named type %v %v", 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.Fatalf("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 		case t.IsArray():
    257 			if t.NumElem() == 0 {
    258 				// TODO(khr): Not sure what to do here.  Probably nothing.
    259 				// Names for empty arrays aren't important.
    260 				break
    261 			}
    262 			if t.NumElem() != 1 {
    263 				f.Fatalf("array not of size 1")
    264 			}
    265 			elemName := f.Config.fe.SplitArray(name)
    266 			for _, v := range f.NamedValues[name] {
    267 				e := v.Block.NewValue1I(v.Line, OpArraySelect, t.ElemType(), 0, v)
    268 				f.NamedValues[elemName] = append(f.NamedValues[elemName], e)
    269 			}
    270 
    271 		default:
    272 			f.Names[i] = name
    273 			i++
    274 		}
    275 	}
    276 	f.Names = f.Names[:i]
    277 	f.Names = append(f.Names, newNames...)
    278 }
    279 
    280 func decomposeUserPhi(v *Value) {
    281 	switch {
    282 	case v.Type.IsStruct():
    283 		decomposeStructPhi(v)
    284 	case v.Type.IsArray():
    285 		decomposeArrayPhi(v)
    286 	}
    287 }
    288 
    289 // decomposeStructPhi replaces phi-of-struct with structmake(phi-for-each-field),
    290 // and then recursively decomposes the phis for each field.
    291 func decomposeStructPhi(v *Value) {
    292 	t := v.Type
    293 	n := t.NumFields()
    294 	var fields [MaxStruct]*Value
    295 	for i := 0; i < n; i++ {
    296 		fields[i] = v.Block.NewValue0(v.Line, OpPhi, t.FieldType(i))
    297 	}
    298 	for _, a := range v.Args {
    299 		for i := 0; i < n; i++ {
    300 			fields[i].AddArg(a.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), a))
    301 		}
    302 	}
    303 	v.reset(StructMakeOp(n))
    304 	v.AddArgs(fields[:n]...)
    305 
    306 	// Recursively decompose phis for each field.
    307 	for _, f := range fields[:n] {
    308 		decomposeUserPhi(f)
    309 	}
    310 }
    311 
    312 // decomposeArrayPhi replaces phi-of-array with arraymake(phi-of-array-element),
    313 // and then recursively decomposes the element phi.
    314 func decomposeArrayPhi(v *Value) {
    315 	t := v.Type
    316 	if t.NumElem() == 0 {
    317 		v.reset(OpArrayMake0)
    318 		return
    319 	}
    320 	if t.NumElem() != 1 {
    321 		v.Fatalf("SSAable array must have no more than 1 element")
    322 	}
    323 	elem := v.Block.NewValue0(v.Line, OpPhi, t.ElemType())
    324 	for _, a := range v.Args {
    325 		elem.AddArg(a.Block.NewValue1I(v.Line, OpArraySelect, t.ElemType(), 0, a))
    326 	}
    327 	v.reset(OpArrayMake1)
    328 	v.AddArg(elem)
    329 
    330 	// Recursively decompose elem phi.
    331 	decomposeUserPhi(elem)
    332 }
    333 
    334 // MaxStruct is the maximum number of fields a struct
    335 // can have and still be SSAable.
    336 const MaxStruct = 4
    337 
    338 // StructMakeOp returns the opcode to construct a struct with the
    339 // given number of fields.
    340 func StructMakeOp(nf int) Op {
    341 	switch nf {
    342 	case 0:
    343 		return OpStructMake0
    344 	case 1:
    345 		return OpStructMake1
    346 	case 2:
    347 		return OpStructMake2
    348 	case 3:
    349 		return OpStructMake3
    350 	case 4:
    351 		return OpStructMake4
    352 	}
    353 	panic("too many fields in an SSAable struct")
    354 }
    355