github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/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 ( 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 uintptrType := v.Block.Func.Config.Types.Uintptr 204 ptrType := v.Block.Func.Config.Types.BytePtr 205 206 itab := v.Block.NewValue0(v.Pos, OpPhi, uintptrType) 207 data := v.Block.NewValue0(v.Pos, OpPhi, ptrType) 208 for _, a := range v.Args { 209 itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, uintptrType, a)) 210 data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a)) 211 } 212 v.reset(OpIMake) 213 v.AddArg(itab) 214 v.AddArg(data) 215 } 216 217 func decomposeUser(f *Func) { 218 for _, b := range f.Blocks { 219 for _, v := range b.Values { 220 if v.Op != OpPhi { 221 continue 222 } 223 decomposeUserPhi(v) 224 } 225 } 226 // Split up named values into their components. 227 i := 0 228 var newNames []LocalSlot 229 for _, name := range f.Names { 230 t := name.Type 231 switch { 232 case t.IsStruct(): 233 newNames = decomposeUserStructInto(f, name, newNames) 234 case t.IsArray(): 235 newNames = decomposeUserArrayInto(f, name, newNames) 236 default: 237 f.Names[i] = name 238 i++ 239 } 240 } 241 f.Names = f.Names[:i] 242 f.Names = append(f.Names, newNames...) 243 } 244 245 // decomposeUserArrayInto creates names for the element(s) of arrays referenced 246 // by name where possible, and appends those new names to slots, which is then 247 // returned. 248 func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot { 249 t := name.Type 250 if t.NumElem() == 0 { 251 // TODO(khr): Not sure what to do here. Probably nothing. 252 // Names for empty arrays aren't important. 253 return slots 254 } 255 if t.NumElem() != 1 { 256 // shouldn't get here due to CanSSA 257 f.Fatalf("array not of size 1") 258 } 259 elemName := f.fe.SplitArray(name) 260 for _, v := range f.NamedValues[name] { 261 if v.Op != OpArrayMake1 { 262 continue 263 } 264 f.NamedValues[elemName] = append(f.NamedValues[elemName], v.Args[0]) 265 } 266 // delete the name for the array as a whole 267 delete(f.NamedValues, name) 268 269 if t.Elem().IsArray() { 270 return decomposeUserArrayInto(f, elemName, slots) 271 } else if t.Elem().IsStruct() { 272 return decomposeUserStructInto(f, elemName, slots) 273 } 274 275 return append(slots, elemName) 276 } 277 278 // decomposeUserStructInto creates names for the fields(s) of structs referenced 279 // by name where possible, and appends those new names to slots, which is then 280 // returned. 281 func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot { 282 fnames := []LocalSlot{} // slots for struct in name 283 t := name.Type 284 n := t.NumFields() 285 286 for i := 0; i < n; i++ { 287 fs := f.fe.SplitStruct(name, i) 288 fnames = append(fnames, fs) 289 // arrays and structs will be decomposed further, so 290 // there's no need to record a name 291 if !fs.Type.IsArray() && !fs.Type.IsStruct() { 292 slots = append(slots, fs) 293 } 294 } 295 296 makeOp := StructMakeOp(n) 297 // create named values for each struct field 298 for _, v := range f.NamedValues[name] { 299 if v.Op != makeOp { 300 continue 301 } 302 for i := 0; i < len(fnames); i++ { 303 f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], v.Args[i]) 304 } 305 } 306 // remove the name of the struct as a whole 307 delete(f.NamedValues, name) 308 309 // now that this f.NamedValues contains values for the struct 310 // fields, recurse into nested structs 311 for i := 0; i < n; i++ { 312 if name.Type.FieldType(i).IsStruct() { 313 slots = decomposeUserStructInto(f, fnames[i], slots) 314 delete(f.NamedValues, fnames[i]) 315 } else if name.Type.FieldType(i).IsArray() { 316 slots = decomposeUserArrayInto(f, fnames[i], slots) 317 delete(f.NamedValues, fnames[i]) 318 } 319 } 320 return slots 321 } 322 func decomposeUserPhi(v *Value) { 323 switch { 324 case v.Type.IsStruct(): 325 decomposeStructPhi(v) 326 case v.Type.IsArray(): 327 decomposeArrayPhi(v) 328 } 329 } 330 331 // decomposeStructPhi replaces phi-of-struct with structmake(phi-for-each-field), 332 // and then recursively decomposes the phis for each field. 333 func decomposeStructPhi(v *Value) { 334 t := v.Type 335 n := t.NumFields() 336 var fields [MaxStruct]*Value 337 for i := 0; i < n; i++ { 338 fields[i] = v.Block.NewValue0(v.Pos, OpPhi, t.FieldType(i)) 339 } 340 for _, a := range v.Args { 341 for i := 0; i < n; i++ { 342 fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a)) 343 } 344 } 345 v.reset(StructMakeOp(n)) 346 v.AddArgs(fields[:n]...) 347 348 // Recursively decompose phis for each field. 349 for _, f := range fields[:n] { 350 decomposeUserPhi(f) 351 } 352 } 353 354 // decomposeArrayPhi replaces phi-of-array with arraymake(phi-of-array-element), 355 // and then recursively decomposes the element phi. 356 func decomposeArrayPhi(v *Value) { 357 t := v.Type 358 if t.NumElem() == 0 { 359 v.reset(OpArrayMake0) 360 return 361 } 362 if t.NumElem() != 1 { 363 v.Fatalf("SSAable array must have no more than 1 element") 364 } 365 elem := v.Block.NewValue0(v.Pos, OpPhi, t.Elem()) 366 for _, a := range v.Args { 367 elem.AddArg(a.Block.NewValue1I(v.Pos, OpArraySelect, t.Elem(), 0, a)) 368 } 369 v.reset(OpArrayMake1) 370 v.AddArg(elem) 371 372 // Recursively decompose elem phi. 373 decomposeUserPhi(elem) 374 } 375 376 // MaxStruct is the maximum number of fields a struct 377 // can have and still be SSAable. 378 const MaxStruct = 4 379 380 // StructMakeOp returns the opcode to construct a struct with the 381 // given number of fields. 382 func StructMakeOp(nf int) Op { 383 switch nf { 384 case 0: 385 return OpStructMake0 386 case 1: 387 return OpStructMake1 388 case 2: 389 return OpStructMake2 390 case 3: 391 return OpStructMake3 392 case 4: 393 return OpStructMake4 394 } 395 panic("too many fields in an SSAable struct") 396 }