annotate gcc/config/sh/sh_treg_combine.cc @ 111:04ced10e8804

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