//
// Choose the first/innermost such h.
//
- // IF s itself dominates b, the s is a loop header;
+ // IF s itself dominates b, then s is a loop header;
// and there may be more than one such s.
// Since there's at most 2 successors, the inner/outer ordering
// between them can be established with simple comparisons.
return
}
+ idToIdx := make([]int, f.NumBlocks())
+ for i, b := range f.Blocks {
+ idToIdx[b.ID] = i
+ }
+
// Set of blocks we're moving, by ID.
move := map[ID]struct{}{}
- // Map from block ID to the moving block that should
+ // Map from block ID to the moving blocks that should
// come right after it.
- after := map[ID]*Block{}
+ after := map[ID][]*Block{}
// Check each loop header and decide if we want to move it.
for _, loop := range loopnest.loops {
if p == nil || p == b {
continue
}
+ after[p.ID] = []*Block{b}
+ for {
+ nextIdx := idToIdx[b.ID] + 1
+ if nextIdx >= len(f.Blocks) { // reached end of function (maybe impossible?)
+ break
+ }
+ nextb := f.Blocks[nextIdx]
+ if nextb == p { // original loop precedessor is next
+ break
+ }
+ if loopnest.b2l[nextb.ID] != loop { // about to leave loop
+ break
+ }
+ after[p.ID] = append(after[p.ID], nextb)
+ b = nextb
+ }
// Place b after p.
- move[b.ID] = struct{}{}
- after[p.ID] = b
+ for _, b := range after[p.ID] {
+ move[b.ID] = struct{}{}
+ }
}
// Move blocks to their destinations in a single pass.
}
f.Blocks[j] = b
j++
- if a := after[b.ID]; a != nil {
+ for _, a := range after[b.ID] {
if j > i {
f.Fatalf("head before tail in loop %s", b)
}