github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/cmd/compile/internal/ssa/trim.go (about)

     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  // trim removes blocks with no code in them.
     8  // These blocks were inserted to remove critical edges.
     9  func trim(f *Func) {
    10  	n := 0
    11  	for _, b := range f.Blocks {
    12  		if !trimmableBlock(b) {
    13  			f.Blocks[n] = b
    14  			n++
    15  			continue
    16  		}
    17  
    18  		// Splice b out of the graph. NOTE: `mergePhi` depends on the
    19  		// order, in which the predecessors edges are merged here.
    20  		p, i := b.Preds[0].b, b.Preds[0].i
    21  		s, j := b.Succs[0].b, b.Succs[0].i
    22  		ns := len(s.Preds)
    23  		p.Succs[i] = Edge{s, j}
    24  		s.Preds[j] = Edge{p, i}
    25  
    26  		for _, e := range b.Preds[1:] {
    27  			p, i := e.b, e.i
    28  			p.Succs[i] = Edge{s, len(s.Preds)}
    29  			s.Preds = append(s.Preds, Edge{p, i})
    30  		}
    31  
    32  		// If `s` had more than one predecessor, update its phi-ops to
    33  		// account for the merge.
    34  		if ns > 1 {
    35  			for _, v := range s.Values {
    36  				if v.Op == OpPhi {
    37  					mergePhi(v, j, b)
    38  				}
    39  			}
    40  			// Remove the phi-ops from `b` if they were merged into the
    41  			// phi-ops of `s`.
    42  			k := 0
    43  			for _, v := range b.Values {
    44  				if v.Op == OpPhi {
    45  					if v.Uses == 0 {
    46  						v.resetArgs()
    47  						continue
    48  					}
    49  					// Pad the arguments of the remaining phi-ops, so
    50  					// they match the new predecessor count of `s`.
    51  					for len(v.Args) < len(s.Preds) {
    52  						v.AddArg(v.Args[0])
    53  					}
    54  				}
    55  				b.Values[k] = v
    56  				k++
    57  			}
    58  			b.Values = b.Values[:k]
    59  		}
    60  
    61  		// Merge the blocks' values.
    62  		for _, v := range b.Values {
    63  			v.Block = s
    64  		}
    65  		k := len(b.Values)
    66  		m := len(s.Values)
    67  		for i := 0; i < k; i++ {
    68  			s.Values = append(s.Values, nil)
    69  		}
    70  		copy(s.Values[k:], s.Values[:m])
    71  		copy(s.Values, b.Values)
    72  	}
    73  	if n < len(f.Blocks) {
    74  		f.invalidateCFG()
    75  		tail := f.Blocks[n:]
    76  		for i := range tail {
    77  			tail[i] = nil
    78  		}
    79  		f.Blocks = f.Blocks[:n]
    80  	}
    81  }
    82  
    83  // emptyBlock returns true if the block does not contain actual
    84  // instructions
    85  func emptyBlock(b *Block) bool {
    86  	for _, v := range b.Values {
    87  		if v.Op != OpPhi {
    88  			return false
    89  		}
    90  	}
    91  	return true
    92  }
    93  
    94  // trimmableBlock returns true if the block can be trimmed from the CFG,
    95  // subject to the following criteria:
    96  //  - it should not be the first block
    97  //  - it should be BlockPlain
    98  //  - it should not loop back to itself
    99  //  - it either is the single predecessor of the successor block or
   100  //    contains no actual instructions
   101  func trimmableBlock(b *Block) bool {
   102  	if b.Kind != BlockPlain || b == b.Func.Entry {
   103  		return false
   104  	}
   105  	s := b.Succs[0].b
   106  	return s != b && (len(s.Preds) == 1 || emptyBlock(b))
   107  }
   108  
   109  // mergePhi adjusts the number of `v`s arguments to account for merge
   110  // of `b`, which was `i`th predecessor of the `v`s block. Returns
   111  // `v`.
   112  func mergePhi(v *Value, i int, b *Block) *Value {
   113  	u := v.Args[i]
   114  	if u.Block == b {
   115  		if u.Op != OpPhi {
   116  			b.Func.Fatalf("value %s is not a phi operation", u.LongString())
   117  		}
   118  		// If the original block contained u = φ(u0, u1, ..., un) and
   119  		// the current phi is
   120  		//    v = φ(v0, v1, ..., u, ..., vk)
   121  		// then the merged phi is
   122  		//    v = φ(v0, v1, ..., u0, ..., vk, u1, ..., un)
   123  		v.SetArg(i, u.Args[0])
   124  		v.AddArgs(u.Args[1:]...)
   125  	} else {
   126  		// If the original block contained u = φ(u0, u1, ..., un) and
   127  		// the current phi is
   128  		//    v = φ(v0, v1, ...,  vi, ..., vk)
   129  		// i.e. it does not use a value from the predecessor block,
   130  		// then the merged phi is
   131  		//    v = φ(v0, v1, ..., vk, vi, vi, ...)
   132  		for j := 1; j < len(b.Preds); j++ {
   133  			v.AddArg(v.Args[i])
   134  		}
   135  	}
   136  	return v
   137  }