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