github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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  			var flag *Value
    22  			for _, c := range b.ControlValues() {
    23  				if c.Type.IsFlags() {
    24  					if flag != nil {
    25  						panic("cannot have multiple controls using flags")
    26  					}
    27  					flag = c
    28  				}
    29  			}
    30  			if flag == nil {
    31  				flag = end[b.ID]
    32  			}
    33  			for j := len(b.Values) - 1; j >= 0; j-- {
    34  				v := b.Values[j]
    35  				if v == flag {
    36  					flag = nil
    37  				}
    38  				if v.clobbersFlags() {
    39  					flag = nil
    40  				}
    41  				for _, a := range v.Args {
    42  					if a.Type.IsFlags() {
    43  						flag = a
    44  					}
    45  				}
    46  			}
    47  			if flag != nil {
    48  				for _, e := range b.Preds {
    49  					p := e.b
    50  					end[p.ID] = flag
    51  				}
    52  			}
    53  		}
    54  	}
    55  
    56  	// For blocks which have a flags control value, that's the only value
    57  	// we can leave in the flags register at the end of the block. (There
    58  	// is no place to put a flag regeneration instruction.)
    59  	for _, b := range f.Blocks {
    60  		if b.Kind == BlockDefer {
    61  			// Defer blocks internally use/clobber the flags value.
    62  			end[b.ID] = nil
    63  			continue
    64  		}
    65  		for _, v := range b.ControlValues() {
    66  			if v.Type.IsFlags() && end[b.ID] != v {
    67  				end[b.ID] = nil
    68  			}
    69  		}
    70  	}
    71  
    72  	// Compute which flags values will need to be spilled.
    73  	spill := map[ID]bool{}
    74  	for _, b := range f.Blocks {
    75  		var flag *Value
    76  		if len(b.Preds) > 0 {
    77  			flag = end[b.Preds[0].b.ID]
    78  		}
    79  		for _, v := range b.Values {
    80  			for _, a := range v.Args {
    81  				if !a.Type.IsFlags() {
    82  					continue
    83  				}
    84  				if a == flag {
    85  					continue
    86  				}
    87  				// a will need to be restored here.
    88  				spill[a.ID] = true
    89  				flag = a
    90  			}
    91  			if v.clobbersFlags() {
    92  				flag = nil
    93  			}
    94  			if v.Type.IsFlags() {
    95  				flag = v
    96  			}
    97  		}
    98  		for _, v := range b.ControlValues() {
    99  			if v != flag && v.Type.IsFlags() {
   100  				spill[v.ID] = true
   101  			}
   102  		}
   103  		if v := end[b.ID]; v != nil && v != flag {
   104  			spill[v.ID] = true
   105  		}
   106  	}
   107  
   108  	// Add flag spill and recomputation where they are needed.
   109  	// TODO: Remove original instructions if they are never used.
   110  	var oldSched []*Value
   111  	for _, b := range f.Blocks {
   112  		oldSched = append(oldSched[:0], b.Values...)
   113  		b.Values = b.Values[:0]
   114  		// The current live flag value (the pre-flagalloc copy).
   115  		var flag *Value
   116  		if len(b.Preds) > 0 {
   117  			flag = end[b.Preds[0].b.ID]
   118  			// Note: the following condition depends on the lack of critical edges.
   119  			for _, e := range b.Preds[1:] {
   120  				p := e.b
   121  				if end[p.ID] != flag {
   122  					f.Fatalf("live flag in %s's predecessors not consistent", b)
   123  				}
   124  			}
   125  		}
   126  		for _, v := range oldSched {
   127  			if v.Op == OpPhi && v.Type.IsFlags() {
   128  				f.Fatalf("phi of flags not supported: %s", v.LongString())
   129  			}
   130  
   131  			// If v will be spilled, and v uses memory, then we must split it
   132  			// into a load + a flag generator.
   133  			if spill[v.ID] && v.MemoryArg() != nil {
   134  				if !f.Config.splitLoad(v) {
   135  					f.Fatalf("can't split flag generator: %s", v.LongString())
   136  				}
   137  			}
   138  
   139  			// Make sure any flag arg of v is in the flags register.
   140  			// If not, recompute it.
   141  			for i, a := range v.Args {
   142  				if !a.Type.IsFlags() {
   143  					continue
   144  				}
   145  				if a == flag {
   146  					continue
   147  				}
   148  				// Recalculate a
   149  				c := copyFlags(a, b)
   150  				// Update v.
   151  				v.SetArg(i, c)
   152  				// Remember the most-recently computed flag value.
   153  				flag = a
   154  			}
   155  			// Issue v.
   156  			b.Values = append(b.Values, v)
   157  			if v.clobbersFlags() {
   158  				flag = nil
   159  			}
   160  			if v.Type.IsFlags() {
   161  				flag = v
   162  			}
   163  		}
   164  		for i, v := range b.ControlValues() {
   165  			if v != flag && v.Type.IsFlags() {
   166  				// Recalculate control value.
   167  				c := copyFlags(v, b)
   168  				b.ReplaceControl(i, c)
   169  				flag = v
   170  			}
   171  		}
   172  		if v := end[b.ID]; v != nil && v != flag {
   173  			// Need to reissue flag generator for use by
   174  			// subsequent blocks.
   175  			copyFlags(v, b)
   176  			// Note: this flag generator is not properly linked up
   177  			// with the flag users. This breaks the SSA representation.
   178  			// We could fix up the users with another pass, but for now
   179  			// we'll just leave it.  (Regalloc has the same issue for
   180  			// standard regs, and it runs next.)
   181  		}
   182  	}
   183  
   184  	// Save live flag state for later.
   185  	for _, b := range f.Blocks {
   186  		b.FlagsLiveAtEnd = end[b.ID] != nil
   187  	}
   188  }
   189  
   190  func (v *Value) clobbersFlags() bool {
   191  	if opcodeTable[v.Op].clobberFlags {
   192  		return true
   193  	}
   194  	if v.Type.IsTuple() && (v.Type.FieldType(0).IsFlags() || v.Type.FieldType(1).IsFlags()) {
   195  		// This case handles the possibility where a flag value is generated but never used.
   196  		// In that case, there's no corresponding Select to overwrite the flags value,
   197  		// so we must consider flags clobbered by the tuple-generating instruction.
   198  		return true
   199  	}
   200  	return false
   201  }
   202  
   203  // copyFlags copies v (flag generator) into b, returns the copy.
   204  // If v's arg is also flags, copy recursively.
   205  func copyFlags(v *Value, b *Block) *Value {
   206  	flagsArgs := make(map[int]*Value)
   207  	for i, a := range v.Args {
   208  		if a.Type.IsFlags() || a.Type.IsTuple() {
   209  			flagsArgs[i] = copyFlags(a, b)
   210  		}
   211  	}
   212  	c := v.copyInto(b)
   213  	for i, a := range flagsArgs {
   214  		c.SetArg(i, a)
   215  	}
   216  	return c
   217  }