github.com/bir3/gocompiler@v0.9.2202/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 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 9 "sort" 10 ) 11 12 // decompose converts phi ops on compound builtin types into phi 13 // ops on simple types, then invokes rewrite rules to decompose 14 // other ops on those types. 15 func decomposeBuiltIn(f *Func) { 16 // Decompose phis 17 for _, b := range f.Blocks { 18 for _, v := range b.Values { 19 if v.Op != OpPhi { 20 continue 21 } 22 decomposeBuiltInPhi(v) 23 } 24 } 25 26 // Decompose other values 27 // Note: Leave dead values because we need to keep the original 28 // values around so the name component resolution below can still work. 29 applyRewrite(f, rewriteBlockdec, rewriteValuedec, leaveDeadValues) 30 if f.Config.RegSize == 4 { 31 applyRewrite(f, rewriteBlockdec64, rewriteValuedec64, leaveDeadValues) 32 } 33 34 // Split up named values into their components. 35 // accumulate old names for aggregates (that are decomposed) in toDelete for efficient bulk deletion, 36 // accumulate new LocalSlots in newNames for addition after the iteration. This decomposition is for 37 // builtin types with leaf components, and thus there is no need to reprocess the newly create LocalSlots. 38 var toDelete []namedVal 39 var newNames []*LocalSlot 40 for i, name := range f.Names { 41 t := name.Type 42 switch { 43 case t.IsInteger() && t.Size() > f.Config.RegSize: 44 hiName, loName := f.SplitInt64(name) 45 newNames = maybeAppend2(f, newNames, hiName, loName) 46 for j, v := range f.NamedValues[*name] { 47 if v.Op != OpInt64Make { 48 continue 49 } 50 f.NamedValues[*hiName] = append(f.NamedValues[*hiName], v.Args[0]) 51 f.NamedValues[*loName] = append(f.NamedValues[*loName], v.Args[1]) 52 toDelete = append(toDelete, namedVal{i, j}) 53 } 54 case t.IsComplex(): 55 rName, iName := f.SplitComplex(name) 56 newNames = maybeAppend2(f, newNames, rName, iName) 57 for j, v := range f.NamedValues[*name] { 58 if v.Op != OpComplexMake { 59 continue 60 } 61 f.NamedValues[*rName] = append(f.NamedValues[*rName], v.Args[0]) 62 f.NamedValues[*iName] = append(f.NamedValues[*iName], v.Args[1]) 63 toDelete = append(toDelete, namedVal{i, j}) 64 } 65 case t.IsString(): 66 ptrName, lenName := f.SplitString(name) 67 newNames = maybeAppend2(f, newNames, ptrName, lenName) 68 for j, v := range f.NamedValues[*name] { 69 if v.Op != OpStringMake { 70 continue 71 } 72 f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0]) 73 f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1]) 74 toDelete = append(toDelete, namedVal{i, j}) 75 } 76 case t.IsSlice(): 77 ptrName, lenName, capName := f.SplitSlice(name) 78 newNames = maybeAppend2(f, newNames, ptrName, lenName) 79 newNames = maybeAppend(f, newNames, capName) 80 for j, v := range f.NamedValues[*name] { 81 if v.Op != OpSliceMake { 82 continue 83 } 84 f.NamedValues[*ptrName] = append(f.NamedValues[*ptrName], v.Args[0]) 85 f.NamedValues[*lenName] = append(f.NamedValues[*lenName], v.Args[1]) 86 f.NamedValues[*capName] = append(f.NamedValues[*capName], v.Args[2]) 87 toDelete = append(toDelete, namedVal{i, j}) 88 } 89 case t.IsInterface(): 90 typeName, dataName := f.SplitInterface(name) 91 newNames = maybeAppend2(f, newNames, typeName, dataName) 92 for j, v := range f.NamedValues[*name] { 93 if v.Op != OpIMake { 94 continue 95 } 96 f.NamedValues[*typeName] = append(f.NamedValues[*typeName], v.Args[0]) 97 f.NamedValues[*dataName] = append(f.NamedValues[*dataName], v.Args[1]) 98 toDelete = append(toDelete, namedVal{i, j}) 99 } 100 case t.IsFloat(): 101 // floats are never decomposed, even ones bigger than RegSize 102 case t.Size() > f.Config.RegSize: 103 f.Fatalf("undecomposed named type %s %v", name, t) 104 } 105 } 106 107 deleteNamedVals(f, toDelete) 108 f.Names = append(f.Names, newNames...) 109 } 110 111 func maybeAppend(f *Func, ss []*LocalSlot, s *LocalSlot) []*LocalSlot { 112 if _, ok := f.NamedValues[*s]; !ok { 113 f.NamedValues[*s] = nil 114 return append(ss, s) 115 } 116 return ss 117 } 118 119 func maybeAppend2(f *Func, ss []*LocalSlot, s1, s2 *LocalSlot) []*LocalSlot { 120 return maybeAppend(f, maybeAppend(f, ss, s1), s2) 121 } 122 123 func decomposeBuiltInPhi(v *Value) { 124 switch { 125 case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize: 126 decomposeInt64Phi(v) 127 case v.Type.IsComplex(): 128 decomposeComplexPhi(v) 129 case v.Type.IsString(): 130 decomposeStringPhi(v) 131 case v.Type.IsSlice(): 132 decomposeSlicePhi(v) 133 case v.Type.IsInterface(): 134 decomposeInterfacePhi(v) 135 case v.Type.IsFloat(): 136 // floats are never decomposed, even ones bigger than RegSize 137 case v.Type.Size() > v.Block.Func.Config.RegSize: 138 v.Fatalf("%v undecomposed type %v", v, v.Type) 139 } 140 } 141 142 func decomposeStringPhi(v *Value) { 143 types := &v.Block.Func.Config.Types 144 ptrType := types.BytePtr 145 lenType := types.Int 146 147 ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType) 148 len := v.Block.NewValue0(v.Pos, OpPhi, lenType) 149 for _, a := range v.Args { 150 ptr.AddArg(a.Block.NewValue1(v.Pos, OpStringPtr, ptrType, a)) 151 len.AddArg(a.Block.NewValue1(v.Pos, OpStringLen, lenType, a)) 152 } 153 v.reset(OpStringMake) 154 v.AddArg(ptr) 155 v.AddArg(len) 156 } 157 158 func decomposeSlicePhi(v *Value) { 159 types := &v.Block.Func.Config.Types 160 ptrType := v.Type.Elem().PtrTo() 161 lenType := types.Int 162 163 ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType) 164 len := v.Block.NewValue0(v.Pos, OpPhi, lenType) 165 cap := v.Block.NewValue0(v.Pos, OpPhi, lenType) 166 for _, a := range v.Args { 167 ptr.AddArg(a.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, a)) 168 len.AddArg(a.Block.NewValue1(v.Pos, OpSliceLen, lenType, a)) 169 cap.AddArg(a.Block.NewValue1(v.Pos, OpSliceCap, lenType, a)) 170 } 171 v.reset(OpSliceMake) 172 v.AddArg(ptr) 173 v.AddArg(len) 174 v.AddArg(cap) 175 } 176 177 func decomposeInt64Phi(v *Value) { 178 cfgtypes := &v.Block.Func.Config.Types 179 var partType *types.Type 180 if v.Type.IsSigned() { 181 partType = cfgtypes.Int32 182 } else { 183 partType = cfgtypes.UInt32 184 } 185 186 hi := v.Block.NewValue0(v.Pos, OpPhi, partType) 187 lo := v.Block.NewValue0(v.Pos, OpPhi, cfgtypes.UInt32) 188 for _, a := range v.Args { 189 hi.AddArg(a.Block.NewValue1(v.Pos, OpInt64Hi, partType, a)) 190 lo.AddArg(a.Block.NewValue1(v.Pos, OpInt64Lo, cfgtypes.UInt32, a)) 191 } 192 v.reset(OpInt64Make) 193 v.AddArg(hi) 194 v.AddArg(lo) 195 } 196 197 func decomposeComplexPhi(v *Value) { 198 cfgtypes := &v.Block.Func.Config.Types 199 var partType *types.Type 200 switch z := v.Type.Size(); z { 201 case 8: 202 partType = cfgtypes.Float32 203 case 16: 204 partType = cfgtypes.Float64 205 default: 206 v.Fatalf("decomposeComplexPhi: bad complex size %d", z) 207 } 208 209 real := v.Block.NewValue0(v.Pos, OpPhi, partType) 210 imag := v.Block.NewValue0(v.Pos, OpPhi, partType) 211 for _, a := range v.Args { 212 real.AddArg(a.Block.NewValue1(v.Pos, OpComplexReal, partType, a)) 213 imag.AddArg(a.Block.NewValue1(v.Pos, OpComplexImag, partType, a)) 214 } 215 v.reset(OpComplexMake) 216 v.AddArg(real) 217 v.AddArg(imag) 218 } 219 220 func decomposeInterfacePhi(v *Value) { 221 uintptrType := v.Block.Func.Config.Types.Uintptr 222 ptrType := v.Block.Func.Config.Types.BytePtr 223 224 itab := v.Block.NewValue0(v.Pos, OpPhi, uintptrType) 225 data := v.Block.NewValue0(v.Pos, OpPhi, ptrType) 226 for _, a := range v.Args { 227 itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, uintptrType, a)) 228 data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a)) 229 } 230 v.reset(OpIMake) 231 v.AddArg(itab) 232 v.AddArg(data) 233 } 234 235 func decomposeUser(f *Func) { 236 for _, b := range f.Blocks { 237 for _, v := range b.Values { 238 if v.Op != OpPhi { 239 continue 240 } 241 decomposeUserPhi(v) 242 } 243 } 244 // Split up named values into their components. 245 i := 0 246 var newNames []*LocalSlot 247 for _, name := range f.Names { 248 t := name.Type 249 switch { 250 case t.IsStruct(): 251 newNames = decomposeUserStructInto(f, name, newNames) 252 case t.IsArray(): 253 newNames = decomposeUserArrayInto(f, name, newNames) 254 default: 255 f.Names[i] = name 256 i++ 257 } 258 } 259 f.Names = f.Names[:i] 260 f.Names = append(f.Names, newNames...) 261 } 262 263 // decomposeUserArrayInto creates names for the element(s) of arrays referenced 264 // by name where possible, and appends those new names to slots, which is then 265 // returned. 266 func decomposeUserArrayInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot { 267 t := name.Type 268 if t.NumElem() == 0 { 269 // TODO(khr): Not sure what to do here. Probably nothing. 270 // Names for empty arrays aren't important. 271 return slots 272 } 273 if t.NumElem() != 1 { 274 // shouldn't get here due to CanSSA 275 f.Fatalf("array not of size 1") 276 } 277 elemName := f.SplitArray(name) 278 var keep []*Value 279 for _, v := range f.NamedValues[*name] { 280 if v.Op != OpArrayMake1 { 281 keep = append(keep, v) 282 continue 283 } 284 f.NamedValues[*elemName] = append(f.NamedValues[*elemName], v.Args[0]) 285 } 286 if len(keep) == 0 { 287 // delete the name for the array as a whole 288 delete(f.NamedValues, *name) 289 } else { 290 f.NamedValues[*name] = keep 291 } 292 293 if t.Elem().IsArray() { 294 return decomposeUserArrayInto(f, elemName, slots) 295 } else if t.Elem().IsStruct() { 296 return decomposeUserStructInto(f, elemName, slots) 297 } 298 299 return append(slots, elemName) 300 } 301 302 // decomposeUserStructInto creates names for the fields(s) of structs referenced 303 // by name where possible, and appends those new names to slots, which is then 304 // returned. 305 func decomposeUserStructInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*LocalSlot { 306 fnames := []*LocalSlot{} // slots for struct in name 307 t := name.Type 308 n := t.NumFields() 309 310 for i := 0; i < n; i++ { 311 fs := f.SplitStruct(name, i) 312 fnames = append(fnames, fs) 313 // arrays and structs will be decomposed further, so 314 // there's no need to record a name 315 if !fs.Type.IsArray() && !fs.Type.IsStruct() { 316 slots = maybeAppend(f, slots, fs) 317 } 318 } 319 320 makeOp := StructMakeOp(n) 321 var keep []*Value 322 // create named values for each struct field 323 for _, v := range f.NamedValues[*name] { 324 if v.Op != makeOp { 325 keep = append(keep, v) 326 continue 327 } 328 for i := 0; i < len(fnames); i++ { 329 f.NamedValues[*fnames[i]] = append(f.NamedValues[*fnames[i]], v.Args[i]) 330 } 331 } 332 if len(keep) == 0 { 333 // delete the name for the struct as a whole 334 delete(f.NamedValues, *name) 335 } else { 336 f.NamedValues[*name] = keep 337 } 338 339 // now that this f.NamedValues contains values for the struct 340 // fields, recurse into nested structs 341 for i := 0; i < n; i++ { 342 if name.Type.FieldType(i).IsStruct() { 343 slots = decomposeUserStructInto(f, fnames[i], slots) 344 delete(f.NamedValues, *fnames[i]) 345 } else if name.Type.FieldType(i).IsArray() { 346 slots = decomposeUserArrayInto(f, fnames[i], slots) 347 delete(f.NamedValues, *fnames[i]) 348 } 349 } 350 return slots 351 } 352 func decomposeUserPhi(v *Value) { 353 switch { 354 case v.Type.IsStruct(): 355 decomposeStructPhi(v) 356 case v.Type.IsArray(): 357 decomposeArrayPhi(v) 358 } 359 } 360 361 // decomposeStructPhi replaces phi-of-struct with structmake(phi-for-each-field), 362 // and then recursively decomposes the phis for each field. 363 func decomposeStructPhi(v *Value) { 364 t := v.Type 365 n := t.NumFields() 366 var fields [MaxStruct]*Value 367 for i := 0; i < n; i++ { 368 fields[i] = v.Block.NewValue0(v.Pos, OpPhi, t.FieldType(i)) 369 } 370 for _, a := range v.Args { 371 for i := 0; i < n; i++ { 372 fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a)) 373 } 374 } 375 v.reset(StructMakeOp(n)) 376 v.AddArgs(fields[:n]...) 377 378 // Recursively decompose phis for each field. 379 for _, f := range fields[:n] { 380 decomposeUserPhi(f) 381 } 382 } 383 384 // decomposeArrayPhi replaces phi-of-array with arraymake(phi-of-array-element), 385 // and then recursively decomposes the element phi. 386 func decomposeArrayPhi(v *Value) { 387 t := v.Type 388 if t.NumElem() == 0 { 389 v.reset(OpArrayMake0) 390 return 391 } 392 if t.NumElem() != 1 { 393 v.Fatalf("SSAable array must have no more than 1 element") 394 } 395 elem := v.Block.NewValue0(v.Pos, OpPhi, t.Elem()) 396 for _, a := range v.Args { 397 elem.AddArg(a.Block.NewValue1I(v.Pos, OpArraySelect, t.Elem(), 0, a)) 398 } 399 v.reset(OpArrayMake1) 400 v.AddArg(elem) 401 402 // Recursively decompose elem phi. 403 decomposeUserPhi(elem) 404 } 405 406 // MaxStruct is the maximum number of fields a struct 407 // can have and still be SSAable. 408 const MaxStruct = 4 409 410 // StructMakeOp returns the opcode to construct a struct with the 411 // given number of fields. 412 func StructMakeOp(nf int) Op { 413 switch nf { 414 case 0: 415 return OpStructMake0 416 case 1: 417 return OpStructMake1 418 case 2: 419 return OpStructMake2 420 case 3: 421 return OpStructMake3 422 case 4: 423 return OpStructMake4 424 } 425 panic("too many fields in an SSAable struct") 426 } 427 428 type namedVal struct { 429 locIndex, valIndex int // f.NamedValues[f.Names[locIndex]][valIndex] = key 430 } 431 432 // deleteNamedVals removes particular values with debugger names from f's naming data structures, 433 // removes all values with OpInvalid, and re-sorts the list of Names. 434 func deleteNamedVals(f *Func, toDelete []namedVal) { 435 // Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalidate pending indices. 436 sort.Slice(toDelete, func(i, j int) bool { 437 if toDelete[i].locIndex != toDelete[j].locIndex { 438 return toDelete[i].locIndex > toDelete[j].locIndex 439 } 440 return toDelete[i].valIndex > toDelete[j].valIndex 441 442 }) 443 444 // Get rid of obsolete names 445 for _, d := range toDelete { 446 loc := f.Names[d.locIndex] 447 vals := f.NamedValues[*loc] 448 l := len(vals) - 1 449 if l > 0 { 450 vals[d.valIndex] = vals[l] 451 } 452 vals[l] = nil 453 f.NamedValues[*loc] = vals[:l] 454 } 455 // Delete locations with no values attached. 456 end := len(f.Names) 457 for i := len(f.Names) - 1; i >= 0; i-- { 458 loc := f.Names[i] 459 vals := f.NamedValues[*loc] 460 last := len(vals) 461 for j := len(vals) - 1; j >= 0; j-- { 462 if vals[j].Op == OpInvalid { 463 last-- 464 vals[j] = vals[last] 465 vals[last] = nil 466 } 467 } 468 if last < len(vals) { 469 f.NamedValues[*loc] = vals[:last] 470 } 471 if len(vals) == 0 { 472 delete(f.NamedValues, *loc) 473 end-- 474 f.Names[i] = f.Names[end] 475 f.Names[end] = nil 476 } 477 } 478 f.Names = f.Names[:end] 479 }