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