Home | History | Annotate | Download | only in ssa
      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 }
    161