github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/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 // For now, it handles only the trivial case in which a 11 // Value with one or fewer args is only used in a single Block, 12 // and not in a phi value. 13 // TODO: Do something smarter. 14 // A Value can be moved to any block that 15 // dominates all blocks in which it is used. 16 // Figure out when that will be an improvement. 17 func tighten(f *Func) { 18 // For each value, the number of blocks in which it is used. 19 uses := make([]int32, f.NumValues()) 20 21 // For each value, whether that value is ever an arg to a phi value. 22 phi := make([]bool, f.NumValues()) 23 24 // For each value, one block in which that value is used. 25 home := make([]*Block, f.NumValues()) 26 27 changed := true 28 for changed { 29 changed = false 30 31 // Reset uses 32 for i := range uses { 33 uses[i] = 0 34 } 35 // No need to reset home; any relevant values will be written anew anyway. 36 // No need to reset phi; once used in a phi, always used in a phi. 37 38 for _, b := range f.Blocks { 39 for _, v := range b.Values { 40 for _, w := range v.Args { 41 if v.Op == OpPhi { 42 phi[w.ID] = true 43 } 44 uses[w.ID]++ 45 home[w.ID] = b 46 } 47 } 48 if b.Control != nil { 49 uses[b.Control.ID]++ 50 home[b.Control.ID] = b 51 } 52 } 53 54 for _, b := range f.Blocks { 55 for i := 0; i < len(b.Values); i++ { 56 v := b.Values[i] 57 if v.Op == OpPhi || v.Op == OpGetClosurePtr || v.Op == OpConvert || v.Op == OpArg { 58 // GetClosurePtr & Arg must stay in entry block. 59 // OpConvert must not float over call sites. 60 // TODO do we instead need a dependence edge of some sort for OpConvert? 61 // Would memory do the trick, or do we need something else that relates 62 // to safe point operations? 63 continue 64 } 65 if len(v.Args) > 0 && v.Args[len(v.Args)-1].Type.IsMemory() { 66 // We can't move values which have a memory arg - it might 67 // make two memory values live across a block boundary. 68 continue 69 } 70 if uses[v.ID] == 1 && !phi[v.ID] && home[v.ID] != b && len(v.Args) < 2 { 71 // v is used in exactly one block, and it is not b. 72 // Furthermore, it takes at most one input, 73 // so moving it will not increase the 74 // number of live values anywhere. 75 // Move v to that block. 76 c := home[v.ID] 77 c.Values = append(c.Values, v) 78 v.Block = c 79 last := len(b.Values) - 1 80 b.Values[i] = b.Values[last] 81 b.Values[last] = nil 82 b.Values = b.Values[:last] 83 changed = true 84 } 85 } 86 } 87 } 88 }