github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/compile/internal/ssa/tighten.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 // tighten moves Values closer to the Blocks in which they are used. 8 // This can reduce the amount of register spilling required, 9 // if it doesn't also create more live values. 10 // A Value can be moved to any block that 11 // dominates all blocks in which it is used. 12 func tighten(f *Func) { 13 canMove := make([]bool, f.NumValues()) 14 for _, b := range f.Blocks { 15 for _, v := range b.Values { 16 if v.Op.isLoweredGetClosurePtr() { 17 // Must stay in the entry block. 18 continue 19 } 20 switch v.Op { 21 case OpPhi, OpArg, OpSelect0, OpSelect1: 22 // Phis need to stay in their block. 23 // Arg must stay in the entry block. 24 // Tuple selectors must stay with the tuple generator. 25 continue 26 } 27 if v.MemoryArg() != nil { 28 // We can't move values which have a memory arg - it might 29 // make two memory values live across a block boundary. 30 continue 31 } 32 // Count arguments which will need a register. 33 narg := 0 34 for _, a := range v.Args { 35 if !a.rematerializeable() { 36 narg++ 37 } 38 } 39 if narg >= 2 && !v.Type.IsFlags() { 40 // Don't move values with more than one input, as that may 41 // increase register pressure. 42 // We make an exception for flags, as we want flag generators 43 // moved next to uses (because we only have 1 flag register). 44 continue 45 } 46 canMove[v.ID] = true 47 } 48 } 49 50 // Build data structure for fast least-common-ancestor queries. 51 lca := makeLCArange(f) 52 53 // For each moveable value, record the block that dominates all uses found so far. 54 target := make([]*Block, f.NumValues()) 55 56 // Grab loop information. 57 // We use this to make sure we don't tighten a value into a (deeper) loop. 58 idom := f.Idom() 59 loops := f.loopnest() 60 loops.calculateDepths() 61 62 changed := true 63 for changed { 64 changed = false 65 66 // Reset target 67 for i := range target { 68 target[i] = nil 69 } 70 71 // Compute target locations (for moveable values only). 72 // target location = the least common ancestor of all uses in the dominator tree. 73 for _, b := range f.Blocks { 74 for _, v := range b.Values { 75 for i, a := range v.Args { 76 if !canMove[a.ID] { 77 continue 78 } 79 use := b 80 if v.Op == OpPhi { 81 use = b.Preds[i].b 82 } 83 if target[a.ID] == nil { 84 target[a.ID] = use 85 } else { 86 target[a.ID] = lca.find(target[a.ID], use) 87 } 88 } 89 } 90 if c := b.Control; c != nil { 91 if !canMove[c.ID] { 92 continue 93 } 94 if target[c.ID] == nil { 95 target[c.ID] = b 96 } else { 97 target[c.ID] = lca.find(target[c.ID], b) 98 } 99 } 100 } 101 102 // If the target location is inside a loop, 103 // move the target location up to just before the loop head. 104 for _, b := range f.Blocks { 105 origloop := loops.b2l[b.ID] 106 for _, v := range b.Values { 107 t := target[v.ID] 108 if t == nil { 109 continue 110 } 111 targetloop := loops.b2l[t.ID] 112 for targetloop != nil && (origloop == nil || targetloop.depth > origloop.depth) { 113 t = idom[targetloop.header.ID] 114 target[v.ID] = t 115 targetloop = loops.b2l[t.ID] 116 } 117 } 118 } 119 120 // Move values to target locations. 121 for _, b := range f.Blocks { 122 for i := 0; i < len(b.Values); i++ { 123 v := b.Values[i] 124 t := target[v.ID] 125 if t == nil || t == b { 126 // v is not moveable, or is already in correct place. 127 continue 128 } 129 // Move v to the block which dominates its uses. 130 t.Values = append(t.Values, v) 131 v.Block = t 132 last := len(b.Values) - 1 133 b.Values[i] = b.Values[last] 134 b.Values[last] = nil 135 b.Values = b.Values[:last] 136 changed = true 137 i-- 138 } 139 } 140 } 141 } 142 143 // phiTighten moves constants closer to phi users. 144 // This pass avoids having lots of constants live for lots of the program. 145 // See issue 16407. 146 func phiTighten(f *Func) { 147 for _, b := range f.Blocks { 148 for _, v := range b.Values { 149 if v.Op != OpPhi { 150 continue 151 } 152 for i, a := range v.Args { 153 if !a.rematerializeable() { 154 continue // not a constant we can move around 155 } 156 if a.Block == b.Preds[i].b { 157 continue // already in the right place 158 } 159 // Make a copy of a, put in predecessor block. 160 v.SetArg(i, a.copyInto(b.Preds[i].b)) 161 } 162 } 163 } 164 }