Source file src/cmd/compile/internal/ssa/critical.go
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 // critical splits critical edges (those that go from a block with 8 // more than one outedge to a block with more than one inedge). 9 // Regalloc wants a critical-edge-free CFG so it can implement phi values. 10 func critical(f *Func) { 11 // maps from phi arg ID to the new block created for that argument 12 blocks := make([]*Block, f.NumValues()) 13 // need to iterate over f.Blocks without range, as we might 14 // need to split critical edges on newly constructed blocks 15 for j := 0; j < len(f.Blocks); j++ { 16 b := f.Blocks[j] 17 if len(b.Preds) <= 1 { 18 continue 19 } 20 21 var phi *Value 22 // determine if we've only got a single phi in this 23 // block, this is easier to handle than the general 24 // case of a block with multiple phi values. 25 for _, v := range b.Values { 26 if v.Op == OpPhi { 27 if phi != nil { 28 phi = nil 29 break 30 } 31 phi = v 32 } 33 } 34 35 // reset our block map 36 if phi != nil { 37 for _, v := range phi.Args { 38 blocks[v.ID] = nil 39 } 40 } 41 42 // split input edges coming from multi-output blocks. 43 for i := 0; i < len(b.Preds); { 44 e := b.Preds[i] 45 p := e.b 46 pi := e.i 47 if p.Kind == BlockPlain { 48 i++ 49 continue // only single output block 50 } 51 52 var d *Block // new block used to remove critical edge 53 reusedBlock := false // if true, then this is not the first use of this block 54 if phi != nil { 55 argID := phi.Args[i].ID 56 // find or record the block that we used to split 57 // critical edges for this argument 58 if d = blocks[argID]; d == nil { 59 // splitting doesn't necessarily remove the critical edge, 60 // since we're iterating over len(f.Blocks) above, this forces 61 // the new blocks to be re-examined. 62 d = f.NewBlock(BlockPlain) 63 d.Pos = p.Pos 64 blocks[argID] = d 65 if f.pass.debug > 0 { 66 f.Warnl(p.Pos, "split critical edge") 67 } 68 } else { 69 reusedBlock = true 70 } 71 } else { 72 // no existing block, so allocate a new block 73 // to place on the edge 74 d = f.NewBlock(BlockPlain) 75 d.Pos = p.Pos 76 if f.pass.debug > 0 { 77 f.Warnl(p.Pos, "split critical edge") 78 } 79 } 80 81 // if this not the first argument for the 82 // block, then we need to remove the 83 // corresponding elements from the block 84 // predecessors and phi args 85 if reusedBlock { 86 // Add p->d edge 87 p.Succs[pi] = Edge{d, len(d.Preds)} 88 d.Preds = append(d.Preds, Edge{p, pi}) 89 90 // Remove p as a predecessor from b. 91 b.removePred(i) 92 93 // Update corresponding phi args 94 b.removePhiArg(phi, i) 95 96 // splitting occasionally leads to a phi having 97 // a single argument (occurs with -N) 98 // TODO(cuonglm,khr): replace this with phielimValue, and 99 // make removePhiArg incorporates that. 100 if len(b.Preds) == 1 { 101 phi.Op = OpCopy 102 } 103 // Don't increment i in this case because we moved 104 // an unprocessed predecessor down into slot i. 105 } else { 106 // splice it in 107 p.Succs[pi] = Edge{d, 0} 108 b.Preds[i] = Edge{d, 0} 109 d.Preds = append(d.Preds, Edge{p, pi}) 110 d.Succs = append(d.Succs, Edge{b, i}) 111 i++ 112 } 113 } 114 } 115 } 116