github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/ssa/layout.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  // layout orders basic blocks in f with the goal of minimizing control flow instructions.
     8  // After this phase returns, the order of f.Blocks matters and is the order
     9  // in which those blocks will appear in the assembly output.
    10  func layout(f *Func) {
    11  	order := make([]*Block, 0, f.NumBlocks())
    12  	scheduled := make([]bool, f.NumBlocks())
    13  	idToBlock := make([]*Block, f.NumBlocks())
    14  	indegree := make([]int, f.NumBlocks())
    15  	posdegree := f.newSparseSet(f.NumBlocks()) // blocks with positive remaining degree
    16  	defer f.retSparseSet(posdegree)
    17  	zerodegree := f.newSparseSet(f.NumBlocks()) // blocks with zero remaining degree
    18  	defer f.retSparseSet(zerodegree)
    19  
    20  	// Initialize indegree of each block
    21  	for _, b := range f.Blocks {
    22  		idToBlock[b.ID] = b
    23  		indegree[b.ID] = len(b.Preds)
    24  		if len(b.Preds) == 0 {
    25  			zerodegree.add(b.ID)
    26  		} else {
    27  			posdegree.add(b.ID)
    28  		}
    29  	}
    30  
    31  	bid := f.Entry.ID
    32  blockloop:
    33  	for {
    34  		// add block to schedule
    35  		b := idToBlock[bid]
    36  		order = append(order, b)
    37  		scheduled[bid] = true
    38  		if len(order) == len(f.Blocks) {
    39  			break
    40  		}
    41  
    42  		for _, e := range b.Succs {
    43  			c := e.b
    44  			indegree[c.ID]--
    45  			if indegree[c.ID] == 0 {
    46  				posdegree.remove(c.ID)
    47  				zerodegree.add(c.ID)
    48  			}
    49  		}
    50  
    51  		// Pick the next block to schedule
    52  		// Pick among the successor blocks that have not been scheduled yet.
    53  
    54  		// Use likely direction if we have it.
    55  		var likely *Block
    56  		switch b.Likely {
    57  		case BranchLikely:
    58  			likely = b.Succs[0].b
    59  		case BranchUnlikely:
    60  			likely = b.Succs[1].b
    61  		}
    62  		if likely != nil && !scheduled[likely.ID] {
    63  			bid = likely.ID
    64  			continue
    65  		}
    66  
    67  		// Use degree for now.
    68  		bid = 0
    69  		mindegree := f.NumBlocks()
    70  		for _, e := range order[len(order)-1].Succs {
    71  			c := e.b
    72  			if scheduled[c.ID] {
    73  				continue
    74  			}
    75  			if indegree[c.ID] < mindegree {
    76  				mindegree = indegree[c.ID]
    77  				bid = c.ID
    78  			}
    79  		}
    80  		if bid != 0 {
    81  			continue
    82  		}
    83  		// TODO: improve this part
    84  		// No successor of the previously scheduled block works.
    85  		// Pick a zero-degree block if we can.
    86  		for zerodegree.size() > 0 {
    87  			cid := zerodegree.pop()
    88  			if !scheduled[cid] {
    89  				bid = cid
    90  				continue blockloop
    91  			}
    92  		}
    93  		// Still nothing, pick any block.
    94  		for {
    95  			cid := posdegree.pop()
    96  			if !scheduled[cid] {
    97  				bid = cid
    98  				continue blockloop
    99  			}
   100  		}
   101  	}
   102  	f.Blocks = order
   103  }