github.com/bir3/gocompiler@v0.9.2202/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 := f.Cache.allocValueSlice(f.NumBlocks())
    15  	defer f.Cache.freeValueSlice(end)
    16  	po := f.postorder()
    17  	for n := 0; n < 2; n++ {
    18  		for _, b := range po {
    19  			// Walk values backwards to figure out what flag
    20  			// value we want in the flag register at the start
    21  			// of the block.
    22  			var flag *Value
    23  			for _, c := range b.ControlValues() {
    24  				if c.Type.IsFlags() {
    25  					if flag != nil {
    26  						panic("cannot have multiple controls using flags")
    27  					}
    28  					flag = c
    29  				}
    30  			}
    31  			if flag == nil {
    32  				flag = end[b.ID]
    33  			}
    34  			for j := len(b.Values) - 1; j >= 0; j-- {
    35  				v := b.Values[j]
    36  				if v == flag {
    37  					flag = nil
    38  				}
    39  				if v.clobbersFlags() {
    40  					flag = nil
    41  				}
    42  				for _, a := range v.Args {
    43  					if a.Type.IsFlags() {
    44  						flag = a
    45  					}
    46  				}
    47  			}
    48  			if flag != nil {
    49  				for _, e := range b.Preds {
    50  					p := e.b
    51  					end[p.ID] = flag
    52  				}
    53  			}
    54  		}
    55  	}
    56  
    57  	// For blocks which have a flags control value, that's the only value
    58  	// we can leave in the flags register at the end of the block. (There
    59  	// is no place to put a flag regeneration instruction.)
    60  	for _, b := range f.Blocks {
    61  		if b.Kind == BlockDefer {
    62  			// Defer blocks internally use/clobber the flags value.
    63  			end[b.ID] = nil
    64  			continue
    65  		}
    66  		for _, v := range b.ControlValues() {
    67  			if v.Type.IsFlags() && end[b.ID] != v {
    68  				end[b.ID] = nil
    69  			}
    70  		}
    71  	}
    72  
    73  	// Compute which flags values will need to be spilled.
    74  	spill := map[ID]bool{}
    75  	for _, b := range f.Blocks {
    76  		var flag *Value
    77  		if len(b.Preds) > 0 {
    78  			flag = end[b.Preds[0].b.ID]
    79  		}
    80  		for _, v := range b.Values {
    81  			for _, a := range v.Args {
    82  				if !a.Type.IsFlags() {
    83  					continue
    84  				}
    85  				if a == flag {
    86  					continue
    87  				}
    88  				// a will need to be restored here.
    89  				spill[a.ID] = true
    90  				flag = a
    91  			}
    92  			if v.clobbersFlags() {
    93  				flag = nil
    94  			}
    95  			if v.Type.IsFlags() {
    96  				flag = v
    97  			}
    98  		}
    99  		for _, v := range b.ControlValues() {
   100  			if v != flag && v.Type.IsFlags() {
   101  				spill[v.ID] = true
   102  			}
   103  		}
   104  		if v := end[b.ID]; v != nil && v != flag {
   105  			spill[v.ID] = true
   106  		}
   107  	}
   108  
   109  	// Add flag spill and recomputation where they are needed.
   110  	var remove []*Value // values that should be checked for possible removal
   111  	var oldSched []*Value
   112  	for _, b := range f.Blocks {
   113  		oldSched = append(oldSched[:0], b.Values...)
   114  		b.Values = b.Values[:0]
   115  		// The current live flag value (the pre-flagalloc copy).
   116  		var flag *Value
   117  		if len(b.Preds) > 0 {
   118  			flag = end[b.Preds[0].b.ID]
   119  			// Note: the following condition depends on the lack of critical edges.
   120  			for _, e := range b.Preds[1:] {
   121  				p := e.b
   122  				if end[p.ID] != flag {
   123  					f.Fatalf("live flag in %s's predecessors not consistent", b)
   124  				}
   125  			}
   126  		}
   127  		for _, v := range oldSched {
   128  			if v.Op == OpPhi && v.Type.IsFlags() {
   129  				f.Fatalf("phi of flags not supported: %s", v.LongString())
   130  			}
   131  
   132  			// If v will be spilled, and v uses memory, then we must split it
   133  			// into a load + a flag generator.
   134  			if spill[v.ID] && v.MemoryArg() != nil {
   135  				remove = append(remove, v)
   136  				if !f.Config.splitLoad(v) {
   137  					f.Fatalf("can't split flag generator: %s", v.LongString())
   138  				}
   139  			}
   140  
   141  			// Make sure any flag arg of v is in the flags register.
   142  			// If not, recompute it.
   143  			for i, a := range v.Args {
   144  				if !a.Type.IsFlags() {
   145  					continue
   146  				}
   147  				if a == flag {
   148  					continue
   149  				}
   150  				// Recalculate a
   151  				c := copyFlags(a, b)
   152  				// Update v.
   153  				v.SetArg(i, c)
   154  				// Remember the most-recently computed flag value.
   155  				flag = a
   156  			}
   157  			// Issue v.
   158  			b.Values = append(b.Values, v)
   159  			if v.clobbersFlags() {
   160  				flag = nil
   161  			}
   162  			if v.Type.IsFlags() {
   163  				flag = v
   164  			}
   165  		}
   166  		for i, v := range b.ControlValues() {
   167  			if v != flag && v.Type.IsFlags() {
   168  				// Recalculate control value.
   169  				remove = append(remove, v)
   170  				c := copyFlags(v, b)
   171  				b.ReplaceControl(i, c)
   172  				flag = v
   173  			}
   174  		}
   175  		if v := end[b.ID]; v != nil && v != flag {
   176  			// Need to reissue flag generator for use by
   177  			// subsequent blocks.
   178  			remove = append(remove, v)
   179  			copyFlags(v, b)
   180  			// Note: this flag generator is not properly linked up
   181  			// with the flag users. This breaks the SSA representation.
   182  			// We could fix up the users with another pass, but for now
   183  			// we'll just leave it. (Regalloc has the same issue for
   184  			// standard regs, and it runs next.)
   185  			// For this reason, take care not to add this flag
   186  			// generator to the remove list.
   187  		}
   188  	}
   189  
   190  	// Save live flag state for later.
   191  	for _, b := range f.Blocks {
   192  		b.FlagsLiveAtEnd = end[b.ID] != nil
   193  	}
   194  
   195  	// Remove any now-dead values.
   196  	// The number of values to remove is likely small,
   197  	// and removing them requires processing all values in a block,
   198  	// so minimize the number of blocks that we touch.
   199  
   200  	// Shrink remove to contain only dead values, and clobber those dead values.
   201  	for i := 0; i < len(remove); i++ {
   202  		v := remove[i]
   203  		if v.Uses == 0 {
   204  			v.reset(OpInvalid)
   205  			continue
   206  		}
   207  		// Remove v.
   208  		last := len(remove) - 1
   209  		remove[i] = remove[last]
   210  		remove[last] = nil
   211  		remove = remove[:last]
   212  		i-- // reprocess value at i
   213  	}
   214  
   215  	if len(remove) == 0 {
   216  		return
   217  	}
   218  
   219  	removeBlocks := f.newSparseSet(f.NumBlocks())
   220  	defer f.retSparseSet(removeBlocks)
   221  	for _, v := range remove {
   222  		removeBlocks.add(v.Block.ID)
   223  	}
   224  
   225  	// Process affected blocks, preserving value order.
   226  	for _, b := range f.Blocks {
   227  		if !removeBlocks.contains(b.ID) {
   228  			continue
   229  		}
   230  		i := 0
   231  		for j := 0; j < len(b.Values); j++ {
   232  			v := b.Values[j]
   233  			if v.Op == OpInvalid {
   234  				continue
   235  			}
   236  			b.Values[i] = v
   237  			i++
   238  		}
   239  		b.truncateValues(i)
   240  	}
   241  }
   242  
   243  func (v *Value) clobbersFlags() bool {
   244  	if opcodeTable[v.Op].clobberFlags {
   245  		return true
   246  	}
   247  	if v.Type.IsTuple() && (v.Type.FieldType(0).IsFlags() || v.Type.FieldType(1).IsFlags()) {
   248  		// This case handles the possibility where a flag value is generated but never used.
   249  		// In that case, there's no corresponding Select to overwrite the flags value,
   250  		// so we must consider flags clobbered by the tuple-generating instruction.
   251  		return true
   252  	}
   253  	return false
   254  }
   255  
   256  // copyFlags copies v (flag generator) into b, returns the copy.
   257  // If v's arg is also flags, copy recursively.
   258  func copyFlags(v *Value, b *Block) *Value {
   259  	flagsArgs := make(map[int]*Value)
   260  	for i, a := range v.Args {
   261  		if a.Type.IsFlags() || a.Type.IsTuple() {
   262  			flagsArgs[i] = copyFlags(a, b)
   263  		}
   264  	}
   265  	c := v.copyInto(b)
   266  	for i, a := range flagsArgs {
   267  		c.SetArg(i, a)
   268  	}
   269  	return c
   270  }