1
2
3
4
5 package ssa
6
7 import "fmt"
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 func maybeRewriteLoopToDownwardCountingLoop(f *Func, v indVar) {
47 ind := v.ind
48 nxt := v.nxt
49 if !(ind.Uses == 2 &&
50 nxt.Uses == 1) {
51 return
52 }
53
54 start, end := v.min, v.max
55
56 if !start.isGenericIntConst() {
57
58 return
59 }
60 if end.isGenericIntConst() {
61
62
63
64
65
66
67 return
68 }
69
70 if end.Block == ind.Block {
71
72
73 return
74 }
75
76 check := v.entry.Preds[0].b.Controls[0]
77
78 neededRoom := -v.step
79
80
81 if neededRoom < 0 && v.flags&indVarMinExc == 1 {
82 neededRoom++
83 }
84 if neededRoom > 0 && v.flags&indVarMaxInc == 0 {
85 neededRoom--
86 }
87
88 switch check.Op {
89 case OpLess8, OpLess16, OpLess32, OpLess64, OpLeq8, OpLeq16, OpLeq32, OpLeq64:
90 if _, ok := safeAdd(start.AuxInt, neededRoom, uint(start.Type.Size())*8); !ok {
91
92
93 return
94 }
95 case OpLess8U, OpLess16U, OpLess32U, OpLess64U, OpLeq8U, OpLeq16U, OpLeq32U, OpLeq64U:
96 panic(`parseIndVar didn't yet support unsigned induction variables, this code doesn't yet support them either.
97 If you are seeing this it is probably because you've fixed https://go.dev/issue/65918.
98 You need to update this code and add tests then.`)
99 case OpEq8, OpEq16, OpEq32, OpEq64, OpNeq8, OpNeq16, OpNeq32, OpNeq64:
100 panic(`parseIndVar didn't yet support induction variables using == or !=.
101 If you are seeing this it is probably because you've added support for them.
102 You need to update this code and add tests then.`)
103 default:
104 panic(fmt.Sprintf("unreachable; unexpected induction variable comparator %v %v", check, check.Op))
105 }
106
107 idxEnd, idxStart := -1, -1
108 for i, v := range check.Args {
109 if v == end {
110 idxEnd = i
111 break
112 }
113 }
114 for i, v := range ind.Args {
115 if v == start {
116 idxStart = i
117 break
118 }
119 }
120 if idxEnd < 0 || idxStart < 0 {
121 return
122 }
123
124 sdom := f.Sdom()
125
126 if !sdom.IsAncestorEq(end.Block, ind.Block) {
127 return
128 }
129
130
131 check.SetArg(idxEnd, start)
132 ind.SetArg(idxStart, end)
133
134
135 check.Args[0], check.Args[1] = check.Args[1], check.Args[0]
136
137 if nxt.Args[0] != ind {
138
139 nxt.Args[0], nxt.Args[1] = nxt.Args[1], nxt.Args[0]
140 }
141
142 switch nxt.Op {
143 case OpAdd8:
144 nxt.Op = OpSub8
145 case OpAdd16:
146 nxt.Op = OpSub16
147 case OpAdd32:
148 nxt.Op = OpSub32
149 case OpAdd64:
150 nxt.Op = OpSub64
151 case OpSub8:
152 nxt.Op = OpAdd8
153 case OpSub16:
154 nxt.Op = OpAdd16
155 case OpSub32:
156 nxt.Op = OpAdd32
157 case OpSub64:
158 nxt.Op = OpAdd64
159 default:
160 panic("unreachable")
161 }
162
163 if f.pass.debug > 0 {
164 f.Warnl(ind.Pos, "Inverted loop iteration")
165 }
166 }
167
View as plain text