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 }