github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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 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 }