annotate gcc/config/sh/sh_optimize_sett_clrt.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 optimize clrt and sett insns.
kono
parents:
diff changeset
2 Copyright (C) 2013-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
3
kono
parents:
diff changeset
4 This file is part of GCC.
kono
parents:
diff changeset
5
kono
parents:
diff changeset
6 GCC is free software; you can redistribute it and/or modify
kono
parents:
diff changeset
7 it under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
8 the Free Software Foundation; either version 3, or (at your option)
kono
parents:
diff changeset
9 any later version.
kono
parents:
diff changeset
10
kono
parents:
diff changeset
11 GCC is distributed in the hope that it will be useful,
kono
parents:
diff changeset
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kono
parents:
diff changeset
14 GNU General Public License for more details.
kono
parents:
diff changeset
15
kono
parents:
diff changeset
16 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
17 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
18 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
19
kono
parents:
diff changeset
20 #include "config.h"
kono
parents:
diff changeset
21 #include "system.h"
kono
parents:
diff changeset
22 #include "coretypes.h"
kono
parents:
diff changeset
23 #include "backend.h"
kono
parents:
diff changeset
24 #include "target.h"
kono
parents:
diff changeset
25 #include "rtl.h"
kono
parents:
diff changeset
26 #include "df.h"
kono
parents:
diff changeset
27 #include "cfgrtl.h"
kono
parents:
diff changeset
28 #include "tree-pass.h"
kono
parents:
diff changeset
29
kono
parents:
diff changeset
30 #include <vector>
kono
parents:
diff changeset
31 #include <algorithm>
kono
parents:
diff changeset
32
kono
parents:
diff changeset
33 /*
kono
parents:
diff changeset
34 This pass tries to eliminate unnecessary sett or clrt instructions in cases
kono
parents:
diff changeset
35 where the ccreg value is already known to be the same as the constant set
kono
parents:
diff changeset
36 would set it to. This is done as follows:
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 Check every BB's insn and see if it's a sett or clrt.
kono
parents:
diff changeset
39 Once a sett or clrt insn is hit, walk insns and predecessor basic blocks
kono
parents:
diff changeset
40 backwards from that insn and determine all possible ccreg values from all
kono
parents:
diff changeset
41 basic block paths.
kono
parents:
diff changeset
42 Insns that set the ccreg value in some way (simple set, clobber etc) are
kono
parents:
diff changeset
43 recorded. Conditional branches where one edge leads to the sett / clrt insn
kono
parents:
diff changeset
44 are also recorded, since for each edge in the conditional branch the ccreg
kono
parents:
diff changeset
45 value is known constant.
kono
parents:
diff changeset
46 After collecting all possible ccreg values at the sett / clrt insn, check that
kono
parents:
diff changeset
47 all the values are the same. If that value is the same as the sett / clrt
kono
parents:
diff changeset
48 insn would set the ccreg to, the sett / clrt insn can be eliminated.
kono
parents:
diff changeset
49 */
kono
parents:
diff changeset
50
kono
parents:
diff changeset
51
kono
parents:
diff changeset
52 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
kono
parents:
diff changeset
53 // Helper functions
kono
parents:
diff changeset
54
kono
parents:
diff changeset
55 #define log_msg(...)\
kono
parents:
diff changeset
56 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); } while (0)
kono
parents:
diff changeset
57
kono
parents:
diff changeset
58 #define log_insn(i)\
kono
parents:
diff changeset
59 do { if (dump_file != NULL) print_rtl_single (dump_file, \
kono
parents:
diff changeset
60 (const_rtx)i); } while (0)
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 #define log_rtx(r)\
kono
parents:
diff changeset
63 do { if (dump_file != NULL) print_rtl (dump_file, (const_rtx)r); } while (0)
kono
parents:
diff changeset
64
kono
parents:
diff changeset
65 #define log_return(retval, ...)\
kono
parents:
diff changeset
66 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); \
kono
parents:
diff changeset
67 return retval; } while (0)
kono
parents:
diff changeset
68
kono
parents:
diff changeset
69 #define log_return_void(...)\
kono
parents:
diff changeset
70 do { if (dump_file != NULL) fprintf (dump_file, __VA_ARGS__); \
kono
parents:
diff changeset
71 return; } while (0)
kono
parents:
diff changeset
72
kono
parents:
diff changeset
73 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
kono
parents:
diff changeset
74 // RTL pass class
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 class sh_optimize_sett_clrt : public rtl_opt_pass
kono
parents:
diff changeset
77 {
kono
parents:
diff changeset
78 public:
kono
parents:
diff changeset
79 sh_optimize_sett_clrt (gcc::context* ctx, const char* name);
kono
parents:
diff changeset
80 virtual ~sh_optimize_sett_clrt (void);
kono
parents:
diff changeset
81 virtual bool gate (function*);
kono
parents:
diff changeset
82 virtual unsigned int execute (function* fun);
kono
parents:
diff changeset
83
kono
parents:
diff changeset
84 private:
kono
parents:
diff changeset
85 static const pass_data default_pass_data;
kono
parents:
diff changeset
86
kono
parents:
diff changeset
87 struct ccreg_value
kono
parents:
diff changeset
88 {
kono
parents:
diff changeset
89 // The insn at which the ccreg value was determined.
kono
parents:
diff changeset
90 // Might be NULL if e.g. an unknown value is recorded for an
kono
parents:
diff changeset
91 // empty basic block.
kono
parents:
diff changeset
92 rtx_insn *insn;
kono
parents:
diff changeset
93
kono
parents:
diff changeset
94 // The basic block where the insn was discovered.
kono
parents:
diff changeset
95 basic_block bb;
kono
parents:
diff changeset
96
kono
parents:
diff changeset
97 // The value of ccreg. If NULL_RTX, the exact value is not known, but
kono
parents:
diff changeset
98 // the ccreg is changed in some way (e.g. clobbered).
kono
parents:
diff changeset
99 rtx value;
kono
parents:
diff changeset
100 };
kono
parents:
diff changeset
101
kono
parents:
diff changeset
102 // Update the mode of the captured m_ccreg with the specified mode.
kono
parents:
diff changeset
103 void update_ccreg_mode (machine_mode m);
kono
parents:
diff changeset
104
kono
parents:
diff changeset
105 // Given an insn pattern, check if it sets the ccreg to a constant value
kono
parents:
diff changeset
106 // of either zero or STORE_FLAG_VALUE. If so, return the value rtx,
kono
parents:
diff changeset
107 // NULL_RTX otherwise.
kono
parents:
diff changeset
108 rtx const_setcc_value (rtx pat) const;
kono
parents:
diff changeset
109
kono
parents:
diff changeset
110 // Given a start insn and its basic block, recursively determine all
kono
parents:
diff changeset
111 // possible ccreg values in all basic block paths that can lead to the
kono
parents:
diff changeset
112 // start insn.
kono
parents:
diff changeset
113 bool find_last_ccreg_values (rtx_insn *start_insn, basic_block bb,
kono
parents:
diff changeset
114 std::vector<ccreg_value>& values_out,
kono
parents:
diff changeset
115 std::vector<basic_block>& prev_visited_bb) const;
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 // Given a cbranch insn, its basic block and another basic block, determine
kono
parents:
diff changeset
118 // the value to which the ccreg will be set after jumping/falling through to
kono
parents:
diff changeset
119 // the specified target basic block.
kono
parents:
diff changeset
120 bool sh_cbranch_ccreg_value (rtx_insn *cbranch_insn,
kono
parents:
diff changeset
121 basic_block cbranch_insn_bb,
kono
parents:
diff changeset
122 basic_block branch_target_bb) const;
kono
parents:
diff changeset
123
kono
parents:
diff changeset
124 // Check whether all of the ccreg values are the same.
kono
parents:
diff changeset
125 static bool all_ccreg_values_equal (const std::vector<ccreg_value>& values);
kono
parents:
diff changeset
126
kono
parents:
diff changeset
127 // Remove REG_DEAD and REG_UNUSED notes from insns of the specified
kono
parents:
diff changeset
128 // ccreg_value entries.
kono
parents:
diff changeset
129 void remove_ccreg_dead_unused_notes (std::vector<ccreg_value>& values) const;
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 // rtx of the ccreg that is obtained from the target.
kono
parents:
diff changeset
132 rtx m_ccreg;
kono
parents:
diff changeset
133 };
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135 const pass_data sh_optimize_sett_clrt::default_pass_data =
kono
parents:
diff changeset
136 {
kono
parents:
diff changeset
137 RTL_PASS, // type
kono
parents:
diff changeset
138 "", // name (overwritten by the constructor)
kono
parents:
diff changeset
139 OPTGROUP_NONE, // optinfo_flags
kono
parents:
diff changeset
140 TV_OPTIMIZE, // tv_id
kono
parents:
diff changeset
141 0, // properties_required
kono
parents:
diff changeset
142 0, // properties_provided
kono
parents:
diff changeset
143 0, // properties_destroyed
kono
parents:
diff changeset
144 0, // todo_flags_start
kono
parents:
diff changeset
145 0 // todo_flags_finish
kono
parents:
diff changeset
146 };
kono
parents:
diff changeset
147
kono
parents:
diff changeset
148 sh_optimize_sett_clrt::sh_optimize_sett_clrt (gcc::context* ctx,
kono
parents:
diff changeset
149 const char* name)
kono
parents:
diff changeset
150 : rtl_opt_pass (default_pass_data, ctx),
kono
parents:
diff changeset
151 m_ccreg (NULL_RTX)
kono
parents:
diff changeset
152 {
kono
parents:
diff changeset
153 // Overwrite default name in pass_data base class.
kono
parents:
diff changeset
154 this->name = name;
kono
parents:
diff changeset
155 }
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 sh_optimize_sett_clrt::~sh_optimize_sett_clrt (void)
kono
parents:
diff changeset
158 {
kono
parents:
diff changeset
159 }
kono
parents:
diff changeset
160
kono
parents:
diff changeset
161 bool
kono
parents:
diff changeset
162 sh_optimize_sett_clrt::gate (function*)
kono
parents:
diff changeset
163 {
kono
parents:
diff changeset
164 return optimize > 0;
kono
parents:
diff changeset
165 }
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167 unsigned int
kono
parents:
diff changeset
168 sh_optimize_sett_clrt::execute (function* fun)
kono
parents:
diff changeset
169 {
kono
parents:
diff changeset
170 unsigned int ccr0 = INVALID_REGNUM;
kono
parents:
diff changeset
171 unsigned int ccr1 = INVALID_REGNUM;
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 if (targetm.fixed_condition_code_regs (&ccr0, &ccr1)
kono
parents:
diff changeset
174 && ccr0 != INVALID_REGNUM)
kono
parents:
diff changeset
175 {
kono
parents:
diff changeset
176 // Initially create a reg rtx with VOIDmode.
kono
parents:
diff changeset
177 // When the constant setcc is discovered, the mode is changed
kono
parents:
diff changeset
178 // to the mode that is actually used by the target.
kono
parents:
diff changeset
179 m_ccreg = gen_rtx_REG (VOIDmode, ccr0);
kono
parents:
diff changeset
180 }
kono
parents:
diff changeset
181
kono
parents:
diff changeset
182 if (m_ccreg == NULL_RTX)
kono
parents:
diff changeset
183 log_return (0, "no ccreg.\n\n");
kono
parents:
diff changeset
184
kono
parents:
diff changeset
185 if (STORE_FLAG_VALUE != 1)
kono
parents:
diff changeset
186 log_return (0, "unsupported STORE_FLAG_VALUE %d", STORE_FLAG_VALUE);
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188 log_msg ("ccreg: ");
kono
parents:
diff changeset
189 log_rtx (m_ccreg);
kono
parents:
diff changeset
190 log_msg (" STORE_FLAG_VALUE = %d\n", STORE_FLAG_VALUE);
kono
parents:
diff changeset
191
kono
parents:
diff changeset
192 if (!df_regs_ever_live_p (ccr0))
kono
parents:
diff changeset
193 log_return (0, "ccreg never live\n\n");
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 // Output vector for find_known_ccreg_values.
kono
parents:
diff changeset
196 std::vector<ccreg_value> ccreg_values;
kono
parents:
diff changeset
197 ccreg_values.reserve (32);
kono
parents:
diff changeset
198
kono
parents:
diff changeset
199 // Something for recording visited basic blocks to avoid infinite recursion.
kono
parents:
diff changeset
200 std::vector<basic_block> visited_bbs;
kono
parents:
diff changeset
201 visited_bbs.reserve (32);
kono
parents:
diff changeset
202
kono
parents:
diff changeset
203 // Look for insns that set the ccreg to a constant value and see if it can
kono
parents:
diff changeset
204 // be optimized.
kono
parents:
diff changeset
205 basic_block bb;
kono
parents:
diff changeset
206 FOR_EACH_BB_REVERSE_FN (bb, fun)
kono
parents:
diff changeset
207 for (rtx_insn *next_i, *i = NEXT_INSN (BB_HEAD (bb));
kono
parents:
diff changeset
208 i != NULL_RTX && i != BB_END (bb); i = next_i)
kono
parents:
diff changeset
209 {
kono
parents:
diff changeset
210 next_i = NEXT_INSN (i);
kono
parents:
diff changeset
211
kono
parents:
diff changeset
212 if (!INSN_P (i) || !NONDEBUG_INSN_P (i))
kono
parents:
diff changeset
213 continue;
kono
parents:
diff changeset
214
kono
parents:
diff changeset
215 rtx setcc_val = const_setcc_value (PATTERN (i));
kono
parents:
diff changeset
216 if (setcc_val != NULL_RTX)
kono
parents:
diff changeset
217 {
kono
parents:
diff changeset
218 update_ccreg_mode (GET_MODE (XEXP (PATTERN (i), 0)));
kono
parents:
diff changeset
219
kono
parents:
diff changeset
220 log_msg ("\n\nfound const setcc insn in [bb %d]: \n", bb->index);
kono
parents:
diff changeset
221 log_insn (i);
kono
parents:
diff changeset
222 log_msg ("\n");
kono
parents:
diff changeset
223
kono
parents:
diff changeset
224 ccreg_values.clear ();
kono
parents:
diff changeset
225 visited_bbs.clear ();
kono
parents:
diff changeset
226 bool ok = find_last_ccreg_values (PREV_INSN (i), bb, ccreg_values,
kono
parents:
diff changeset
227 visited_bbs);
kono
parents:
diff changeset
228
kono
parents:
diff changeset
229 log_msg ("number of ccreg values collected: %u\n",
kono
parents:
diff changeset
230 (unsigned int)ccreg_values.size ());
kono
parents:
diff changeset
231
kono
parents:
diff changeset
232 // If all the collected values are equal and are equal to the
kono
parents:
diff changeset
233 // constant value of the setcc insn, the setcc insn can be
kono
parents:
diff changeset
234 // removed.
kono
parents:
diff changeset
235 if (ok && all_ccreg_values_equal (ccreg_values)
kono
parents:
diff changeset
236 && rtx_equal_p (ccreg_values.front ().value, setcc_val))
kono
parents:
diff changeset
237 {
kono
parents:
diff changeset
238 log_msg ("all values are ");
kono
parents:
diff changeset
239 log_rtx (setcc_val);
kono
parents:
diff changeset
240 log_msg ("\n");
kono
parents:
diff changeset
241
kono
parents:
diff changeset
242 delete_insn (i);
kono
parents:
diff changeset
243 remove_ccreg_dead_unused_notes (ccreg_values);
kono
parents:
diff changeset
244 }
kono
parents:
diff changeset
245 }
kono
parents:
diff changeset
246 }
kono
parents:
diff changeset
247
kono
parents:
diff changeset
248 log_return (0, "\n\n");
kono
parents:
diff changeset
249 }
kono
parents:
diff changeset
250
kono
parents:
diff changeset
251 void
kono
parents:
diff changeset
252 sh_optimize_sett_clrt::update_ccreg_mode (machine_mode m)
kono
parents:
diff changeset
253 {
kono
parents:
diff changeset
254 if (GET_MODE (m_ccreg) == m)
kono
parents:
diff changeset
255 return;
kono
parents:
diff changeset
256
kono
parents:
diff changeset
257 PUT_MODE (m_ccreg, m);
kono
parents:
diff changeset
258 log_msg ("updated ccreg mode: ");
kono
parents:
diff changeset
259 log_rtx (m_ccreg);
kono
parents:
diff changeset
260 log_msg ("\n\n");
kono
parents:
diff changeset
261 }
kono
parents:
diff changeset
262
kono
parents:
diff changeset
263 rtx
kono
parents:
diff changeset
264 sh_optimize_sett_clrt::const_setcc_value (rtx pat) const
kono
parents:
diff changeset
265 {
kono
parents:
diff changeset
266 if (GET_CODE (pat) == SET
kono
parents:
diff changeset
267 && REG_P (XEXP (pat, 0)) && REGNO (XEXP (pat, 0)) == REGNO (m_ccreg)
kono
parents:
diff changeset
268 && CONST_INT_P (XEXP (pat, 1))
kono
parents:
diff changeset
269 && (INTVAL (XEXP (pat, 1)) == 0
kono
parents:
diff changeset
270 || INTVAL (XEXP (pat, 1)) == STORE_FLAG_VALUE))
kono
parents:
diff changeset
271 return XEXP (pat, 1);
kono
parents:
diff changeset
272 else
kono
parents:
diff changeset
273 return NULL_RTX;
kono
parents:
diff changeset
274 }
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 bool
kono
parents:
diff changeset
277 sh_optimize_sett_clrt
kono
parents:
diff changeset
278 ::sh_cbranch_ccreg_value (rtx_insn *cbranch_insn, basic_block cbranch_insn_bb,
kono
parents:
diff changeset
279 basic_block branch_target_bb) const
kono
parents:
diff changeset
280 {
kono
parents:
diff changeset
281 rtx pc_set_rtx = pc_set (cbranch_insn);
kono
parents:
diff changeset
282 gcc_assert (pc_set_rtx != NULL_RTX);
kono
parents:
diff changeset
283 gcc_assert (branch_target_bb != NULL);
kono
parents:
diff changeset
284
kono
parents:
diff changeset
285 rtx cond = XEXP (XEXP (pc_set_rtx, 1), 0);
kono
parents:
diff changeset
286 bool branch_if;
kono
parents:
diff changeset
287
kono
parents:
diff changeset
288 if (GET_CODE (cond) == NE
kono
parents:
diff changeset
289 && REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) == REGNO (m_ccreg)
kono
parents:
diff changeset
290 && XEXP (cond, 1) == const0_rtx)
kono
parents:
diff changeset
291 branch_if = true;
kono
parents:
diff changeset
292
kono
parents:
diff changeset
293 else if (GET_CODE (cond) == EQ
kono
parents:
diff changeset
294 && REG_P (XEXP (cond, 0)) && REGNO (XEXP (cond, 0)) == REGNO (m_ccreg)
kono
parents:
diff changeset
295 && XEXP (cond, 1) == const0_rtx)
kono
parents:
diff changeset
296 branch_if = false;
kono
parents:
diff changeset
297
kono
parents:
diff changeset
298 else
kono
parents:
diff changeset
299 gcc_unreachable ();
kono
parents:
diff changeset
300
kono
parents:
diff changeset
301 if (branch_target_bb == BRANCH_EDGE (cbranch_insn_bb)->dest)
kono
parents:
diff changeset
302 return branch_if;
kono
parents:
diff changeset
303 else if (branch_target_bb == FALLTHRU_EDGE (cbranch_insn_bb)->dest)
kono
parents:
diff changeset
304 return !branch_if;
kono
parents:
diff changeset
305 else
kono
parents:
diff changeset
306 gcc_unreachable ();
kono
parents:
diff changeset
307 }
kono
parents:
diff changeset
308
kono
parents:
diff changeset
309 bool
kono
parents:
diff changeset
310 sh_optimize_sett_clrt
kono
parents:
diff changeset
311 ::find_last_ccreg_values (rtx_insn *start_insn, basic_block bb,
kono
parents:
diff changeset
312 std::vector<ccreg_value>& values_out,
kono
parents:
diff changeset
313 std::vector<basic_block>& prev_visited_bb) const
kono
parents:
diff changeset
314 {
kono
parents:
diff changeset
315 // FIXME: For larger CFGs this will unnecessarily re-visit basic blocks.
kono
parents:
diff changeset
316 // Once a basic block has been visited, the result should be stored in
kono
parents:
diff changeset
317 // some container so that it can be looked up quickly eliminating the
kono
parents:
diff changeset
318 // re-visits.
kono
parents:
diff changeset
319 log_msg ("looking for ccreg values in [bb %d] ", bb->index);
kono
parents:
diff changeset
320 if (!prev_visited_bb.empty ())
kono
parents:
diff changeset
321 log_msg ("(prev visited [bb %d])", prev_visited_bb.back ()->index);
kono
parents:
diff changeset
322 log_msg ("\n");
kono
parents:
diff changeset
323
kono
parents:
diff changeset
324 for (rtx_insn *i = start_insn; i != NULL && i != PREV_INSN (BB_HEAD (bb));
kono
parents:
diff changeset
325 i = PREV_INSN (i))
kono
parents:
diff changeset
326 {
kono
parents:
diff changeset
327 if (!INSN_P (i))
kono
parents:
diff changeset
328 continue;
kono
parents:
diff changeset
329
kono
parents:
diff changeset
330 if (reg_set_p (m_ccreg, i))
kono
parents:
diff changeset
331 {
kono
parents:
diff changeset
332 const_rtx set_rtx = set_of (m_ccreg, i);
kono
parents:
diff changeset
333
kono
parents:
diff changeset
334 ccreg_value v;
kono
parents:
diff changeset
335 v.insn = i;
kono
parents:
diff changeset
336 v.bb = bb;
kono
parents:
diff changeset
337 v.value = set_rtx != NULL_RTX && GET_CODE (set_rtx) == SET
kono
parents:
diff changeset
338 ? XEXP (set_rtx, 1)
kono
parents:
diff changeset
339 : NULL_RTX;
kono
parents:
diff changeset
340
kono
parents:
diff changeset
341 log_msg ("found setcc in [bb %d] in insn:\n", bb->index);
kono
parents:
diff changeset
342 log_insn (i);
kono
parents:
diff changeset
343 log_msg ("\nccreg value: ");
kono
parents:
diff changeset
344 log_rtx (v.value);
kono
parents:
diff changeset
345 log_msg ("\n");
kono
parents:
diff changeset
346
kono
parents:
diff changeset
347 values_out.push_back (v);
kono
parents:
diff changeset
348 return true;
kono
parents:
diff changeset
349 }
kono
parents:
diff changeset
350
kono
parents:
diff changeset
351 if (any_condjump_p (i) && onlyjump_p (i) && !prev_visited_bb.empty ())
kono
parents:
diff changeset
352 {
kono
parents:
diff changeset
353 // For a conditional branch the ccreg value will be a known constant
kono
parents:
diff changeset
354 // of either 0 or STORE_FLAG_VALUE after branching/falling through
kono
parents:
diff changeset
355 // to one of the two successor BBs. Record the value for the BB
kono
parents:
diff changeset
356 // where we came from.
kono
parents:
diff changeset
357 log_msg ("found cbranch in [bb %d]:\n", bb->index);
kono
parents:
diff changeset
358 log_insn (i);
kono
parents:
diff changeset
359
kono
parents:
diff changeset
360 ccreg_value v;
kono
parents:
diff changeset
361 v.insn = i;
kono
parents:
diff changeset
362 v.bb = bb;
kono
parents:
diff changeset
363 v.value = GEN_INT (sh_cbranch_ccreg_value (i, bb,
kono
parents:
diff changeset
364 prev_visited_bb.back ()));
kono
parents:
diff changeset
365
kono
parents:
diff changeset
366 log_msg (" branches to [bb %d] with ccreg value ",
kono
parents:
diff changeset
367 prev_visited_bb.back ()->index);
kono
parents:
diff changeset
368 log_rtx (v.value);
kono
parents:
diff changeset
369 log_msg ("\n");
kono
parents:
diff changeset
370
kono
parents:
diff changeset
371 values_out.push_back (v);
kono
parents:
diff changeset
372 return true;
kono
parents:
diff changeset
373 }
kono
parents:
diff changeset
374 }
kono
parents:
diff changeset
375
kono
parents:
diff changeset
376 // If here, we've walked up all the insns of the current basic block
kono
parents:
diff changeset
377 // and none of them seems to modify the ccreg.
kono
parents:
diff changeset
378 // In this case, check the predecessor basic blocks.
kono
parents:
diff changeset
379 unsigned int pred_bb_count = 0;
kono
parents:
diff changeset
380
kono
parents:
diff changeset
381 // If the current basic block is not in the stack of previously visited
kono
parents:
diff changeset
382 // basic blocks yet, we can recursively check the predecessor basic blocks.
kono
parents:
diff changeset
383 // Otherwise we have a loop in the CFG and recursing again will result in
kono
parents:
diff changeset
384 // an infinite loop.
kono
parents:
diff changeset
385 if (std::find (prev_visited_bb.rbegin (), prev_visited_bb.rend (), bb)
kono
parents:
diff changeset
386 == prev_visited_bb.rend ())
kono
parents:
diff changeset
387 {
kono
parents:
diff changeset
388 prev_visited_bb.push_back (bb);
kono
parents:
diff changeset
389
kono
parents:
diff changeset
390 for (edge_iterator ei = ei_start (bb->preds); !ei_end_p (ei);
kono
parents:
diff changeset
391 ei_next (&ei))
kono
parents:
diff changeset
392 {
kono
parents:
diff changeset
393 if (ei_edge (ei)->flags & EDGE_COMPLEX)
kono
parents:
diff changeset
394 log_return (false, "aborting due to complex edge\n");
kono
parents:
diff changeset
395
kono
parents:
diff changeset
396 basic_block pred_bb = ei_edge (ei)->src;
kono
parents:
diff changeset
397 pred_bb_count += 1;
kono
parents:
diff changeset
398 if (!find_last_ccreg_values (BB_END (pred_bb), pred_bb, values_out,
kono
parents:
diff changeset
399 prev_visited_bb))
kono
parents:
diff changeset
400 return false;
kono
parents:
diff changeset
401 }
kono
parents:
diff changeset
402
kono
parents:
diff changeset
403 prev_visited_bb.pop_back ();
kono
parents:
diff changeset
404 }
kono
parents:
diff changeset
405 else
kono
parents:
diff changeset
406 log_msg ("loop detected for [bb %d]\n", bb->index);
kono
parents:
diff changeset
407
kono
parents:
diff changeset
408 log_msg ("[bb %d] pred_bb_count = %u\n", bb->index, pred_bb_count);
kono
parents:
diff changeset
409
kono
parents:
diff changeset
410 if (pred_bb_count == 0)
kono
parents:
diff changeset
411 {
kono
parents:
diff changeset
412 // If we haven't checked a single predecessor basic block, the current
kono
parents:
diff changeset
413 // basic block is probably a leaf block and we don't know the ccreg value.
kono
parents:
diff changeset
414 log_msg ("unknown ccreg value for [bb %d]\n", bb->index);
kono
parents:
diff changeset
415
kono
parents:
diff changeset
416 ccreg_value v;
kono
parents:
diff changeset
417 v.insn = BB_END (bb);
kono
parents:
diff changeset
418 v.bb = bb;
kono
parents:
diff changeset
419 v.value = NULL_RTX;
kono
parents:
diff changeset
420
kono
parents:
diff changeset
421 values_out.push_back (v);
kono
parents:
diff changeset
422 }
kono
parents:
diff changeset
423
kono
parents:
diff changeset
424 return true;
kono
parents:
diff changeset
425 }
kono
parents:
diff changeset
426
kono
parents:
diff changeset
427 bool
kono
parents:
diff changeset
428 sh_optimize_sett_clrt
kono
parents:
diff changeset
429 ::all_ccreg_values_equal (const std::vector<ccreg_value>& values)
kono
parents:
diff changeset
430 {
kono
parents:
diff changeset
431 if (values.empty ())
kono
parents:
diff changeset
432 return false;
kono
parents:
diff changeset
433
kono
parents:
diff changeset
434 rtx last_value = values.front ().value;
kono
parents:
diff changeset
435
kono
parents:
diff changeset
436 // If the ccreg is modified in the insn but the exact value is not known
kono
parents:
diff changeset
437 // the value rtx might be null.
kono
parents:
diff changeset
438 if (last_value == NULL_RTX)
kono
parents:
diff changeset
439 return false;
kono
parents:
diff changeset
440
kono
parents:
diff changeset
441 for (std::vector<ccreg_value>::const_iterator i = values.begin ();
kono
parents:
diff changeset
442 i != values.end (); ++i)
kono
parents:
diff changeset
443 if (i->value == NULL_RTX || !rtx_equal_p (last_value, i->value))
kono
parents:
diff changeset
444 return false;
kono
parents:
diff changeset
445
kono
parents:
diff changeset
446 return true;
kono
parents:
diff changeset
447 }
kono
parents:
diff changeset
448
kono
parents:
diff changeset
449 void
kono
parents:
diff changeset
450 sh_optimize_sett_clrt
kono
parents:
diff changeset
451 ::remove_ccreg_dead_unused_notes (std::vector<ccreg_value>& values) const
kono
parents:
diff changeset
452 {
kono
parents:
diff changeset
453 for (std::vector<ccreg_value>::iterator i = values.begin ();
kono
parents:
diff changeset
454 i != values.end (); ++i)
kono
parents:
diff changeset
455 {
kono
parents:
diff changeset
456 if (i->insn == NULL_RTX)
kono
parents:
diff changeset
457 continue;
kono
parents:
diff changeset
458
kono
parents:
diff changeset
459 rtx n = find_regno_note (i->insn, REG_DEAD, REGNO (m_ccreg));
kono
parents:
diff changeset
460 if (n != NULL_RTX)
kono
parents:
diff changeset
461 remove_note (i->insn, n);
kono
parents:
diff changeset
462
kono
parents:
diff changeset
463 n = find_regno_note (i->insn, REG_UNUSED, REGNO (m_ccreg));
kono
parents:
diff changeset
464 if (n != NULL_RTX)
kono
parents:
diff changeset
465 remove_note (i->insn, n);
kono
parents:
diff changeset
466 }
kono
parents:
diff changeset
467 }
kono
parents:
diff changeset
468
kono
parents:
diff changeset
469 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
kono
parents:
diff changeset
470 // This allows instantiating the pass somewhere else without having to pull
kono
parents:
diff changeset
471 // in a header file.
kono
parents:
diff changeset
472 opt_pass*
kono
parents:
diff changeset
473 make_pass_sh_optimize_sett_clrt (gcc::context* ctx, const char* name)
kono
parents:
diff changeset
474 {
kono
parents:
diff changeset
475 return new sh_optimize_sett_clrt (ctx, name);
kono
parents:
diff changeset
476 }