Source file src/cmd/compile/internal/ssa/licm.go

     1  // Copyright 2016 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  // We are looking for loops with following structure
     8  // (loop bodies may have control flow inside):
     9  //
    10  //              +--------------+
    11  //              |              |
    12  //              |  preheader   |
    13  //              |              |
    14  //              +-------+------+
    15  //                      |
    16  //                      |
    17  //              +-------v------+
    18  //              |              |
    19  //       +------>    header    |
    20  //       |      |              |
    21  //       |      +-------+------+
    22  //       |              |
    23  //       |              |
    24  //       |      +-------v------+
    25  //       |      |              |
    26  //       +------+  loop body   |
    27  //              |              |
    28  //              +--------------+
    29  //
    30  //
    31  // We consider all phis and memory operations as initial loop dependent set.
    32  // So loop independent values are all loop values,
    33  // minus transitive closure of initial loop dependent values.
    34  // We remove those values from their BBs and move them to preheader.
    35  
    36  func licm(f *Func) {
    37  	// See likelyadjust.go for details about loop info.
    38  	nest := loopnestfor(f)
    39  	if len(nest.loops) == 0 || nest.hasIrreducible {
    40  		return
    41  	}
    42  
    43  	uses := uses(f)
    44  	defer uses.free(f)
    45  
    46  	loopDependent := f.Cache.allocBoolSlice(f.NumValues())
    47  	defer f.Cache.freeBoolSlice(loopDependent)
    48  	queue := f.Cache.allocValueSlice(f.NumValues())
    49  	defer f.Cache.freeValueSlice(queue)
    50  	queue = queue[:0]
    51  
    52  	// Start with all values we can't move out of loops.
    53  	for _, b := range f.Blocks {
    54  		if loop := nest.b2l[b.ID]; loop == nil || !loop.isInner {
    55  			// Values outside any loop we don't care about.
    56  			// Values not in a leaf loop we can't handle.
    57  			continue
    58  		}
    59  		for _, v := range b.Values {
    60  			loopDep := false
    61  			if v.Op == OpPhi {
    62  				loopDep = true
    63  			} else if v.Type.IsMemory() {
    64  				// We can't move state-modifying code.
    65  				// (TODO: but maybe this is handled by memory Phis anyway?)
    66  				loopDep = true
    67  			} else if v.Type.IsFlags() || v.Type.IsTuple() && (v.Type.FieldType(0).IsFlags() || v.Type.FieldType(1).IsFlags()) {
    68  				// This is not required for correctness. It is just to
    69  				// keep the live range of flag values low.
    70  				loopDep = true
    71  			} else if opcodeTable[v.Op].nilCheck {
    72  				// NilCheck in case loop executes 0 times. (It has a memory arg anyway?)
    73  				loopDep = true
    74  			} else if v.MemoryArg() != nil {
    75  				// Because the state of memory might be different at the loop start. (Also handled by Phi?)
    76  				loopDep = true
    77  			} else if v.Type.IsPtr() {
    78  				// Can't move pointer arithmetic, as it may be guarded by conditionals
    79  				// and this could materialize a bad pointer across a safepoint.
    80  				loopDep = true
    81  			}
    82  			if loopDep {
    83  				loopDependent[v.ID] = true
    84  				queue = append(queue, v)
    85  			}
    86  		}
    87  	}
    88  
    89  	// If a value can't be moved out of a loop, neither can its users.
    90  	// The queue contains values which are loop dependent, but their users
    91  	// have not been marked as loop dependent yet.
    92  	for len(queue) > 0 {
    93  		v := queue[len(queue)-1]
    94  		queue = queue[:len(queue)-1]
    95  
    96  		for _, u := range uses.get(v) {
    97  			if loop := nest.b2l[u.Block.ID]; loop == nil || !loop.isInner {
    98  				continue // see above
    99  			}
   100  			if loopDependent[u.ID] {
   101  				continue
   102  			}
   103  			loopDependent[u.ID] = true
   104  			queue = append(queue, u)
   105  		}
   106  	}
   107  
   108  	// Anything not marked as loop-dependent can be moved out of its loop.
   109  	for _, b := range f.Blocks {
   110  		loop := nest.b2l[b.ID]
   111  		if loop == nil || !loop.isInner {
   112  			// loopDependent check is wrong for loops containing other loops,
   113  			// because then a value might have an argument computed inside
   114  			// a nested loop.
   115  			continue
   116  		}
   117  		if len(loop.header.Preds) != 2 {
   118  			continue // is never true?
   119  		}
   120  		anyMoved := false
   121  		for i, v := range b.Values {
   122  			if loopDependent[v.ID] {
   123  				continue
   124  			}
   125  			// Figure out where to move loop-independent values.
   126  			h := loop.header
   127  			var inIdx int
   128  			if int(h.Preds[0].b.ID) >= len(nest.b2l) || nest.b2l[h.Preds[0].b.ID] != loop {
   129  				inIdx = 0
   130  			} else {
   131  				inIdx = 1
   132  			}
   133  			dest := h.Preds[inIdx].b
   134  			if dest.Kind != BlockPlain {
   135  				outIdx := h.Preds[inIdx].i
   136  				// Introduce a new block between the loop
   137  				// header predecessor and the loop header itself.
   138  				mid := f.NewBlock(BlockPlain)
   139  				mid.Pos = dest.Pos
   140  				// Splice into graph.
   141  				mid.Preds = append(mid.Preds, Edge{dest, outIdx})
   142  				mid.Succs = append(mid.Succs, Edge{h, inIdx})
   143  				h.Preds[inIdx] = Edge{mid, 0}
   144  				dest.Succs[outIdx] = Edge{mid, 0}
   145  
   146  				dest = mid
   147  			}
   148  
   149  			b.Values[i] = nil
   150  			v.Block = dest
   151  			dest.Values = append(dest.Values, v)
   152  			anyMoved = true
   153  		}
   154  		if anyMoved {
   155  			// We just nil'd entries in b.Values above. Compact out the nils.
   156  			i := 0
   157  			for _, v := range b.Values {
   158  				if v == nil {
   159  					continue
   160  				}
   161  				b.Values[i] = v
   162  				i++
   163  			}
   164  			b.Values = b.Values[:i]
   165  		}
   166  	}
   167  }
   168  

View as plain text