github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/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 exit := f.newSparseSet(f.NumBlocks()) // exit blocks 20 defer f.retSparseSet(exit) 21 22 // Initialize indegree of each block 23 for _, b := range f.Blocks { 24 idToBlock[b.ID] = b 25 if b.Kind == BlockExit { 26 // exit blocks are always scheduled last 27 // TODO: also add blocks post-dominated by exit blocks 28 exit.add(b.ID) 29 continue 30 } 31 indegree[b.ID] = len(b.Preds) 32 if len(b.Preds) == 0 { 33 zerodegree.add(b.ID) 34 } else { 35 posdegree.add(b.ID) 36 } 37 } 38 39 bid := f.Entry.ID 40 blockloop: 41 for { 42 // add block to schedule 43 b := idToBlock[bid] 44 order = append(order, b) 45 scheduled[bid] = true 46 if len(order) == len(f.Blocks) { 47 break 48 } 49 50 for _, e := range b.Succs { 51 c := e.b 52 indegree[c.ID]-- 53 if indegree[c.ID] == 0 { 54 posdegree.remove(c.ID) 55 zerodegree.add(c.ID) 56 } 57 } 58 59 // Pick the next block to schedule 60 // Pick among the successor blocks that have not been scheduled yet. 61 62 // Use likely direction if we have it. 63 var likely *Block 64 switch b.Likely { 65 case BranchLikely: 66 likely = b.Succs[0].b 67 case BranchUnlikely: 68 likely = b.Succs[1].b 69 } 70 if likely != nil && !scheduled[likely.ID] { 71 bid = likely.ID 72 continue 73 } 74 75 // Use degree for now. 76 bid = 0 77 mindegree := f.NumBlocks() 78 for _, e := range order[len(order)-1].Succs { 79 c := e.b 80 if scheduled[c.ID] || c.Kind == BlockExit { 81 continue 82 } 83 if indegree[c.ID] < mindegree { 84 mindegree = indegree[c.ID] 85 bid = c.ID 86 } 87 } 88 if bid != 0 { 89 continue 90 } 91 // TODO: improve this part 92 // No successor of the previously scheduled block works. 93 // Pick a zero-degree block if we can. 94 for zerodegree.size() > 0 { 95 cid := zerodegree.pop() 96 if !scheduled[cid] { 97 bid = cid 98 continue blockloop 99 } 100 } 101 // Still nothing, pick any non-exit block. 102 for posdegree.size() > 0 { 103 cid := posdegree.pop() 104 if !scheduled[cid] { 105 bid = cid 106 continue blockloop 107 } 108 } 109 // Pick any exit block. 110 // TODO: Order these to minimize jump distances? 111 for { 112 cid := exit.pop() 113 if !scheduled[cid] { 114 bid = cid 115 continue blockloop 116 } 117 } 118 } 119 f.Blocks = order 120 }