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