github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/ssa/flagalloc.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 // flagalloc allocates the flag register among all the flag-generating 8 // instructions. Flag values are recomputed if they need to be 9 // spilled/restored. 10 func flagalloc(f *Func) { 11 // Compute the in-register flag value we want at the end of 12 // each block. This is basically a best-effort live variable 13 // analysis, so it can be much simpler than a full analysis. 14 // TODO: do we really need to keep flag values live across blocks? 15 // Could we force the flags register to be unused at basic block 16 // boundaries? Then we wouldn't need this computation. 17 end := make([]*Value, f.NumBlocks()) 18 for n := 0; n < 2; n++ { 19 // Walk blocks backwards. Poor-man's postorder traversal. 20 for i := len(f.Blocks) - 1; i >= 0; i-- { 21 b := f.Blocks[i] 22 // Walk values backwards to figure out what flag 23 // value we want in the flag register at the start 24 // of the block. 25 flag := end[b.ID] 26 if b.Control != nil && b.Control.Type.IsFlags() { 27 flag = b.Control 28 } 29 for j := len(b.Values) - 1; j >= 0; j-- { 30 v := b.Values[j] 31 if v == flag { 32 flag = nil 33 } 34 if opcodeTable[v.Op].clobberFlags { 35 flag = nil 36 } 37 for _, a := range v.Args { 38 if a.Type.IsFlags() { 39 flag = a 40 } 41 } 42 } 43 if flag != nil { 44 for _, e := range b.Preds { 45 p := e.b 46 end[p.ID] = flag 47 } 48 } 49 } 50 } 51 52 // For blocks which have a flags control value, that's the only value 53 // we can leave in the flags register at the end of the block. (There 54 // is no place to put a flag regeneration instruction.) 55 for _, b := range f.Blocks { 56 v := b.Control 57 if v != nil && v.Type.IsFlags() && end[b.ID] != v { 58 end[b.ID] = nil 59 } 60 if b.Kind == BlockDefer { 61 // Defer blocks internally use/clobber the flags value. 62 end[b.ID] = nil 63 } 64 } 65 66 // Add flag recomputations where they are needed. 67 // TODO: Remove original instructions if they are never used. 68 var oldSched []*Value 69 for _, b := range f.Blocks { 70 oldSched = append(oldSched[:0], b.Values...) 71 b.Values = b.Values[:0] 72 // The current live flag value the pre-flagalloc copy). 73 var flag *Value 74 if len(b.Preds) > 0 { 75 flag = end[b.Preds[0].b.ID] 76 // Note: the following condition depends on the lack of critical edges. 77 for _, e := range b.Preds[1:] { 78 p := e.b 79 if end[p.ID] != flag { 80 f.Fatalf("live flag in %s's predecessors not consistent", b) 81 } 82 } 83 } 84 for _, v := range oldSched { 85 if v.Op == OpPhi && v.Type.IsFlags() { 86 f.Fatalf("phi of flags not supported: %s", v.LongString()) 87 } 88 // Make sure any flag arg of v is in the flags register. 89 // If not, recompute it. 90 for i, a := range v.Args { 91 if !a.Type.IsFlags() { 92 continue 93 } 94 if a == flag { 95 continue 96 } 97 // Recalculate a 98 c := copyFlags(a, b) 99 // Update v. 100 v.SetArg(i, c) 101 // Remember the most-recently computed flag value. 102 flag = a 103 } 104 // Issue v. 105 b.Values = append(b.Values, v) 106 if opcodeTable[v.Op].clobberFlags { 107 flag = nil 108 } 109 if v.Type.IsFlags() { 110 flag = v 111 } 112 } 113 if v := b.Control; v != nil && v != flag && v.Type.IsFlags() { 114 // Recalculate control value. 115 c := v.copyInto(b) 116 b.SetControl(c) 117 flag = v 118 } 119 if v := end[b.ID]; v != nil && v != flag { 120 // Need to reissue flag generator for use by 121 // subsequent blocks. 122 copyFlags(v, b) 123 // Note: this flag generator is not properly linked up 124 // with the flag users. This breaks the SSA representation. 125 // We could fix up the users with another pass, but for now 126 // we'll just leave it. (Regalloc has the same issue for 127 // standard regs, and it runs next.) 128 } 129 } 130 131 // Save live flag state for later. 132 for _, b := range f.Blocks { 133 b.FlagsLiveAtEnd = end[b.ID] != nil 134 } 135 } 136 137 // copyFlags copies v (flag generator) into b, returns the copy. 138 // If v's arg is also flags, copy recursively. 139 func copyFlags(v *Value, b *Block) *Value { 140 flagsArgs := make(map[int]*Value) 141 for i, a := range v.Args { 142 if a.Type.IsFlags() || a.Type.IsTuple() { 143 flagsArgs[i] = copyFlags(a, b) 144 } 145 } 146 c := v.copyInto(b) 147 for i, a := range flagsArgs { 148 c.SetArg(i, a) 149 } 150 return c 151 }