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