annotate gcc/config/sh/sh_treg_combine.cc @ 143:76e1cf5455ef

add cbc_gc test
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sun, 23 Dec 2018 19:24:05 +0900
parents 84e7813d76e9
children 1830386684a0
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* An SH specific RTL pass that tries to combine comparisons and redundant
kono
parents:
diff changeset
2 condition code register stores across multiple basic blocks.
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
3 Copyright (C) 2013-2018 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify
kono
parents:
diff changeset
8 it under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
9 the Free Software Foundation; either version 3, or (at your option)
kono
parents:
diff changeset
10 any later version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful,
kono
parents:
diff changeset
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kono
parents:
diff changeset
15 GNU General Public License for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
21 #define IN_TARGET_CODE 1
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
22
111
kono
parents:
diff changeset
23 #include "config.h"
kono
parents:
diff changeset
24 #define INCLUDE_ALGORITHM
kono
parents:
diff changeset
25 #define INCLUDE_LIST
kono
parents:
diff changeset
26 #define INCLUDE_VECTOR
kono
parents:
diff changeset
27 #include "system.h"
kono
parents:
diff changeset
28 #include "coretypes.h"
kono
parents:
diff changeset
29 #include "backend.h"
kono
parents:
diff changeset
30 #include "target.h"
kono
parents:
diff changeset
31 #include "rtl.h"
kono
parents:
diff changeset
32 #include "tree.h"
kono
parents:
diff changeset
33 #include "memmodel.h"
kono
parents:
diff changeset
34 #include "optabs.h"
kono
parents:
diff changeset
35 #include "emit-rtl.h"
kono
parents:
diff changeset
36 #include "recog.h"
kono
parents:
diff changeset
37 #include "cfgrtl.h"
kono
parents:
diff changeset
38 #include "tree-pass.h"
kono
parents:
diff changeset
39 #include "expr.h"
kono
parents:
diff changeset
40
kono
parents:
diff changeset
41 /*
kono
parents:
diff changeset
42 This pass tries to optimize for example this:
kono
parents:
diff changeset
43 mov.l @(4,r4),r1
kono
parents:
diff changeset
44 tst r1,r1
kono
parents:
diff changeset
45 movt r1
kono
parents:
diff changeset
46 tst r1,r1
kono
parents:
diff changeset
47 bt/s .L5
kono
parents:
diff changeset
48
kono
parents:
diff changeset
49 into something simpler:
kono
parents:
diff changeset
50 mov.l @(4,r4),r1
kono
parents:
diff changeset
51 tst r1,r1
kono
parents:
diff changeset
52 bf/s .L5
kono
parents:
diff changeset
53
kono
parents:
diff changeset
54 Such sequences can be identified by looking for conditional branches and
kono
parents:
diff changeset
55 checking whether the ccreg is set before the conditional branch
kono
parents:
diff changeset
56 by testing another register for != 0, which was set by a ccreg store.
kono
parents:
diff changeset
57 This can be optimized by eliminating the redundant comparison and
kono
parents:
diff changeset
58 inverting the branch condition. There can be multiple comparisons in
kono
parents:
diff changeset
59 different basic blocks that all end up in the redunant test insn before the
kono
parents:
diff changeset
60 conditional branch. Some example RTL ...
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 Example 1)
kono
parents:
diff changeset
63 ----------
kono
parents:
diff changeset
64
kono
parents:
diff changeset
65 [bb 3]
kono
parents:
diff changeset
66 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 0)))
kono
parents:
diff changeset
67 (set (reg:SI 167) (xor:SI (reg:SI 147 t) (const_int 1)))
kono
parents:
diff changeset
68 -> bb 5
kono
parents:
diff changeset
69
kono
parents:
diff changeset
70 [bb 4]
kono
parents:
diff changeset
71 (set (reg:SI 147 t) (eq:SI (reg:SI 177) (const_int 0)))
kono
parents:
diff changeset
72 (set (reg:SI 167) (reg:SI 147 t))
kono
parents:
diff changeset
73 -> bb 5
kono
parents:
diff changeset
74
kono
parents:
diff changeset
75 [bb 5]
kono
parents:
diff changeset
76 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
kono
parents:
diff changeset
77 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
kono
parents:
diff changeset
78 (label_ref:SI 50) (pc)))
kono
parents:
diff changeset
79
kono
parents:
diff changeset
80 In [bb 4] elimination of the comparison would require inversion of the branch
kono
parents:
diff changeset
81 condition and compensation of other BBs.
kono
parents:
diff changeset
82 Instead the comparison in [bb 3] can be replaced with the comparison in [bb 5]
kono
parents:
diff changeset
83 by using a reg-reg move. In [bb 4] a logical not is used to compensate the
kono
parents:
diff changeset
84 inverted condition.
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 [bb 3]
kono
parents:
diff changeset
87 (set (reg:SI 167) (reg:SI 173))
kono
parents:
diff changeset
88 -> bb 5
kono
parents:
diff changeset
89
kono
parents:
diff changeset
90 [BB 4]
kono
parents:
diff changeset
91 (set (reg:SI 147 t) (eq:SI (reg:SI 177) (const_int 0)))
kono
parents:
diff changeset
92 (set (reg:SI 167) (reg:SI 147 t))
kono
parents:
diff changeset
93 -> bb 5
kono
parents:
diff changeset
94
kono
parents:
diff changeset
95 [bb 5]
kono
parents:
diff changeset
96 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
kono
parents:
diff changeset
97 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0)))
kono
parents:
diff changeset
98 (label_ref:SI 50) (pc)))
kono
parents:
diff changeset
99
kono
parents:
diff changeset
100
kono
parents:
diff changeset
101 Example 2)
kono
parents:
diff changeset
102 ----------
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 [bb 3]
kono
parents:
diff changeset
105 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
kono
parents:
diff changeset
106 (set (reg:SI 167) (reg:SI 147 t))
kono
parents:
diff changeset
107 -> bb 5
kono
parents:
diff changeset
108
kono
parents:
diff changeset
109 [bb 4]
kono
parents:
diff changeset
110 (set (reg:SI 147 t) (gt:SI (reg:SI 177) (reg:SI 179)))
kono
parents:
diff changeset
111 (set (reg:SI 167) (reg:SI 147 t))
kono
parents:
diff changeset
112 -> bb 5
kono
parents:
diff changeset
113
kono
parents:
diff changeset
114 [bb 5]
kono
parents:
diff changeset
115 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
kono
parents:
diff changeset
116 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
kono
parents:
diff changeset
117 (label_ref:SI 51) (pc)))
kono
parents:
diff changeset
118
kono
parents:
diff changeset
119 The common comparison is factored out and the branch condition is inverted:
kono
parents:
diff changeset
120
kono
parents:
diff changeset
121 [bb 3]
kono
parents:
diff changeset
122 (set (reg:SI 167) (reg:SI 173))
kono
parents:
diff changeset
123 (set (reg:SI 200) (reg:SI 175))
kono
parents:
diff changeset
124 -> bb 5
kono
parents:
diff changeset
125
kono
parents:
diff changeset
126 [bb 4]
kono
parents:
diff changeset
127 (set (reg:SI 167) (reg:SI 177))
kono
parents:
diff changeset
128 (set (reg:SI 200) (reg:SI 179))
kono
parents:
diff changeset
129 -> bb 5
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 [bb 5]
kono
parents:
diff changeset
132 (set (reg:SI 147 t) (gt:SI (reg:SI 167) (reg:SI 200)))
kono
parents:
diff changeset
133 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0))
kono
parents:
diff changeset
134 (label_ref:SI 51) (pc)))
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136
kono
parents:
diff changeset
137 Example 3)
kono
parents:
diff changeset
138 ----------
kono
parents:
diff changeset
139
kono
parents:
diff changeset
140 [bb 3]
kono
parents:
diff changeset
141 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
kono
parents:
diff changeset
142 (set (reg:SI 167) (reg:SI 147 t))
kono
parents:
diff changeset
143 -> bb 5
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 [bb 4]
kono
parents:
diff changeset
146 (set (reg:SI 147 t) (ge:SI (reg:SI 179) (reg:SI 177)))
kono
parents:
diff changeset
147 (set (reg:SI 167) (reg:SI 147 t))
kono
parents:
diff changeset
148 -> bb 5
kono
parents:
diff changeset
149
kono
parents:
diff changeset
150 [bb 5]
kono
parents:
diff changeset
151 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
kono
parents:
diff changeset
152 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
kono
parents:
diff changeset
153 (label_ref:SI 51) (pc)))
kono
parents:
diff changeset
154
kono
parents:
diff changeset
155 The T bit lifetime is extended and the branch condition is inverted:
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 [bb 3]
kono
parents:
diff changeset
158 (set (reg:SI 147 t) (gt:SI (reg:SI 173) (reg:SI 175)))
kono
parents:
diff changeset
159 -> bb 5
kono
parents:
diff changeset
160
kono
parents:
diff changeset
161 [bb 4]
kono
parents:
diff changeset
162 (set (reg:SI 147 t) (ge:SI (reg:SI 179) (reg:SI 177)))
kono
parents:
diff changeset
163 -> bb 5
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 [bb 5]
kono
parents:
diff changeset
166 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0))
kono
parents:
diff changeset
167 (label_ref:SI 51) (pc)))
kono
parents:
diff changeset
168
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 Example 4)
kono
parents:
diff changeset
171 ----------
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 [bb 3]
kono
parents:
diff changeset
174 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 5)))
kono
parents:
diff changeset
175 (set (reg:SI 167) (reg:SI 147 t))
kono
parents:
diff changeset
176 -> bb 5
kono
parents:
diff changeset
177
kono
parents:
diff changeset
178 [bb 4]
kono
parents:
diff changeset
179 (set (reg:SI 147 t) (eq:SI (reg:SI 176) (const_int 5)))
kono
parents:
diff changeset
180 (set (reg:SI 167) (xor:SI (reg:SI 147 t) (const_int 1)))
kono
parents:
diff changeset
181 -> bb 5
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 [bb 5]
kono
parents:
diff changeset
184 (set (reg:SI 147 t) (eq:SI (reg:SI 167) (const_int 0)))
kono
parents:
diff changeset
185 (set (pc) (if_then_else (ne (reg:SI 147 t) (const_int 0))
kono
parents:
diff changeset
186 (label_ref:SI 50) (pc)))
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188 In this case the comparisons are the same and could be combined, but the
kono
parents:
diff changeset
189 branch condition is different for [bb 3] and [bb 5]. Since the comparison
kono
parents:
diff changeset
190 is not a zero comparison, we can't negate one of the operands. The best thing
kono
parents:
diff changeset
191 we can do here is to eliminate the comparison before the cbranch and invert
kono
parents:
diff changeset
192 the ccreg in one of the BBs. On SH2A this will utilize the 'nott' instruction.
kono
parents:
diff changeset
193
kono
parents:
diff changeset
194 [bb 3]
kono
parents:
diff changeset
195 (set (reg:SI 147 t) (eq:SI (reg:SI 173) (const_int 5)))
kono
parents:
diff changeset
196 -> bb 5
kono
parents:
diff changeset
197
kono
parents:
diff changeset
198 [bb 4]
kono
parents:
diff changeset
199 (set (reg:SI 147 t) (eq:SI (reg:SI 176) (const_int 5)))
kono
parents:
diff changeset
200 (set (reg:SI 147 t) (xor:SI (reg:SI 147 t) (const_int 1)))
kono
parents:
diff changeset
201 -> bb 5
kono
parents:
diff changeset
202
kono
parents:
diff changeset
203 [bb 5]
kono
parents:
diff changeset
204 (set (pc) (if_then_else (eq (reg:SI 147 t) (const_int 0)) // inverted
kono
parents:
diff changeset
205 (label_ref:SI 50) (pc)))
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207
kono
parents:
diff changeset
208 In order to handle cases such as above the RTL pass does the following:
kono
parents:
diff changeset
209
kono
parents:
diff changeset
210 - Find the ccreg sets (comparisons) and ccreg stores
kono
parents:
diff changeset
211 (inverting and non-inverting) in all related BBs.
kono
parents:
diff changeset
212
kono
parents:
diff changeset
213 - If the comparison types in the BBs are all the same, try to combine the
kono
parents:
diff changeset
214 comparisons in the BBs and replace the zero comparison before the cbranch
kono
parents:
diff changeset
215 with the common comparison.
kono
parents:
diff changeset
216
kono
parents:
diff changeset
217 - If the cstores are the same, move the comparison before the cbranch
kono
parents:
diff changeset
218 and replace the comparisons in the BBs with reg-reg copies to get the
kono
parents:
diff changeset
219 operands in place (create new pseudo regs).
kono
parents:
diff changeset
220
kono
parents:
diff changeset
221 - If the cstores differ and the comparison is a test against zero,
kono
parents:
diff changeset
222 use reg-reg copies for the dominating cstores and logical not cstores
kono
parents:
diff changeset
223 for the subordinate cstores.
kono
parents:
diff changeset
224
kono
parents:
diff changeset
225 - If the comparison types in the BBs are not the same, or the first approach
kono
parents:
diff changeset
226 doesn't work out for some reason, try to eliminate the comparison before the
kono
parents:
diff changeset
227 cbranch by extending the lifetime of the ccreg by leaving the individual
kono
parents:
diff changeset
228 comparisons but eliminating the cstores.
kono
parents:
diff changeset
229 If the cstores are all the same this is straight forward.
kono
parents:
diff changeset
230 If they're not, try to reverse the ccreg for the subordinate cstore type
kono
parents:
diff changeset
231 and eliminate the dominating one.
kono
parents:
diff changeset
232 */
kono
parents:
diff changeset
233
kono
parents:
diff changeset
234 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
kono
parents:
diff changeset
235 // Helper functions
kono
parents:
diff changeset
236
kono
parents:
diff changeset
237 #define log_msg(...)\
kono
parents:
diff changeset
238 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); } while (0)
kono
parents:
diff changeset
239
kono
parents:
diff changeset
240 #define log_insn(i)\
kono
parents:
diff changeset
241 do { if (dump_file != NULL) print_rtl_single (dump_file, \
kono
parents:
diff changeset
242 (const_rtx)i); } while (0)
kono
parents:
diff changeset
243
kono
parents:
diff changeset
244 #define log_rtx(r)\
kono
parents:
diff changeset
245 do { if (dump_file != NULL) print_rtl (dump_file, (const_rtx)r); } while (0)
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 #define log_return(retval, ...)\
kono
parents:
diff changeset
248 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); \
kono
parents:
diff changeset
249 return retval; } while (0)
kono
parents:
diff changeset
250
kono
parents:
diff changeset
251 #define log_return_void(...)\
kono
parents:
diff changeset
252 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); \
kono
parents:
diff changeset
253 return; } while (0)
kono
parents:
diff changeset
254
kono
parents:
diff changeset
255 struct set_of_reg
kono
parents:
diff changeset
256 {
kono
parents:
diff changeset
257 // The insn where the search stopped or NULL.
kono
parents:
diff changeset
258 rtx_insn *insn;
kono
parents:
diff changeset
259
kono
parents:
diff changeset
260 // The set rtx of the specified reg if found, NULL_RTX otherwise.
kono
parents:
diff changeset
261 // Notice that the set rtx can also be in a parallel.
kono
parents:
diff changeset
262 const_rtx set_rtx;
kono
parents:
diff changeset
263
kono
parents:
diff changeset
264 // The set source operand rtx if found, NULL_RTX otherwise.
kono
parents:
diff changeset
265 rtx
kono
parents:
diff changeset
266 set_src (void) const
kono
parents:
diff changeset
267 {
kono
parents:
diff changeset
268 return set_rtx == NULL_RTX ? NULL_RTX : XEXP (set_rtx, 1);
kono
parents:
diff changeset
269 }
kono
parents:
diff changeset
270
kono
parents:
diff changeset
271 // The set destination operand rtx if found, NULL_RTX otherwise.
kono
parents:
diff changeset
272 rtx
kono
parents:
diff changeset
273 set_dst (void) const
kono
parents:
diff changeset
274 {
kono
parents:
diff changeset
275 return set_rtx == NULL_RTX ? NULL_RTX : XEXP (set_rtx, 0);
kono
parents:
diff changeset
276 }
kono
parents:
diff changeset
277
kono
parents:
diff changeset
278 bool
kono
parents:
diff changeset
279 empty (void) const
kono
parents:
diff changeset
280 {
kono
parents:
diff changeset
281 return insn == NULL_RTX || set_rtx == NULL_RTX;
kono
parents:
diff changeset
282 }
kono
parents:
diff changeset
283 };
kono
parents:
diff changeset
284
kono
parents:
diff changeset
285 // Given a reg rtx and a start insn find the insn (in the same basic block)
kono
parents:
diff changeset
286 // that sets the reg.
kono
parents:
diff changeset
287 static set_of_reg
kono
parents:
diff changeset
288 find_set_of_reg_bb (rtx reg, rtx_insn *insn)
kono
parents:
diff changeset
289 {
kono
parents:
diff changeset
290 set_of_reg result = { insn, NULL_RTX };
kono
parents:
diff changeset
291
kono
parents:
diff changeset
292 if (!REG_P (reg) || insn == NULL)
kono
parents:
diff changeset
293 return result;
kono
parents:
diff changeset
294
kono
parents:
diff changeset
295 for (result.insn = insn; result.insn != NULL;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
296 result.insn = prev_nonnote_nondebug_insn_bb (result.insn))
111
kono
parents:
diff changeset
297 {
kono
parents:
diff changeset
298 if (BARRIER_P (result.insn))
kono
parents:
diff changeset
299 return result;
kono
parents:
diff changeset
300 if (!NONJUMP_INSN_P (result.insn))
kono
parents:
diff changeset
301 continue;
kono
parents:
diff changeset
302 if (reg_set_p (reg, result.insn))
kono
parents:
diff changeset
303 {
kono
parents:
diff changeset
304 result.set_rtx = set_of (reg, result.insn);
kono
parents:
diff changeset
305 if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET)
kono
parents:
diff changeset
306 result.set_rtx = NULL_RTX;
kono
parents:
diff changeset
307 return result;
kono
parents:
diff changeset
308 }
kono
parents:
diff changeset
309 }
kono
parents:
diff changeset
310
kono
parents:
diff changeset
311 return result;
kono
parents:
diff changeset
312 }
kono
parents:
diff changeset
313
kono
parents:
diff changeset
314 static bool
kono
parents:
diff changeset
315 reg_dead_after_insn (const_rtx reg, const_rtx insn)
kono
parents:
diff changeset
316 {
kono
parents:
diff changeset
317 return find_regno_note (insn, REG_DEAD, REGNO (reg)) != NULL_RTX;
kono
parents:
diff changeset
318 }
kono
parents:
diff changeset
319
kono
parents:
diff changeset
320 static bool
kono
parents:
diff changeset
321 reg_unused_after_insn (const_rtx reg, const_rtx insn)
kono
parents:
diff changeset
322 {
kono
parents:
diff changeset
323 return find_regno_note (insn, REG_UNUSED, REGNO (reg)) != NULL_RTX;
kono
parents:
diff changeset
324 }
kono
parents:
diff changeset
325
kono
parents:
diff changeset
326 // Check whether the two specified basic blocks are adjacent, i.e. there's no
kono
parents:
diff changeset
327 // other basic block in between them.
kono
parents:
diff changeset
328 static bool
kono
parents:
diff changeset
329 is_adjacent_bb (basic_block a, basic_block b)
kono
parents:
diff changeset
330 {
kono
parents:
diff changeset
331 basic_block bb0[] = { a, b };
kono
parents:
diff changeset
332 basic_block bb1[] = { b, a };
kono
parents:
diff changeset
333
kono
parents:
diff changeset
334 for (int i = 0; i < 2; ++i)
kono
parents:
diff changeset
335 for (edge_iterator ei = ei_start (bb0[i]->succs);
kono
parents:
diff changeset
336 !ei_end_p (ei); ei_next (&ei))
kono
parents:
diff changeset
337 if (ei_edge (ei)->dest == bb1[i])
kono
parents:
diff changeset
338 return true;
kono
parents:
diff changeset
339
kono
parents:
diff changeset
340 return false;
kono
parents:
diff changeset
341 }
kono
parents:
diff changeset
342
kono
parents:
diff changeset
343 // Internal function of trace_reg_uses.
kono
parents:
diff changeset
344 static void
kono
parents:
diff changeset
345 trace_reg_uses_1 (rtx reg, rtx_insn *start_insn, basic_block bb, int& count,
kono
parents:
diff changeset
346 std::vector<basic_block>& visited_bb, rtx abort_at_insn)
kono
parents:
diff changeset
347 {
kono
parents:
diff changeset
348 if (bb == NULL)
kono
parents:
diff changeset
349 return;
kono
parents:
diff changeset
350
kono
parents:
diff changeset
351 if (std::find (visited_bb.begin (), visited_bb.end (), bb)
kono
parents:
diff changeset
352 != visited_bb.end ())
kono
parents:
diff changeset
353 log_return_void ("[bb %d] already visited\n", bb->index);
kono
parents:
diff changeset
354
kono
parents:
diff changeset
355 visited_bb.push_back (bb);
kono
parents:
diff changeset
356
kono
parents:
diff changeset
357 if (BB_END (bb) == NULL_RTX)
kono
parents:
diff changeset
358 log_return_void ("[bb %d] BB_END is null\n", bb->index);
kono
parents:
diff changeset
359
kono
parents:
diff changeset
360 if (start_insn == NULL_RTX)
kono
parents:
diff changeset
361 log_return_void ("[bb %d] start_insn is null\n", bb->index);
kono
parents:
diff changeset
362
kono
parents:
diff changeset
363 rtx end_insn = NEXT_INSN (BB_END (bb));
kono
parents:
diff changeset
364 if (end_insn == NULL_RTX)
kono
parents:
diff changeset
365 log_return_void ("[bb %d] end_insn is null\n", bb->index);
kono
parents:
diff changeset
366
kono
parents:
diff changeset
367 for (rtx_insn *i = NEXT_INSN (start_insn); i != end_insn; i = NEXT_INSN (i))
kono
parents:
diff changeset
368 {
kono
parents:
diff changeset
369 if (INSN_P (i))
kono
parents:
diff changeset
370 {
kono
parents:
diff changeset
371 if (NONDEBUG_INSN_P (i)
kono
parents:
diff changeset
372 && (reg_overlap_mentioned_p (reg, PATTERN (i))
kono
parents:
diff changeset
373 || (CALL_P (i) && find_reg_fusage (i, USE, reg))))
kono
parents:
diff changeset
374 {
kono
parents:
diff changeset
375 log_msg ("found use in [bb %d] at insn:\n", bb->index);
kono
parents:
diff changeset
376 log_insn (i);
kono
parents:
diff changeset
377 log_msg ("\n");
kono
parents:
diff changeset
378 count += 1;
kono
parents:
diff changeset
379 }
kono
parents:
diff changeset
380
kono
parents:
diff changeset
381 // Stop following this BB if the reg is set or dies along the way.
kono
parents:
diff changeset
382 if (reg_set_p (reg, i) || reg_dead_after_insn (reg, i))
kono
parents:
diff changeset
383 return;
kono
parents:
diff changeset
384 }
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 if (abort_at_insn != NULL_RTX && abort_at_insn == i)
kono
parents:
diff changeset
387 return;
kono
parents:
diff changeset
388 }
kono
parents:
diff changeset
389
kono
parents:
diff changeset
390 for (edge_iterator ei = ei_start (bb->succs); !ei_end_p (ei); ei_next (&ei))
kono
parents:
diff changeset
391 {
kono
parents:
diff changeset
392 basic_block succ_bb = ei_edge (ei)->dest;
kono
parents:
diff changeset
393 trace_reg_uses_1 (reg, BB_HEAD (succ_bb), succ_bb, count, visited_bb,
kono
parents:
diff changeset
394 abort_at_insn);
kono
parents:
diff changeset
395 }
kono
parents:
diff changeset
396 }
kono
parents:
diff changeset
397
kono
parents:
diff changeset
398 // Trace uses of the specified reg in all basic blocks that are reachable from
kono
parents:
diff changeset
399 // the specified insn. If 'abort_at_insn' is not null, abort the trace at
kono
parents:
diff changeset
400 // that insn. If the insn 'abort_at_insn' uses the specified reg, it is also
kono
parents:
diff changeset
401 // counted.
kono
parents:
diff changeset
402 static int
kono
parents:
diff changeset
403 trace_reg_uses (rtx reg, rtx_insn *start_insn, rtx abort_at_insn)
kono
parents:
diff changeset
404 {
kono
parents:
diff changeset
405 log_msg ("\ntrace_reg_uses\nreg = ");
kono
parents:
diff changeset
406 log_rtx (reg);
kono
parents:
diff changeset
407 log_msg ("\nstart_insn = ");
kono
parents:
diff changeset
408 log_insn (start_insn);
kono
parents:
diff changeset
409
kono
parents:
diff changeset
410 int count = 0;
kono
parents:
diff changeset
411 std::vector<basic_block> visited_bb;
kono
parents:
diff changeset
412 visited_bb.reserve (32);
kono
parents:
diff changeset
413
kono
parents:
diff changeset
414 trace_reg_uses_1 (reg, start_insn, BLOCK_FOR_INSN (start_insn),
kono
parents:
diff changeset
415 count, visited_bb, abort_at_insn);
kono
parents:
diff changeset
416 return count;
kono
parents:
diff changeset
417 }
kono
parents:
diff changeset
418
kono
parents:
diff changeset
419 static bool
kono
parents:
diff changeset
420 is_conditional_insn (rtx_insn* i)
kono
parents:
diff changeset
421 {
kono
parents:
diff changeset
422 if (! (INSN_P (i) && NONDEBUG_INSN_P (i)))
kono
parents:
diff changeset
423 return false;
kono
parents:
diff changeset
424
kono
parents:
diff changeset
425 rtx p = PATTERN (i);
kono
parents:
diff changeset
426 return GET_CODE (p) == SET && GET_CODE (XEXP (p, 1)) == IF_THEN_ELSE;
kono
parents:
diff changeset
427 }
kono
parents:
diff changeset
428
kono
parents:
diff changeset
429 // FIXME: Remove dependency on SH predicate function somehow.
kono
parents:
diff changeset
430 extern int t_reg_operand (rtx, machine_mode);
kono
parents:
diff changeset
431 extern int negt_reg_operand (rtx, machine_mode);
kono
parents:
diff changeset
432
kono
parents:
diff changeset
433 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
kono
parents:
diff changeset
434 // RTL pass class
kono
parents:
diff changeset
435
kono
parents:
diff changeset
436 class sh_treg_combine : public rtl_opt_pass
kono
parents:
diff changeset
437 {
kono
parents:
diff changeset
438 public:
kono
parents:
diff changeset
439 sh_treg_combine (gcc::context* ctx, bool split_insns, const char* name);
kono
parents:
diff changeset
440 virtual ~sh_treg_combine (void);
kono
parents:
diff changeset
441 virtual bool gate (function *);
kono
parents:
diff changeset
442 virtual unsigned int execute (function *);
kono
parents:
diff changeset
443
kono
parents:
diff changeset
444 private:
kono
parents:
diff changeset
445 // Type of ccreg store that is supported.
kono
parents:
diff changeset
446 enum cstore_type_t
kono
parents:
diff changeset
447 {
kono
parents:
diff changeset
448 cstore_normal = 0,
kono
parents:
diff changeset
449 cstore_inverted = 1,
kono
parents:
diff changeset
450 cstore_unknown = -1
kono
parents:
diff changeset
451 };
kono
parents:
diff changeset
452
kono
parents:
diff changeset
453 // Type of branch condition that is supported.
kono
parents:
diff changeset
454 enum branch_condition_type_t
kono
parents:
diff changeset
455 {
kono
parents:
diff changeset
456 branch_if_true = 1,
kono
parents:
diff changeset
457 branch_if_false = 0,
kono
parents:
diff changeset
458 unknown_branch_condition = -1
kono
parents:
diff changeset
459 };
kono
parents:
diff changeset
460
kono
parents:
diff changeset
461 // For each basic block there can be a trace entry which consists of an
kono
parents:
diff changeset
462 // insn that sets the ccreg (usually a comparison) and a ccreg store.
kono
parents:
diff changeset
463 struct bb_entry
kono
parents:
diff changeset
464 {
kono
parents:
diff changeset
465 basic_block bb;
kono
parents:
diff changeset
466 set_of_reg setcc;
kono
parents:
diff changeset
467 set_of_reg cstore;
kono
parents:
diff changeset
468 cstore_type_t cstore_type;
kono
parents:
diff changeset
469 std::vector<set_of_reg> cstore_reg_reg_copies;
kono
parents:
diff changeset
470
kono
parents:
diff changeset
471 bb_entry (basic_block b)
kono
parents:
diff changeset
472 : bb (b), setcc (), cstore (), cstore_type (cstore_unknown) { }
kono
parents:
diff changeset
473
kono
parents:
diff changeset
474 rtx comparison_rtx (void) const { return setcc.set_src (); }
kono
parents:
diff changeset
475 };
kono
parents:
diff changeset
476
kono
parents:
diff changeset
477 // A ccreg trace for a conditional branch.
kono
parents:
diff changeset
478 struct cbranch_trace
kono
parents:
diff changeset
479 {
kono
parents:
diff changeset
480 rtx_insn *cbranch_insn;
kono
parents:
diff changeset
481 rtx* condition_rtx_in_insn;
kono
parents:
diff changeset
482 branch_condition_type_t cbranch_type;
kono
parents:
diff changeset
483
kono
parents:
diff changeset
484 // The comparison against zero right before the conditional branch.
kono
parents:
diff changeset
485 set_of_reg setcc;
kono
parents:
diff changeset
486
kono
parents:
diff changeset
487 // All BBs that are related to the cbranch. The last BB in the list is
kono
parents:
diff changeset
488 // the BB of the cbranch itself and might be empty.
kono
parents:
diff changeset
489 std::list<bb_entry> bb_entries;
kono
parents:
diff changeset
490
kono
parents:
diff changeset
491 cbranch_trace (rtx_insn *insn)
kono
parents:
diff changeset
492 : cbranch_insn (insn),
kono
parents:
diff changeset
493 condition_rtx_in_insn (NULL),
kono
parents:
diff changeset
494 cbranch_type (unknown_branch_condition),
kono
parents:
diff changeset
495 setcc ()
kono
parents:
diff changeset
496 {
kono
parents:
diff changeset
497 if (is_conditional_insn (cbranch_insn))
kono
parents:
diff changeset
498 condition_rtx_in_insn = &XEXP (XEXP (PATTERN (cbranch_insn), 1), 0);
kono
parents:
diff changeset
499 else if (rtx x = pc_set (cbranch_insn))
kono
parents:
diff changeset
500 condition_rtx_in_insn = &XEXP (XEXP (x, 1), 0);
kono
parents:
diff changeset
501 }
kono
parents:
diff changeset
502
kono
parents:
diff changeset
503 basic_block bb (void) const { return BLOCK_FOR_INSN (cbranch_insn); }
kono
parents:
diff changeset
504
kono
parents:
diff changeset
505 rtx
kono
parents:
diff changeset
506 branch_condition_rtx (void) const
kono
parents:
diff changeset
507 {
kono
parents:
diff changeset
508 return condition_rtx_in_insn != NULL ? *condition_rtx_in_insn : NULL;
kono
parents:
diff changeset
509 }
kono
parents:
diff changeset
510 rtx&
kono
parents:
diff changeset
511 branch_condition_rtx_ref (void) const
kono
parents:
diff changeset
512 {
kono
parents:
diff changeset
513 // Before anything gets to invoke this function, there are other checks
kono
parents:
diff changeset
514 // in place to make sure that we have a known branch condition and thus
kono
parents:
diff changeset
515 // the ref to the rtx in the insn.
kono
parents:
diff changeset
516 gcc_assert (condition_rtx_in_insn != NULL);
kono
parents:
diff changeset
517 return *condition_rtx_in_insn;
kono
parents:
diff changeset
518 }
kono
parents:
diff changeset
519
kono
parents:
diff changeset
520 bool
kono
parents:
diff changeset
521 can_invert_condition (void) const
kono
parents:
diff changeset
522 {
kono
parents:
diff changeset
523 // The branch condition can be inverted safely only if the condition
kono
parents:
diff changeset
524 // reg is dead after the cbranch.
kono
parents:
diff changeset
525 return reg_dead_after_insn (XEXP (branch_condition_rtx (), 0),
kono
parents:
diff changeset
526 cbranch_insn);
kono
parents:
diff changeset
527 }
kono
parents:
diff changeset
528 };
kono
parents:
diff changeset
529
kono
parents:
diff changeset
530 static const pass_data default_pass_data;
kono
parents:
diff changeset
531
kono
parents:
diff changeset
532 // Tells whether modified or newly added insns are to be split at the end
kono
parents:
diff changeset
533 // of the pass.
kono
parents:
diff changeset
534 const bool m_split_insns;
kono
parents:
diff changeset
535
kono
parents:
diff changeset
536 // rtx of the ccreg that is obtained from the target.
kono
parents:
diff changeset
537 rtx m_ccreg;
kono
parents:
diff changeset
538
kono
parents:
diff changeset
539 // Newly added or modified insns.
kono
parents:
diff changeset
540 std::vector<rtx> m_touched_insns;
kono
parents:
diff changeset
541
kono
parents:
diff changeset
542 // Given an rtx determine whether it's a comparison with a constant zero.
kono
parents:
diff changeset
543 static bool is_cmp_eq_zero (const_rtx i);
kono
parents:
diff changeset
544
kono
parents:
diff changeset
545 // Update the stored mode of the ccreg from the given branch condition rtx.
kono
parents:
diff changeset
546 void update_ccreg_mode (const_rtx cond);
kono
parents:
diff changeset
547
kono
parents:
diff changeset
548 // Given an rtx, figure out the branch condition, assuming that it is
kono
parents:
diff changeset
549 // in canonical form:
kono
parents:
diff changeset
550 // (ne (reg) (const_int 0))
kono
parents:
diff changeset
551 // (eq (reg) (const_int 0))
kono
parents:
diff changeset
552 branch_condition_type_t branch_condition_type (const_rtx cond) const;
kono
parents:
diff changeset
553
kono
parents:
diff changeset
554 // Return true if the specified rtx is either a normal ccreg or
kono
parents:
diff changeset
555 // a negated form of the ccreg.
kono
parents:
diff changeset
556 bool is_normal_ccreg (const_rtx x) const;
kono
parents:
diff changeset
557 bool is_inverted_ccreg (const_rtx x) const;
kono
parents:
diff changeset
558
kono
parents:
diff changeset
559 // Given a reg rtx and a start insn rtx, try to find the insn in the same
kono
parents:
diff changeset
560 // basic block that sets the specified reg.
kono
parents:
diff changeset
561 // Return how the search ended and the insn where it stopped or NULL_RTX.
kono
parents:
diff changeset
562 enum record_return_t
kono
parents:
diff changeset
563 {
kono
parents:
diff changeset
564 set_found,
kono
parents:
diff changeset
565 set_not_found,
kono
parents:
diff changeset
566 other_set_found
kono
parents:
diff changeset
567 };
kono
parents:
diff changeset
568 record_return_t record_set_of_reg (rtx reg, rtx_insn *start_insn,
kono
parents:
diff changeset
569 bb_entry& e);
kono
parents:
diff changeset
570
kono
parents:
diff changeset
571 // Tells whether the cbranch insn of the specified bb_entry can be removed
kono
parents:
diff changeset
572 // safely without triggering any side effects.
kono
parents:
diff changeset
573 bool can_remove_cstore (const bb_entry& e,
kono
parents:
diff changeset
574 const cbranch_trace& trace) const;
kono
parents:
diff changeset
575
kono
parents:
diff changeset
576 // Tells whether the setcc insn of the specified bb_entry can be removed
kono
parents:
diff changeset
577 // safely without triggering any side effects.
kono
parents:
diff changeset
578 bool can_remove_comparison (const bb_entry& e,
kono
parents:
diff changeset
579 const cbranch_trace& trace) const;
kono
parents:
diff changeset
580
kono
parents:
diff changeset
581 // Tells whether the two specified comparison rtx can be combined into a
kono
parents:
diff changeset
582 // single comparison.
kono
parents:
diff changeset
583 bool can_combine_comparisons (const_rtx x, const_rtx y) const;
kono
parents:
diff changeset
584
kono
parents:
diff changeset
585 // Tells whether the ccreg usage can be extended from the bb_entry on until
kono
parents:
diff changeset
586 // the final cbranch of the trace.
kono
parents:
diff changeset
587 bool can_extend_ccreg_usage (const bb_entry& e,
kono
parents:
diff changeset
588 const cbranch_trace& trace) const;
kono
parents:
diff changeset
589
kono
parents:
diff changeset
590 // Create an insn rtx that performs a logical not (test != 0) on the src_reg
kono
parents:
diff changeset
591 // and stores the result in dst_reg.
kono
parents:
diff changeset
592 rtx make_not_reg_insn (rtx dst_reg, rtx src_reg) const;
kono
parents:
diff changeset
593
kono
parents:
diff changeset
594 // Create an insn rtx that inverts the ccreg.
kono
parents:
diff changeset
595 rtx_insn *make_inv_ccreg_insn (void) const;
kono
parents:
diff changeset
596
kono
parents:
diff changeset
597 // Adds the specified insn to the set of modified or newly added insns that
kono
parents:
diff changeset
598 // might need splitting at the end of the pass.
kono
parents:
diff changeset
599 rtx touched_insn (rtx i);
kono
parents:
diff changeset
600
kono
parents:
diff changeset
601 // Try to invert the branch condition of the specified trace.
kono
parents:
diff changeset
602 bool try_invert_branch_condition (cbranch_trace& trace);
kono
parents:
diff changeset
603
kono
parents:
diff changeset
604 // Try to optimize a cbranch trace by combining comparisons in BBs and
kono
parents:
diff changeset
605 // eliminate the cstores.
kono
parents:
diff changeset
606 bool try_combine_comparisons (cbranch_trace& trace,
kono
parents:
diff changeset
607 int cstore_count, int inv_cstore_count,
kono
parents:
diff changeset
608 cstore_type_t dominating_cstore);
kono
parents:
diff changeset
609
kono
parents:
diff changeset
610 // Try to optimize a cbranch trace by eliminating the cstores in BBs only.
kono
parents:
diff changeset
611 bool try_eliminate_cstores (cbranch_trace& trace,
kono
parents:
diff changeset
612 int cstore_count, int inv_cstore_count,
kono
parents:
diff changeset
613 cstore_type_t dominating_cstore);
kono
parents:
diff changeset
614
kono
parents:
diff changeset
615 // Given a branch insn, try to optimize its branch condition.
kono
parents:
diff changeset
616 // If any insns are modified or added they are added to 'm_touched_insns'.
kono
parents:
diff changeset
617 void try_optimize_cbranch (rtx_insn *i);
kono
parents:
diff changeset
618 };
kono
parents:
diff changeset
619
kono
parents:
diff changeset
620
kono
parents:
diff changeset
621 const pass_data sh_treg_combine::default_pass_data =
kono
parents:
diff changeset
622 {
kono
parents:
diff changeset
623 RTL_PASS, // type
kono
parents:
diff changeset
624 "", // name (overwritten by the constructor)
kono
parents:
diff changeset
625 OPTGROUP_NONE, // optinfo_flags
kono
parents:
diff changeset
626 TV_OPTIMIZE, // tv_id
kono
parents:
diff changeset
627 0, // properties_required
kono
parents:
diff changeset
628 0, // properties_provided
kono
parents:
diff changeset
629 0, // properties_destroyed
kono
parents:
diff changeset
630 0, // todo_flags_start
kono
parents:
diff changeset
631 TODO_df_finish | TODO_df_verify // todo_flags_finish
kono
parents:
diff changeset
632 };
kono
parents:
diff changeset
633
kono
parents:
diff changeset
634 sh_treg_combine::sh_treg_combine (gcc::context* ctx, bool split_insns,
kono
parents:
diff changeset
635 const char* name)
kono
parents:
diff changeset
636 : rtl_opt_pass (default_pass_data, ctx),
kono
parents:
diff changeset
637 m_split_insns (split_insns),
kono
parents:
diff changeset
638 m_ccreg (NULL_RTX)
kono
parents:
diff changeset
639 {
kono
parents:
diff changeset
640 // Overwrite default name in pass_data base class.
kono
parents:
diff changeset
641 this->name = name;
kono
parents:
diff changeset
642 }
kono
parents:
diff changeset
643
kono
parents:
diff changeset
644 sh_treg_combine::~sh_treg_combine (void)
kono
parents:
diff changeset
645 {
kono
parents:
diff changeset
646 }
kono
parents:
diff changeset
647
kono
parents:
diff changeset
648 void sh_treg_combine::update_ccreg_mode (const_rtx cond)
kono
parents:
diff changeset
649 {
kono
parents:
diff changeset
650 if (REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) != REGNO (m_ccreg))
kono
parents:
diff changeset
651 return;
kono
parents:
diff changeset
652
kono
parents:
diff changeset
653 machine_mode m = GET_MODE (XEXP (cond, 0));
kono
parents:
diff changeset
654 if (m == GET_MODE (m_ccreg))
kono
parents:
diff changeset
655 return;
kono
parents:
diff changeset
656
kono
parents:
diff changeset
657 PUT_MODE (m_ccreg, m);
kono
parents:
diff changeset
658 log_msg ("updated ccreg mode: ");
kono
parents:
diff changeset
659 log_rtx (m_ccreg);
kono
parents:
diff changeset
660 log_msg ("\n");
kono
parents:
diff changeset
661 }
kono
parents:
diff changeset
662
kono
parents:
diff changeset
663 bool
kono
parents:
diff changeset
664 sh_treg_combine::is_cmp_eq_zero (const_rtx i)
kono
parents:
diff changeset
665 {
kono
parents:
diff changeset
666 return i != NULL_RTX && GET_CODE (i) == EQ
kono
parents:
diff changeset
667 && REG_P (XEXP (i, 0)) && XEXP (i, 1) == const0_rtx;
kono
parents:
diff changeset
668 }
kono
parents:
diff changeset
669
kono
parents:
diff changeset
670 sh_treg_combine::branch_condition_type_t
kono
parents:
diff changeset
671 sh_treg_combine::branch_condition_type (const_rtx cond) const
kono
parents:
diff changeset
672 {
kono
parents:
diff changeset
673 if (cond == NULL_RTX)
kono
parents:
diff changeset
674 return unknown_branch_condition;
kono
parents:
diff changeset
675
kono
parents:
diff changeset
676 if (GET_CODE (cond) == NE
kono
parents:
diff changeset
677 && REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) == REGNO (m_ccreg)
kono
parents:
diff changeset
678 && XEXP (cond, 1) == const0_rtx)
kono
parents:
diff changeset
679 return branch_if_true;
kono
parents:
diff changeset
680
kono
parents:
diff changeset
681 else if (GET_CODE (cond) == EQ
kono
parents:
diff changeset
682 && REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) == REGNO (m_ccreg)
kono
parents:
diff changeset
683 && XEXP (cond, 1) == const0_rtx)
kono
parents:
diff changeset
684 return branch_if_false;
kono
parents:
diff changeset
685
kono
parents:
diff changeset
686 else
kono
parents:
diff changeset
687 return unknown_branch_condition;
kono
parents:
diff changeset
688 }
kono
parents:
diff changeset
689
kono
parents:
diff changeset
690 bool
kono
parents:
diff changeset
691 sh_treg_combine::is_normal_ccreg (const_rtx x) const
kono
parents:
diff changeset
692 {
kono
parents:
diff changeset
693 return t_reg_operand (const_cast<rtx> (x), VOIDmode);
kono
parents:
diff changeset
694 }
kono
parents:
diff changeset
695
kono
parents:
diff changeset
696 bool
kono
parents:
diff changeset
697 sh_treg_combine::is_inverted_ccreg (const_rtx x) const
kono
parents:
diff changeset
698 {
kono
parents:
diff changeset
699 return negt_reg_operand (const_cast<rtx> (x), VOIDmode);
kono
parents:
diff changeset
700 }
kono
parents:
diff changeset
701
kono
parents:
diff changeset
702 sh_treg_combine::record_return_t
kono
parents:
diff changeset
703 sh_treg_combine::record_set_of_reg (rtx reg, rtx_insn *start_insn,
kono
parents:
diff changeset
704 bb_entry& new_entry)
kono
parents:
diff changeset
705 {
kono
parents:
diff changeset
706 log_msg ("\n[bb %d]\n", new_entry.bb->index);
kono
parents:
diff changeset
707
kono
parents:
diff changeset
708 if (start_insn == NULL_RTX)
kono
parents:
diff changeset
709 log_return (set_not_found, "set of reg not found. empty BB?\n");
kono
parents:
diff changeset
710
kono
parents:
diff changeset
711 new_entry.cstore_type = cstore_unknown;
kono
parents:
diff changeset
712
kono
parents:
diff changeset
713 for (rtx_insn *i = start_insn; i != NULL; )
kono
parents:
diff changeset
714 {
kono
parents:
diff changeset
715 new_entry.cstore = find_set_of_reg_bb (reg, i);
kono
parents:
diff changeset
716
kono
parents:
diff changeset
717 if (new_entry.cstore.set_src () == NULL_RTX)
kono
parents:
diff changeset
718 log_return (set_not_found, "set of reg not found (cstore)\n");
kono
parents:
diff changeset
719
kono
parents:
diff changeset
720 log_insn (new_entry.cstore.insn);
kono
parents:
diff changeset
721 log_msg ("\n");
kono
parents:
diff changeset
722
kono
parents:
diff changeset
723 if (is_normal_ccreg (new_entry.cstore.set_src ()))
kono
parents:
diff changeset
724 {
kono
parents:
diff changeset
725 log_msg ("normal condition store\n");
kono
parents:
diff changeset
726 new_entry.cstore_type = cstore_normal;
kono
parents:
diff changeset
727 }
kono
parents:
diff changeset
728 else if (is_inverted_ccreg (new_entry.cstore.set_src ()))
kono
parents:
diff changeset
729 {
kono
parents:
diff changeset
730 log_msg ("inverted condition store\n");
kono
parents:
diff changeset
731 new_entry.cstore_type = cstore_inverted;
kono
parents:
diff changeset
732 }
kono
parents:
diff changeset
733 else if (REG_P (new_entry.cstore.set_src ()))
kono
parents:
diff changeset
734 {
kono
parents:
diff changeset
735 // If it's a reg-reg copy follow the copied reg.
kono
parents:
diff changeset
736 new_entry.cstore_reg_reg_copies.push_back (new_entry.cstore);
kono
parents:
diff changeset
737 reg = new_entry.cstore.set_src ();
kono
parents:
diff changeset
738 i = new_entry.cstore.insn;
kono
parents:
diff changeset
739
kono
parents:
diff changeset
740 log_msg ("reg-reg copy. tracing ");
kono
parents:
diff changeset
741 log_rtx (reg);
kono
parents:
diff changeset
742 log_msg ("\n");
kono
parents:
diff changeset
743 continue;
kono
parents:
diff changeset
744 }
kono
parents:
diff changeset
745 else
kono
parents:
diff changeset
746 log_return (other_set_found, "not a condition store\n");
kono
parents:
diff changeset
747
kono
parents:
diff changeset
748 gcc_assert (new_entry.cstore_type != cstore_unknown);
kono
parents:
diff changeset
749
kono
parents:
diff changeset
750 // Now see how the ccreg was set.
kono
parents:
diff changeset
751 // For now it must be in the same BB.
kono
parents:
diff changeset
752 log_msg ("tracing ccreg\n");
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
753 new_entry.setcc = find_set_of_reg_bb
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
754 (m_ccreg, prev_nonnote_nondebug_insn_bb (new_entry.cstore.insn));
111
kono
parents:
diff changeset
755
kono
parents:
diff changeset
756 // If cstore was found but setcc was not found continue anyway, as
kono
parents:
diff changeset
757 // for some of the optimization types the setcc is irrelevant.
kono
parents:
diff changeset
758 if (new_entry.setcc.set_src () == NULL_RTX)
kono
parents:
diff changeset
759 log_return (set_found, "set of ccreg not found\n");
kono
parents:
diff changeset
760
kono
parents:
diff changeset
761 else if (GET_CODE (new_entry.setcc.set_rtx) == SET)
kono
parents:
diff changeset
762 {
kono
parents:
diff changeset
763 // Also allow insns that set the ccreg, but are not true comparison
kono
parents:
diff changeset
764 // insns, as long as they are sets and not e.g. clobbers.
kono
parents:
diff changeset
765 log_insn (new_entry.setcc.insn);
kono
parents:
diff changeset
766 log_msg ("\n");
kono
parents:
diff changeset
767 return set_found;
kono
parents:
diff changeset
768 }
kono
parents:
diff changeset
769 else
kono
parents:
diff changeset
770 // If cstore was found but setcc was not found continue anyway, as
kono
parents:
diff changeset
771 // for some of the optimization types the setcc is irrelevant.
kono
parents:
diff changeset
772 log_return (set_found, "unknown set of ccreg\n");
kono
parents:
diff changeset
773 }
kono
parents:
diff changeset
774
kono
parents:
diff changeset
775 log_return (set_not_found, "set of reg not found\n");
kono
parents:
diff changeset
776 }
kono
parents:
diff changeset
777
kono
parents:
diff changeset
778 bool
kono
parents:
diff changeset
779 sh_treg_combine::can_remove_cstore (const bb_entry& e,
kono
parents:
diff changeset
780 const cbranch_trace& trace) const
kono
parents:
diff changeset
781 {
kono
parents:
diff changeset
782 if (volatile_insn_p (PATTERN (e.cstore.insn)))
kono
parents:
diff changeset
783 {
kono
parents:
diff changeset
784 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
785 log_insn (e.cstore.insn);
kono
parents:
diff changeset
786 log_return (false, "\nbecause it's volatile\n");
kono
parents:
diff changeset
787 }
kono
parents:
diff changeset
788
kono
parents:
diff changeset
789 // On SH there are parallel patterns which store the ccreg multiple times.
kono
parents:
diff changeset
790 // In this case it's not safe.
kono
parents:
diff changeset
791 rtx cstore_pat = PATTERN (e.cstore.insn);
kono
parents:
diff changeset
792 if (GET_CODE (cstore_pat) == PARALLEL)
kono
parents:
diff changeset
793 for (int i = 0; i < XVECLEN (cstore_pat, 0); ++i)
kono
parents:
diff changeset
794 {
kono
parents:
diff changeset
795 rtx x = XVECEXP (cstore_pat, 0, i);
kono
parents:
diff changeset
796
kono
parents:
diff changeset
797 // It's the cstore set that we're referring to, ignore that one.
kono
parents:
diff changeset
798 if (x != e.cstore.set_rtx
kono
parents:
diff changeset
799 && GET_CODE (x) == SET && reg_referenced_p (m_ccreg, x))
kono
parents:
diff changeset
800 {
kono
parents:
diff changeset
801 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
802 log_insn (e.cstore.insn);
kono
parents:
diff changeset
803 log_return (false, "\nbecause it's a multiple ccreg store\n");
kono
parents:
diff changeset
804 }
kono
parents:
diff changeset
805 }
kono
parents:
diff changeset
806
kono
parents:
diff changeset
807 // If the cstore sets the ccreg (e.g. negc) and the ccreg is used afterwards
kono
parents:
diff changeset
808 // it's not safe.
kono
parents:
diff changeset
809 if (modified_in_p (m_ccreg, e.cstore.insn)
kono
parents:
diff changeset
810 && !(reg_dead_after_insn (m_ccreg, e.cstore.insn)
kono
parents:
diff changeset
811 || reg_unused_after_insn (m_ccreg, e.cstore.insn)))
kono
parents:
diff changeset
812 {
kono
parents:
diff changeset
813 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
814 log_insn (e.cstore.insn);
kono
parents:
diff changeset
815 log_return (false, "\nbecause it sets the ccreg\n");
kono
parents:
diff changeset
816 }
kono
parents:
diff changeset
817
kono
parents:
diff changeset
818 // If the cstore destination reg is copied around check the reg-reg
kono
parents:
diff changeset
819 // copies. At every reg-reg copy the copied reg must be dead and there
kono
parents:
diff changeset
820 // must not be a usage of the copied regs between the reg-reg copies.
kono
parents:
diff changeset
821 // Otherwise we assume that the result of the cstore is used in some
kono
parents:
diff changeset
822 // other way.
kono
parents:
diff changeset
823 rtx_insn *prev_insn = e.cstore.insn;
kono
parents:
diff changeset
824 for (std::vector<set_of_reg>::const_reverse_iterator i =
kono
parents:
diff changeset
825 e.cstore_reg_reg_copies.rbegin ();
kono
parents:
diff changeset
826 i != e.cstore_reg_reg_copies.rend (); ++i)
kono
parents:
diff changeset
827 {
kono
parents:
diff changeset
828 if (!reg_dead_after_insn (i->set_src (), i->insn))
kono
parents:
diff changeset
829 {
kono
parents:
diff changeset
830 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
831 log_insn (i->insn);
kono
parents:
diff changeset
832 log_return (false, "\nbecause source of reg-reg copy doesn't die\n");
kono
parents:
diff changeset
833 }
kono
parents:
diff changeset
834
kono
parents:
diff changeset
835 if (reg_used_between_p (i->set_src (), prev_insn, i->insn))
kono
parents:
diff changeset
836 {
kono
parents:
diff changeset
837 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
838 log_insn (i->insn);
kono
parents:
diff changeset
839 log_return (false, "\nbecause reg %d is otherwise used\n",
kono
parents:
diff changeset
840 REGNO (i->set_src ()));
kono
parents:
diff changeset
841 }
kono
parents:
diff changeset
842
kono
parents:
diff changeset
843 prev_insn = i->insn;
kono
parents:
diff changeset
844 }
kono
parents:
diff changeset
845
kono
parents:
diff changeset
846 // The cstore_dst reg must die after the test before the cbranch, otherwise
kono
parents:
diff changeset
847 // it's not safe to remove the cstore.
kono
parents:
diff changeset
848 // If the cstore destination reg is copied around check the effective
kono
parents:
diff changeset
849 // destination reg of the cstore. The reg-reg copies are recorded in
kono
parents:
diff changeset
850 // reverse order, i.e. the most recent reg-reg copy in the insn list
kono
parents:
diff changeset
851 // comes first.
kono
parents:
diff changeset
852 rtx cstore_dst = e.cstore_reg_reg_copies.empty ()
kono
parents:
diff changeset
853 ? e.cstore.set_dst ()
kono
parents:
diff changeset
854 : e.cstore_reg_reg_copies.front ().set_dst ();
kono
parents:
diff changeset
855
kono
parents:
diff changeset
856 if (!reg_dead_after_insn (cstore_dst, trace.setcc.insn))
kono
parents:
diff changeset
857 {
kono
parents:
diff changeset
858 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
859 log_insn (e.cstore.insn);
kono
parents:
diff changeset
860 log_return (false, "\nbecause its effective target reg %d doesn't die "
kono
parents:
diff changeset
861 "after trace.setcc.insn\n", REGNO (cstore_dst));
kono
parents:
diff changeset
862 }
kono
parents:
diff changeset
863
kono
parents:
diff changeset
864 // Also check that the cstore_dst reg is not used in other reachable code
kono
parents:
diff changeset
865 // paths before it dies.
kono
parents:
diff changeset
866 // Count the uses of the effective cstore_dst reg (i.e. the last known reg
kono
parents:
diff changeset
867 // that holds the cstore value after reg-reg copies) in all BBs that can be
kono
parents:
diff changeset
868 // reached from bb_entry's BB including the BB of the cstore insn.
kono
parents:
diff changeset
869 // If we get more than 1 uses we assume that it's used somewhere else and is
kono
parents:
diff changeset
870 // not safe to be removed.
kono
parents:
diff changeset
871 int cstore_dst_use_count = trace_reg_uses (cstore_dst, e.cstore.insn,
kono
parents:
diff changeset
872 trace.setcc.insn);
kono
parents:
diff changeset
873 if (cstore_dst_use_count > 1)
kono
parents:
diff changeset
874 {
kono
parents:
diff changeset
875 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
876 log_insn (e.cstore.insn);
kono
parents:
diff changeset
877 log_return (false, "\nbecause its effective target reg %d is used "
kono
parents:
diff changeset
878 "in %d other places\n", REGNO (cstore_dst),
kono
parents:
diff changeset
879 cstore_dst_use_count - 1);
kono
parents:
diff changeset
880 }
kono
parents:
diff changeset
881
kono
parents:
diff changeset
882 return true;
kono
parents:
diff changeset
883 }
kono
parents:
diff changeset
884
kono
parents:
diff changeset
885 bool
kono
parents:
diff changeset
886 sh_treg_combine::can_remove_comparison (const bb_entry& e,
kono
parents:
diff changeset
887 const cbranch_trace&/* trace*/) const
kono
parents:
diff changeset
888 {
kono
parents:
diff changeset
889 // If the ccreg is used otherwise between the comparison and the cstore,
kono
parents:
diff changeset
890 // it's not safe.
kono
parents:
diff changeset
891 if (reg_used_between_p (m_ccreg, e.setcc.insn, e.cstore.insn))
kono
parents:
diff changeset
892 {
kono
parents:
diff changeset
893 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
894 log_insn (e.setcc.insn);
kono
parents:
diff changeset
895 log_return (false, "\nbecause the ccreg is used otherwise\n");
kono
parents:
diff changeset
896 }
kono
parents:
diff changeset
897
kono
parents:
diff changeset
898 if (!reg_dead_after_insn (m_ccreg, e.cstore.insn)
kono
parents:
diff changeset
899 && !reg_unused_after_insn (m_ccreg, e.cstore.insn))
kono
parents:
diff changeset
900 {
kono
parents:
diff changeset
901 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
902 log_insn (e.cstore.insn);
kono
parents:
diff changeset
903 log_return (false, "\nbecause ccreg is not dead or unused afterwards\n");
kono
parents:
diff changeset
904 }
kono
parents:
diff changeset
905
kono
parents:
diff changeset
906 // On SH there are also multiple set patterns that can be used for
kono
parents:
diff changeset
907 // comparisons, such as "shll". It's not safe to remove those.
kono
parents:
diff changeset
908 if (multiple_sets (e.setcc.insn))
kono
parents:
diff changeset
909 {
kono
parents:
diff changeset
910 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
911 log_insn (e.cstore.insn);
kono
parents:
diff changeset
912 log_return (false, "\nbecause it's a multiple set\n");
kono
parents:
diff changeset
913 }
kono
parents:
diff changeset
914
kono
parents:
diff changeset
915 return true;
kono
parents:
diff changeset
916 }
kono
parents:
diff changeset
917
kono
parents:
diff changeset
918 rtx
kono
parents:
diff changeset
919 sh_treg_combine::make_not_reg_insn (rtx dst_reg, rtx src_reg) const
kono
parents:
diff changeset
920 {
kono
parents:
diff changeset
921 // On SH we can do only SImode and DImode comparisons.
kono
parents:
diff changeset
922 if (! (GET_MODE (src_reg) == SImode || GET_MODE (src_reg) == DImode))
kono
parents:
diff changeset
923 return NULL;
kono
parents:
diff changeset
924
kono
parents:
diff changeset
925 // On SH we can store the ccreg into an SImode or DImode reg only.
kono
parents:
diff changeset
926 if (! (GET_MODE (dst_reg) == SImode || GET_MODE (dst_reg) == DImode))
kono
parents:
diff changeset
927 return NULL;
kono
parents:
diff changeset
928
kono
parents:
diff changeset
929 start_sequence ();
kono
parents:
diff changeset
930
kono
parents:
diff changeset
931 emit_insn (gen_rtx_SET (m_ccreg, gen_rtx_fmt_ee (EQ, SImode,
kono
parents:
diff changeset
932 src_reg, const0_rtx)));
kono
parents:
diff changeset
933
kono
parents:
diff changeset
934 if (GET_MODE (dst_reg) == SImode)
kono
parents:
diff changeset
935 emit_move_insn (dst_reg, m_ccreg);
kono
parents:
diff changeset
936 else if (GET_MODE (dst_reg) == DImode)
kono
parents:
diff changeset
937 {
kono
parents:
diff changeset
938 emit_move_insn (gen_lowpart (SImode, dst_reg), m_ccreg);
kono
parents:
diff changeset
939 emit_move_insn (gen_highpart (SImode, dst_reg), const0_rtx);
kono
parents:
diff changeset
940 }
kono
parents:
diff changeset
941 else
kono
parents:
diff changeset
942 gcc_unreachable ();
kono
parents:
diff changeset
943
kono
parents:
diff changeset
944 rtx i = get_insns ();
kono
parents:
diff changeset
945 end_sequence ();
kono
parents:
diff changeset
946
kono
parents:
diff changeset
947 return i;
kono
parents:
diff changeset
948 }
kono
parents:
diff changeset
949
kono
parents:
diff changeset
950 rtx_insn *
kono
parents:
diff changeset
951 sh_treg_combine::make_inv_ccreg_insn (void) const
kono
parents:
diff changeset
952 {
kono
parents:
diff changeset
953 start_sequence ();
kono
parents:
diff changeset
954 rtx_insn *i = emit_insn (gen_rtx_SET (m_ccreg,
kono
parents:
diff changeset
955 gen_rtx_fmt_ee (XOR, GET_MODE (m_ccreg),
kono
parents:
diff changeset
956 m_ccreg, const1_rtx)));
kono
parents:
diff changeset
957 end_sequence ();
kono
parents:
diff changeset
958 return i;
kono
parents:
diff changeset
959 }
kono
parents:
diff changeset
960
kono
parents:
diff changeset
961 rtx
kono
parents:
diff changeset
962 sh_treg_combine::touched_insn (rtx i)
kono
parents:
diff changeset
963 {
kono
parents:
diff changeset
964 m_touched_insns.push_back (i);
kono
parents:
diff changeset
965 return i;
kono
parents:
diff changeset
966 }
kono
parents:
diff changeset
967
kono
parents:
diff changeset
968 bool
kono
parents:
diff changeset
969 sh_treg_combine::can_combine_comparisons (const_rtx x, const_rtx y) const
kono
parents:
diff changeset
970 {
kono
parents:
diff changeset
971 if (GET_CODE (x) != GET_CODE (y))
kono
parents:
diff changeset
972 return false;
kono
parents:
diff changeset
973
kono
parents:
diff changeset
974 rtx x_op0 = XEXP (x, 0);
kono
parents:
diff changeset
975 rtx x_op1 = XEXP (x, 1);
kono
parents:
diff changeset
976
kono
parents:
diff changeset
977 rtx y_op0 = XEXP (y, 0);
kono
parents:
diff changeset
978 rtx y_op1 = XEXP (y, 1);
kono
parents:
diff changeset
979
kono
parents:
diff changeset
980 if (!REG_P (x_op0) || !REG_P (y_op0))
kono
parents:
diff changeset
981 return false;
kono
parents:
diff changeset
982
kono
parents:
diff changeset
983 if (GET_MODE (x_op0) != GET_MODE (y_op0))
kono
parents:
diff changeset
984 return false;
kono
parents:
diff changeset
985
kono
parents:
diff changeset
986 // rtx_equal_p also compares the reg numbers which we do not care about
kono
parents:
diff changeset
987 // here, as long as both are regs and the modes are the same.
kono
parents:
diff changeset
988 if (REG_P (x_op1))
kono
parents:
diff changeset
989 return REG_P (y_op1) && GET_MODE (x_op1) == GET_MODE (y_op1);
kono
parents:
diff changeset
990
kono
parents:
diff changeset
991 return rtx_equal_p (x_op1, y_op1);
kono
parents:
diff changeset
992 }
kono
parents:
diff changeset
993
kono
parents:
diff changeset
994 bool
kono
parents:
diff changeset
995 sh_treg_combine::can_extend_ccreg_usage (const bb_entry& e,
kono
parents:
diff changeset
996 const cbranch_trace& trace) const
kono
parents:
diff changeset
997 {
kono
parents:
diff changeset
998 // Check if the ccreg is not modified by other insins in the BB path until
kono
parents:
diff changeset
999 // the final cbranch of the trace.
kono
parents:
diff changeset
1000 // Start checking after the cstore that follows the setcc, assuming that
kono
parents:
diff changeset
1001 // the cstore will be removed.
kono
parents:
diff changeset
1002
kono
parents:
diff changeset
1003 // The assumption here is that the specified bb_entry's BB is a direct
kono
parents:
diff changeset
1004 // predecessor of the trace.cbranch_insn's BB.
kono
parents:
diff changeset
1005 if (e.bb != trace.bb () && !is_adjacent_bb (e.bb, trace.bb ()))
kono
parents:
diff changeset
1006 log_return (false,
kono
parents:
diff changeset
1007 "can't extend ccreg usage -- [bb %d] and [bb %d] are not adjacent\n",
kono
parents:
diff changeset
1008 e.bb->index, trace.bb ()->index);
kono
parents:
diff changeset
1009
kono
parents:
diff changeset
1010 if (e.cstore.empty ())
kono
parents:
diff changeset
1011 log_return (false, "can't extend ccreg usage -- no cstore\n");
kono
parents:
diff changeset
1012
kono
parents:
diff changeset
1013 // The entry's cstore is in the same BB as the final cbranch.
kono
parents:
diff changeset
1014 if (e.bb == trace.bb ())
kono
parents:
diff changeset
1015 {
kono
parents:
diff changeset
1016 if (reg_set_between_p (m_ccreg, e.cstore.insn, trace.setcc.insn))
kono
parents:
diff changeset
1017 log_return (false,
kono
parents:
diff changeset
1018 "can't extend ccreg usage -- it's modified between e.cstore.insn "
kono
parents:
diff changeset
1019 "and trace.setcc.insn");
kono
parents:
diff changeset
1020 else
kono
parents:
diff changeset
1021 return true;
kono
parents:
diff changeset
1022 }
kono
parents:
diff changeset
1023
kono
parents:
diff changeset
1024 // The entry's cstore and the final cbranch are in different BBs.
kono
parents:
diff changeset
1025 if (reg_set_between_p (m_ccreg, e.cstore.insn, NEXT_INSN (BB_END (e.bb))))
kono
parents:
diff changeset
1026 log_return (false,
kono
parents:
diff changeset
1027 "can't extend ccreg usage -- it's modified in [bb %d]", e.bb->index);
kono
parents:
diff changeset
1028
kono
parents:
diff changeset
1029 if (reg_set_between_p (m_ccreg, PREV_INSN (BB_HEAD (trace.bb ())),
kono
parents:
diff changeset
1030 trace.setcc.insn))
kono
parents:
diff changeset
1031 log_return (false,
kono
parents:
diff changeset
1032 "can't extend ccreg usage -- it's modified in [bb %d]",
kono
parents:
diff changeset
1033 trace.bb ()->index);
kono
parents:
diff changeset
1034
kono
parents:
diff changeset
1035 return true;
kono
parents:
diff changeset
1036 }
kono
parents:
diff changeset
1037
kono
parents:
diff changeset
1038 bool
kono
parents:
diff changeset
1039 sh_treg_combine::try_invert_branch_condition (cbranch_trace& trace)
kono
parents:
diff changeset
1040 {
kono
parents:
diff changeset
1041 log_msg ("inverting branch condition\n");
kono
parents:
diff changeset
1042
kono
parents:
diff changeset
1043 rtx& comp = trace.branch_condition_rtx_ref ();
kono
parents:
diff changeset
1044
kono
parents:
diff changeset
1045 rtx_code rev_cmp_code = reversed_comparison_code (comp, trace.cbranch_insn);
kono
parents:
diff changeset
1046
kono
parents:
diff changeset
1047 if (rev_cmp_code == UNKNOWN)
kono
parents:
diff changeset
1048 log_return (false, "reversed_comparison_code = UNKNOWN\n");
kono
parents:
diff changeset
1049
kono
parents:
diff changeset
1050 validate_change (trace.cbranch_insn, &comp,
kono
parents:
diff changeset
1051 gen_rtx_fmt_ee (rev_cmp_code,
kono
parents:
diff changeset
1052 GET_MODE (comp), XEXP (comp, 0),
kono
parents:
diff changeset
1053 XEXP (comp, 1)),
kono
parents:
diff changeset
1054 1);
kono
parents:
diff changeset
1055
kono
parents:
diff changeset
1056 if (verify_changes (num_validated_changes ()))
kono
parents:
diff changeset
1057 confirm_change_group ();
kono
parents:
diff changeset
1058 else
kono
parents:
diff changeset
1059 log_return (false, "verify_changed failed\n");
kono
parents:
diff changeset
1060
kono
parents:
diff changeset
1061 touched_insn (trace.cbranch_insn);
kono
parents:
diff changeset
1062 return true;
kono
parents:
diff changeset
1063 }
kono
parents:
diff changeset
1064
kono
parents:
diff changeset
1065 bool
kono
parents:
diff changeset
1066 sh_treg_combine::try_combine_comparisons (cbranch_trace& trace,
kono
parents:
diff changeset
1067 int cstore_count,
kono
parents:
diff changeset
1068 int inv_cstore_count,
kono
parents:
diff changeset
1069 cstore_type_t dominating_cstore)
kono
parents:
diff changeset
1070 {
kono
parents:
diff changeset
1071 log_msg ("\ntry_combine_comparisons\n");
kono
parents:
diff changeset
1072
kono
parents:
diff changeset
1073 // This function will always try to create new pseudos.
kono
parents:
diff changeset
1074 if (!can_create_pseudo_p ())
kono
parents:
diff changeset
1075 log_return (false, "can't create pseudos\n");
kono
parents:
diff changeset
1076
kono
parents:
diff changeset
1077 // Check that all ccset insns are comparisons and all comparison types in
kono
parents:
diff changeset
1078 // all BBs are the same and could be combined into one single comparison.
kono
parents:
diff changeset
1079 rtx comp = NULL_RTX;
kono
parents:
diff changeset
1080 rtx comp_insn = NULL_RTX;
kono
parents:
diff changeset
1081
kono
parents:
diff changeset
1082 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
kono
parents:
diff changeset
1083 i != trace.bb_entries.end (); ++i)
kono
parents:
diff changeset
1084 {
kono
parents:
diff changeset
1085 int i_empty_count = i->setcc.empty () + i->cstore.empty ();
kono
parents:
diff changeset
1086
kono
parents:
diff changeset
1087 // A completly empty entry is OK (could be the BB of the cbranch).
kono
parents:
diff changeset
1088 if (i_empty_count == 2)
kono
parents:
diff changeset
1089 continue;
kono
parents:
diff changeset
1090
kono
parents:
diff changeset
1091 // Otherwise we need both, the setcc and the cstore.
kono
parents:
diff changeset
1092 if (i_empty_count != 0)
kono
parents:
diff changeset
1093 log_return (false, "bb entry is not a setcc cstore pair\n");
kono
parents:
diff changeset
1094
kono
parents:
diff changeset
1095 rtx other_comp = i->comparison_rtx ();
kono
parents:
diff changeset
1096
kono
parents:
diff changeset
1097 if (!COMPARISON_P (other_comp))
kono
parents:
diff changeset
1098 {
kono
parents:
diff changeset
1099 log_msg ("setcc is not a comparison:\n");
kono
parents:
diff changeset
1100 log_rtx (other_comp);
kono
parents:
diff changeset
1101 log_return (false, "\n");
kono
parents:
diff changeset
1102 }
kono
parents:
diff changeset
1103
kono
parents:
diff changeset
1104 if (comp_insn == NULL_RTX)
kono
parents:
diff changeset
1105 {
kono
parents:
diff changeset
1106 comp = other_comp;
kono
parents:
diff changeset
1107 comp_insn = i->setcc.insn;
kono
parents:
diff changeset
1108 }
kono
parents:
diff changeset
1109 else if (!can_combine_comparisons (comp, other_comp))
kono
parents:
diff changeset
1110 return false;
kono
parents:
diff changeset
1111
kono
parents:
diff changeset
1112 // The goal here is to eliminate all cstores and comparisons in the BBs.
kono
parents:
diff changeset
1113 // Thus check if every cstore can actually be removed safely.
kono
parents:
diff changeset
1114 if (!can_remove_cstore (*i, trace) || !can_remove_comparison (*i, trace))
kono
parents:
diff changeset
1115 return false;
kono
parents:
diff changeset
1116 }
kono
parents:
diff changeset
1117
kono
parents:
diff changeset
1118 // FIXME: The first operand of the comparison must be a simple reg.
kono
parents:
diff changeset
1119 // This effectively prohibits combining div0s comparisons such as
kono
parents:
diff changeset
1120 // (lt:SI (xor:SI (reg:SI) (reg:SI)))
kono
parents:
diff changeset
1121 if (!REG_P (XEXP (comp, 0)))
kono
parents:
diff changeset
1122 {
kono
parents:
diff changeset
1123 log_msg ("comparison operand 0\n");
kono
parents:
diff changeset
1124 log_rtx (XEXP (comp, 0));
kono
parents:
diff changeset
1125 log_return (false, "\nis not a reg\n");
kono
parents:
diff changeset
1126 }
kono
parents:
diff changeset
1127
kono
parents:
diff changeset
1128 rtx comp_op0 = gen_reg_rtx (GET_MODE (XEXP (comp, 0)));
kono
parents:
diff changeset
1129 rtx comp_op1 = REG_P (XEXP (comp, 1))
kono
parents:
diff changeset
1130 ? gen_reg_rtx (GET_MODE (XEXP (comp, 1)))
kono
parents:
diff changeset
1131 : XEXP (comp, 1);
kono
parents:
diff changeset
1132
kono
parents:
diff changeset
1133 // If there are both, inverting and non-inverting cstores, they can only
kono
parents:
diff changeset
1134 // be eliminated if the comparison can be inverted. We assume that the
kono
parents:
diff changeset
1135 // comparison insns that we find are already minimal and canonicalized.
kono
parents:
diff changeset
1136 // There is one special case though, where an integer comparison
kono
parents:
diff changeset
1137 // (eq (reg) (const_int 0))
kono
parents:
diff changeset
1138 // can be inverted with a sequence
kono
parents:
diff changeset
1139 // (set (t) (eq (reg) (const_int 0))
kono
parents:
diff changeset
1140 // (set (reg) (t))
kono
parents:
diff changeset
1141 // (eq (reg) (const_int 0))
kono
parents:
diff changeset
1142 //
kono
parents:
diff changeset
1143 // FIXME: On SH2A it might be better to use the nott insn in this case,
kono
parents:
diff changeset
1144 // i.e. do the try_eliminate_cstores approach instead.
kono
parents:
diff changeset
1145 if (inv_cstore_count != 0 && cstore_count != 0)
kono
parents:
diff changeset
1146 {
kono
parents:
diff changeset
1147 if (make_not_reg_insn (comp_op0, comp_op0) == NULL_RTX)
kono
parents:
diff changeset
1148 log_return (false, "make_not_reg_insn failed.\n");
kono
parents:
diff changeset
1149
kono
parents:
diff changeset
1150 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
kono
parents:
diff changeset
1151 i != trace.bb_entries.end (); ++i)
kono
parents:
diff changeset
1152 {
kono
parents:
diff changeset
1153 if (i->setcc.empty () || i->cstore.empty ())
kono
parents:
diff changeset
1154 continue;
kono
parents:
diff changeset
1155
kono
parents:
diff changeset
1156 if (i->cstore_type != dominating_cstore
kono
parents:
diff changeset
1157 && !is_cmp_eq_zero (i->comparison_rtx ()))
kono
parents:
diff changeset
1158 {
kono
parents:
diff changeset
1159 log_msg ("can't invert comparison in insn\n");
kono
parents:
diff changeset
1160 log_insn (i->setcc.insn);
kono
parents:
diff changeset
1161 log_return (false,
kono
parents:
diff changeset
1162 "\nbecause it's not a (eq (reg) (const_int 0))\n");
kono
parents:
diff changeset
1163 }
kono
parents:
diff changeset
1164 }
kono
parents:
diff changeset
1165 }
kono
parents:
diff changeset
1166
kono
parents:
diff changeset
1167 if (dominating_cstore == cstore_normal
kono
parents:
diff changeset
1168 && !try_invert_branch_condition (trace))
kono
parents:
diff changeset
1169 return false;
kono
parents:
diff changeset
1170
kono
parents:
diff changeset
1171 // Replace the test insn before the cbranch with the common comparison.
kono
parents:
diff changeset
1172 // Instead of creating a new insn from scratch we copy the common comparison
kono
parents:
diff changeset
1173 // pattern. This simplifies handling parallel comparison patterns, such as
kono
parents:
diff changeset
1174 // FP comparisons on SH, which have an extra use on FPSCR.
kono
parents:
diff changeset
1175 log_msg ("installing common comparison in [bb %d]\n", trace.bb ()->index);
kono
parents:
diff changeset
1176
kono
parents:
diff changeset
1177 rtx common_comp_pat = copy_rtx (PATTERN (comp_insn));
kono
parents:
diff changeset
1178 rtx common_comp = const_cast<rtx> (set_of (m_ccreg, common_comp_pat));
kono
parents:
diff changeset
1179
kono
parents:
diff changeset
1180 gcc_assert (common_comp != NULL_RTX);
kono
parents:
diff changeset
1181
kono
parents:
diff changeset
1182 XEXP (XEXP (common_comp, 1), 0) = comp_op0;
kono
parents:
diff changeset
1183 XEXP (XEXP (common_comp, 1), 1) = comp_op1;
kono
parents:
diff changeset
1184
kono
parents:
diff changeset
1185 log_rtx (common_comp_pat);
kono
parents:
diff changeset
1186 log_msg ("\n");
kono
parents:
diff changeset
1187
kono
parents:
diff changeset
1188 rtx common_comp_insn = touched_insn (emit_insn_after (common_comp_pat,
kono
parents:
diff changeset
1189 trace.setcc.insn));
kono
parents:
diff changeset
1190
kono
parents:
diff changeset
1191 if (REG_P (comp_op0))
kono
parents:
diff changeset
1192 add_reg_note (common_comp_insn, REG_DEAD, copy_rtx (comp_op0));
kono
parents:
diff changeset
1193 if (REG_P (comp_op1))
kono
parents:
diff changeset
1194 add_reg_note (common_comp_insn, REG_DEAD, copy_rtx (comp_op1));
kono
parents:
diff changeset
1195
kono
parents:
diff changeset
1196 delete_insn (trace.setcc.insn);
kono
parents:
diff changeset
1197
kono
parents:
diff changeset
1198 // Replace comparison and cstore insns with reg-reg moves in all BBs.
kono
parents:
diff changeset
1199 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
kono
parents:
diff changeset
1200 i != trace.bb_entries.end (); ++i)
kono
parents:
diff changeset
1201 {
kono
parents:
diff changeset
1202 if (i->setcc.empty () || i->cstore.empty ())
kono
parents:
diff changeset
1203 continue;
kono
parents:
diff changeset
1204
kono
parents:
diff changeset
1205 rtx i_comp_op0 = XEXP (i->comparison_rtx (), 0);
kono
parents:
diff changeset
1206 rtx i_comp_op1 = XEXP (i->comparison_rtx (), 1);
kono
parents:
diff changeset
1207
kono
parents:
diff changeset
1208 if (i->cstore_type == dominating_cstore)
kono
parents:
diff changeset
1209 {
kono
parents:
diff changeset
1210 log_msg ("replacing comparison and cstore with reg move "
kono
parents:
diff changeset
1211 "in [bb %d]\n", i->bb->index);
kono
parents:
diff changeset
1212
kono
parents:
diff changeset
1213 rtx new_i = touched_insn (
kono
parents:
diff changeset
1214 emit_insn_after (gen_move_insn (comp_op0, i_comp_op0),
kono
parents:
diff changeset
1215 i->setcc.insn));
kono
parents:
diff changeset
1216
kono
parents:
diff changeset
1217 if (REG_P (i_comp_op0)
kono
parents:
diff changeset
1218 && reg_dead_after_insn (i_comp_op0, i->setcc.insn))
kono
parents:
diff changeset
1219 add_reg_note (new_i, REG_DEAD, copy_rtx (i_comp_op0));
kono
parents:
diff changeset
1220
kono
parents:
diff changeset
1221 // If the second operand is a reg, have to emit a move insn.
kono
parents:
diff changeset
1222 // Otherwise assume it's a const_int and just reference it.
kono
parents:
diff changeset
1223 if (REG_P (comp_op1))
kono
parents:
diff changeset
1224 {
kono
parents:
diff changeset
1225 new_i = touched_insn (
kono
parents:
diff changeset
1226 emit_insn_after (gen_move_insn (comp_op1, i_comp_op1),
kono
parents:
diff changeset
1227 i->setcc.insn));
kono
parents:
diff changeset
1228
kono
parents:
diff changeset
1229 if (reg_dead_after_insn (i_comp_op1, i->setcc.insn))
kono
parents:
diff changeset
1230 add_reg_note (new_i, REG_DEAD, copy_rtx (i_comp_op1));
kono
parents:
diff changeset
1231 }
kono
parents:
diff changeset
1232 }
kono
parents:
diff changeset
1233 else
kono
parents:
diff changeset
1234 {
kono
parents:
diff changeset
1235 log_msg ("replacing comparison and cstore with inverting reg move "
kono
parents:
diff changeset
1236 "in [bb %d]\n", i->bb->index);
kono
parents:
diff changeset
1237
kono
parents:
diff changeset
1238 rtx new_i = make_not_reg_insn (comp_op0, i_comp_op0);
kono
parents:
diff changeset
1239 if (REG_P (i_comp_op0)
kono
parents:
diff changeset
1240 && reg_dead_after_insn (i_comp_op0, i->setcc.insn))
kono
parents:
diff changeset
1241 add_reg_note (new_i, REG_DEAD, copy_rtx (i_comp_op0));
kono
parents:
diff changeset
1242
kono
parents:
diff changeset
1243 touched_insn (emit_insn_after (new_i, i->setcc.insn));
kono
parents:
diff changeset
1244 }
kono
parents:
diff changeset
1245
kono
parents:
diff changeset
1246 delete_insn (i->cstore.insn);
kono
parents:
diff changeset
1247 delete_insn (i->setcc.insn);
kono
parents:
diff changeset
1248 }
kono
parents:
diff changeset
1249
kono
parents:
diff changeset
1250 return true;
kono
parents:
diff changeset
1251 }
kono
parents:
diff changeset
1252
kono
parents:
diff changeset
1253 bool
kono
parents:
diff changeset
1254 sh_treg_combine::try_eliminate_cstores (cbranch_trace& trace,
kono
parents:
diff changeset
1255 int cstore_count, int inv_cstore_count,
kono
parents:
diff changeset
1256 cstore_type_t dominating_cstore)
kono
parents:
diff changeset
1257 {
kono
parents:
diff changeset
1258 log_msg ("\ntry_eliminate_cstores\n");
kono
parents:
diff changeset
1259
kono
parents:
diff changeset
1260 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
kono
parents:
diff changeset
1261 i != trace.bb_entries.end (); ++i)
kono
parents:
diff changeset
1262 {
kono
parents:
diff changeset
1263 // A completly empty entry is OK (could be the BB of the cbranch).
kono
parents:
diff changeset
1264 if (i->setcc.empty () && i->cstore.empty ())
kono
parents:
diff changeset
1265 continue;
kono
parents:
diff changeset
1266
kono
parents:
diff changeset
1267 // We're going to eliminate cstores, but for that they have to be
kono
parents:
diff changeset
1268 // there. We don't care about the setcc in this case.
kono
parents:
diff changeset
1269 if (i->cstore.empty ())
kono
parents:
diff changeset
1270 log_return (false, "bb entry cstore empty -- aborting\n");
kono
parents:
diff changeset
1271
kono
parents:
diff changeset
1272 // The goal here is to eliminate all cstores in the BBs and extend the
kono
parents:
diff changeset
1273 // ccreg usage.
kono
parents:
diff changeset
1274 if (!can_extend_ccreg_usage (*i, trace))
kono
parents:
diff changeset
1275 return false;
kono
parents:
diff changeset
1276
kono
parents:
diff changeset
1277 // If the cstore can't be removed we can keep it around as long as
kono
parents:
diff changeset
1278 // it doesn't modify the ccreg.
kono
parents:
diff changeset
1279 if (!can_remove_cstore (*i, trace)
kono
parents:
diff changeset
1280 && modified_in_p (m_ccreg, i->cstore.insn))
kono
parents:
diff changeset
1281 log_return (false, "cstore sets ccreg -- aborting\n");
kono
parents:
diff changeset
1282 }
kono
parents:
diff changeset
1283
kono
parents:
diff changeset
1284 // If there are both, inverting and non-inverting cstores, we'll have to
kono
parents:
diff changeset
1285 // invert the ccreg as a replacement for one of them.
kono
parents:
diff changeset
1286 if (cstore_count != 0 && inv_cstore_count != 0)
kono
parents:
diff changeset
1287 {
kono
parents:
diff changeset
1288 rtx_insn *i = make_inv_ccreg_insn ();
kono
parents:
diff changeset
1289 if (recog_memoized (i) < 0)
kono
parents:
diff changeset
1290 {
kono
parents:
diff changeset
1291 log_msg ("failed to match ccreg inversion insn:\n");
kono
parents:
diff changeset
1292 log_rtx (PATTERN (i));
kono
parents:
diff changeset
1293 log_return (false, "\naborting\n");
kono
parents:
diff changeset
1294 }
kono
parents:
diff changeset
1295 }
kono
parents:
diff changeset
1296
kono
parents:
diff changeset
1297 if (dominating_cstore == cstore_normal
kono
parents:
diff changeset
1298 && !try_invert_branch_condition (trace))
kono
parents:
diff changeset
1299 return false;
kono
parents:
diff changeset
1300
kono
parents:
diff changeset
1301 // Eliminate cstores in all BBs.
kono
parents:
diff changeset
1302 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
kono
parents:
diff changeset
1303 i != trace.bb_entries.end (); ++i)
kono
parents:
diff changeset
1304 {
kono
parents:
diff changeset
1305 if (i->cstore.empty ())
kono
parents:
diff changeset
1306 continue;
kono
parents:
diff changeset
1307
kono
parents:
diff changeset
1308 if (i->cstore_type == dominating_cstore)
kono
parents:
diff changeset
1309 log_msg ("removing cstore in [bb %d]\n", i->bb->index);
kono
parents:
diff changeset
1310 else
kono
parents:
diff changeset
1311 {
kono
parents:
diff changeset
1312 log_msg ("replacing cstore with ccreg inversion in [bb %d]\n",
kono
parents:
diff changeset
1313 i->bb->index);
kono
parents:
diff changeset
1314
kono
parents:
diff changeset
1315 touched_insn (
kono
parents:
diff changeset
1316 emit_insn_after (make_inv_ccreg_insn (), i->cstore.insn));
kono
parents:
diff changeset
1317 }
kono
parents:
diff changeset
1318
kono
parents:
diff changeset
1319 if (can_remove_cstore (*i, trace))
kono
parents:
diff changeset
1320 delete_insn (i->cstore.insn);
kono
parents:
diff changeset
1321 }
kono
parents:
diff changeset
1322
kono
parents:
diff changeset
1323 log_msg ("removing test insn before cbranch\n");
kono
parents:
diff changeset
1324 delete_insn (trace.setcc.insn);
kono
parents:
diff changeset
1325 return true;
kono
parents:
diff changeset
1326 }
kono
parents:
diff changeset
1327
kono
parents:
diff changeset
1328 void
kono
parents:
diff changeset
1329 sh_treg_combine::try_optimize_cbranch (rtx_insn *insn)
kono
parents:
diff changeset
1330 {
kono
parents:
diff changeset
1331 cbranch_trace trace (insn);
kono
parents:
diff changeset
1332
kono
parents:
diff changeset
1333 log_msg ("\n\n--------------------------------------\n");
kono
parents:
diff changeset
1334 log_msg ("found cbranch insn in [bb %d]:\n", trace.bb ()->index);
kono
parents:
diff changeset
1335 log_insn (insn);
kono
parents:
diff changeset
1336
kono
parents:
diff changeset
1337 trace.cbranch_type = branch_condition_type (trace.branch_condition_rtx ());
kono
parents:
diff changeset
1338
kono
parents:
diff changeset
1339 if (trace.cbranch_type == branch_if_true)
kono
parents:
diff changeset
1340 log_msg ("condition: branch if true\n");
kono
parents:
diff changeset
1341 else if (trace.cbranch_type == branch_if_false)
kono
parents:
diff changeset
1342 log_msg ("condition: branch if false\n");
kono
parents:
diff changeset
1343 else
kono
parents:
diff changeset
1344 {
kono
parents:
diff changeset
1345 log_msg ("unknown branch condition\n");
kono
parents:
diff changeset
1346 log_rtx (trace.branch_condition_rtx ());
kono
parents:
diff changeset
1347 log_return_void ("\n");
kono
parents:
diff changeset
1348 }
kono
parents:
diff changeset
1349
kono
parents:
diff changeset
1350 update_ccreg_mode (trace.branch_condition_rtx ());
kono
parents:
diff changeset
1351
kono
parents:
diff changeset
1352 // Scan the insns backwards for an insn that sets the ccreg by testing a
kono
parents:
diff changeset
1353 // reg against zero like
kono
parents:
diff changeset
1354 // (set (reg ccreg) (eq (reg) (const_int 0)))
kono
parents:
diff changeset
1355 // The testing insn could also be outside of the current basic block, but
kono
parents:
diff changeset
1356 // for now we limit the search to the current basic block.
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1357 trace.setcc = find_set_of_reg_bb
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1358 (m_ccreg, prev_nonnote_nondebug_insn_bb (insn));
111
kono
parents:
diff changeset
1359
kono
parents:
diff changeset
1360 if (trace.setcc.set_src () == NULL_RTX)
kono
parents:
diff changeset
1361 log_return_void ("could not find set of ccreg in current BB\n");
kono
parents:
diff changeset
1362
kono
parents:
diff changeset
1363 if (!is_cmp_eq_zero (trace.setcc.set_src ())
kono
parents:
diff changeset
1364 && !is_inverted_ccreg (trace.setcc.set_src ()))
kono
parents:
diff changeset
1365 {
kono
parents:
diff changeset
1366 log_msg ("unsupported set of ccreg in current BB: ");
kono
parents:
diff changeset
1367 log_rtx (trace.setcc.set_src ());
kono
parents:
diff changeset
1368 log_return_void ("\n");
kono
parents:
diff changeset
1369 }
kono
parents:
diff changeset
1370
kono
parents:
diff changeset
1371 rtx trace_reg = XEXP (trace.setcc.set_src (), 0);
kono
parents:
diff changeset
1372
kono
parents:
diff changeset
1373 log_msg ("set of ccreg:\n");
kono
parents:
diff changeset
1374 log_insn (trace.setcc.insn);
kono
parents:
diff changeset
1375
kono
parents:
diff changeset
1376 // See if we can remove the trace.setcc insn safely.
kono
parents:
diff changeset
1377 if (reg_used_between_p (m_ccreg, trace.setcc.insn, trace.cbranch_insn))
kono
parents:
diff changeset
1378 log_return_void ("ccreg used between testing insn and branch insn\n");
kono
parents:
diff changeset
1379
kono
parents:
diff changeset
1380 if (volatile_insn_p (PATTERN (trace.setcc.insn)))
kono
parents:
diff changeset
1381 {
kono
parents:
diff changeset
1382 log_msg ("can't remove insn\n");
kono
parents:
diff changeset
1383 log_insn (trace.setcc.insn);
kono
parents:
diff changeset
1384 log_return_void ("\nbecause it's volatile\n");
kono
parents:
diff changeset
1385 }
kono
parents:
diff changeset
1386
kono
parents:
diff changeset
1387 // If the ccreg is inverted before cbranch try inverting the branch
kono
parents:
diff changeset
1388 // condition.
kono
parents:
diff changeset
1389 if (is_inverted_ccreg (trace.setcc.set_src ()))
kono
parents:
diff changeset
1390 {
kono
parents:
diff changeset
1391 if (!trace.can_invert_condition ())
kono
parents:
diff changeset
1392 log_return_void ("branch condition can't be inverted - aborting\n");
kono
parents:
diff changeset
1393
kono
parents:
diff changeset
1394 if (try_invert_branch_condition (trace))
kono
parents:
diff changeset
1395 delete_insn (trace.setcc.insn);
kono
parents:
diff changeset
1396
kono
parents:
diff changeset
1397 return;
kono
parents:
diff changeset
1398 }
kono
parents:
diff changeset
1399
kono
parents:
diff changeset
1400 // Now that we have an insn which tests some reg and sets the condition
kono
parents:
diff changeset
1401 // reg before the conditional branch, try to figure out how that tested
kono
parents:
diff changeset
1402 // reg was formed, i.e. find all the insns that set the tested reg in
kono
parents:
diff changeset
1403 // some way.
kono
parents:
diff changeset
1404 // The tested reg might be set in multiple basic blocks so we need to
kono
parents:
diff changeset
1405 // check all basic blocks which can reach this current basic block.
kono
parents:
diff changeset
1406 // If the set of reg is an inverting or non-inverting store of the condition
kono
parents:
diff changeset
1407 // register, check how the ccreg value was obtained.
kono
parents:
diff changeset
1408 log_msg ("\ntracing ");
kono
parents:
diff changeset
1409 log_rtx (trace_reg);
kono
parents:
diff changeset
1410 log_msg ("\n");
kono
parents:
diff changeset
1411
kono
parents:
diff changeset
1412
kono
parents:
diff changeset
1413 // First check the basic block where the conditional branch is in.
kono
parents:
diff changeset
1414 // If we find it here there's no point in checking other BBs.
kono
parents:
diff changeset
1415 trace.bb_entries.push_front (bb_entry (trace.bb ()));
kono
parents:
diff changeset
1416
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1417 record_return_t res = record_set_of_reg
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1418 (trace_reg, prev_nonnote_nondebug_insn_bb (trace.setcc.insn),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1419 trace.bb_entries.front ());
111
kono
parents:
diff changeset
1420
kono
parents:
diff changeset
1421 if (res == other_set_found)
kono
parents:
diff changeset
1422 log_return_void ("other set found - aborting trace\n");
kono
parents:
diff changeset
1423 else if (res == set_not_found)
kono
parents:
diff changeset
1424 {
kono
parents:
diff changeset
1425 // It seems the initial search in the BB of the conditional branch
kono
parents:
diff changeset
1426 // didn't find anything. Now look in all predecessor BBs.
kono
parents:
diff changeset
1427 for (edge_iterator ei = ei_start (trace.bb ()->preds);
kono
parents:
diff changeset
1428 !ei_end_p (ei); ei_next (&ei))
kono
parents:
diff changeset
1429 {
kono
parents:
diff changeset
1430 edge e = ei_edge (ei);
kono
parents:
diff changeset
1431 trace.bb_entries.push_front (bb_entry (e->src));
kono
parents:
diff changeset
1432
kono
parents:
diff changeset
1433 res = record_set_of_reg (trace_reg, BB_END (e->src),
kono
parents:
diff changeset
1434 trace.bb_entries.front ());
kono
parents:
diff changeset
1435 if (res != set_found)
kono
parents:
diff changeset
1436 log_return_void ("set not found - aborting trace\n");
kono
parents:
diff changeset
1437 }
kono
parents:
diff changeset
1438 }
kono
parents:
diff changeset
1439
kono
parents:
diff changeset
1440 if (dump_file != NULL)
kono
parents:
diff changeset
1441 {
kono
parents:
diff changeset
1442 log_msg ("\ncbranch trace summary:\n");
kono
parents:
diff changeset
1443 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
kono
parents:
diff changeset
1444 i != trace.bb_entries.end (); ++i)
kono
parents:
diff changeset
1445 {
kono
parents:
diff changeset
1446 log_msg ("\n[bb %d]\n", i->bb->index);
kono
parents:
diff changeset
1447 if (!i->setcc.empty ())
kono
parents:
diff changeset
1448 {
kono
parents:
diff changeset
1449 log_rtx (i->setcc.set_rtx);
kono
parents:
diff changeset
1450 log_msg ("\n");
kono
parents:
diff changeset
1451 }
kono
parents:
diff changeset
1452 if (!i->cstore.empty ())
kono
parents:
diff changeset
1453 {
kono
parents:
diff changeset
1454 log_rtx (i->cstore.set_rtx);
kono
parents:
diff changeset
1455 log_msg ("\n");
kono
parents:
diff changeset
1456 }
kono
parents:
diff changeset
1457
kono
parents:
diff changeset
1458 for (std::vector<set_of_reg>::const_reverse_iterator j =
kono
parents:
diff changeset
1459 i->cstore_reg_reg_copies.rbegin ();
kono
parents:
diff changeset
1460 j != i->cstore_reg_reg_copies.rend (); ++j)
kono
parents:
diff changeset
1461 {
kono
parents:
diff changeset
1462 log_rtx (j->set_rtx);
kono
parents:
diff changeset
1463 log_msg ("\n");
kono
parents:
diff changeset
1464 }
kono
parents:
diff changeset
1465 }
kono
parents:
diff changeset
1466
kono
parents:
diff changeset
1467 log_rtx (trace.setcc.set_rtx);
kono
parents:
diff changeset
1468 log_msg ("\n");
kono
parents:
diff changeset
1469 log_rtx (PATTERN (trace.cbranch_insn));
kono
parents:
diff changeset
1470 log_msg ("\n");
kono
parents:
diff changeset
1471 }
kono
parents:
diff changeset
1472
kono
parents:
diff changeset
1473 // Check that we don't have any empty BBs.
kono
parents:
diff changeset
1474 // Only the BB with the cbranch may be empty.
kono
parents:
diff changeset
1475 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
kono
parents:
diff changeset
1476 i != trace.bb_entries.end (); ++i)
kono
parents:
diff changeset
1477 if (i->setcc.empty () && i->cstore.empty () && i->bb != trace.bb ())
kono
parents:
diff changeset
1478 log_return_void ("\n[bb %d] is empty - aborting.\n", i->bb->index);
kono
parents:
diff changeset
1479
kono
parents:
diff changeset
1480 // Determine the dominating cstore type
kono
parents:
diff changeset
1481 // FIXME: Try to take the probabilities of the BBs into account somehow.
kono
parents:
diff changeset
1482 int cstore_count = 0;
kono
parents:
diff changeset
1483 int inv_cstore_count = 0;
kono
parents:
diff changeset
1484
kono
parents:
diff changeset
1485 for (std::list<bb_entry>::const_iterator i = trace.bb_entries.begin ();
kono
parents:
diff changeset
1486 i != trace.bb_entries.end (); ++i)
kono
parents:
diff changeset
1487 {
kono
parents:
diff changeset
1488 if (i->cstore_type == cstore_normal)
kono
parents:
diff changeset
1489 cstore_count += 1;
kono
parents:
diff changeset
1490 else if (i->cstore_type == cstore_inverted)
kono
parents:
diff changeset
1491 inv_cstore_count += 1;
kono
parents:
diff changeset
1492 }
kono
parents:
diff changeset
1493
kono
parents:
diff changeset
1494 log_msg ("cstore count = %d inverted cstore count = %d\n",
kono
parents:
diff changeset
1495 cstore_count, inv_cstore_count);
kono
parents:
diff changeset
1496
kono
parents:
diff changeset
1497 // This puts a priority on inverting cstores.
kono
parents:
diff changeset
1498 cstore_type_t dominating_cstore = inv_cstore_count >= cstore_count
kono
parents:
diff changeset
1499 ? cstore_inverted
kono
parents:
diff changeset
1500 : cstore_normal;
kono
parents:
diff changeset
1501
kono
parents:
diff changeset
1502 if (dominating_cstore == cstore_inverted)
kono
parents:
diff changeset
1503 log_msg ("will try to eliminate inverted cstore\n");
kono
parents:
diff changeset
1504 else if (dominating_cstore == cstore_normal)
kono
parents:
diff changeset
1505 {
kono
parents:
diff changeset
1506 log_msg ("will try to eliminate normal cstore\n");
kono
parents:
diff changeset
1507 if (!trace.can_invert_condition ())
kono
parents:
diff changeset
1508 log_return_void ("branch condition can't be inverted - aborting\n");
kono
parents:
diff changeset
1509 }
kono
parents:
diff changeset
1510 else
kono
parents:
diff changeset
1511 gcc_unreachable ();
kono
parents:
diff changeset
1512
kono
parents:
diff changeset
1513 if (try_combine_comparisons (trace, cstore_count, inv_cstore_count,
kono
parents:
diff changeset
1514 dominating_cstore))
kono
parents:
diff changeset
1515 return;
kono
parents:
diff changeset
1516
kono
parents:
diff changeset
1517 try_eliminate_cstores (trace, cstore_count, inv_cstore_count,
kono
parents:
diff changeset
1518 dominating_cstore);
kono
parents:
diff changeset
1519 }
kono
parents:
diff changeset
1520
kono
parents:
diff changeset
1521 bool
kono
parents:
diff changeset
1522 sh_treg_combine::gate (function *)
kono
parents:
diff changeset
1523 {
kono
parents:
diff changeset
1524 return optimize > 0;
kono
parents:
diff changeset
1525 }
kono
parents:
diff changeset
1526
kono
parents:
diff changeset
1527 unsigned int
kono
parents:
diff changeset
1528 sh_treg_combine::execute (function *fun)
kono
parents:
diff changeset
1529 {
kono
parents:
diff changeset
1530 unsigned int ccr0 = INVALID_REGNUM;
kono
parents:
diff changeset
1531 unsigned int ccr1 = INVALID_REGNUM;
kono
parents:
diff changeset
1532
kono
parents:
diff changeset
1533 if (targetm.fixed_condition_code_regs (&ccr0, &ccr1)
kono
parents:
diff changeset
1534 && ccr0 != INVALID_REGNUM)
kono
parents:
diff changeset
1535 {
kono
parents:
diff changeset
1536 // Initially create a reg rtx with VOIDmode.
kono
parents:
diff changeset
1537 // When the first conditional branch is discovered, the mode is changed
kono
parents:
diff changeset
1538 // to the mode that is actually used by the target.
kono
parents:
diff changeset
1539 m_ccreg = gen_rtx_REG (VOIDmode, ccr0);
kono
parents:
diff changeset
1540 }
kono
parents:
diff changeset
1541
kono
parents:
diff changeset
1542 if (m_ccreg == NULL_RTX)
kono
parents:
diff changeset
1543 log_return (0, "no ccreg.\n\n");
kono
parents:
diff changeset
1544
kono
parents:
diff changeset
1545 if (STORE_FLAG_VALUE != 1)
kono
parents:
diff changeset
1546 log_return (0, "unsupported STORE_FLAG_VALUE %d", STORE_FLAG_VALUE);
kono
parents:
diff changeset
1547
kono
parents:
diff changeset
1548 log_msg ("ccreg: ");
kono
parents:
diff changeset
1549 log_rtx (m_ccreg);
kono
parents:
diff changeset
1550 log_msg (" STORE_FLAG_VALUE = %d\n", STORE_FLAG_VALUE);
kono
parents:
diff changeset
1551
kono
parents:
diff changeset
1552 // Look for basic blocks that end with a conditional branch or for
kono
parents:
diff changeset
1553 // conditional insns and try to optimize them.
kono
parents:
diff changeset
1554 basic_block bb;
kono
parents:
diff changeset
1555 FOR_EACH_BB_FN (bb, fun)
kono
parents:
diff changeset
1556 {
kono
parents:
diff changeset
1557 rtx_insn* i = BB_END (bb);
kono
parents:
diff changeset
1558 if (i == NULL || i == PREV_INSN (BB_HEAD (bb)))
kono
parents:
diff changeset
1559 continue;
kono
parents:
diff changeset
1560
kono
parents:
diff changeset
1561 // A conditional branch is always the last insn of a basic block.
kono
parents:
diff changeset
1562 if (any_condjump_p (i) && onlyjump_p (i))
kono
parents:
diff changeset
1563 {
kono
parents:
diff changeset
1564 try_optimize_cbranch (i);
kono
parents:
diff changeset
1565 i = PREV_INSN (i);
kono
parents:
diff changeset
1566 }
kono
parents:
diff changeset
1567
kono
parents:
diff changeset
1568 // Check all insns in block for conditional insns.
kono
parents:
diff changeset
1569 for (; i != NULL && i != PREV_INSN (BB_HEAD (bb)); i = PREV_INSN (i))
kono
parents:
diff changeset
1570 if (is_conditional_insn (i))
kono
parents:
diff changeset
1571 try_optimize_cbranch (i);
kono
parents:
diff changeset
1572 }
kono
parents:
diff changeset
1573
kono
parents:
diff changeset
1574 log_msg ("\n\n");
kono
parents:
diff changeset
1575
kono
parents:
diff changeset
1576 // If new insns are created and this pass is executed after all insns
kono
parents:
diff changeset
1577 // have been split already, we must split the insns we've changed or added
kono
parents:
diff changeset
1578 // ourselves here.
kono
parents:
diff changeset
1579 // FIXME: Multi-word operations (which emit multiple insns) are not handled
kono
parents:
diff changeset
1580 // properly here, since only one insn will end up in 'm_touched_insns'.
kono
parents:
diff changeset
1581 // On SH this is not a problem though.
kono
parents:
diff changeset
1582 if (m_split_insns)
kono
parents:
diff changeset
1583 for (std::vector<rtx>::const_iterator i = m_touched_insns.begin ();
kono
parents:
diff changeset
1584 i != m_touched_insns.end (); ++i)
kono
parents:
diff changeset
1585 {
kono
parents:
diff changeset
1586 log_msg ("trying to split insn:\n");
kono
parents:
diff changeset
1587 log_insn (*i);
kono
parents:
diff changeset
1588 log_msg ("\n");
kono
parents:
diff changeset
1589 try_split (PATTERN (*i), safe_as_a <rtx_insn *> (*i), 0);
kono
parents:
diff changeset
1590 }
kono
parents:
diff changeset
1591
kono
parents:
diff changeset
1592 m_touched_insns.clear ();
kono
parents:
diff changeset
1593 log_return (0, "\n\n");
kono
parents:
diff changeset
1594 }
kono
parents:
diff changeset
1595
kono
parents:
diff changeset
1596 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
kono
parents:
diff changeset
1597 // This allows instantiating the pass somewhere else without having to pull
kono
parents:
diff changeset
1598 // in a header file.
kono
parents:
diff changeset
1599 opt_pass*
kono
parents:
diff changeset
1600 make_pass_sh_treg_combine (gcc::context* ctx, bool split_insns,
kono
parents:
diff changeset
1601 const char* name)
kono
parents:
diff changeset
1602 {
kono
parents:
diff changeset
1603 return new sh_treg_combine (ctx, split_insns, name);
kono
parents:
diff changeset
1604 }