github.com/sanprasirt/go@v0.0.0-20170607001320-a027466e4b6d/src/cmd/compile/internal/gc/phi.go (about) 1 // Copyright 2016 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 gc 6 7 import ( 8 "cmd/compile/internal/ssa" 9 "cmd/compile/internal/types" 10 "cmd/internal/src" 11 "container/heap" 12 "fmt" 13 ) 14 15 // This file contains the algorithm to place phi nodes in a function. 16 // For small functions, we use Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau. 17 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf 18 // For large functions, we use Sreedhar & Gao: A Linear Time Algorithm for Placing Φ-Nodes. 19 // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.8.1979&rep=rep1&type=pdf 20 21 const smallBlocks = 500 22 23 const debugPhi = false 24 25 // insertPhis finds all the places in the function where a phi is 26 // necessary and inserts them. 27 // Uses FwdRef ops to find all uses of variables, and s.defvars to find 28 // all definitions. 29 // Phi values are inserted, and all FwdRefs are changed to a Copy 30 // of the appropriate phi or definition. 31 // TODO: make this part of cmd/compile/internal/ssa somehow? 32 func (s *state) insertPhis() { 33 if len(s.f.Blocks) <= smallBlocks { 34 sps := simplePhiState{s: s, f: s.f, defvars: s.defvars} 35 sps.insertPhis() 36 return 37 } 38 ps := phiState{s: s, f: s.f, defvars: s.defvars} 39 ps.insertPhis() 40 } 41 42 type phiState struct { 43 s *state // SSA state 44 f *ssa.Func // function to work on 45 defvars []map[*Node]*ssa.Value // defined variables at end of each block 46 47 varnum map[*Node]int32 // variable numbering 48 49 // properties of the dominator tree 50 idom []*ssa.Block // dominator parents 51 tree []domBlock // dominator child+sibling 52 level []int32 // level in dominator tree (0 = root or unreachable, 1 = children of root, ...) 53 54 // scratch locations 55 priq blockHeap // priority queue of blocks, higher level (toward leaves) = higher priority 56 q []*ssa.Block // inner loop queue 57 queued *sparseSet // has been put in q 58 hasPhi *sparseSet // has a phi 59 hasDef *sparseSet // has a write of the variable we're processing 60 61 // miscellaneous 62 placeholder *ssa.Value // dummy value to use as a "not set yet" placeholder. 63 } 64 65 func (s *phiState) insertPhis() { 66 if debugPhi { 67 fmt.Println(s.f.String()) 68 } 69 70 // Find all the variables for which we need to match up reads & writes. 71 // This step prunes any basic-block-only variables from consideration. 72 // Generate a numbering for these variables. 73 s.varnum = map[*Node]int32{} 74 var vars []*Node 75 var vartypes []*types.Type 76 for _, b := range s.f.Blocks { 77 for _, v := range b.Values { 78 if v.Op != ssa.OpFwdRef { 79 continue 80 } 81 var_ := v.Aux.(*Node) 82 83 // Optimization: look back 1 block for the definition. 84 if len(b.Preds) == 1 { 85 c := b.Preds[0].Block() 86 if w := s.defvars[c.ID][var_]; w != nil { 87 v.Op = ssa.OpCopy 88 v.Aux = nil 89 v.AddArg(w) 90 continue 91 } 92 } 93 94 if _, ok := s.varnum[var_]; ok { 95 continue 96 } 97 s.varnum[var_] = int32(len(vartypes)) 98 if debugPhi { 99 fmt.Printf("var%d = %v\n", len(vartypes), var_) 100 } 101 vars = append(vars, var_) 102 vartypes = append(vartypes, v.Type) 103 } 104 } 105 106 if len(vartypes) == 0 { 107 return 108 } 109 110 // Find all definitions of the variables we need to process. 111 // defs[n] contains all the blocks in which variable number n is assigned. 112 defs := make([][]*ssa.Block, len(vartypes)) 113 for _, b := range s.f.Blocks { 114 for var_ := range s.defvars[b.ID] { // TODO: encode defvars some other way (explicit ops)? make defvars[n] a slice instead of a map. 115 if n, ok := s.varnum[var_]; ok { 116 defs[n] = append(defs[n], b) 117 } 118 } 119 } 120 121 // Make dominator tree. 122 s.idom = s.f.Idom() 123 s.tree = make([]domBlock, s.f.NumBlocks()) 124 for _, b := range s.f.Blocks { 125 p := s.idom[b.ID] 126 if p != nil { 127 s.tree[b.ID].sibling = s.tree[p.ID].firstChild 128 s.tree[p.ID].firstChild = b 129 } 130 } 131 // Compute levels in dominator tree. 132 // With parent pointers we can do a depth-first walk without 133 // any auxiliary storage. 134 s.level = make([]int32, s.f.NumBlocks()) 135 b := s.f.Entry 136 levels: 137 for { 138 if p := s.idom[b.ID]; p != nil { 139 s.level[b.ID] = s.level[p.ID] + 1 140 if debugPhi { 141 fmt.Printf("level %s = %d\n", b, s.level[b.ID]) 142 } 143 } 144 if c := s.tree[b.ID].firstChild; c != nil { 145 b = c 146 continue 147 } 148 for { 149 if c := s.tree[b.ID].sibling; c != nil { 150 b = c 151 continue levels 152 } 153 b = s.idom[b.ID] 154 if b == nil { 155 break levels 156 } 157 } 158 } 159 160 // Allocate scratch locations. 161 s.priq.level = s.level 162 s.q = make([]*ssa.Block, 0, s.f.NumBlocks()) 163 s.queued = newSparseSet(s.f.NumBlocks()) 164 s.hasPhi = newSparseSet(s.f.NumBlocks()) 165 s.hasDef = newSparseSet(s.f.NumBlocks()) 166 s.placeholder = s.s.entryNewValue0(ssa.OpUnknown, types.TypeInvalid) 167 168 // Generate phi ops for each variable. 169 for n := range vartypes { 170 s.insertVarPhis(n, vars[n], defs[n], vartypes[n]) 171 } 172 173 // Resolve FwdRefs to the correct write or phi. 174 s.resolveFwdRefs() 175 176 // Erase variable numbers stored in AuxInt fields of phi ops. They are no longer needed. 177 for _, b := range s.f.Blocks { 178 for _, v := range b.Values { 179 if v.Op == ssa.OpPhi { 180 v.AuxInt = 0 181 } 182 } 183 } 184 } 185 186 func (s *phiState) insertVarPhis(n int, var_ *Node, defs []*ssa.Block, typ *types.Type) { 187 priq := &s.priq 188 q := s.q 189 queued := s.queued 190 queued.clear() 191 hasPhi := s.hasPhi 192 hasPhi.clear() 193 hasDef := s.hasDef 194 hasDef.clear() 195 196 // Add defining blocks to priority queue. 197 for _, b := range defs { 198 priq.a = append(priq.a, b) 199 hasDef.add(b.ID) 200 if debugPhi { 201 fmt.Printf("def of var%d in %s\n", n, b) 202 } 203 } 204 heap.Init(priq) 205 206 // Visit blocks defining variable n, from deepest to shallowest. 207 for len(priq.a) > 0 { 208 currentRoot := heap.Pop(priq).(*ssa.Block) 209 if debugPhi { 210 fmt.Printf("currentRoot %s\n", currentRoot) 211 } 212 // Walk subtree below definition. 213 // Skip subtrees we've done in previous iterations. 214 // Find edges exiting tree dominated by definition (the dominance frontier). 215 // Insert phis at target blocks. 216 if queued.contains(currentRoot.ID) { 217 s.s.Fatalf("root already in queue") 218 } 219 q = append(q, currentRoot) 220 queued.add(currentRoot.ID) 221 for len(q) > 0 { 222 b := q[len(q)-1] 223 q = q[:len(q)-1] 224 if debugPhi { 225 fmt.Printf(" processing %s\n", b) 226 } 227 228 currentRootLevel := s.level[currentRoot.ID] 229 for _, e := range b.Succs { 230 c := e.Block() 231 // TODO: if the variable is dead at c, skip it. 232 if s.level[c.ID] > currentRootLevel { 233 // a D-edge, or an edge whose target is in currentRoot's subtree. 234 continue 235 } 236 if !hasPhi.contains(c.ID) { 237 // Add a phi to block c for variable n. 238 hasPhi.add(c.ID) 239 v := c.NewValue0I(currentRoot.Pos, ssa.OpPhi, typ, int64(n)) // TODO: line number right? 240 // Note: we store the variable number in the phi's AuxInt field. Used temporarily by phi building. 241 s.s.addNamedValue(var_, v) 242 for i := 0; i < len(c.Preds); i++ { 243 v.AddArg(s.placeholder) // Actual args will be filled in by resolveFwdRefs. 244 } 245 if debugPhi { 246 fmt.Printf("new phi for var%d in %s: %s\n", n, c, v) 247 } 248 if !hasDef.contains(c.ID) { 249 // There's now a new definition of this variable in block c. 250 // Add it to the priority queue to explore. 251 heap.Push(priq, c) 252 hasDef.add(c.ID) 253 } 254 } 255 } 256 257 // Visit children if they have not been visited yet. 258 for c := s.tree[b.ID].firstChild; c != nil; c = s.tree[c.ID].sibling { 259 if !queued.contains(c.ID) { 260 q = append(q, c) 261 queued.add(c.ID) 262 } 263 } 264 } 265 } 266 } 267 268 // resolveFwdRefs links all FwdRef uses up to their nearest dominating definition. 269 func (s *phiState) resolveFwdRefs() { 270 // Do a depth-first walk of the dominator tree, keeping track 271 // of the most-recently-seen value for each variable. 272 273 // Map from variable ID to SSA value at the current point of the walk. 274 values := make([]*ssa.Value, len(s.varnum)) 275 for i := range values { 276 values[i] = s.placeholder 277 } 278 279 // Stack of work to do. 280 type stackEntry struct { 281 b *ssa.Block // block to explore 282 283 // variable/value pair to reinstate on exit 284 n int32 // variable ID 285 v *ssa.Value 286 287 // Note: only one of b or n,v will be set. 288 } 289 var stk []stackEntry 290 291 stk = append(stk, stackEntry{b: s.f.Entry}) 292 for len(stk) > 0 { 293 work := stk[len(stk)-1] 294 stk = stk[:len(stk)-1] 295 296 b := work.b 297 if b == nil { 298 // On exit from a block, this case will undo any assignments done below. 299 values[work.n] = work.v 300 continue 301 } 302 303 // Process phis as new defs. They come before FwdRefs in this block. 304 for _, v := range b.Values { 305 if v.Op != ssa.OpPhi { 306 continue 307 } 308 n := int32(v.AuxInt) 309 // Remember the old assignment so we can undo it when we exit b. 310 stk = append(stk, stackEntry{n: n, v: values[n]}) 311 // Record the new assignment. 312 values[n] = v 313 } 314 315 // Replace a FwdRef op with the current incoming value for its variable. 316 for _, v := range b.Values { 317 if v.Op != ssa.OpFwdRef { 318 continue 319 } 320 n := s.varnum[v.Aux.(*Node)] 321 v.Op = ssa.OpCopy 322 v.Aux = nil 323 v.AddArg(values[n]) 324 } 325 326 // Establish values for variables defined in b. 327 for var_, v := range s.defvars[b.ID] { 328 n, ok := s.varnum[var_] 329 if !ok { 330 // some variable not live across a basic block boundary. 331 continue 332 } 333 // Remember the old assignment so we can undo it when we exit b. 334 stk = append(stk, stackEntry{n: n, v: values[n]}) 335 // Record the new assignment. 336 values[n] = v 337 } 338 339 // Replace phi args in successors with the current incoming value. 340 for _, e := range b.Succs { 341 c, i := e.Block(), e.Index() 342 for j := len(c.Values) - 1; j >= 0; j-- { 343 v := c.Values[j] 344 if v.Op != ssa.OpPhi { 345 break // All phis will be at the end of the block during phi building. 346 } 347 // Only set arguments that have been resolved. 348 // For very wide CFGs, this significantly speeds up phi resolution. 349 // See golang.org/issue/8225. 350 if w := values[v.AuxInt]; w.Op != ssa.OpUnknown { 351 v.SetArg(i, w) 352 } 353 } 354 } 355 356 // Walk children in dominator tree. 357 for c := s.tree[b.ID].firstChild; c != nil; c = s.tree[c.ID].sibling { 358 stk = append(stk, stackEntry{b: c}) 359 } 360 } 361 } 362 363 // domBlock contains extra per-block information to record the dominator tree. 364 type domBlock struct { 365 firstChild *ssa.Block // first child of block in dominator tree 366 sibling *ssa.Block // next child of parent in dominator tree 367 } 368 369 // A block heap is used as a priority queue to implement the PiggyBank 370 // from Sreedhar and Gao. That paper uses an array which is better 371 // asymptotically but worse in the common case when the PiggyBank 372 // holds a sparse set of blocks. 373 type blockHeap struct { 374 a []*ssa.Block // block IDs in heap 375 level []int32 // depth in dominator tree (static, used for determining priority) 376 } 377 378 func (h *blockHeap) Len() int { return len(h.a) } 379 func (h *blockHeap) Swap(i, j int) { a := h.a; a[i], a[j] = a[j], a[i] } 380 381 func (h *blockHeap) Push(x interface{}) { 382 v := x.(*ssa.Block) 383 h.a = append(h.a, v) 384 } 385 func (h *blockHeap) Pop() interface{} { 386 old := h.a 387 n := len(old) 388 x := old[n-1] 389 h.a = old[:n-1] 390 return x 391 } 392 func (h *blockHeap) Less(i, j int) bool { 393 return h.level[h.a[i].ID] > h.level[h.a[j].ID] 394 } 395 396 // TODO: stop walking the iterated domininance frontier when 397 // the variable is dead. Maybe detect that by checking if the 398 // node we're on is reverse dominated by all the reads? 399 // Reverse dominated by the highest common successor of all the reads? 400 401 // copy of ../ssa/sparseset.go 402 // TODO: move this file to ../ssa, then use sparseSet there. 403 type sparseSet struct { 404 dense []ssa.ID 405 sparse []int32 406 } 407 408 // newSparseSet returns a sparseSet that can represent 409 // integers between 0 and n-1 410 func newSparseSet(n int) *sparseSet { 411 return &sparseSet{dense: nil, sparse: make([]int32, n)} 412 } 413 414 func (s *sparseSet) contains(x ssa.ID) bool { 415 i := s.sparse[x] 416 return i < int32(len(s.dense)) && s.dense[i] == x 417 } 418 419 func (s *sparseSet) add(x ssa.ID) { 420 i := s.sparse[x] 421 if i < int32(len(s.dense)) && s.dense[i] == x { 422 return 423 } 424 s.dense = append(s.dense, x) 425 s.sparse[x] = int32(len(s.dense)) - 1 426 } 427 428 func (s *sparseSet) clear() { 429 s.dense = s.dense[:0] 430 } 431 432 // Variant to use for small functions. 433 type simplePhiState struct { 434 s *state // SSA state 435 f *ssa.Func // function to work on 436 fwdrefs []*ssa.Value // list of FwdRefs to be processed 437 defvars []map[*Node]*ssa.Value // defined variables at end of each block 438 reachable []bool // which blocks are reachable 439 } 440 441 func (s *simplePhiState) insertPhis() { 442 s.reachable = ssa.ReachableBlocks(s.f) 443 444 // Find FwdRef ops. 445 for _, b := range s.f.Blocks { 446 for _, v := range b.Values { 447 if v.Op != ssa.OpFwdRef { 448 continue 449 } 450 s.fwdrefs = append(s.fwdrefs, v) 451 var_ := v.Aux.(*Node) 452 if _, ok := s.defvars[b.ID][var_]; !ok { 453 s.defvars[b.ID][var_] = v // treat FwdDefs as definitions. 454 } 455 } 456 } 457 458 var args []*ssa.Value 459 460 loop: 461 for len(s.fwdrefs) > 0 { 462 v := s.fwdrefs[len(s.fwdrefs)-1] 463 s.fwdrefs = s.fwdrefs[:len(s.fwdrefs)-1] 464 b := v.Block 465 var_ := v.Aux.(*Node) 466 if b == s.f.Entry { 467 // No variable should be live at entry. 468 s.s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, var_, v) 469 } 470 if !s.reachable[b.ID] { 471 // This block is dead. 472 // It doesn't matter what we use here as long as it is well-formed. 473 v.Op = ssa.OpUnknown 474 v.Aux = nil 475 continue 476 } 477 // Find variable value on each predecessor. 478 args = args[:0] 479 for _, e := range b.Preds { 480 args = append(args, s.lookupVarOutgoing(e.Block(), v.Type, var_, v.Pos)) 481 } 482 483 // Decide if we need a phi or not. We need a phi if there 484 // are two different args (which are both not v). 485 var w *ssa.Value 486 for _, a := range args { 487 if a == v { 488 continue // self-reference 489 } 490 if a == w { 491 continue // already have this witness 492 } 493 if w != nil { 494 // two witnesses, need a phi value 495 v.Op = ssa.OpPhi 496 v.AddArgs(args...) 497 v.Aux = nil 498 continue loop 499 } 500 w = a // save witness 501 } 502 if w == nil { 503 s.s.Fatalf("no witness for reachable phi %s", v) 504 } 505 // One witness. Make v a copy of w. 506 v.Op = ssa.OpCopy 507 v.Aux = nil 508 v.AddArg(w) 509 } 510 } 511 512 // lookupVarOutgoing finds the variable's value at the end of block b. 513 func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t *types.Type, var_ *Node, line src.XPos) *ssa.Value { 514 for { 515 if v := s.defvars[b.ID][var_]; v != nil { 516 return v 517 } 518 // The variable is not defined by b and we haven't looked it up yet. 519 // If b has exactly one predecessor, loop to look it up there. 520 // Otherwise, give up and insert a new FwdRef and resolve it later. 521 if len(b.Preds) != 1 { 522 break 523 } 524 b = b.Preds[0].Block() 525 if !s.reachable[b.ID] { 526 // This is rare; it happens with oddly interleaved infinite loops in dead code. 527 // See issue 19783. 528 break 529 } 530 } 531 // Generate a FwdRef for the variable and return that. 532 v := b.NewValue0A(line, ssa.OpFwdRef, t, var_) 533 s.defvars[b.ID][var_] = v 534 s.s.addNamedValue(var_, v) 535 s.fwdrefs = append(s.fwdrefs, v) 536 return v 537 }