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