github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 _, c := range b.Succs {
    43  			indegree[c.ID]--
    44  			if indegree[c.ID] == 0 {
    45  				posdegree.remove(c.ID)
    46  				zerodegree.add(c.ID)
    47  			}
    48  		}
    49  
    50  		// Pick the next block to schedule
    51  		// Pick among the successor blocks that have not been scheduled yet.
    52  
    53  		// Use likely direction if we have it.
    54  		var likely *Block
    55  		switch b.Likely {
    56  		case BranchLikely:
    57  			likely = b.Succs[0]
    58  		case BranchUnlikely:
    59  			likely = b.Succs[1]
    60  		}
    61  		if likely != nil && !scheduled[likely.ID] {
    62  			bid = likely.ID
    63  			continue
    64  		}
    65  
    66  		// Use degree for now.
    67  		bid = 0
    68  		mindegree := f.NumBlocks()
    69  		for _, c := range order[len(order)-1].Succs {
    70  			if scheduled[c.ID] {
    71  				continue
    72  			}
    73  			if indegree[c.ID] < mindegree {
    74  				mindegree = indegree[c.ID]
    75  				bid = c.ID
    76  			}
    77  		}
    78  		if bid != 0 {
    79  			continue
    80  		}
    81  		// TODO: improve this part
    82  		// No successor of the previously scheduled block works.
    83  		// Pick a zero-degree block if we can.
    84  		for zerodegree.size() > 0 {
    85  			cid := zerodegree.pop()
    86  			if !scheduled[cid] {
    87  				bid = cid
    88  				continue blockloop
    89  			}
    90  		}
    91  		// Still nothing, pick any block.
    92  		for {
    93  			cid := posdegree.pop()
    94  			if !scheduled[cid] {
    95  				bid = cid
    96  				continue blockloop
    97  			}
    98  		}
    99  	}
   100  	f.Blocks = order
   101  }