liyujie
2025-08-28 d9927380ed7c8366f762049be9f3fee225860833
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
 
package ssa
 
// loopRotate converts loops with a check-loop-condition-at-beginning
// to loops with a check-loop-condition-at-end.
// This helps loops avoid extra unnecessary jumps.
//
//   loop:
//     CMPQ ...
//     JGE exit
//     ...
//     JMP loop
//   exit:
//
//    JMP entry
//  loop:
//    ...
//  entry:
//    CMPQ ...
//    JLT loop
func loopRotate(f *Func) {
   loopnest := f.loopnest()
   if loopnest.hasIrreducible {
       return
   }
   if len(loopnest.loops) == 0 {
       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 blocks that should
   // come right after it.
   after := map[ID][]*Block{}
 
   // Check each loop header and decide if we want to move it.
   for _, loop := range loopnest.loops {
       b := loop.header
       var p *Block // b's in-loop predecessor
       for _, e := range b.Preds {
           if e.b.Kind != BlockPlain {
               continue
           }
           if loopnest.b2l[e.b.ID] != loop {
               continue
           }
           p = e.b
       }
       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 predecessor 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.
       for _, b := range after[p.ID] {
           move[b.ID] = struct{}{}
       }
   }
 
   // Move blocks to their destinations in a single pass.
   // We rely here on the fact that loop headers must come
   // before the rest of the loop.  And that relies on the
   // fact that we only identify reducible loops.
   j := 0
   for i, b := range f.Blocks {
       if _, ok := move[b.ID]; ok {
           continue
       }
       f.Blocks[j] = b
       j++
       for _, a := range after[b.ID] {
           if j > i {
               f.Fatalf("head before tail in loop %s", b)
           }
           f.Blocks[j] = a
           j++
       }
   }
   if j != len(f.Blocks) {
       f.Fatalf("bad reordering in looprotate")
   }
}