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  }