1e4b17023SJohn Marino /* If-conversion support.
2e4b17023SJohn Marino Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010,
3e4b17023SJohn Marino 2011
4e4b17023SJohn Marino Free Software Foundation, Inc.
5e4b17023SJohn Marino
6e4b17023SJohn Marino This file is part of GCC.
7e4b17023SJohn Marino
8e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it
9e4b17023SJohn Marino under the terms of the GNU General Public License as published by
10e4b17023SJohn Marino the Free Software Foundation; either version 3, or (at your option)
11e4b17023SJohn Marino any later version.
12e4b17023SJohn Marino
13e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT
14e4b17023SJohn Marino ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15e4b17023SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16e4b17023SJohn Marino License for more details.
17e4b17023SJohn Marino
18e4b17023SJohn Marino You should have received a copy of the GNU General Public License
19e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
20e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
21e4b17023SJohn Marino
22e4b17023SJohn Marino #include "config.h"
23e4b17023SJohn Marino #include "system.h"
24e4b17023SJohn Marino #include "coretypes.h"
25e4b17023SJohn Marino #include "tm.h"
26e4b17023SJohn Marino
27e4b17023SJohn Marino #include "rtl.h"
28e4b17023SJohn Marino #include "regs.h"
29e4b17023SJohn Marino #include "function.h"
30e4b17023SJohn Marino #include "flags.h"
31e4b17023SJohn Marino #include "insn-config.h"
32e4b17023SJohn Marino #include "recog.h"
33e4b17023SJohn Marino #include "except.h"
34e4b17023SJohn Marino #include "hard-reg-set.h"
35e4b17023SJohn Marino #include "basic-block.h"
36e4b17023SJohn Marino #include "expr.h"
37e4b17023SJohn Marino #include "output.h"
38e4b17023SJohn Marino #include "optabs.h"
39e4b17023SJohn Marino #include "diagnostic-core.h"
40e4b17023SJohn Marino #include "tm_p.h"
41e4b17023SJohn Marino #include "cfgloop.h"
42e4b17023SJohn Marino #include "target.h"
43e4b17023SJohn Marino #include "timevar.h"
44e4b17023SJohn Marino #include "tree-pass.h"
45e4b17023SJohn Marino #include "df.h"
46e4b17023SJohn Marino #include "vec.h"
47*5ce9237cSJohn Marino #include "pointer-set.h"
48e4b17023SJohn Marino #include "vecprim.h"
49e4b17023SJohn Marino #include "dbgcnt.h"
50e4b17023SJohn Marino
51e4b17023SJohn Marino #ifndef HAVE_conditional_move
52e4b17023SJohn Marino #define HAVE_conditional_move 0
53e4b17023SJohn Marino #endif
54e4b17023SJohn Marino #ifndef HAVE_incscc
55e4b17023SJohn Marino #define HAVE_incscc 0
56e4b17023SJohn Marino #endif
57e4b17023SJohn Marino #ifndef HAVE_decscc
58e4b17023SJohn Marino #define HAVE_decscc 0
59e4b17023SJohn Marino #endif
60e4b17023SJohn Marino #ifndef HAVE_trap
61e4b17023SJohn Marino #define HAVE_trap 0
62e4b17023SJohn Marino #endif
63e4b17023SJohn Marino
64e4b17023SJohn Marino #ifndef MAX_CONDITIONAL_EXECUTE
65e4b17023SJohn Marino #define MAX_CONDITIONAL_EXECUTE \
66e4b17023SJohn Marino (BRANCH_COST (optimize_function_for_speed_p (cfun), false) \
67e4b17023SJohn Marino + 1)
68e4b17023SJohn Marino #endif
69e4b17023SJohn Marino
70e4b17023SJohn Marino #define IFCVT_MULTIPLE_DUMPS 1
71e4b17023SJohn Marino
72e4b17023SJohn Marino #define NULL_BLOCK ((basic_block) NULL)
73e4b17023SJohn Marino
74e4b17023SJohn Marino /* # of IF-THEN or IF-THEN-ELSE blocks we looked at */
75e4b17023SJohn Marino static int num_possible_if_blocks;
76e4b17023SJohn Marino
77e4b17023SJohn Marino /* # of IF-THEN or IF-THEN-ELSE blocks were converted to conditional
78e4b17023SJohn Marino execution. */
79e4b17023SJohn Marino static int num_updated_if_blocks;
80e4b17023SJohn Marino
81e4b17023SJohn Marino /* # of changes made. */
82e4b17023SJohn Marino static int num_true_changes;
83e4b17023SJohn Marino
84e4b17023SJohn Marino /* Whether conditional execution changes were made. */
85e4b17023SJohn Marino static int cond_exec_changed_p;
86e4b17023SJohn Marino
87e4b17023SJohn Marino /* Forward references. */
88e4b17023SJohn Marino static int count_bb_insns (const_basic_block);
89e4b17023SJohn Marino static bool cheap_bb_rtx_cost_p (const_basic_block, int, int);
90e4b17023SJohn Marino static rtx first_active_insn (basic_block);
91e4b17023SJohn Marino static rtx last_active_insn (basic_block, int);
92e4b17023SJohn Marino static rtx find_active_insn_before (basic_block, rtx);
93e4b17023SJohn Marino static rtx find_active_insn_after (basic_block, rtx);
94e4b17023SJohn Marino static basic_block block_fallthru (basic_block);
95e4b17023SJohn Marino static int cond_exec_process_insns (ce_if_block_t *, rtx, rtx, rtx, rtx, int);
96e4b17023SJohn Marino static rtx cond_exec_get_condition (rtx);
97e4b17023SJohn Marino static rtx noce_get_condition (rtx, rtx *, bool);
98e4b17023SJohn Marino static int noce_operand_ok (const_rtx);
99e4b17023SJohn Marino static void merge_if_block (ce_if_block_t *);
100e4b17023SJohn Marino static int find_cond_trap (basic_block, edge, edge);
101e4b17023SJohn Marino static basic_block find_if_header (basic_block, int);
102e4b17023SJohn Marino static int block_jumps_and_fallthru_p (basic_block, basic_block);
103e4b17023SJohn Marino static int noce_find_if_block (basic_block, edge, edge, int);
104e4b17023SJohn Marino static int cond_exec_find_if_block (ce_if_block_t *);
105e4b17023SJohn Marino static int find_if_case_1 (basic_block, edge, edge);
106e4b17023SJohn Marino static int find_if_case_2 (basic_block, edge, edge);
107e4b17023SJohn Marino static int dead_or_predicable (basic_block, basic_block, basic_block,
108e4b17023SJohn Marino edge, int);
109e4b17023SJohn Marino static void noce_emit_move_insn (rtx, rtx);
110e4b17023SJohn Marino static rtx block_has_only_trap (basic_block);
111e4b17023SJohn Marino
112e4b17023SJohn Marino /* Count the number of non-jump active insns in BB. */
113e4b17023SJohn Marino
114e4b17023SJohn Marino static int
count_bb_insns(const_basic_block bb)115e4b17023SJohn Marino count_bb_insns (const_basic_block bb)
116e4b17023SJohn Marino {
117e4b17023SJohn Marino int count = 0;
118e4b17023SJohn Marino rtx insn = BB_HEAD (bb);
119e4b17023SJohn Marino
120e4b17023SJohn Marino while (1)
121e4b17023SJohn Marino {
122e4b17023SJohn Marino if (CALL_P (insn) || NONJUMP_INSN_P (insn))
123e4b17023SJohn Marino count++;
124e4b17023SJohn Marino
125e4b17023SJohn Marino if (insn == BB_END (bb))
126e4b17023SJohn Marino break;
127e4b17023SJohn Marino insn = NEXT_INSN (insn);
128e4b17023SJohn Marino }
129e4b17023SJohn Marino
130e4b17023SJohn Marino return count;
131e4b17023SJohn Marino }
132e4b17023SJohn Marino
133e4b17023SJohn Marino /* Determine whether the total insn_rtx_cost on non-jump insns in
134e4b17023SJohn Marino basic block BB is less than MAX_COST. This function returns
135e4b17023SJohn Marino false if the cost of any instruction could not be estimated.
136e4b17023SJohn Marino
137e4b17023SJohn Marino The cost of the non-jump insns in BB is scaled by REG_BR_PROB_BASE
138e4b17023SJohn Marino as those insns are being speculated. MAX_COST is scaled with SCALE
139e4b17023SJohn Marino plus a small fudge factor. */
140e4b17023SJohn Marino
141e4b17023SJohn Marino static bool
cheap_bb_rtx_cost_p(const_basic_block bb,int scale,int max_cost)142e4b17023SJohn Marino cheap_bb_rtx_cost_p (const_basic_block bb, int scale, int max_cost)
143e4b17023SJohn Marino {
144e4b17023SJohn Marino int count = 0;
145e4b17023SJohn Marino rtx insn = BB_HEAD (bb);
146e4b17023SJohn Marino bool speed = optimize_bb_for_speed_p (bb);
147e4b17023SJohn Marino
148e4b17023SJohn Marino /* Our branch probability/scaling factors are just estimates and don't
149e4b17023SJohn Marino account for cases where we can get speculation for free and other
150e4b17023SJohn Marino secondary benefits. So we fudge the scale factor to make speculating
151e4b17023SJohn Marino appear a little more profitable. */
152e4b17023SJohn Marino scale += REG_BR_PROB_BASE / 8;
153e4b17023SJohn Marino max_cost *= scale;
154e4b17023SJohn Marino
155e4b17023SJohn Marino while (1)
156e4b17023SJohn Marino {
157e4b17023SJohn Marino if (NONJUMP_INSN_P (insn))
158e4b17023SJohn Marino {
159e4b17023SJohn Marino int cost = insn_rtx_cost (PATTERN (insn), speed) * REG_BR_PROB_BASE;
160e4b17023SJohn Marino if (cost == 0)
161e4b17023SJohn Marino return false;
162e4b17023SJohn Marino
163e4b17023SJohn Marino /* If this instruction is the load or set of a "stack" register,
164e4b17023SJohn Marino such as a floating point register on x87, then the cost of
165e4b17023SJohn Marino speculatively executing this insn may need to include
166e4b17023SJohn Marino the additional cost of popping its result off of the
167e4b17023SJohn Marino register stack. Unfortunately, correctly recognizing and
168e4b17023SJohn Marino accounting for this additional overhead is tricky, so for
169e4b17023SJohn Marino now we simply prohibit such speculative execution. */
170e4b17023SJohn Marino #ifdef STACK_REGS
171e4b17023SJohn Marino {
172e4b17023SJohn Marino rtx set = single_set (insn);
173e4b17023SJohn Marino if (set && STACK_REG_P (SET_DEST (set)))
174e4b17023SJohn Marino return false;
175e4b17023SJohn Marino }
176e4b17023SJohn Marino #endif
177e4b17023SJohn Marino
178e4b17023SJohn Marino count += cost;
179e4b17023SJohn Marino if (count >= max_cost)
180e4b17023SJohn Marino return false;
181e4b17023SJohn Marino }
182e4b17023SJohn Marino else if (CALL_P (insn))
183e4b17023SJohn Marino return false;
184e4b17023SJohn Marino
185e4b17023SJohn Marino if (insn == BB_END (bb))
186e4b17023SJohn Marino break;
187e4b17023SJohn Marino insn = NEXT_INSN (insn);
188e4b17023SJohn Marino }
189e4b17023SJohn Marino
190e4b17023SJohn Marino return true;
191e4b17023SJohn Marino }
192e4b17023SJohn Marino
193e4b17023SJohn Marino /* Return the first non-jump active insn in the basic block. */
194e4b17023SJohn Marino
195e4b17023SJohn Marino static rtx
first_active_insn(basic_block bb)196e4b17023SJohn Marino first_active_insn (basic_block bb)
197e4b17023SJohn Marino {
198e4b17023SJohn Marino rtx insn = BB_HEAD (bb);
199e4b17023SJohn Marino
200e4b17023SJohn Marino if (LABEL_P (insn))
201e4b17023SJohn Marino {
202e4b17023SJohn Marino if (insn == BB_END (bb))
203e4b17023SJohn Marino return NULL_RTX;
204e4b17023SJohn Marino insn = NEXT_INSN (insn);
205e4b17023SJohn Marino }
206e4b17023SJohn Marino
207e4b17023SJohn Marino while (NOTE_P (insn) || DEBUG_INSN_P (insn))
208e4b17023SJohn Marino {
209e4b17023SJohn Marino if (insn == BB_END (bb))
210e4b17023SJohn Marino return NULL_RTX;
211e4b17023SJohn Marino insn = NEXT_INSN (insn);
212e4b17023SJohn Marino }
213e4b17023SJohn Marino
214e4b17023SJohn Marino if (JUMP_P (insn))
215e4b17023SJohn Marino return NULL_RTX;
216e4b17023SJohn Marino
217e4b17023SJohn Marino return insn;
218e4b17023SJohn Marino }
219e4b17023SJohn Marino
220e4b17023SJohn Marino /* Return the last non-jump active (non-jump) insn in the basic block. */
221e4b17023SJohn Marino
222e4b17023SJohn Marino static rtx
last_active_insn(basic_block bb,int skip_use_p)223e4b17023SJohn Marino last_active_insn (basic_block bb, int skip_use_p)
224e4b17023SJohn Marino {
225e4b17023SJohn Marino rtx insn = BB_END (bb);
226e4b17023SJohn Marino rtx head = BB_HEAD (bb);
227e4b17023SJohn Marino
228e4b17023SJohn Marino while (NOTE_P (insn)
229e4b17023SJohn Marino || JUMP_P (insn)
230e4b17023SJohn Marino || DEBUG_INSN_P (insn)
231e4b17023SJohn Marino || (skip_use_p
232e4b17023SJohn Marino && NONJUMP_INSN_P (insn)
233e4b17023SJohn Marino && GET_CODE (PATTERN (insn)) == USE))
234e4b17023SJohn Marino {
235e4b17023SJohn Marino if (insn == head)
236e4b17023SJohn Marino return NULL_RTX;
237e4b17023SJohn Marino insn = PREV_INSN (insn);
238e4b17023SJohn Marino }
239e4b17023SJohn Marino
240e4b17023SJohn Marino if (LABEL_P (insn))
241e4b17023SJohn Marino return NULL_RTX;
242e4b17023SJohn Marino
243e4b17023SJohn Marino return insn;
244e4b17023SJohn Marino }
245e4b17023SJohn Marino
246e4b17023SJohn Marino /* Return the active insn before INSN inside basic block CURR_BB. */
247e4b17023SJohn Marino
248e4b17023SJohn Marino static rtx
find_active_insn_before(basic_block curr_bb,rtx insn)249e4b17023SJohn Marino find_active_insn_before (basic_block curr_bb, rtx insn)
250e4b17023SJohn Marino {
251e4b17023SJohn Marino if (!insn || insn == BB_HEAD (curr_bb))
252e4b17023SJohn Marino return NULL_RTX;
253e4b17023SJohn Marino
254e4b17023SJohn Marino while ((insn = PREV_INSN (insn)) != NULL_RTX)
255e4b17023SJohn Marino {
256e4b17023SJohn Marino if (NONJUMP_INSN_P (insn) || JUMP_P (insn) || CALL_P (insn))
257e4b17023SJohn Marino break;
258e4b17023SJohn Marino
259e4b17023SJohn Marino /* No other active insn all the way to the start of the basic block. */
260e4b17023SJohn Marino if (insn == BB_HEAD (curr_bb))
261e4b17023SJohn Marino return NULL_RTX;
262e4b17023SJohn Marino }
263e4b17023SJohn Marino
264e4b17023SJohn Marino return insn;
265e4b17023SJohn Marino }
266e4b17023SJohn Marino
267e4b17023SJohn Marino /* Return the active insn after INSN inside basic block CURR_BB. */
268e4b17023SJohn Marino
269e4b17023SJohn Marino static rtx
find_active_insn_after(basic_block curr_bb,rtx insn)270e4b17023SJohn Marino find_active_insn_after (basic_block curr_bb, rtx insn)
271e4b17023SJohn Marino {
272e4b17023SJohn Marino if (!insn || insn == BB_END (curr_bb))
273e4b17023SJohn Marino return NULL_RTX;
274e4b17023SJohn Marino
275e4b17023SJohn Marino while ((insn = NEXT_INSN (insn)) != NULL_RTX)
276e4b17023SJohn Marino {
277e4b17023SJohn Marino if (NONJUMP_INSN_P (insn) || JUMP_P (insn) || CALL_P (insn))
278e4b17023SJohn Marino break;
279e4b17023SJohn Marino
280e4b17023SJohn Marino /* No other active insn all the way to the end of the basic block. */
281e4b17023SJohn Marino if (insn == BB_END (curr_bb))
282e4b17023SJohn Marino return NULL_RTX;
283e4b17023SJohn Marino }
284e4b17023SJohn Marino
285e4b17023SJohn Marino return insn;
286e4b17023SJohn Marino }
287e4b17023SJohn Marino
288e4b17023SJohn Marino /* Return the basic block reached by falling though the basic block BB. */
289e4b17023SJohn Marino
290e4b17023SJohn Marino static basic_block
block_fallthru(basic_block bb)291e4b17023SJohn Marino block_fallthru (basic_block bb)
292e4b17023SJohn Marino {
293e4b17023SJohn Marino edge e = find_fallthru_edge (bb->succs);
294e4b17023SJohn Marino
295e4b17023SJohn Marino return (e) ? e->dest : NULL_BLOCK;
296e4b17023SJohn Marino }
297e4b17023SJohn Marino
298e4b17023SJohn Marino /* Go through a bunch of insns, converting them to conditional
299e4b17023SJohn Marino execution format if possible. Return TRUE if all of the non-note
300e4b17023SJohn Marino insns were processed. */
301e4b17023SJohn Marino
302e4b17023SJohn Marino static int
cond_exec_process_insns(ce_if_block_t * ce_info ATTRIBUTE_UNUSED,rtx start,rtx end,rtx test,rtx prob_val,int mod_ok)303e4b17023SJohn Marino cond_exec_process_insns (ce_if_block_t *ce_info ATTRIBUTE_UNUSED,
304e4b17023SJohn Marino /* if block information */rtx start,
305e4b17023SJohn Marino /* first insn to look at */rtx end,
306e4b17023SJohn Marino /* last insn to look at */rtx test,
307e4b17023SJohn Marino /* conditional execution test */rtx prob_val,
308e4b17023SJohn Marino /* probability of branch taken. */int mod_ok)
309e4b17023SJohn Marino {
310e4b17023SJohn Marino int must_be_last = FALSE;
311e4b17023SJohn Marino rtx insn;
312e4b17023SJohn Marino rtx xtest;
313e4b17023SJohn Marino rtx pattern;
314e4b17023SJohn Marino
315e4b17023SJohn Marino if (!start || !end)
316e4b17023SJohn Marino return FALSE;
317e4b17023SJohn Marino
318e4b17023SJohn Marino for (insn = start; ; insn = NEXT_INSN (insn))
319e4b17023SJohn Marino {
320e4b17023SJohn Marino /* dwarf2out can't cope with conditional prologues. */
321e4b17023SJohn Marino if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END)
322e4b17023SJohn Marino return FALSE;
323e4b17023SJohn Marino
324e4b17023SJohn Marino if (NOTE_P (insn) || DEBUG_INSN_P (insn))
325e4b17023SJohn Marino goto insn_done;
326e4b17023SJohn Marino
327e4b17023SJohn Marino gcc_assert(NONJUMP_INSN_P (insn) || CALL_P (insn));
328e4b17023SJohn Marino
329e4b17023SJohn Marino /* Remove USE insns that get in the way. */
330e4b17023SJohn Marino if (reload_completed && GET_CODE (PATTERN (insn)) == USE)
331e4b17023SJohn Marino {
332e4b17023SJohn Marino /* ??? Ug. Actually unlinking the thing is problematic,
333e4b17023SJohn Marino given what we'd have to coordinate with our callers. */
334e4b17023SJohn Marino SET_INSN_DELETED (insn);
335e4b17023SJohn Marino goto insn_done;
336e4b17023SJohn Marino }
337e4b17023SJohn Marino
338e4b17023SJohn Marino /* Last insn wasn't last? */
339e4b17023SJohn Marino if (must_be_last)
340e4b17023SJohn Marino return FALSE;
341e4b17023SJohn Marino
342e4b17023SJohn Marino if (modified_in_p (test, insn))
343e4b17023SJohn Marino {
344e4b17023SJohn Marino if (!mod_ok)
345e4b17023SJohn Marino return FALSE;
346e4b17023SJohn Marino must_be_last = TRUE;
347e4b17023SJohn Marino }
348e4b17023SJohn Marino
349e4b17023SJohn Marino /* Now build the conditional form of the instruction. */
350e4b17023SJohn Marino pattern = PATTERN (insn);
351e4b17023SJohn Marino xtest = copy_rtx (test);
352e4b17023SJohn Marino
353e4b17023SJohn Marino /* If this is already a COND_EXEC, rewrite the test to be an AND of the
354e4b17023SJohn Marino two conditions. */
355e4b17023SJohn Marino if (GET_CODE (pattern) == COND_EXEC)
356e4b17023SJohn Marino {
357e4b17023SJohn Marino if (GET_MODE (xtest) != GET_MODE (COND_EXEC_TEST (pattern)))
358e4b17023SJohn Marino return FALSE;
359e4b17023SJohn Marino
360e4b17023SJohn Marino xtest = gen_rtx_AND (GET_MODE (xtest), xtest,
361e4b17023SJohn Marino COND_EXEC_TEST (pattern));
362e4b17023SJohn Marino pattern = COND_EXEC_CODE (pattern);
363e4b17023SJohn Marino }
364e4b17023SJohn Marino
365e4b17023SJohn Marino pattern = gen_rtx_COND_EXEC (VOIDmode, xtest, pattern);
366e4b17023SJohn Marino
367e4b17023SJohn Marino /* If the machine needs to modify the insn being conditionally executed,
368e4b17023SJohn Marino say for example to force a constant integer operand into a temp
369e4b17023SJohn Marino register, do so here. */
370e4b17023SJohn Marino #ifdef IFCVT_MODIFY_INSN
371e4b17023SJohn Marino IFCVT_MODIFY_INSN (ce_info, pattern, insn);
372e4b17023SJohn Marino if (! pattern)
373e4b17023SJohn Marino return FALSE;
374e4b17023SJohn Marino #endif
375e4b17023SJohn Marino
376e4b17023SJohn Marino validate_change (insn, &PATTERN (insn), pattern, 1);
377e4b17023SJohn Marino
378e4b17023SJohn Marino if (CALL_P (insn) && prob_val)
379e4b17023SJohn Marino validate_change (insn, ®_NOTES (insn),
380e4b17023SJohn Marino alloc_EXPR_LIST (REG_BR_PROB, prob_val,
381e4b17023SJohn Marino REG_NOTES (insn)), 1);
382e4b17023SJohn Marino
383e4b17023SJohn Marino insn_done:
384e4b17023SJohn Marino if (insn == end)
385e4b17023SJohn Marino break;
386e4b17023SJohn Marino }
387e4b17023SJohn Marino
388e4b17023SJohn Marino return TRUE;
389e4b17023SJohn Marino }
390e4b17023SJohn Marino
391e4b17023SJohn Marino /* Return the condition for a jump. Do not do any special processing. */
392e4b17023SJohn Marino
393e4b17023SJohn Marino static rtx
cond_exec_get_condition(rtx jump)394e4b17023SJohn Marino cond_exec_get_condition (rtx jump)
395e4b17023SJohn Marino {
396e4b17023SJohn Marino rtx test_if, cond;
397e4b17023SJohn Marino
398e4b17023SJohn Marino if (any_condjump_p (jump))
399e4b17023SJohn Marino test_if = SET_SRC (pc_set (jump));
400e4b17023SJohn Marino else
401e4b17023SJohn Marino return NULL_RTX;
402e4b17023SJohn Marino cond = XEXP (test_if, 0);
403e4b17023SJohn Marino
404e4b17023SJohn Marino /* If this branches to JUMP_LABEL when the condition is false,
405e4b17023SJohn Marino reverse the condition. */
406e4b17023SJohn Marino if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF
407e4b17023SJohn Marino && XEXP (XEXP (test_if, 2), 0) == JUMP_LABEL (jump))
408e4b17023SJohn Marino {
409e4b17023SJohn Marino enum rtx_code rev = reversed_comparison_code (cond, jump);
410e4b17023SJohn Marino if (rev == UNKNOWN)
411e4b17023SJohn Marino return NULL_RTX;
412e4b17023SJohn Marino
413e4b17023SJohn Marino cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
414e4b17023SJohn Marino XEXP (cond, 1));
415e4b17023SJohn Marino }
416e4b17023SJohn Marino
417e4b17023SJohn Marino return cond;
418e4b17023SJohn Marino }
419e4b17023SJohn Marino
420e4b17023SJohn Marino /* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it
421e4b17023SJohn Marino to conditional execution. Return TRUE if we were successful at
422e4b17023SJohn Marino converting the block. */
423e4b17023SJohn Marino
424e4b17023SJohn Marino static int
cond_exec_process_if_block(ce_if_block_t * ce_info,int do_multiple_p)425e4b17023SJohn Marino cond_exec_process_if_block (ce_if_block_t * ce_info,
426e4b17023SJohn Marino /* if block information */int do_multiple_p)
427e4b17023SJohn Marino {
428e4b17023SJohn Marino basic_block test_bb = ce_info->test_bb; /* last test block */
429e4b17023SJohn Marino basic_block then_bb = ce_info->then_bb; /* THEN */
430e4b17023SJohn Marino basic_block else_bb = ce_info->else_bb; /* ELSE or NULL */
431e4b17023SJohn Marino rtx test_expr; /* expression in IF_THEN_ELSE that is tested */
432e4b17023SJohn Marino rtx then_start; /* first insn in THEN block */
433e4b17023SJohn Marino rtx then_end; /* last insn + 1 in THEN block */
434e4b17023SJohn Marino rtx else_start = NULL_RTX; /* first insn in ELSE block or NULL */
435e4b17023SJohn Marino rtx else_end = NULL_RTX; /* last insn + 1 in ELSE block */
436e4b17023SJohn Marino int max; /* max # of insns to convert. */
437e4b17023SJohn Marino int then_mod_ok; /* whether conditional mods are ok in THEN */
438e4b17023SJohn Marino rtx true_expr; /* test for else block insns */
439e4b17023SJohn Marino rtx false_expr; /* test for then block insns */
440e4b17023SJohn Marino rtx true_prob_val; /* probability of else block */
441e4b17023SJohn Marino rtx false_prob_val; /* probability of then block */
442e4b17023SJohn Marino rtx then_last_head = NULL_RTX; /* Last match at the head of THEN */
443e4b17023SJohn Marino rtx else_last_head = NULL_RTX; /* Last match at the head of ELSE */
444e4b17023SJohn Marino rtx then_first_tail = NULL_RTX; /* First match at the tail of THEN */
445e4b17023SJohn Marino rtx else_first_tail = NULL_RTX; /* First match at the tail of ELSE */
446e4b17023SJohn Marino int then_n_insns, else_n_insns, n_insns;
447e4b17023SJohn Marino enum rtx_code false_code;
448e4b17023SJohn Marino
449e4b17023SJohn Marino /* If test is comprised of && or || elements, and we've failed at handling
450e4b17023SJohn Marino all of them together, just use the last test if it is the special case of
451e4b17023SJohn Marino && elements without an ELSE block. */
452e4b17023SJohn Marino if (!do_multiple_p && ce_info->num_multiple_test_blocks)
453e4b17023SJohn Marino {
454e4b17023SJohn Marino if (else_bb || ! ce_info->and_and_p)
455e4b17023SJohn Marino return FALSE;
456e4b17023SJohn Marino
457e4b17023SJohn Marino ce_info->test_bb = test_bb = ce_info->last_test_bb;
458e4b17023SJohn Marino ce_info->num_multiple_test_blocks = 0;
459e4b17023SJohn Marino ce_info->num_and_and_blocks = 0;
460e4b17023SJohn Marino ce_info->num_or_or_blocks = 0;
461e4b17023SJohn Marino }
462e4b17023SJohn Marino
463e4b17023SJohn Marino /* Find the conditional jump to the ELSE or JOIN part, and isolate
464e4b17023SJohn Marino the test. */
465e4b17023SJohn Marino test_expr = cond_exec_get_condition (BB_END (test_bb));
466e4b17023SJohn Marino if (! test_expr)
467e4b17023SJohn Marino return FALSE;
468e4b17023SJohn Marino
469e4b17023SJohn Marino /* If the conditional jump is more than just a conditional jump,
470e4b17023SJohn Marino then we can not do conditional execution conversion on this block. */
471e4b17023SJohn Marino if (! onlyjump_p (BB_END (test_bb)))
472e4b17023SJohn Marino return FALSE;
473e4b17023SJohn Marino
474e4b17023SJohn Marino /* Collect the bounds of where we're to search, skipping any labels, jumps
475e4b17023SJohn Marino and notes at the beginning and end of the block. Then count the total
476e4b17023SJohn Marino number of insns and see if it is small enough to convert. */
477e4b17023SJohn Marino then_start = first_active_insn (then_bb);
478e4b17023SJohn Marino then_end = last_active_insn (then_bb, TRUE);
479e4b17023SJohn Marino then_n_insns = ce_info->num_then_insns = count_bb_insns (then_bb);
480e4b17023SJohn Marino n_insns = then_n_insns;
481e4b17023SJohn Marino max = MAX_CONDITIONAL_EXECUTE;
482e4b17023SJohn Marino
483e4b17023SJohn Marino if (else_bb)
484e4b17023SJohn Marino {
485e4b17023SJohn Marino int n_matching;
486e4b17023SJohn Marino
487e4b17023SJohn Marino max *= 2;
488e4b17023SJohn Marino else_start = first_active_insn (else_bb);
489e4b17023SJohn Marino else_end = last_active_insn (else_bb, TRUE);
490e4b17023SJohn Marino else_n_insns = ce_info->num_else_insns = count_bb_insns (else_bb);
491e4b17023SJohn Marino n_insns += else_n_insns;
492e4b17023SJohn Marino
493e4b17023SJohn Marino /* Look for matching sequences at the head and tail of the two blocks,
494e4b17023SJohn Marino and limit the range of insns to be converted if possible. */
495e4b17023SJohn Marino n_matching = flow_find_cross_jump (then_bb, else_bb,
496e4b17023SJohn Marino &then_first_tail, &else_first_tail,
497e4b17023SJohn Marino NULL);
498e4b17023SJohn Marino if (then_first_tail == BB_HEAD (then_bb))
499e4b17023SJohn Marino then_start = then_end = NULL_RTX;
500e4b17023SJohn Marino if (else_first_tail == BB_HEAD (else_bb))
501e4b17023SJohn Marino else_start = else_end = NULL_RTX;
502e4b17023SJohn Marino
503e4b17023SJohn Marino if (n_matching > 0)
504e4b17023SJohn Marino {
505e4b17023SJohn Marino if (then_end)
506e4b17023SJohn Marino then_end = find_active_insn_before (then_bb, then_first_tail);
507e4b17023SJohn Marino if (else_end)
508e4b17023SJohn Marino else_end = find_active_insn_before (else_bb, else_first_tail);
509e4b17023SJohn Marino n_insns -= 2 * n_matching;
510e4b17023SJohn Marino }
511e4b17023SJohn Marino
512e4b17023SJohn Marino if (then_start && else_start)
513e4b17023SJohn Marino {
514e4b17023SJohn Marino int longest_match = MIN (then_n_insns - n_matching,
515e4b17023SJohn Marino else_n_insns - n_matching);
516e4b17023SJohn Marino n_matching
517e4b17023SJohn Marino = flow_find_head_matching_sequence (then_bb, else_bb,
518e4b17023SJohn Marino &then_last_head,
519e4b17023SJohn Marino &else_last_head,
520e4b17023SJohn Marino longest_match);
521e4b17023SJohn Marino
522e4b17023SJohn Marino if (n_matching > 0)
523e4b17023SJohn Marino {
524e4b17023SJohn Marino rtx insn;
525e4b17023SJohn Marino
526e4b17023SJohn Marino /* We won't pass the insns in the head sequence to
527e4b17023SJohn Marino cond_exec_process_insns, so we need to test them here
528e4b17023SJohn Marino to make sure that they don't clobber the condition. */
529e4b17023SJohn Marino for (insn = BB_HEAD (then_bb);
530e4b17023SJohn Marino insn != NEXT_INSN (then_last_head);
531e4b17023SJohn Marino insn = NEXT_INSN (insn))
532e4b17023SJohn Marino if (!LABEL_P (insn) && !NOTE_P (insn)
533e4b17023SJohn Marino && !DEBUG_INSN_P (insn)
534e4b17023SJohn Marino && modified_in_p (test_expr, insn))
535e4b17023SJohn Marino return FALSE;
536e4b17023SJohn Marino }
537e4b17023SJohn Marino
538e4b17023SJohn Marino if (then_last_head == then_end)
539e4b17023SJohn Marino then_start = then_end = NULL_RTX;
540e4b17023SJohn Marino if (else_last_head == else_end)
541e4b17023SJohn Marino else_start = else_end = NULL_RTX;
542e4b17023SJohn Marino
543e4b17023SJohn Marino if (n_matching > 0)
544e4b17023SJohn Marino {
545e4b17023SJohn Marino if (then_start)
546e4b17023SJohn Marino then_start = find_active_insn_after (then_bb, then_last_head);
547e4b17023SJohn Marino if (else_start)
548e4b17023SJohn Marino else_start = find_active_insn_after (else_bb, else_last_head);
549e4b17023SJohn Marino n_insns -= 2 * n_matching;
550e4b17023SJohn Marino }
551e4b17023SJohn Marino }
552e4b17023SJohn Marino }
553e4b17023SJohn Marino
554e4b17023SJohn Marino if (n_insns > max)
555e4b17023SJohn Marino return FALSE;
556e4b17023SJohn Marino
557e4b17023SJohn Marino /* Map test_expr/test_jump into the appropriate MD tests to use on
558e4b17023SJohn Marino the conditionally executed code. */
559e4b17023SJohn Marino
560e4b17023SJohn Marino true_expr = test_expr;
561e4b17023SJohn Marino
562e4b17023SJohn Marino false_code = reversed_comparison_code (true_expr, BB_END (test_bb));
563e4b17023SJohn Marino if (false_code != UNKNOWN)
564e4b17023SJohn Marino false_expr = gen_rtx_fmt_ee (false_code, GET_MODE (true_expr),
565e4b17023SJohn Marino XEXP (true_expr, 0), XEXP (true_expr, 1));
566e4b17023SJohn Marino else
567e4b17023SJohn Marino false_expr = NULL_RTX;
568e4b17023SJohn Marino
569e4b17023SJohn Marino #ifdef IFCVT_MODIFY_TESTS
570e4b17023SJohn Marino /* If the machine description needs to modify the tests, such as setting a
571e4b17023SJohn Marino conditional execution register from a comparison, it can do so here. */
572e4b17023SJohn Marino IFCVT_MODIFY_TESTS (ce_info, true_expr, false_expr);
573e4b17023SJohn Marino
574e4b17023SJohn Marino /* See if the conversion failed. */
575e4b17023SJohn Marino if (!true_expr || !false_expr)
576e4b17023SJohn Marino goto fail;
577e4b17023SJohn Marino #endif
578e4b17023SJohn Marino
579e4b17023SJohn Marino true_prob_val = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX);
580e4b17023SJohn Marino if (true_prob_val)
581e4b17023SJohn Marino {
582e4b17023SJohn Marino true_prob_val = XEXP (true_prob_val, 0);
583e4b17023SJohn Marino false_prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (true_prob_val));
584e4b17023SJohn Marino }
585e4b17023SJohn Marino else
586e4b17023SJohn Marino false_prob_val = NULL_RTX;
587e4b17023SJohn Marino
588e4b17023SJohn Marino /* If we have && or || tests, do them here. These tests are in the adjacent
589e4b17023SJohn Marino blocks after the first block containing the test. */
590e4b17023SJohn Marino if (ce_info->num_multiple_test_blocks > 0)
591e4b17023SJohn Marino {
592e4b17023SJohn Marino basic_block bb = test_bb;
593e4b17023SJohn Marino basic_block last_test_bb = ce_info->last_test_bb;
594e4b17023SJohn Marino
595e4b17023SJohn Marino if (! false_expr)
596e4b17023SJohn Marino goto fail;
597e4b17023SJohn Marino
598e4b17023SJohn Marino do
599e4b17023SJohn Marino {
600e4b17023SJohn Marino rtx start, end;
601e4b17023SJohn Marino rtx t, f;
602e4b17023SJohn Marino enum rtx_code f_code;
603e4b17023SJohn Marino
604e4b17023SJohn Marino bb = block_fallthru (bb);
605e4b17023SJohn Marino start = first_active_insn (bb);
606e4b17023SJohn Marino end = last_active_insn (bb, TRUE);
607e4b17023SJohn Marino if (start
608e4b17023SJohn Marino && ! cond_exec_process_insns (ce_info, start, end, false_expr,
609e4b17023SJohn Marino false_prob_val, FALSE))
610e4b17023SJohn Marino goto fail;
611e4b17023SJohn Marino
612e4b17023SJohn Marino /* If the conditional jump is more than just a conditional jump, then
613e4b17023SJohn Marino we can not do conditional execution conversion on this block. */
614e4b17023SJohn Marino if (! onlyjump_p (BB_END (bb)))
615e4b17023SJohn Marino goto fail;
616e4b17023SJohn Marino
617e4b17023SJohn Marino /* Find the conditional jump and isolate the test. */
618e4b17023SJohn Marino t = cond_exec_get_condition (BB_END (bb));
619e4b17023SJohn Marino if (! t)
620e4b17023SJohn Marino goto fail;
621e4b17023SJohn Marino
622e4b17023SJohn Marino f_code = reversed_comparison_code (t, BB_END (bb));
623e4b17023SJohn Marino if (f_code == UNKNOWN)
624e4b17023SJohn Marino goto fail;
625e4b17023SJohn Marino
626e4b17023SJohn Marino f = gen_rtx_fmt_ee (f_code, GET_MODE (t), XEXP (t, 0), XEXP (t, 1));
627e4b17023SJohn Marino if (ce_info->and_and_p)
628e4b17023SJohn Marino {
629e4b17023SJohn Marino t = gen_rtx_AND (GET_MODE (t), true_expr, t);
630e4b17023SJohn Marino f = gen_rtx_IOR (GET_MODE (t), false_expr, f);
631e4b17023SJohn Marino }
632e4b17023SJohn Marino else
633e4b17023SJohn Marino {
634e4b17023SJohn Marino t = gen_rtx_IOR (GET_MODE (t), true_expr, t);
635e4b17023SJohn Marino f = gen_rtx_AND (GET_MODE (t), false_expr, f);
636e4b17023SJohn Marino }
637e4b17023SJohn Marino
638e4b17023SJohn Marino /* If the machine description needs to modify the tests, such as
639e4b17023SJohn Marino setting a conditional execution register from a comparison, it can
640e4b17023SJohn Marino do so here. */
641e4b17023SJohn Marino #ifdef IFCVT_MODIFY_MULTIPLE_TESTS
642e4b17023SJohn Marino IFCVT_MODIFY_MULTIPLE_TESTS (ce_info, bb, t, f);
643e4b17023SJohn Marino
644e4b17023SJohn Marino /* See if the conversion failed. */
645e4b17023SJohn Marino if (!t || !f)
646e4b17023SJohn Marino goto fail;
647e4b17023SJohn Marino #endif
648e4b17023SJohn Marino
649e4b17023SJohn Marino true_expr = t;
650e4b17023SJohn Marino false_expr = f;
651e4b17023SJohn Marino }
652e4b17023SJohn Marino while (bb != last_test_bb);
653e4b17023SJohn Marino }
654e4b17023SJohn Marino
655e4b17023SJohn Marino /* For IF-THEN-ELSE blocks, we don't allow modifications of the test
656e4b17023SJohn Marino on then THEN block. */
657e4b17023SJohn Marino then_mod_ok = (else_bb == NULL_BLOCK);
658e4b17023SJohn Marino
659e4b17023SJohn Marino /* Go through the THEN and ELSE blocks converting the insns if possible
660e4b17023SJohn Marino to conditional execution. */
661e4b17023SJohn Marino
662e4b17023SJohn Marino if (then_end
663e4b17023SJohn Marino && (! false_expr
664e4b17023SJohn Marino || ! cond_exec_process_insns (ce_info, then_start, then_end,
665e4b17023SJohn Marino false_expr, false_prob_val,
666e4b17023SJohn Marino then_mod_ok)))
667e4b17023SJohn Marino goto fail;
668e4b17023SJohn Marino
669e4b17023SJohn Marino if (else_bb && else_end
670e4b17023SJohn Marino && ! cond_exec_process_insns (ce_info, else_start, else_end,
671e4b17023SJohn Marino true_expr, true_prob_val, TRUE))
672e4b17023SJohn Marino goto fail;
673e4b17023SJohn Marino
674e4b17023SJohn Marino /* If we cannot apply the changes, fail. Do not go through the normal fail
675e4b17023SJohn Marino processing, since apply_change_group will call cancel_changes. */
676e4b17023SJohn Marino if (! apply_change_group ())
677e4b17023SJohn Marino {
678e4b17023SJohn Marino #ifdef IFCVT_MODIFY_CANCEL
679e4b17023SJohn Marino /* Cancel any machine dependent changes. */
680e4b17023SJohn Marino IFCVT_MODIFY_CANCEL (ce_info);
681e4b17023SJohn Marino #endif
682e4b17023SJohn Marino return FALSE;
683e4b17023SJohn Marino }
684e4b17023SJohn Marino
685e4b17023SJohn Marino #ifdef IFCVT_MODIFY_FINAL
686e4b17023SJohn Marino /* Do any machine dependent final modifications. */
687e4b17023SJohn Marino IFCVT_MODIFY_FINAL (ce_info);
688e4b17023SJohn Marino #endif
689e4b17023SJohn Marino
690e4b17023SJohn Marino /* Conversion succeeded. */
691e4b17023SJohn Marino if (dump_file)
692e4b17023SJohn Marino fprintf (dump_file, "%d insn%s converted to conditional execution.\n",
693e4b17023SJohn Marino n_insns, (n_insns == 1) ? " was" : "s were");
694e4b17023SJohn Marino
695e4b17023SJohn Marino /* Merge the blocks! If we had matching sequences, make sure to delete one
696e4b17023SJohn Marino copy at the appropriate location first: delete the copy in the THEN branch
697e4b17023SJohn Marino for a tail sequence so that the remaining one is executed last for both
698e4b17023SJohn Marino branches, and delete the copy in the ELSE branch for a head sequence so
699e4b17023SJohn Marino that the remaining one is executed first for both branches. */
700e4b17023SJohn Marino if (then_first_tail)
701e4b17023SJohn Marino {
702e4b17023SJohn Marino rtx from = then_first_tail;
703e4b17023SJohn Marino if (!INSN_P (from))
704e4b17023SJohn Marino from = find_active_insn_after (then_bb, from);
705e4b17023SJohn Marino delete_insn_chain (from, BB_END (then_bb), false);
706e4b17023SJohn Marino }
707e4b17023SJohn Marino if (else_last_head)
708e4b17023SJohn Marino delete_insn_chain (first_active_insn (else_bb), else_last_head, false);
709e4b17023SJohn Marino
710e4b17023SJohn Marino merge_if_block (ce_info);
711e4b17023SJohn Marino cond_exec_changed_p = TRUE;
712e4b17023SJohn Marino return TRUE;
713e4b17023SJohn Marino
714e4b17023SJohn Marino fail:
715e4b17023SJohn Marino #ifdef IFCVT_MODIFY_CANCEL
716e4b17023SJohn Marino /* Cancel any machine dependent changes. */
717e4b17023SJohn Marino IFCVT_MODIFY_CANCEL (ce_info);
718e4b17023SJohn Marino #endif
719e4b17023SJohn Marino
720e4b17023SJohn Marino cancel_changes (0);
721e4b17023SJohn Marino return FALSE;
722e4b17023SJohn Marino }
723e4b17023SJohn Marino
724e4b17023SJohn Marino /* Used by noce_process_if_block to communicate with its subroutines.
725e4b17023SJohn Marino
726e4b17023SJohn Marino The subroutines know that A and B may be evaluated freely. They
727e4b17023SJohn Marino know that X is a register. They should insert new instructions
728e4b17023SJohn Marino before cond_earliest. */
729e4b17023SJohn Marino
730e4b17023SJohn Marino struct noce_if_info
731e4b17023SJohn Marino {
732e4b17023SJohn Marino /* The basic blocks that make up the IF-THEN-{ELSE-,}JOIN block. */
733e4b17023SJohn Marino basic_block test_bb, then_bb, else_bb, join_bb;
734e4b17023SJohn Marino
735e4b17023SJohn Marino /* The jump that ends TEST_BB. */
736e4b17023SJohn Marino rtx jump;
737e4b17023SJohn Marino
738e4b17023SJohn Marino /* The jump condition. */
739e4b17023SJohn Marino rtx cond;
740e4b17023SJohn Marino
741e4b17023SJohn Marino /* New insns should be inserted before this one. */
742e4b17023SJohn Marino rtx cond_earliest;
743e4b17023SJohn Marino
744e4b17023SJohn Marino /* Insns in the THEN and ELSE block. There is always just this
745e4b17023SJohn Marino one insns in those blocks. The insns are single_set insns.
746e4b17023SJohn Marino If there was no ELSE block, INSN_B is the last insn before
747e4b17023SJohn Marino COND_EARLIEST, or NULL_RTX. In the former case, the insn
748e4b17023SJohn Marino operands are still valid, as if INSN_B was moved down below
749e4b17023SJohn Marino the jump. */
750e4b17023SJohn Marino rtx insn_a, insn_b;
751e4b17023SJohn Marino
752e4b17023SJohn Marino /* The SET_SRC of INSN_A and INSN_B. */
753e4b17023SJohn Marino rtx a, b;
754e4b17023SJohn Marino
755e4b17023SJohn Marino /* The SET_DEST of INSN_A. */
756e4b17023SJohn Marino rtx x;
757e4b17023SJohn Marino
758e4b17023SJohn Marino /* True if this if block is not canonical. In the canonical form of
759e4b17023SJohn Marino if blocks, the THEN_BB is the block reached via the fallthru edge
760e4b17023SJohn Marino from TEST_BB. For the noce transformations, we allow the symmetric
761e4b17023SJohn Marino form as well. */
762e4b17023SJohn Marino bool then_else_reversed;
763e4b17023SJohn Marino
764e4b17023SJohn Marino /* Estimated cost of the particular branch instruction. */
765e4b17023SJohn Marino int branch_cost;
766e4b17023SJohn Marino };
767e4b17023SJohn Marino
768e4b17023SJohn Marino static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
769e4b17023SJohn Marino static int noce_try_move (struct noce_if_info *);
770e4b17023SJohn Marino static int noce_try_store_flag (struct noce_if_info *);
771e4b17023SJohn Marino static int noce_try_addcc (struct noce_if_info *);
772e4b17023SJohn Marino static int noce_try_store_flag_constants (struct noce_if_info *);
773e4b17023SJohn Marino static int noce_try_store_flag_mask (struct noce_if_info *);
774e4b17023SJohn Marino static rtx noce_emit_cmove (struct noce_if_info *, rtx, enum rtx_code, rtx,
775e4b17023SJohn Marino rtx, rtx, rtx);
776e4b17023SJohn Marino static int noce_try_cmove (struct noce_if_info *);
777e4b17023SJohn Marino static int noce_try_cmove_arith (struct noce_if_info *);
778e4b17023SJohn Marino static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx *);
779e4b17023SJohn Marino static int noce_try_minmax (struct noce_if_info *);
780e4b17023SJohn Marino static int noce_try_abs (struct noce_if_info *);
781e4b17023SJohn Marino static int noce_try_sign_mask (struct noce_if_info *);
782e4b17023SJohn Marino
783e4b17023SJohn Marino /* Helper function for noce_try_store_flag*. */
784e4b17023SJohn Marino
785e4b17023SJohn Marino static rtx
noce_emit_store_flag(struct noce_if_info * if_info,rtx x,int reversep,int normalize)786e4b17023SJohn Marino noce_emit_store_flag (struct noce_if_info *if_info, rtx x, int reversep,
787e4b17023SJohn Marino int normalize)
788e4b17023SJohn Marino {
789e4b17023SJohn Marino rtx cond = if_info->cond;
790e4b17023SJohn Marino int cond_complex;
791e4b17023SJohn Marino enum rtx_code code;
792e4b17023SJohn Marino
793e4b17023SJohn Marino cond_complex = (! general_operand (XEXP (cond, 0), VOIDmode)
794e4b17023SJohn Marino || ! general_operand (XEXP (cond, 1), VOIDmode));
795e4b17023SJohn Marino
796e4b17023SJohn Marino /* If earliest == jump, or when the condition is complex, try to
797e4b17023SJohn Marino build the store_flag insn directly. */
798e4b17023SJohn Marino
799e4b17023SJohn Marino if (cond_complex)
800e4b17023SJohn Marino {
801e4b17023SJohn Marino rtx set = pc_set (if_info->jump);
802e4b17023SJohn Marino cond = XEXP (SET_SRC (set), 0);
803e4b17023SJohn Marino if (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
804e4b17023SJohn Marino && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump))
805e4b17023SJohn Marino reversep = !reversep;
806e4b17023SJohn Marino if (if_info->then_else_reversed)
807e4b17023SJohn Marino reversep = !reversep;
808e4b17023SJohn Marino }
809e4b17023SJohn Marino
810e4b17023SJohn Marino if (reversep)
811e4b17023SJohn Marino code = reversed_comparison_code (cond, if_info->jump);
812e4b17023SJohn Marino else
813e4b17023SJohn Marino code = GET_CODE (cond);
814e4b17023SJohn Marino
815e4b17023SJohn Marino if ((if_info->cond_earliest == if_info->jump || cond_complex)
816e4b17023SJohn Marino && (normalize == 0 || STORE_FLAG_VALUE == normalize))
817e4b17023SJohn Marino {
818e4b17023SJohn Marino rtx tmp;
819e4b17023SJohn Marino
820e4b17023SJohn Marino tmp = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0),
821e4b17023SJohn Marino XEXP (cond, 1));
822e4b17023SJohn Marino tmp = gen_rtx_SET (VOIDmode, x, tmp);
823e4b17023SJohn Marino
824e4b17023SJohn Marino start_sequence ();
825e4b17023SJohn Marino tmp = emit_insn (tmp);
826e4b17023SJohn Marino
827e4b17023SJohn Marino if (recog_memoized (tmp) >= 0)
828e4b17023SJohn Marino {
829e4b17023SJohn Marino tmp = get_insns ();
830e4b17023SJohn Marino end_sequence ();
831e4b17023SJohn Marino emit_insn (tmp);
832e4b17023SJohn Marino
833e4b17023SJohn Marino if_info->cond_earliest = if_info->jump;
834e4b17023SJohn Marino
835e4b17023SJohn Marino return x;
836e4b17023SJohn Marino }
837e4b17023SJohn Marino
838e4b17023SJohn Marino end_sequence ();
839e4b17023SJohn Marino }
840e4b17023SJohn Marino
841e4b17023SJohn Marino /* Don't even try if the comparison operands or the mode of X are weird. */
842e4b17023SJohn Marino if (cond_complex || !SCALAR_INT_MODE_P (GET_MODE (x)))
843e4b17023SJohn Marino return NULL_RTX;
844e4b17023SJohn Marino
845e4b17023SJohn Marino return emit_store_flag (x, code, XEXP (cond, 0),
846e4b17023SJohn Marino XEXP (cond, 1), VOIDmode,
847e4b17023SJohn Marino (code == LTU || code == LEU
848e4b17023SJohn Marino || code == GEU || code == GTU), normalize);
849e4b17023SJohn Marino }
850e4b17023SJohn Marino
851e4b17023SJohn Marino /* Emit instruction to move an rtx, possibly into STRICT_LOW_PART.
852e4b17023SJohn Marino X is the destination/target and Y is the value to copy. */
853e4b17023SJohn Marino
854e4b17023SJohn Marino static void
noce_emit_move_insn(rtx x,rtx y)855e4b17023SJohn Marino noce_emit_move_insn (rtx x, rtx y)
856e4b17023SJohn Marino {
857e4b17023SJohn Marino enum machine_mode outmode;
858e4b17023SJohn Marino rtx outer, inner;
859e4b17023SJohn Marino int bitpos;
860e4b17023SJohn Marino
861e4b17023SJohn Marino if (GET_CODE (x) != STRICT_LOW_PART)
862e4b17023SJohn Marino {
863e4b17023SJohn Marino rtx seq, insn, target;
864e4b17023SJohn Marino optab ot;
865e4b17023SJohn Marino
866e4b17023SJohn Marino start_sequence ();
867e4b17023SJohn Marino /* Check that the SET_SRC is reasonable before calling emit_move_insn,
868e4b17023SJohn Marino otherwise construct a suitable SET pattern ourselves. */
869e4b17023SJohn Marino insn = (OBJECT_P (y) || CONSTANT_P (y) || GET_CODE (y) == SUBREG)
870e4b17023SJohn Marino ? emit_move_insn (x, y)
871e4b17023SJohn Marino : emit_insn (gen_rtx_SET (VOIDmode, x, y));
872e4b17023SJohn Marino seq = get_insns ();
873e4b17023SJohn Marino end_sequence ();
874e4b17023SJohn Marino
875e4b17023SJohn Marino if (recog_memoized (insn) <= 0)
876e4b17023SJohn Marino {
877e4b17023SJohn Marino if (GET_CODE (x) == ZERO_EXTRACT)
878e4b17023SJohn Marino {
879e4b17023SJohn Marino rtx op = XEXP (x, 0);
880e4b17023SJohn Marino unsigned HOST_WIDE_INT size = INTVAL (XEXP (x, 1));
881e4b17023SJohn Marino unsigned HOST_WIDE_INT start = INTVAL (XEXP (x, 2));
882e4b17023SJohn Marino
883e4b17023SJohn Marino /* store_bit_field expects START to be relative to
884e4b17023SJohn Marino BYTES_BIG_ENDIAN and adjusts this value for machines with
885e4b17023SJohn Marino BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN. In order to be able to
886e4b17023SJohn Marino invoke store_bit_field again it is necessary to have the START
887e4b17023SJohn Marino value from the first call. */
888e4b17023SJohn Marino if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
889e4b17023SJohn Marino {
890e4b17023SJohn Marino if (MEM_P (op))
891e4b17023SJohn Marino start = BITS_PER_UNIT - start - size;
892e4b17023SJohn Marino else
893e4b17023SJohn Marino {
894e4b17023SJohn Marino gcc_assert (REG_P (op));
895e4b17023SJohn Marino start = BITS_PER_WORD - start - size;
896e4b17023SJohn Marino }
897e4b17023SJohn Marino }
898e4b17023SJohn Marino
899e4b17023SJohn Marino gcc_assert (start < (MEM_P (op) ? BITS_PER_UNIT : BITS_PER_WORD));
900e4b17023SJohn Marino store_bit_field (op, size, start, 0, 0, GET_MODE (x), y);
901e4b17023SJohn Marino return;
902e4b17023SJohn Marino }
903e4b17023SJohn Marino
904e4b17023SJohn Marino switch (GET_RTX_CLASS (GET_CODE (y)))
905e4b17023SJohn Marino {
906e4b17023SJohn Marino case RTX_UNARY:
907e4b17023SJohn Marino ot = code_to_optab[GET_CODE (y)];
908e4b17023SJohn Marino if (ot)
909e4b17023SJohn Marino {
910e4b17023SJohn Marino start_sequence ();
911e4b17023SJohn Marino target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
912e4b17023SJohn Marino if (target != NULL_RTX)
913e4b17023SJohn Marino {
914e4b17023SJohn Marino if (target != x)
915e4b17023SJohn Marino emit_move_insn (x, target);
916e4b17023SJohn Marino seq = get_insns ();
917e4b17023SJohn Marino }
918e4b17023SJohn Marino end_sequence ();
919e4b17023SJohn Marino }
920e4b17023SJohn Marino break;
921e4b17023SJohn Marino
922e4b17023SJohn Marino case RTX_BIN_ARITH:
923e4b17023SJohn Marino case RTX_COMM_ARITH:
924e4b17023SJohn Marino ot = code_to_optab[GET_CODE (y)];
925e4b17023SJohn Marino if (ot)
926e4b17023SJohn Marino {
927e4b17023SJohn Marino start_sequence ();
928e4b17023SJohn Marino target = expand_binop (GET_MODE (y), ot,
929e4b17023SJohn Marino XEXP (y, 0), XEXP (y, 1),
930e4b17023SJohn Marino x, 0, OPTAB_DIRECT);
931e4b17023SJohn Marino if (target != NULL_RTX)
932e4b17023SJohn Marino {
933e4b17023SJohn Marino if (target != x)
934e4b17023SJohn Marino emit_move_insn (x, target);
935e4b17023SJohn Marino seq = get_insns ();
936e4b17023SJohn Marino }
937e4b17023SJohn Marino end_sequence ();
938e4b17023SJohn Marino }
939e4b17023SJohn Marino break;
940e4b17023SJohn Marino
941e4b17023SJohn Marino default:
942e4b17023SJohn Marino break;
943e4b17023SJohn Marino }
944e4b17023SJohn Marino }
945e4b17023SJohn Marino
946e4b17023SJohn Marino emit_insn (seq);
947e4b17023SJohn Marino return;
948e4b17023SJohn Marino }
949e4b17023SJohn Marino
950e4b17023SJohn Marino outer = XEXP (x, 0);
951e4b17023SJohn Marino inner = XEXP (outer, 0);
952e4b17023SJohn Marino outmode = GET_MODE (outer);
953e4b17023SJohn Marino bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT;
954e4b17023SJohn Marino store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos,
955e4b17023SJohn Marino 0, 0, outmode, y);
956e4b17023SJohn Marino }
957e4b17023SJohn Marino
958e4b17023SJohn Marino /* Return sequence of instructions generated by if conversion. This
959e4b17023SJohn Marino function calls end_sequence() to end the current stream, ensures
960e4b17023SJohn Marino that are instructions are unshared, recognizable non-jump insns.
961e4b17023SJohn Marino On failure, this function returns a NULL_RTX. */
962e4b17023SJohn Marino
963e4b17023SJohn Marino static rtx
end_ifcvt_sequence(struct noce_if_info * if_info)964e4b17023SJohn Marino end_ifcvt_sequence (struct noce_if_info *if_info)
965e4b17023SJohn Marino {
966e4b17023SJohn Marino rtx insn;
967e4b17023SJohn Marino rtx seq = get_insns ();
968e4b17023SJohn Marino
969e4b17023SJohn Marino set_used_flags (if_info->x);
970e4b17023SJohn Marino set_used_flags (if_info->cond);
971e4b17023SJohn Marino unshare_all_rtl_in_chain (seq);
972e4b17023SJohn Marino end_sequence ();
973e4b17023SJohn Marino
974e4b17023SJohn Marino /* Make sure that all of the instructions emitted are recognizable,
975e4b17023SJohn Marino and that we haven't introduced a new jump instruction.
976e4b17023SJohn Marino As an exercise for the reader, build a general mechanism that
977e4b17023SJohn Marino allows proper placement of required clobbers. */
978e4b17023SJohn Marino for (insn = seq; insn; insn = NEXT_INSN (insn))
979e4b17023SJohn Marino if (JUMP_P (insn)
980e4b17023SJohn Marino || recog_memoized (insn) == -1)
981e4b17023SJohn Marino return NULL_RTX;
982e4b17023SJohn Marino
983e4b17023SJohn Marino return seq;
984e4b17023SJohn Marino }
985e4b17023SJohn Marino
986e4b17023SJohn Marino /* Convert "if (a != b) x = a; else x = b" into "x = a" and
987e4b17023SJohn Marino "if (a == b) x = a; else x = b" into "x = b". */
988e4b17023SJohn Marino
989e4b17023SJohn Marino static int
noce_try_move(struct noce_if_info * if_info)990e4b17023SJohn Marino noce_try_move (struct noce_if_info *if_info)
991e4b17023SJohn Marino {
992e4b17023SJohn Marino rtx cond = if_info->cond;
993e4b17023SJohn Marino enum rtx_code code = GET_CODE (cond);
994e4b17023SJohn Marino rtx y, seq;
995e4b17023SJohn Marino
996e4b17023SJohn Marino if (code != NE && code != EQ)
997e4b17023SJohn Marino return FALSE;
998e4b17023SJohn Marino
999e4b17023SJohn Marino /* This optimization isn't valid if either A or B could be a NaN
1000e4b17023SJohn Marino or a signed zero. */
1001e4b17023SJohn Marino if (HONOR_NANS (GET_MODE (if_info->x))
1002e4b17023SJohn Marino || HONOR_SIGNED_ZEROS (GET_MODE (if_info->x)))
1003e4b17023SJohn Marino return FALSE;
1004e4b17023SJohn Marino
1005e4b17023SJohn Marino /* Check whether the operands of the comparison are A and in
1006e4b17023SJohn Marino either order. */
1007e4b17023SJohn Marino if ((rtx_equal_p (if_info->a, XEXP (cond, 0))
1008e4b17023SJohn Marino && rtx_equal_p (if_info->b, XEXP (cond, 1)))
1009e4b17023SJohn Marino || (rtx_equal_p (if_info->a, XEXP (cond, 1))
1010e4b17023SJohn Marino && rtx_equal_p (if_info->b, XEXP (cond, 0))))
1011e4b17023SJohn Marino {
1012e4b17023SJohn Marino y = (code == EQ) ? if_info->a : if_info->b;
1013e4b17023SJohn Marino
1014e4b17023SJohn Marino /* Avoid generating the move if the source is the destination. */
1015e4b17023SJohn Marino if (! rtx_equal_p (if_info->x, y))
1016e4b17023SJohn Marino {
1017e4b17023SJohn Marino start_sequence ();
1018e4b17023SJohn Marino noce_emit_move_insn (if_info->x, y);
1019e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
1020e4b17023SJohn Marino if (!seq)
1021e4b17023SJohn Marino return FALSE;
1022e4b17023SJohn Marino
1023e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump,
1024e4b17023SJohn Marino INSN_LOCATOR (if_info->insn_a));
1025e4b17023SJohn Marino }
1026e4b17023SJohn Marino return TRUE;
1027e4b17023SJohn Marino }
1028e4b17023SJohn Marino return FALSE;
1029e4b17023SJohn Marino }
1030e4b17023SJohn Marino
1031e4b17023SJohn Marino /* Convert "if (test) x = 1; else x = 0".
1032e4b17023SJohn Marino
1033e4b17023SJohn Marino Only try 0 and STORE_FLAG_VALUE here. Other combinations will be
1034e4b17023SJohn Marino tried in noce_try_store_flag_constants after noce_try_cmove has had
1035e4b17023SJohn Marino a go at the conversion. */
1036e4b17023SJohn Marino
1037e4b17023SJohn Marino static int
noce_try_store_flag(struct noce_if_info * if_info)1038e4b17023SJohn Marino noce_try_store_flag (struct noce_if_info *if_info)
1039e4b17023SJohn Marino {
1040e4b17023SJohn Marino int reversep;
1041e4b17023SJohn Marino rtx target, seq;
1042e4b17023SJohn Marino
1043e4b17023SJohn Marino if (CONST_INT_P (if_info->b)
1044e4b17023SJohn Marino && INTVAL (if_info->b) == STORE_FLAG_VALUE
1045e4b17023SJohn Marino && if_info->a == const0_rtx)
1046e4b17023SJohn Marino reversep = 0;
1047e4b17023SJohn Marino else if (if_info->b == const0_rtx
1048e4b17023SJohn Marino && CONST_INT_P (if_info->a)
1049e4b17023SJohn Marino && INTVAL (if_info->a) == STORE_FLAG_VALUE
1050e4b17023SJohn Marino && (reversed_comparison_code (if_info->cond, if_info->jump)
1051e4b17023SJohn Marino != UNKNOWN))
1052e4b17023SJohn Marino reversep = 1;
1053e4b17023SJohn Marino else
1054e4b17023SJohn Marino return FALSE;
1055e4b17023SJohn Marino
1056e4b17023SJohn Marino start_sequence ();
1057e4b17023SJohn Marino
1058e4b17023SJohn Marino target = noce_emit_store_flag (if_info, if_info->x, reversep, 0);
1059e4b17023SJohn Marino if (target)
1060e4b17023SJohn Marino {
1061e4b17023SJohn Marino if (target != if_info->x)
1062e4b17023SJohn Marino noce_emit_move_insn (if_info->x, target);
1063e4b17023SJohn Marino
1064e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
1065e4b17023SJohn Marino if (! seq)
1066e4b17023SJohn Marino return FALSE;
1067e4b17023SJohn Marino
1068e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump,
1069e4b17023SJohn Marino INSN_LOCATOR (if_info->insn_a));
1070e4b17023SJohn Marino return TRUE;
1071e4b17023SJohn Marino }
1072e4b17023SJohn Marino else
1073e4b17023SJohn Marino {
1074e4b17023SJohn Marino end_sequence ();
1075e4b17023SJohn Marino return FALSE;
1076e4b17023SJohn Marino }
1077e4b17023SJohn Marino }
1078e4b17023SJohn Marino
1079e4b17023SJohn Marino /* Convert "if (test) x = a; else x = b", for A and B constant. */
1080e4b17023SJohn Marino
1081e4b17023SJohn Marino static int
noce_try_store_flag_constants(struct noce_if_info * if_info)1082e4b17023SJohn Marino noce_try_store_flag_constants (struct noce_if_info *if_info)
1083e4b17023SJohn Marino {
1084e4b17023SJohn Marino rtx target, seq;
1085e4b17023SJohn Marino int reversep;
1086e4b17023SJohn Marino HOST_WIDE_INT itrue, ifalse, diff, tmp;
1087e4b17023SJohn Marino int normalize, can_reverse;
1088e4b17023SJohn Marino enum machine_mode mode;
1089e4b17023SJohn Marino
1090e4b17023SJohn Marino if (CONST_INT_P (if_info->a)
1091e4b17023SJohn Marino && CONST_INT_P (if_info->b))
1092e4b17023SJohn Marino {
1093e4b17023SJohn Marino mode = GET_MODE (if_info->x);
1094e4b17023SJohn Marino ifalse = INTVAL (if_info->a);
1095e4b17023SJohn Marino itrue = INTVAL (if_info->b);
1096e4b17023SJohn Marino
1097e4b17023SJohn Marino /* Make sure we can represent the difference between the two values. */
1098e4b17023SJohn Marino if ((itrue - ifalse > 0)
1099e4b17023SJohn Marino != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue))
1100e4b17023SJohn Marino return FALSE;
1101e4b17023SJohn Marino
1102e4b17023SJohn Marino diff = trunc_int_for_mode (itrue - ifalse, mode);
1103e4b17023SJohn Marino
1104e4b17023SJohn Marino can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump)
1105e4b17023SJohn Marino != UNKNOWN);
1106e4b17023SJohn Marino
1107e4b17023SJohn Marino reversep = 0;
1108e4b17023SJohn Marino if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
1109e4b17023SJohn Marino normalize = 0;
1110e4b17023SJohn Marino else if (ifalse == 0 && exact_log2 (itrue) >= 0
1111e4b17023SJohn Marino && (STORE_FLAG_VALUE == 1
1112e4b17023SJohn Marino || if_info->branch_cost >= 2))
1113e4b17023SJohn Marino normalize = 1;
1114e4b17023SJohn Marino else if (itrue == 0 && exact_log2 (ifalse) >= 0 && can_reverse
1115e4b17023SJohn Marino && (STORE_FLAG_VALUE == 1 || if_info->branch_cost >= 2))
1116e4b17023SJohn Marino normalize = 1, reversep = 1;
1117e4b17023SJohn Marino else if (itrue == -1
1118e4b17023SJohn Marino && (STORE_FLAG_VALUE == -1
1119e4b17023SJohn Marino || if_info->branch_cost >= 2))
1120e4b17023SJohn Marino normalize = -1;
1121e4b17023SJohn Marino else if (ifalse == -1 && can_reverse
1122e4b17023SJohn Marino && (STORE_FLAG_VALUE == -1 || if_info->branch_cost >= 2))
1123e4b17023SJohn Marino normalize = -1, reversep = 1;
1124e4b17023SJohn Marino else if ((if_info->branch_cost >= 2 && STORE_FLAG_VALUE == -1)
1125e4b17023SJohn Marino || if_info->branch_cost >= 3)
1126e4b17023SJohn Marino normalize = -1;
1127e4b17023SJohn Marino else
1128e4b17023SJohn Marino return FALSE;
1129e4b17023SJohn Marino
1130e4b17023SJohn Marino if (reversep)
1131e4b17023SJohn Marino {
1132e4b17023SJohn Marino tmp = itrue; itrue = ifalse; ifalse = tmp;
1133e4b17023SJohn Marino diff = trunc_int_for_mode (-diff, mode);
1134e4b17023SJohn Marino }
1135e4b17023SJohn Marino
1136e4b17023SJohn Marino start_sequence ();
1137e4b17023SJohn Marino target = noce_emit_store_flag (if_info, if_info->x, reversep, normalize);
1138e4b17023SJohn Marino if (! target)
1139e4b17023SJohn Marino {
1140e4b17023SJohn Marino end_sequence ();
1141e4b17023SJohn Marino return FALSE;
1142e4b17023SJohn Marino }
1143e4b17023SJohn Marino
1144e4b17023SJohn Marino /* if (test) x = 3; else x = 4;
1145e4b17023SJohn Marino => x = 3 + (test == 0); */
1146e4b17023SJohn Marino if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
1147e4b17023SJohn Marino {
1148e4b17023SJohn Marino target = expand_simple_binop (mode,
1149e4b17023SJohn Marino (diff == STORE_FLAG_VALUE
1150e4b17023SJohn Marino ? PLUS : MINUS),
1151e4b17023SJohn Marino GEN_INT (ifalse), target, if_info->x, 0,
1152e4b17023SJohn Marino OPTAB_WIDEN);
1153e4b17023SJohn Marino }
1154e4b17023SJohn Marino
1155e4b17023SJohn Marino /* if (test) x = 8; else x = 0;
1156e4b17023SJohn Marino => x = (test != 0) << 3; */
1157e4b17023SJohn Marino else if (ifalse == 0 && (tmp = exact_log2 (itrue)) >= 0)
1158e4b17023SJohn Marino {
1159e4b17023SJohn Marino target = expand_simple_binop (mode, ASHIFT,
1160e4b17023SJohn Marino target, GEN_INT (tmp), if_info->x, 0,
1161e4b17023SJohn Marino OPTAB_WIDEN);
1162e4b17023SJohn Marino }
1163e4b17023SJohn Marino
1164e4b17023SJohn Marino /* if (test) x = -1; else x = b;
1165e4b17023SJohn Marino => x = -(test != 0) | b; */
1166e4b17023SJohn Marino else if (itrue == -1)
1167e4b17023SJohn Marino {
1168e4b17023SJohn Marino target = expand_simple_binop (mode, IOR,
1169e4b17023SJohn Marino target, GEN_INT (ifalse), if_info->x, 0,
1170e4b17023SJohn Marino OPTAB_WIDEN);
1171e4b17023SJohn Marino }
1172e4b17023SJohn Marino
1173e4b17023SJohn Marino /* if (test) x = a; else x = b;
1174e4b17023SJohn Marino => x = (-(test != 0) & (b - a)) + a; */
1175e4b17023SJohn Marino else
1176e4b17023SJohn Marino {
1177e4b17023SJohn Marino target = expand_simple_binop (mode, AND,
1178e4b17023SJohn Marino target, GEN_INT (diff), if_info->x, 0,
1179e4b17023SJohn Marino OPTAB_WIDEN);
1180e4b17023SJohn Marino if (target)
1181e4b17023SJohn Marino target = expand_simple_binop (mode, PLUS,
1182e4b17023SJohn Marino target, GEN_INT (ifalse),
1183e4b17023SJohn Marino if_info->x, 0, OPTAB_WIDEN);
1184e4b17023SJohn Marino }
1185e4b17023SJohn Marino
1186e4b17023SJohn Marino if (! target)
1187e4b17023SJohn Marino {
1188e4b17023SJohn Marino end_sequence ();
1189e4b17023SJohn Marino return FALSE;
1190e4b17023SJohn Marino }
1191e4b17023SJohn Marino
1192e4b17023SJohn Marino if (target != if_info->x)
1193e4b17023SJohn Marino noce_emit_move_insn (if_info->x, target);
1194e4b17023SJohn Marino
1195e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
1196e4b17023SJohn Marino if (!seq)
1197e4b17023SJohn Marino return FALSE;
1198e4b17023SJohn Marino
1199e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump,
1200e4b17023SJohn Marino INSN_LOCATOR (if_info->insn_a));
1201e4b17023SJohn Marino return TRUE;
1202e4b17023SJohn Marino }
1203e4b17023SJohn Marino
1204e4b17023SJohn Marino return FALSE;
1205e4b17023SJohn Marino }
1206e4b17023SJohn Marino
1207e4b17023SJohn Marino /* Convert "if (test) foo++" into "foo += (test != 0)", and
1208e4b17023SJohn Marino similarly for "foo--". */
1209e4b17023SJohn Marino
1210e4b17023SJohn Marino static int
noce_try_addcc(struct noce_if_info * if_info)1211e4b17023SJohn Marino noce_try_addcc (struct noce_if_info *if_info)
1212e4b17023SJohn Marino {
1213e4b17023SJohn Marino rtx target, seq;
1214e4b17023SJohn Marino int subtract, normalize;
1215e4b17023SJohn Marino
1216e4b17023SJohn Marino if (GET_CODE (if_info->a) == PLUS
1217e4b17023SJohn Marino && rtx_equal_p (XEXP (if_info->a, 0), if_info->b)
1218e4b17023SJohn Marino && (reversed_comparison_code (if_info->cond, if_info->jump)
1219e4b17023SJohn Marino != UNKNOWN))
1220e4b17023SJohn Marino {
1221e4b17023SJohn Marino rtx cond = if_info->cond;
1222e4b17023SJohn Marino enum rtx_code code = reversed_comparison_code (cond, if_info->jump);
1223e4b17023SJohn Marino
1224e4b17023SJohn Marino /* First try to use addcc pattern. */
1225e4b17023SJohn Marino if (general_operand (XEXP (cond, 0), VOIDmode)
1226e4b17023SJohn Marino && general_operand (XEXP (cond, 1), VOIDmode))
1227e4b17023SJohn Marino {
1228e4b17023SJohn Marino start_sequence ();
1229e4b17023SJohn Marino target = emit_conditional_add (if_info->x, code,
1230e4b17023SJohn Marino XEXP (cond, 0),
1231e4b17023SJohn Marino XEXP (cond, 1),
1232e4b17023SJohn Marino VOIDmode,
1233e4b17023SJohn Marino if_info->b,
1234e4b17023SJohn Marino XEXP (if_info->a, 1),
1235e4b17023SJohn Marino GET_MODE (if_info->x),
1236e4b17023SJohn Marino (code == LTU || code == GEU
1237e4b17023SJohn Marino || code == LEU || code == GTU));
1238e4b17023SJohn Marino if (target)
1239e4b17023SJohn Marino {
1240e4b17023SJohn Marino if (target != if_info->x)
1241e4b17023SJohn Marino noce_emit_move_insn (if_info->x, target);
1242e4b17023SJohn Marino
1243e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
1244e4b17023SJohn Marino if (!seq)
1245e4b17023SJohn Marino return FALSE;
1246e4b17023SJohn Marino
1247e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump,
1248e4b17023SJohn Marino INSN_LOCATOR (if_info->insn_a));
1249e4b17023SJohn Marino return TRUE;
1250e4b17023SJohn Marino }
1251e4b17023SJohn Marino end_sequence ();
1252e4b17023SJohn Marino }
1253e4b17023SJohn Marino
1254e4b17023SJohn Marino /* If that fails, construct conditional increment or decrement using
1255e4b17023SJohn Marino setcc. */
1256e4b17023SJohn Marino if (if_info->branch_cost >= 2
1257e4b17023SJohn Marino && (XEXP (if_info->a, 1) == const1_rtx
1258e4b17023SJohn Marino || XEXP (if_info->a, 1) == constm1_rtx))
1259e4b17023SJohn Marino {
1260e4b17023SJohn Marino start_sequence ();
1261e4b17023SJohn Marino if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
1262e4b17023SJohn Marino subtract = 0, normalize = 0;
1263e4b17023SJohn Marino else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
1264e4b17023SJohn Marino subtract = 1, normalize = 0;
1265e4b17023SJohn Marino else
1266e4b17023SJohn Marino subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1));
1267e4b17023SJohn Marino
1268e4b17023SJohn Marino
1269e4b17023SJohn Marino target = noce_emit_store_flag (if_info,
1270e4b17023SJohn Marino gen_reg_rtx (GET_MODE (if_info->x)),
1271e4b17023SJohn Marino 1, normalize);
1272e4b17023SJohn Marino
1273e4b17023SJohn Marino if (target)
1274e4b17023SJohn Marino target = expand_simple_binop (GET_MODE (if_info->x),
1275e4b17023SJohn Marino subtract ? MINUS : PLUS,
1276e4b17023SJohn Marino if_info->b, target, if_info->x,
1277e4b17023SJohn Marino 0, OPTAB_WIDEN);
1278e4b17023SJohn Marino if (target)
1279e4b17023SJohn Marino {
1280e4b17023SJohn Marino if (target != if_info->x)
1281e4b17023SJohn Marino noce_emit_move_insn (if_info->x, target);
1282e4b17023SJohn Marino
1283e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
1284e4b17023SJohn Marino if (!seq)
1285e4b17023SJohn Marino return FALSE;
1286e4b17023SJohn Marino
1287e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump,
1288e4b17023SJohn Marino INSN_LOCATOR (if_info->insn_a));
1289e4b17023SJohn Marino return TRUE;
1290e4b17023SJohn Marino }
1291e4b17023SJohn Marino end_sequence ();
1292e4b17023SJohn Marino }
1293e4b17023SJohn Marino }
1294e4b17023SJohn Marino
1295e4b17023SJohn Marino return FALSE;
1296e4b17023SJohn Marino }
1297e4b17023SJohn Marino
1298e4b17023SJohn Marino /* Convert "if (test) x = 0;" to "x &= -(test == 0);" */
1299e4b17023SJohn Marino
1300e4b17023SJohn Marino static int
noce_try_store_flag_mask(struct noce_if_info * if_info)1301e4b17023SJohn Marino noce_try_store_flag_mask (struct noce_if_info *if_info)
1302e4b17023SJohn Marino {
1303e4b17023SJohn Marino rtx target, seq;
1304e4b17023SJohn Marino int reversep;
1305e4b17023SJohn Marino
1306e4b17023SJohn Marino reversep = 0;
1307e4b17023SJohn Marino if ((if_info->branch_cost >= 2
1308e4b17023SJohn Marino || STORE_FLAG_VALUE == -1)
1309e4b17023SJohn Marino && ((if_info->a == const0_rtx
1310e4b17023SJohn Marino && rtx_equal_p (if_info->b, if_info->x))
1311e4b17023SJohn Marino || ((reversep = (reversed_comparison_code (if_info->cond,
1312e4b17023SJohn Marino if_info->jump)
1313e4b17023SJohn Marino != UNKNOWN))
1314e4b17023SJohn Marino && if_info->b == const0_rtx
1315e4b17023SJohn Marino && rtx_equal_p (if_info->a, if_info->x))))
1316e4b17023SJohn Marino {
1317e4b17023SJohn Marino start_sequence ();
1318e4b17023SJohn Marino target = noce_emit_store_flag (if_info,
1319e4b17023SJohn Marino gen_reg_rtx (GET_MODE (if_info->x)),
1320e4b17023SJohn Marino reversep, -1);
1321e4b17023SJohn Marino if (target)
1322e4b17023SJohn Marino target = expand_simple_binop (GET_MODE (if_info->x), AND,
1323e4b17023SJohn Marino if_info->x,
1324e4b17023SJohn Marino target, if_info->x, 0,
1325e4b17023SJohn Marino OPTAB_WIDEN);
1326e4b17023SJohn Marino
1327e4b17023SJohn Marino if (target)
1328e4b17023SJohn Marino {
1329e4b17023SJohn Marino if (target != if_info->x)
1330e4b17023SJohn Marino noce_emit_move_insn (if_info->x, target);
1331e4b17023SJohn Marino
1332e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
1333e4b17023SJohn Marino if (!seq)
1334e4b17023SJohn Marino return FALSE;
1335e4b17023SJohn Marino
1336e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump,
1337e4b17023SJohn Marino INSN_LOCATOR (if_info->insn_a));
1338e4b17023SJohn Marino return TRUE;
1339e4b17023SJohn Marino }
1340e4b17023SJohn Marino
1341e4b17023SJohn Marino end_sequence ();
1342e4b17023SJohn Marino }
1343e4b17023SJohn Marino
1344e4b17023SJohn Marino return FALSE;
1345e4b17023SJohn Marino }
1346e4b17023SJohn Marino
1347e4b17023SJohn Marino /* Helper function for noce_try_cmove and noce_try_cmove_arith. */
1348e4b17023SJohn Marino
1349e4b17023SJohn Marino static rtx
noce_emit_cmove(struct noce_if_info * if_info,rtx x,enum rtx_code code,rtx cmp_a,rtx cmp_b,rtx vfalse,rtx vtrue)1350e4b17023SJohn Marino noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
1351e4b17023SJohn Marino rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue)
1352e4b17023SJohn Marino {
1353e4b17023SJohn Marino rtx target ATTRIBUTE_UNUSED;
1354e4b17023SJohn Marino int unsignedp ATTRIBUTE_UNUSED;
1355e4b17023SJohn Marino
1356e4b17023SJohn Marino /* If earliest == jump, try to build the cmove insn directly.
1357e4b17023SJohn Marino This is helpful when combine has created some complex condition
1358e4b17023SJohn Marino (like for alpha's cmovlbs) that we can't hope to regenerate
1359e4b17023SJohn Marino through the normal interface. */
1360e4b17023SJohn Marino
1361e4b17023SJohn Marino if (if_info->cond_earliest == if_info->jump)
1362e4b17023SJohn Marino {
1363e4b17023SJohn Marino rtx tmp;
1364e4b17023SJohn Marino
1365e4b17023SJohn Marino tmp = gen_rtx_fmt_ee (code, GET_MODE (if_info->cond), cmp_a, cmp_b);
1366e4b17023SJohn Marino tmp = gen_rtx_IF_THEN_ELSE (GET_MODE (x), tmp, vtrue, vfalse);
1367e4b17023SJohn Marino tmp = gen_rtx_SET (VOIDmode, x, tmp);
1368e4b17023SJohn Marino
1369e4b17023SJohn Marino start_sequence ();
1370e4b17023SJohn Marino tmp = emit_insn (tmp);
1371e4b17023SJohn Marino
1372e4b17023SJohn Marino if (recog_memoized (tmp) >= 0)
1373e4b17023SJohn Marino {
1374e4b17023SJohn Marino tmp = get_insns ();
1375e4b17023SJohn Marino end_sequence ();
1376e4b17023SJohn Marino emit_insn (tmp);
1377e4b17023SJohn Marino
1378e4b17023SJohn Marino return x;
1379e4b17023SJohn Marino }
1380e4b17023SJohn Marino
1381e4b17023SJohn Marino end_sequence ();
1382e4b17023SJohn Marino }
1383e4b17023SJohn Marino
1384e4b17023SJohn Marino /* Don't even try if the comparison operands are weird. */
1385e4b17023SJohn Marino if (! general_operand (cmp_a, GET_MODE (cmp_a))
1386e4b17023SJohn Marino || ! general_operand (cmp_b, GET_MODE (cmp_b)))
1387e4b17023SJohn Marino return NULL_RTX;
1388e4b17023SJohn Marino
1389e4b17023SJohn Marino #if HAVE_conditional_move
1390e4b17023SJohn Marino unsignedp = (code == LTU || code == GEU
1391e4b17023SJohn Marino || code == LEU || code == GTU);
1392e4b17023SJohn Marino
1393e4b17023SJohn Marino target = emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode,
1394e4b17023SJohn Marino vtrue, vfalse, GET_MODE (x),
1395e4b17023SJohn Marino unsignedp);
1396e4b17023SJohn Marino if (target)
1397e4b17023SJohn Marino return target;
1398e4b17023SJohn Marino
1399e4b17023SJohn Marino /* We might be faced with a situation like:
1400e4b17023SJohn Marino
1401e4b17023SJohn Marino x = (reg:M TARGET)
1402e4b17023SJohn Marino vtrue = (subreg:M (reg:N VTRUE) BYTE)
1403e4b17023SJohn Marino vfalse = (subreg:M (reg:N VFALSE) BYTE)
1404e4b17023SJohn Marino
1405e4b17023SJohn Marino We can't do a conditional move in mode M, but it's possible that we
1406e4b17023SJohn Marino could do a conditional move in mode N instead and take a subreg of
1407e4b17023SJohn Marino the result.
1408e4b17023SJohn Marino
1409e4b17023SJohn Marino If we can't create new pseudos, though, don't bother. */
1410e4b17023SJohn Marino if (reload_completed)
1411e4b17023SJohn Marino return NULL_RTX;
1412e4b17023SJohn Marino
1413e4b17023SJohn Marino if (GET_CODE (vtrue) == SUBREG && GET_CODE (vfalse) == SUBREG)
1414e4b17023SJohn Marino {
1415e4b17023SJohn Marino rtx reg_vtrue = SUBREG_REG (vtrue);
1416e4b17023SJohn Marino rtx reg_vfalse = SUBREG_REG (vfalse);
1417e4b17023SJohn Marino unsigned int byte_vtrue = SUBREG_BYTE (vtrue);
1418e4b17023SJohn Marino unsigned int byte_vfalse = SUBREG_BYTE (vfalse);
1419e4b17023SJohn Marino rtx promoted_target;
1420e4b17023SJohn Marino
1421e4b17023SJohn Marino if (GET_MODE (reg_vtrue) != GET_MODE (reg_vfalse)
1422e4b17023SJohn Marino || byte_vtrue != byte_vfalse
1423e4b17023SJohn Marino || (SUBREG_PROMOTED_VAR_P (vtrue)
1424e4b17023SJohn Marino != SUBREG_PROMOTED_VAR_P (vfalse))
1425e4b17023SJohn Marino || (SUBREG_PROMOTED_UNSIGNED_P (vtrue)
1426e4b17023SJohn Marino != SUBREG_PROMOTED_UNSIGNED_P (vfalse)))
1427e4b17023SJohn Marino return NULL_RTX;
1428e4b17023SJohn Marino
1429e4b17023SJohn Marino promoted_target = gen_reg_rtx (GET_MODE (reg_vtrue));
1430e4b17023SJohn Marino
1431e4b17023SJohn Marino target = emit_conditional_move (promoted_target, code, cmp_a, cmp_b,
1432e4b17023SJohn Marino VOIDmode, reg_vtrue, reg_vfalse,
1433e4b17023SJohn Marino GET_MODE (reg_vtrue), unsignedp);
1434e4b17023SJohn Marino /* Nope, couldn't do it in that mode either. */
1435e4b17023SJohn Marino if (!target)
1436e4b17023SJohn Marino return NULL_RTX;
1437e4b17023SJohn Marino
1438e4b17023SJohn Marino target = gen_rtx_SUBREG (GET_MODE (vtrue), promoted_target, byte_vtrue);
1439e4b17023SJohn Marino SUBREG_PROMOTED_VAR_P (target) = SUBREG_PROMOTED_VAR_P (vtrue);
1440e4b17023SJohn Marino SUBREG_PROMOTED_UNSIGNED_SET (target, SUBREG_PROMOTED_UNSIGNED_P (vtrue));
1441e4b17023SJohn Marino emit_move_insn (x, target);
1442e4b17023SJohn Marino return x;
1443e4b17023SJohn Marino }
1444e4b17023SJohn Marino else
1445e4b17023SJohn Marino return NULL_RTX;
1446e4b17023SJohn Marino #else
1447e4b17023SJohn Marino /* We'll never get here, as noce_process_if_block doesn't call the
1448e4b17023SJohn Marino functions involved. Ifdef code, however, should be discouraged
1449e4b17023SJohn Marino because it leads to typos in the code not selected. However,
1450e4b17023SJohn Marino emit_conditional_move won't exist either. */
1451e4b17023SJohn Marino return NULL_RTX;
1452e4b17023SJohn Marino #endif
1453e4b17023SJohn Marino }
1454e4b17023SJohn Marino
1455e4b17023SJohn Marino /* Try only simple constants and registers here. More complex cases
1456e4b17023SJohn Marino are handled in noce_try_cmove_arith after noce_try_store_flag_arith
1457e4b17023SJohn Marino has had a go at it. */
1458e4b17023SJohn Marino
1459e4b17023SJohn Marino static int
noce_try_cmove(struct noce_if_info * if_info)1460e4b17023SJohn Marino noce_try_cmove (struct noce_if_info *if_info)
1461e4b17023SJohn Marino {
1462e4b17023SJohn Marino enum rtx_code code;
1463e4b17023SJohn Marino rtx target, seq;
1464e4b17023SJohn Marino
1465e4b17023SJohn Marino if ((CONSTANT_P (if_info->a) || register_operand (if_info->a, VOIDmode))
1466e4b17023SJohn Marino && (CONSTANT_P (if_info->b) || register_operand (if_info->b, VOIDmode)))
1467e4b17023SJohn Marino {
1468e4b17023SJohn Marino start_sequence ();
1469e4b17023SJohn Marino
1470e4b17023SJohn Marino code = GET_CODE (if_info->cond);
1471e4b17023SJohn Marino target = noce_emit_cmove (if_info, if_info->x, code,
1472e4b17023SJohn Marino XEXP (if_info->cond, 0),
1473e4b17023SJohn Marino XEXP (if_info->cond, 1),
1474e4b17023SJohn Marino if_info->a, if_info->b);
1475e4b17023SJohn Marino
1476e4b17023SJohn Marino if (target)
1477e4b17023SJohn Marino {
1478e4b17023SJohn Marino if (target != if_info->x)
1479e4b17023SJohn Marino noce_emit_move_insn (if_info->x, target);
1480e4b17023SJohn Marino
1481e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
1482e4b17023SJohn Marino if (!seq)
1483e4b17023SJohn Marino return FALSE;
1484e4b17023SJohn Marino
1485e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump,
1486e4b17023SJohn Marino INSN_LOCATOR (if_info->insn_a));
1487e4b17023SJohn Marino return TRUE;
1488e4b17023SJohn Marino }
1489e4b17023SJohn Marino else
1490e4b17023SJohn Marino {
1491e4b17023SJohn Marino end_sequence ();
1492e4b17023SJohn Marino return FALSE;
1493e4b17023SJohn Marino }
1494e4b17023SJohn Marino }
1495e4b17023SJohn Marino
1496e4b17023SJohn Marino return FALSE;
1497e4b17023SJohn Marino }
1498e4b17023SJohn Marino
1499e4b17023SJohn Marino /* Try more complex cases involving conditional_move. */
1500e4b17023SJohn Marino
1501e4b17023SJohn Marino static int
noce_try_cmove_arith(struct noce_if_info * if_info)1502e4b17023SJohn Marino noce_try_cmove_arith (struct noce_if_info *if_info)
1503e4b17023SJohn Marino {
1504e4b17023SJohn Marino rtx a = if_info->a;
1505e4b17023SJohn Marino rtx b = if_info->b;
1506e4b17023SJohn Marino rtx x = if_info->x;
1507e4b17023SJohn Marino rtx orig_a, orig_b;
1508e4b17023SJohn Marino rtx insn_a, insn_b;
1509e4b17023SJohn Marino rtx tmp, target;
1510e4b17023SJohn Marino int is_mem = 0;
1511e4b17023SJohn Marino int insn_cost;
1512e4b17023SJohn Marino enum rtx_code code;
1513e4b17023SJohn Marino
1514e4b17023SJohn Marino /* A conditional move from two memory sources is equivalent to a
1515e4b17023SJohn Marino conditional on their addresses followed by a load. Don't do this
1516e4b17023SJohn Marino early because it'll screw alias analysis. Note that we've
1517e4b17023SJohn Marino already checked for no side effects. */
1518e4b17023SJohn Marino /* ??? FIXME: Magic number 5. */
1519e4b17023SJohn Marino if (cse_not_expected
1520e4b17023SJohn Marino && MEM_P (a) && MEM_P (b)
1521e4b17023SJohn Marino && MEM_ADDR_SPACE (a) == MEM_ADDR_SPACE (b)
1522e4b17023SJohn Marino && if_info->branch_cost >= 5)
1523e4b17023SJohn Marino {
1524e4b17023SJohn Marino enum machine_mode address_mode
1525e4b17023SJohn Marino = targetm.addr_space.address_mode (MEM_ADDR_SPACE (a));
1526e4b17023SJohn Marino
1527e4b17023SJohn Marino a = XEXP (a, 0);
1528e4b17023SJohn Marino b = XEXP (b, 0);
1529e4b17023SJohn Marino x = gen_reg_rtx (address_mode);
1530e4b17023SJohn Marino is_mem = 1;
1531e4b17023SJohn Marino }
1532e4b17023SJohn Marino
1533e4b17023SJohn Marino /* ??? We could handle this if we knew that a load from A or B could
1534e4b17023SJohn Marino not trap or fault. This is also true if we've already loaded
1535e4b17023SJohn Marino from the address along the path from ENTRY. */
1536e4b17023SJohn Marino else if (may_trap_or_fault_p (a) || may_trap_or_fault_p (b))
1537e4b17023SJohn Marino return FALSE;
1538e4b17023SJohn Marino
1539e4b17023SJohn Marino /* if (test) x = a + b; else x = c - d;
1540e4b17023SJohn Marino => y = a + b;
1541e4b17023SJohn Marino x = c - d;
1542e4b17023SJohn Marino if (test)
1543e4b17023SJohn Marino x = y;
1544e4b17023SJohn Marino */
1545e4b17023SJohn Marino
1546e4b17023SJohn Marino code = GET_CODE (if_info->cond);
1547e4b17023SJohn Marino insn_a = if_info->insn_a;
1548e4b17023SJohn Marino insn_b = if_info->insn_b;
1549e4b17023SJohn Marino
1550e4b17023SJohn Marino /* Total insn_rtx_cost should be smaller than branch cost. Exit
1551e4b17023SJohn Marino if insn_rtx_cost can't be estimated. */
1552e4b17023SJohn Marino if (insn_a)
1553e4b17023SJohn Marino {
1554e4b17023SJohn Marino insn_cost
1555e4b17023SJohn Marino = insn_rtx_cost (PATTERN (insn_a),
1556e4b17023SJohn Marino optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn_a)));
1557e4b17023SJohn Marino if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (if_info->branch_cost))
1558e4b17023SJohn Marino return FALSE;
1559e4b17023SJohn Marino }
1560e4b17023SJohn Marino else
1561e4b17023SJohn Marino insn_cost = 0;
1562e4b17023SJohn Marino
1563e4b17023SJohn Marino if (insn_b)
1564e4b17023SJohn Marino {
1565e4b17023SJohn Marino insn_cost
1566e4b17023SJohn Marino += insn_rtx_cost (PATTERN (insn_b),
1567e4b17023SJohn Marino optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn_b)));
1568e4b17023SJohn Marino if (insn_cost == 0 || insn_cost > COSTS_N_INSNS (if_info->branch_cost))
1569e4b17023SJohn Marino return FALSE;
1570e4b17023SJohn Marino }
1571e4b17023SJohn Marino
1572e4b17023SJohn Marino /* Possibly rearrange operands to make things come out more natural. */
1573e4b17023SJohn Marino if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)
1574e4b17023SJohn Marino {
1575e4b17023SJohn Marino int reversep = 0;
1576e4b17023SJohn Marino if (rtx_equal_p (b, x))
1577e4b17023SJohn Marino reversep = 1;
1578e4b17023SJohn Marino else if (general_operand (b, GET_MODE (b)))
1579e4b17023SJohn Marino reversep = 1;
1580e4b17023SJohn Marino
1581e4b17023SJohn Marino if (reversep)
1582e4b17023SJohn Marino {
1583e4b17023SJohn Marino code = reversed_comparison_code (if_info->cond, if_info->jump);
1584e4b17023SJohn Marino tmp = a, a = b, b = tmp;
1585e4b17023SJohn Marino tmp = insn_a, insn_a = insn_b, insn_b = tmp;
1586e4b17023SJohn Marino }
1587e4b17023SJohn Marino }
1588e4b17023SJohn Marino
1589e4b17023SJohn Marino start_sequence ();
1590e4b17023SJohn Marino
1591e4b17023SJohn Marino orig_a = a;
1592e4b17023SJohn Marino orig_b = b;
1593e4b17023SJohn Marino
1594e4b17023SJohn Marino /* If either operand is complex, load it into a register first.
1595e4b17023SJohn Marino The best way to do this is to copy the original insn. In this
1596e4b17023SJohn Marino way we preserve any clobbers etc that the insn may have had.
1597e4b17023SJohn Marino This is of course not possible in the IS_MEM case. */
1598e4b17023SJohn Marino if (! general_operand (a, GET_MODE (a)))
1599e4b17023SJohn Marino {
1600e4b17023SJohn Marino rtx set;
1601e4b17023SJohn Marino
1602e4b17023SJohn Marino if (is_mem)
1603e4b17023SJohn Marino {
1604e4b17023SJohn Marino tmp = gen_reg_rtx (GET_MODE (a));
1605e4b17023SJohn Marino tmp = emit_insn (gen_rtx_SET (VOIDmode, tmp, a));
1606e4b17023SJohn Marino }
1607e4b17023SJohn Marino else if (! insn_a)
1608e4b17023SJohn Marino goto end_seq_and_fail;
1609e4b17023SJohn Marino else
1610e4b17023SJohn Marino {
1611e4b17023SJohn Marino a = gen_reg_rtx (GET_MODE (a));
1612e4b17023SJohn Marino tmp = copy_rtx (insn_a);
1613e4b17023SJohn Marino set = single_set (tmp);
1614e4b17023SJohn Marino SET_DEST (set) = a;
1615e4b17023SJohn Marino tmp = emit_insn (PATTERN (tmp));
1616e4b17023SJohn Marino }
1617e4b17023SJohn Marino if (recog_memoized (tmp) < 0)
1618e4b17023SJohn Marino goto end_seq_and_fail;
1619e4b17023SJohn Marino }
1620e4b17023SJohn Marino if (! general_operand (b, GET_MODE (b)))
1621e4b17023SJohn Marino {
1622e4b17023SJohn Marino rtx set, last;
1623e4b17023SJohn Marino
1624e4b17023SJohn Marino if (is_mem)
1625e4b17023SJohn Marino {
1626e4b17023SJohn Marino tmp = gen_reg_rtx (GET_MODE (b));
1627e4b17023SJohn Marino tmp = gen_rtx_SET (VOIDmode, tmp, b);
1628e4b17023SJohn Marino }
1629e4b17023SJohn Marino else if (! insn_b)
1630e4b17023SJohn Marino goto end_seq_and_fail;
1631e4b17023SJohn Marino else
1632e4b17023SJohn Marino {
1633e4b17023SJohn Marino b = gen_reg_rtx (GET_MODE (b));
1634e4b17023SJohn Marino tmp = copy_rtx (insn_b);
1635e4b17023SJohn Marino set = single_set (tmp);
1636e4b17023SJohn Marino SET_DEST (set) = b;
1637e4b17023SJohn Marino tmp = PATTERN (tmp);
1638e4b17023SJohn Marino }
1639e4b17023SJohn Marino
1640e4b17023SJohn Marino /* If insn to set up A clobbers any registers B depends on, try to
1641e4b17023SJohn Marino swap insn that sets up A with the one that sets up B. If even
1642e4b17023SJohn Marino that doesn't help, punt. */
1643e4b17023SJohn Marino last = get_last_insn ();
1644e4b17023SJohn Marino if (last && modified_in_p (orig_b, last))
1645e4b17023SJohn Marino {
1646e4b17023SJohn Marino tmp = emit_insn_before (tmp, get_insns ());
1647e4b17023SJohn Marino if (modified_in_p (orig_a, tmp))
1648e4b17023SJohn Marino goto end_seq_and_fail;
1649e4b17023SJohn Marino }
1650e4b17023SJohn Marino else
1651e4b17023SJohn Marino tmp = emit_insn (tmp);
1652e4b17023SJohn Marino
1653e4b17023SJohn Marino if (recog_memoized (tmp) < 0)
1654e4b17023SJohn Marino goto end_seq_and_fail;
1655e4b17023SJohn Marino }
1656e4b17023SJohn Marino
1657e4b17023SJohn Marino target = noce_emit_cmove (if_info, x, code, XEXP (if_info->cond, 0),
1658e4b17023SJohn Marino XEXP (if_info->cond, 1), a, b);
1659e4b17023SJohn Marino
1660e4b17023SJohn Marino if (! target)
1661e4b17023SJohn Marino goto end_seq_and_fail;
1662e4b17023SJohn Marino
1663e4b17023SJohn Marino /* If we're handling a memory for above, emit the load now. */
1664e4b17023SJohn Marino if (is_mem)
1665e4b17023SJohn Marino {
1666e4b17023SJohn Marino tmp = gen_rtx_MEM (GET_MODE (if_info->x), target);
1667e4b17023SJohn Marino
1668e4b17023SJohn Marino /* Copy over flags as appropriate. */
1669e4b17023SJohn Marino if (MEM_VOLATILE_P (if_info->a) || MEM_VOLATILE_P (if_info->b))
1670e4b17023SJohn Marino MEM_VOLATILE_P (tmp) = 1;
1671e4b17023SJohn Marino if (MEM_ALIAS_SET (if_info->a) == MEM_ALIAS_SET (if_info->b))
1672e4b17023SJohn Marino set_mem_alias_set (tmp, MEM_ALIAS_SET (if_info->a));
1673e4b17023SJohn Marino set_mem_align (tmp,
1674e4b17023SJohn Marino MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b)));
1675e4b17023SJohn Marino
1676e4b17023SJohn Marino gcc_assert (MEM_ADDR_SPACE (if_info->a) == MEM_ADDR_SPACE (if_info->b));
1677e4b17023SJohn Marino set_mem_addr_space (tmp, MEM_ADDR_SPACE (if_info->a));
1678e4b17023SJohn Marino
1679e4b17023SJohn Marino noce_emit_move_insn (if_info->x, tmp);
1680e4b17023SJohn Marino }
1681e4b17023SJohn Marino else if (target != x)
1682e4b17023SJohn Marino noce_emit_move_insn (x, target);
1683e4b17023SJohn Marino
1684e4b17023SJohn Marino tmp = end_ifcvt_sequence (if_info);
1685e4b17023SJohn Marino if (!tmp)
1686e4b17023SJohn Marino return FALSE;
1687e4b17023SJohn Marino
1688e4b17023SJohn Marino emit_insn_before_setloc (tmp, if_info->jump, INSN_LOCATOR (if_info->insn_a));
1689e4b17023SJohn Marino return TRUE;
1690e4b17023SJohn Marino
1691e4b17023SJohn Marino end_seq_and_fail:
1692e4b17023SJohn Marino end_sequence ();
1693e4b17023SJohn Marino return FALSE;
1694e4b17023SJohn Marino }
1695e4b17023SJohn Marino
1696e4b17023SJohn Marino /* For most cases, the simplified condition we found is the best
1697e4b17023SJohn Marino choice, but this is not the case for the min/max/abs transforms.
1698e4b17023SJohn Marino For these we wish to know that it is A or B in the condition. */
1699e4b17023SJohn Marino
1700e4b17023SJohn Marino static rtx
noce_get_alt_condition(struct noce_if_info * if_info,rtx target,rtx * earliest)1701e4b17023SJohn Marino noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
1702e4b17023SJohn Marino rtx *earliest)
1703e4b17023SJohn Marino {
1704e4b17023SJohn Marino rtx cond, set, insn;
1705e4b17023SJohn Marino int reverse;
1706e4b17023SJohn Marino
1707e4b17023SJohn Marino /* If target is already mentioned in the known condition, return it. */
1708e4b17023SJohn Marino if (reg_mentioned_p (target, if_info->cond))
1709e4b17023SJohn Marino {
1710e4b17023SJohn Marino *earliest = if_info->cond_earliest;
1711e4b17023SJohn Marino return if_info->cond;
1712e4b17023SJohn Marino }
1713e4b17023SJohn Marino
1714e4b17023SJohn Marino set = pc_set (if_info->jump);
1715e4b17023SJohn Marino cond = XEXP (SET_SRC (set), 0);
1716e4b17023SJohn Marino reverse
1717e4b17023SJohn Marino = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
1718e4b17023SJohn Marino && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump);
1719e4b17023SJohn Marino if (if_info->then_else_reversed)
1720e4b17023SJohn Marino reverse = !reverse;
1721e4b17023SJohn Marino
1722e4b17023SJohn Marino /* If we're looking for a constant, try to make the conditional
1723e4b17023SJohn Marino have that constant in it. There are two reasons why it may
1724e4b17023SJohn Marino not have the constant we want:
1725e4b17023SJohn Marino
1726e4b17023SJohn Marino 1. GCC may have needed to put the constant in a register, because
1727e4b17023SJohn Marino the target can't compare directly against that constant. For
1728e4b17023SJohn Marino this case, we look for a SET immediately before the comparison
1729e4b17023SJohn Marino that puts a constant in that register.
1730e4b17023SJohn Marino
1731e4b17023SJohn Marino 2. GCC may have canonicalized the conditional, for example
1732e4b17023SJohn Marino replacing "if x < 4" with "if x <= 3". We can undo that (or
1733e4b17023SJohn Marino make equivalent types of changes) to get the constants we need
1734e4b17023SJohn Marino if they're off by one in the right direction. */
1735e4b17023SJohn Marino
1736e4b17023SJohn Marino if (CONST_INT_P (target))
1737e4b17023SJohn Marino {
1738e4b17023SJohn Marino enum rtx_code code = GET_CODE (if_info->cond);
1739e4b17023SJohn Marino rtx op_a = XEXP (if_info->cond, 0);
1740e4b17023SJohn Marino rtx op_b = XEXP (if_info->cond, 1);
1741e4b17023SJohn Marino rtx prev_insn;
1742e4b17023SJohn Marino
1743e4b17023SJohn Marino /* First, look to see if we put a constant in a register. */
1744e4b17023SJohn Marino prev_insn = prev_nonnote_insn (if_info->cond_earliest);
1745e4b17023SJohn Marino if (prev_insn
1746e4b17023SJohn Marino && BLOCK_FOR_INSN (prev_insn)
1747e4b17023SJohn Marino == BLOCK_FOR_INSN (if_info->cond_earliest)
1748e4b17023SJohn Marino && INSN_P (prev_insn)
1749e4b17023SJohn Marino && GET_CODE (PATTERN (prev_insn)) == SET)
1750e4b17023SJohn Marino {
1751e4b17023SJohn Marino rtx src = find_reg_equal_equiv_note (prev_insn);
1752e4b17023SJohn Marino if (!src)
1753e4b17023SJohn Marino src = SET_SRC (PATTERN (prev_insn));
1754e4b17023SJohn Marino if (CONST_INT_P (src))
1755e4b17023SJohn Marino {
1756e4b17023SJohn Marino if (rtx_equal_p (op_a, SET_DEST (PATTERN (prev_insn))))
1757e4b17023SJohn Marino op_a = src;
1758e4b17023SJohn Marino else if (rtx_equal_p (op_b, SET_DEST (PATTERN (prev_insn))))
1759e4b17023SJohn Marino op_b = src;
1760e4b17023SJohn Marino
1761e4b17023SJohn Marino if (CONST_INT_P (op_a))
1762e4b17023SJohn Marino {
1763e4b17023SJohn Marino rtx tmp = op_a;
1764e4b17023SJohn Marino op_a = op_b;
1765e4b17023SJohn Marino op_b = tmp;
1766e4b17023SJohn Marino code = swap_condition (code);
1767e4b17023SJohn Marino }
1768e4b17023SJohn Marino }
1769e4b17023SJohn Marino }
1770e4b17023SJohn Marino
1771e4b17023SJohn Marino /* Now, look to see if we can get the right constant by
1772e4b17023SJohn Marino adjusting the conditional. */
1773e4b17023SJohn Marino if (CONST_INT_P (op_b))
1774e4b17023SJohn Marino {
1775e4b17023SJohn Marino HOST_WIDE_INT desired_val = INTVAL (target);
1776e4b17023SJohn Marino HOST_WIDE_INT actual_val = INTVAL (op_b);
1777e4b17023SJohn Marino
1778e4b17023SJohn Marino switch (code)
1779e4b17023SJohn Marino {
1780e4b17023SJohn Marino case LT:
1781e4b17023SJohn Marino if (actual_val == desired_val + 1)
1782e4b17023SJohn Marino {
1783e4b17023SJohn Marino code = LE;
1784e4b17023SJohn Marino op_b = GEN_INT (desired_val);
1785e4b17023SJohn Marino }
1786e4b17023SJohn Marino break;
1787e4b17023SJohn Marino case LE:
1788e4b17023SJohn Marino if (actual_val == desired_val - 1)
1789e4b17023SJohn Marino {
1790e4b17023SJohn Marino code = LT;
1791e4b17023SJohn Marino op_b = GEN_INT (desired_val);
1792e4b17023SJohn Marino }
1793e4b17023SJohn Marino break;
1794e4b17023SJohn Marino case GT:
1795e4b17023SJohn Marino if (actual_val == desired_val - 1)
1796e4b17023SJohn Marino {
1797e4b17023SJohn Marino code = GE;
1798e4b17023SJohn Marino op_b = GEN_INT (desired_val);
1799e4b17023SJohn Marino }
1800e4b17023SJohn Marino break;
1801e4b17023SJohn Marino case GE:
1802e4b17023SJohn Marino if (actual_val == desired_val + 1)
1803e4b17023SJohn Marino {
1804e4b17023SJohn Marino code = GT;
1805e4b17023SJohn Marino op_b = GEN_INT (desired_val);
1806e4b17023SJohn Marino }
1807e4b17023SJohn Marino break;
1808e4b17023SJohn Marino default:
1809e4b17023SJohn Marino break;
1810e4b17023SJohn Marino }
1811e4b17023SJohn Marino }
1812e4b17023SJohn Marino
1813e4b17023SJohn Marino /* If we made any changes, generate a new conditional that is
1814e4b17023SJohn Marino equivalent to what we started with, but has the right
1815e4b17023SJohn Marino constants in it. */
1816e4b17023SJohn Marino if (code != GET_CODE (if_info->cond)
1817e4b17023SJohn Marino || op_a != XEXP (if_info->cond, 0)
1818e4b17023SJohn Marino || op_b != XEXP (if_info->cond, 1))
1819e4b17023SJohn Marino {
1820e4b17023SJohn Marino cond = gen_rtx_fmt_ee (code, GET_MODE (cond), op_a, op_b);
1821e4b17023SJohn Marino *earliest = if_info->cond_earliest;
1822e4b17023SJohn Marino return cond;
1823e4b17023SJohn Marino }
1824e4b17023SJohn Marino }
1825e4b17023SJohn Marino
1826e4b17023SJohn Marino cond = canonicalize_condition (if_info->jump, cond, reverse,
1827e4b17023SJohn Marino earliest, target, false, true);
1828e4b17023SJohn Marino if (! cond || ! reg_mentioned_p (target, cond))
1829e4b17023SJohn Marino return NULL;
1830e4b17023SJohn Marino
1831e4b17023SJohn Marino /* We almost certainly searched back to a different place.
1832e4b17023SJohn Marino Need to re-verify correct lifetimes. */
1833e4b17023SJohn Marino
1834e4b17023SJohn Marino /* X may not be mentioned in the range (cond_earliest, jump]. */
1835e4b17023SJohn Marino for (insn = if_info->jump; insn != *earliest; insn = PREV_INSN (insn))
1836e4b17023SJohn Marino if (INSN_P (insn) && reg_overlap_mentioned_p (if_info->x, PATTERN (insn)))
1837e4b17023SJohn Marino return NULL;
1838e4b17023SJohn Marino
1839e4b17023SJohn Marino /* A and B may not be modified in the range [cond_earliest, jump). */
1840e4b17023SJohn Marino for (insn = *earliest; insn != if_info->jump; insn = NEXT_INSN (insn))
1841e4b17023SJohn Marino if (INSN_P (insn)
1842e4b17023SJohn Marino && (modified_in_p (if_info->a, insn)
1843e4b17023SJohn Marino || modified_in_p (if_info->b, insn)))
1844e4b17023SJohn Marino return NULL;
1845e4b17023SJohn Marino
1846e4b17023SJohn Marino return cond;
1847e4b17023SJohn Marino }
1848e4b17023SJohn Marino
1849e4b17023SJohn Marino /* Convert "if (a < b) x = a; else x = b;" to "x = min(a, b);", etc. */
1850e4b17023SJohn Marino
1851e4b17023SJohn Marino static int
noce_try_minmax(struct noce_if_info * if_info)1852e4b17023SJohn Marino noce_try_minmax (struct noce_if_info *if_info)
1853e4b17023SJohn Marino {
1854e4b17023SJohn Marino rtx cond, earliest, target, seq;
1855e4b17023SJohn Marino enum rtx_code code, op;
1856e4b17023SJohn Marino int unsignedp;
1857e4b17023SJohn Marino
1858e4b17023SJohn Marino /* ??? Reject modes with NaNs or signed zeros since we don't know how
1859e4b17023SJohn Marino they will be resolved with an SMIN/SMAX. It wouldn't be too hard
1860e4b17023SJohn Marino to get the target to tell us... */
1861e4b17023SJohn Marino if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x))
1862e4b17023SJohn Marino || HONOR_NANS (GET_MODE (if_info->x)))
1863e4b17023SJohn Marino return FALSE;
1864e4b17023SJohn Marino
1865e4b17023SJohn Marino cond = noce_get_alt_condition (if_info, if_info->a, &earliest);
1866e4b17023SJohn Marino if (!cond)
1867e4b17023SJohn Marino return FALSE;
1868e4b17023SJohn Marino
1869e4b17023SJohn Marino /* Verify the condition is of the form we expect, and canonicalize
1870e4b17023SJohn Marino the comparison code. */
1871e4b17023SJohn Marino code = GET_CODE (cond);
1872e4b17023SJohn Marino if (rtx_equal_p (XEXP (cond, 0), if_info->a))
1873e4b17023SJohn Marino {
1874e4b17023SJohn Marino if (! rtx_equal_p (XEXP (cond, 1), if_info->b))
1875e4b17023SJohn Marino return FALSE;
1876e4b17023SJohn Marino }
1877e4b17023SJohn Marino else if (rtx_equal_p (XEXP (cond, 1), if_info->a))
1878e4b17023SJohn Marino {
1879e4b17023SJohn Marino if (! rtx_equal_p (XEXP (cond, 0), if_info->b))
1880e4b17023SJohn Marino return FALSE;
1881e4b17023SJohn Marino code = swap_condition (code);
1882e4b17023SJohn Marino }
1883e4b17023SJohn Marino else
1884e4b17023SJohn Marino return FALSE;
1885e4b17023SJohn Marino
1886e4b17023SJohn Marino /* Determine what sort of operation this is. Note that the code is for
1887e4b17023SJohn Marino a taken branch, so the code->operation mapping appears backwards. */
1888e4b17023SJohn Marino switch (code)
1889e4b17023SJohn Marino {
1890e4b17023SJohn Marino case LT:
1891e4b17023SJohn Marino case LE:
1892e4b17023SJohn Marino case UNLT:
1893e4b17023SJohn Marino case UNLE:
1894e4b17023SJohn Marino op = SMAX;
1895e4b17023SJohn Marino unsignedp = 0;
1896e4b17023SJohn Marino break;
1897e4b17023SJohn Marino case GT:
1898e4b17023SJohn Marino case GE:
1899e4b17023SJohn Marino case UNGT:
1900e4b17023SJohn Marino case UNGE:
1901e4b17023SJohn Marino op = SMIN;
1902e4b17023SJohn Marino unsignedp = 0;
1903e4b17023SJohn Marino break;
1904e4b17023SJohn Marino case LTU:
1905e4b17023SJohn Marino case LEU:
1906e4b17023SJohn Marino op = UMAX;
1907e4b17023SJohn Marino unsignedp = 1;
1908e4b17023SJohn Marino break;
1909e4b17023SJohn Marino case GTU:
1910e4b17023SJohn Marino case GEU:
1911e4b17023SJohn Marino op = UMIN;
1912e4b17023SJohn Marino unsignedp = 1;
1913e4b17023SJohn Marino break;
1914e4b17023SJohn Marino default:
1915e4b17023SJohn Marino return FALSE;
1916e4b17023SJohn Marino }
1917e4b17023SJohn Marino
1918e4b17023SJohn Marino start_sequence ();
1919e4b17023SJohn Marino
1920e4b17023SJohn Marino target = expand_simple_binop (GET_MODE (if_info->x), op,
1921e4b17023SJohn Marino if_info->a, if_info->b,
1922e4b17023SJohn Marino if_info->x, unsignedp, OPTAB_WIDEN);
1923e4b17023SJohn Marino if (! target)
1924e4b17023SJohn Marino {
1925e4b17023SJohn Marino end_sequence ();
1926e4b17023SJohn Marino return FALSE;
1927e4b17023SJohn Marino }
1928e4b17023SJohn Marino if (target != if_info->x)
1929e4b17023SJohn Marino noce_emit_move_insn (if_info->x, target);
1930e4b17023SJohn Marino
1931e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
1932e4b17023SJohn Marino if (!seq)
1933e4b17023SJohn Marino return FALSE;
1934e4b17023SJohn Marino
1935e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
1936e4b17023SJohn Marino if_info->cond = cond;
1937e4b17023SJohn Marino if_info->cond_earliest = earliest;
1938e4b17023SJohn Marino
1939e4b17023SJohn Marino return TRUE;
1940e4b17023SJohn Marino }
1941e4b17023SJohn Marino
1942e4b17023SJohn Marino /* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);",
1943e4b17023SJohn Marino "if (a < 0) x = ~a; else x = a;" to "x = one_cmpl_abs(a);",
1944e4b17023SJohn Marino etc. */
1945e4b17023SJohn Marino
1946e4b17023SJohn Marino static int
noce_try_abs(struct noce_if_info * if_info)1947e4b17023SJohn Marino noce_try_abs (struct noce_if_info *if_info)
1948e4b17023SJohn Marino {
1949e4b17023SJohn Marino rtx cond, earliest, target, seq, a, b, c;
1950e4b17023SJohn Marino int negate;
1951e4b17023SJohn Marino bool one_cmpl = false;
1952e4b17023SJohn Marino
1953e4b17023SJohn Marino /* Reject modes with signed zeros. */
1954e4b17023SJohn Marino if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x)))
1955e4b17023SJohn Marino return FALSE;
1956e4b17023SJohn Marino
1957e4b17023SJohn Marino /* Recognize A and B as constituting an ABS or NABS. The canonical
1958e4b17023SJohn Marino form is a branch around the negation, taken when the object is the
1959e4b17023SJohn Marino first operand of a comparison against 0 that evaluates to true. */
1960e4b17023SJohn Marino a = if_info->a;
1961e4b17023SJohn Marino b = if_info->b;
1962e4b17023SJohn Marino if (GET_CODE (a) == NEG && rtx_equal_p (XEXP (a, 0), b))
1963e4b17023SJohn Marino negate = 0;
1964e4b17023SJohn Marino else if (GET_CODE (b) == NEG && rtx_equal_p (XEXP (b, 0), a))
1965e4b17023SJohn Marino {
1966e4b17023SJohn Marino c = a; a = b; b = c;
1967e4b17023SJohn Marino negate = 1;
1968e4b17023SJohn Marino }
1969e4b17023SJohn Marino else if (GET_CODE (a) == NOT && rtx_equal_p (XEXP (a, 0), b))
1970e4b17023SJohn Marino {
1971e4b17023SJohn Marino negate = 0;
1972e4b17023SJohn Marino one_cmpl = true;
1973e4b17023SJohn Marino }
1974e4b17023SJohn Marino else if (GET_CODE (b) == NOT && rtx_equal_p (XEXP (b, 0), a))
1975e4b17023SJohn Marino {
1976e4b17023SJohn Marino c = a; a = b; b = c;
1977e4b17023SJohn Marino negate = 1;
1978e4b17023SJohn Marino one_cmpl = true;
1979e4b17023SJohn Marino }
1980e4b17023SJohn Marino else
1981e4b17023SJohn Marino return FALSE;
1982e4b17023SJohn Marino
1983e4b17023SJohn Marino cond = noce_get_alt_condition (if_info, b, &earliest);
1984e4b17023SJohn Marino if (!cond)
1985e4b17023SJohn Marino return FALSE;
1986e4b17023SJohn Marino
1987e4b17023SJohn Marino /* Verify the condition is of the form we expect. */
1988e4b17023SJohn Marino if (rtx_equal_p (XEXP (cond, 0), b))
1989e4b17023SJohn Marino c = XEXP (cond, 1);
1990e4b17023SJohn Marino else if (rtx_equal_p (XEXP (cond, 1), b))
1991e4b17023SJohn Marino {
1992e4b17023SJohn Marino c = XEXP (cond, 0);
1993e4b17023SJohn Marino negate = !negate;
1994e4b17023SJohn Marino }
1995e4b17023SJohn Marino else
1996e4b17023SJohn Marino return FALSE;
1997e4b17023SJohn Marino
1998e4b17023SJohn Marino /* Verify that C is zero. Search one step backward for a
1999e4b17023SJohn Marino REG_EQUAL note or a simple source if necessary. */
2000e4b17023SJohn Marino if (REG_P (c))
2001e4b17023SJohn Marino {
2002e4b17023SJohn Marino rtx set, insn = prev_nonnote_insn (earliest);
2003e4b17023SJohn Marino if (insn
2004e4b17023SJohn Marino && BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (earliest)
2005e4b17023SJohn Marino && (set = single_set (insn))
2006e4b17023SJohn Marino && rtx_equal_p (SET_DEST (set), c))
2007e4b17023SJohn Marino {
2008e4b17023SJohn Marino rtx note = find_reg_equal_equiv_note (insn);
2009e4b17023SJohn Marino if (note)
2010e4b17023SJohn Marino c = XEXP (note, 0);
2011e4b17023SJohn Marino else
2012e4b17023SJohn Marino c = SET_SRC (set);
2013e4b17023SJohn Marino }
2014e4b17023SJohn Marino else
2015e4b17023SJohn Marino return FALSE;
2016e4b17023SJohn Marino }
2017e4b17023SJohn Marino if (MEM_P (c)
2018e4b17023SJohn Marino && GET_CODE (XEXP (c, 0)) == SYMBOL_REF
2019e4b17023SJohn Marino && CONSTANT_POOL_ADDRESS_P (XEXP (c, 0)))
2020e4b17023SJohn Marino c = get_pool_constant (XEXP (c, 0));
2021e4b17023SJohn Marino
2022e4b17023SJohn Marino /* Work around funny ideas get_condition has wrt canonicalization.
2023e4b17023SJohn Marino Note that these rtx constants are known to be CONST_INT, and
2024e4b17023SJohn Marino therefore imply integer comparisons. */
2025e4b17023SJohn Marino if (c == constm1_rtx && GET_CODE (cond) == GT)
2026e4b17023SJohn Marino ;
2027e4b17023SJohn Marino else if (c == const1_rtx && GET_CODE (cond) == LT)
2028e4b17023SJohn Marino ;
2029e4b17023SJohn Marino else if (c != CONST0_RTX (GET_MODE (b)))
2030e4b17023SJohn Marino return FALSE;
2031e4b17023SJohn Marino
2032e4b17023SJohn Marino /* Determine what sort of operation this is. */
2033e4b17023SJohn Marino switch (GET_CODE (cond))
2034e4b17023SJohn Marino {
2035e4b17023SJohn Marino case LT:
2036e4b17023SJohn Marino case LE:
2037e4b17023SJohn Marino case UNLT:
2038e4b17023SJohn Marino case UNLE:
2039e4b17023SJohn Marino negate = !negate;
2040e4b17023SJohn Marino break;
2041e4b17023SJohn Marino case GT:
2042e4b17023SJohn Marino case GE:
2043e4b17023SJohn Marino case UNGT:
2044e4b17023SJohn Marino case UNGE:
2045e4b17023SJohn Marino break;
2046e4b17023SJohn Marino default:
2047e4b17023SJohn Marino return FALSE;
2048e4b17023SJohn Marino }
2049e4b17023SJohn Marino
2050e4b17023SJohn Marino start_sequence ();
2051e4b17023SJohn Marino if (one_cmpl)
2052e4b17023SJohn Marino target = expand_one_cmpl_abs_nojump (GET_MODE (if_info->x), b,
2053e4b17023SJohn Marino if_info->x);
2054e4b17023SJohn Marino else
2055e4b17023SJohn Marino target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 1);
2056e4b17023SJohn Marino
2057e4b17023SJohn Marino /* ??? It's a quandary whether cmove would be better here, especially
2058e4b17023SJohn Marino for integers. Perhaps combine will clean things up. */
2059e4b17023SJohn Marino if (target && negate)
2060e4b17023SJohn Marino {
2061e4b17023SJohn Marino if (one_cmpl)
2062e4b17023SJohn Marino target = expand_simple_unop (GET_MODE (target), NOT, target,
2063e4b17023SJohn Marino if_info->x, 0);
2064e4b17023SJohn Marino else
2065e4b17023SJohn Marino target = expand_simple_unop (GET_MODE (target), NEG, target,
2066e4b17023SJohn Marino if_info->x, 0);
2067e4b17023SJohn Marino }
2068e4b17023SJohn Marino
2069e4b17023SJohn Marino if (! target)
2070e4b17023SJohn Marino {
2071e4b17023SJohn Marino end_sequence ();
2072e4b17023SJohn Marino return FALSE;
2073e4b17023SJohn Marino }
2074e4b17023SJohn Marino
2075e4b17023SJohn Marino if (target != if_info->x)
2076e4b17023SJohn Marino noce_emit_move_insn (if_info->x, target);
2077e4b17023SJohn Marino
2078e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
2079e4b17023SJohn Marino if (!seq)
2080e4b17023SJohn Marino return FALSE;
2081e4b17023SJohn Marino
2082e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
2083e4b17023SJohn Marino if_info->cond = cond;
2084e4b17023SJohn Marino if_info->cond_earliest = earliest;
2085e4b17023SJohn Marino
2086e4b17023SJohn Marino return TRUE;
2087e4b17023SJohn Marino }
2088e4b17023SJohn Marino
2089e4b17023SJohn Marino /* Convert "if (m < 0) x = b; else x = 0;" to "x = (m >> C) & b;". */
2090e4b17023SJohn Marino
2091e4b17023SJohn Marino static int
noce_try_sign_mask(struct noce_if_info * if_info)2092e4b17023SJohn Marino noce_try_sign_mask (struct noce_if_info *if_info)
2093e4b17023SJohn Marino {
2094e4b17023SJohn Marino rtx cond, t, m, c, seq;
2095e4b17023SJohn Marino enum machine_mode mode;
2096e4b17023SJohn Marino enum rtx_code code;
2097e4b17023SJohn Marino bool t_unconditional;
2098e4b17023SJohn Marino
2099e4b17023SJohn Marino cond = if_info->cond;
2100e4b17023SJohn Marino code = GET_CODE (cond);
2101e4b17023SJohn Marino m = XEXP (cond, 0);
2102e4b17023SJohn Marino c = XEXP (cond, 1);
2103e4b17023SJohn Marino
2104e4b17023SJohn Marino t = NULL_RTX;
2105e4b17023SJohn Marino if (if_info->a == const0_rtx)
2106e4b17023SJohn Marino {
2107e4b17023SJohn Marino if ((code == LT && c == const0_rtx)
2108e4b17023SJohn Marino || (code == LE && c == constm1_rtx))
2109e4b17023SJohn Marino t = if_info->b;
2110e4b17023SJohn Marino }
2111e4b17023SJohn Marino else if (if_info->b == const0_rtx)
2112e4b17023SJohn Marino {
2113e4b17023SJohn Marino if ((code == GE && c == const0_rtx)
2114e4b17023SJohn Marino || (code == GT && c == constm1_rtx))
2115e4b17023SJohn Marino t = if_info->a;
2116e4b17023SJohn Marino }
2117e4b17023SJohn Marino
2118e4b17023SJohn Marino if (! t || side_effects_p (t))
2119e4b17023SJohn Marino return FALSE;
2120e4b17023SJohn Marino
2121e4b17023SJohn Marino /* We currently don't handle different modes. */
2122e4b17023SJohn Marino mode = GET_MODE (t);
2123e4b17023SJohn Marino if (GET_MODE (m) != mode)
2124e4b17023SJohn Marino return FALSE;
2125e4b17023SJohn Marino
2126e4b17023SJohn Marino /* This is only profitable if T is unconditionally executed/evaluated in the
2127e4b17023SJohn Marino original insn sequence or T is cheap. The former happens if B is the
2128e4b17023SJohn Marino non-zero (T) value and if INSN_B was taken from TEST_BB, or there was no
2129e4b17023SJohn Marino INSN_B which can happen for e.g. conditional stores to memory. For the
2130e4b17023SJohn Marino cost computation use the block TEST_BB where the evaluation will end up
2131e4b17023SJohn Marino after the transformation. */
2132e4b17023SJohn Marino t_unconditional =
2133e4b17023SJohn Marino (t == if_info->b
2134e4b17023SJohn Marino && (if_info->insn_b == NULL_RTX
2135e4b17023SJohn Marino || BLOCK_FOR_INSN (if_info->insn_b) == if_info->test_bb));
2136e4b17023SJohn Marino if (!(t_unconditional
2137e4b17023SJohn Marino || (set_src_cost (t, optimize_bb_for_speed_p (if_info->test_bb))
2138e4b17023SJohn Marino < COSTS_N_INSNS (2))))
2139e4b17023SJohn Marino return FALSE;
2140e4b17023SJohn Marino
2141e4b17023SJohn Marino start_sequence ();
2142e4b17023SJohn Marino /* Use emit_store_flag to generate "m < 0 ? -1 : 0" instead of expanding
2143e4b17023SJohn Marino "(signed) m >> 31" directly. This benefits targets with specialized
2144e4b17023SJohn Marino insns to obtain the signmask, but still uses ashr_optab otherwise. */
2145e4b17023SJohn Marino m = emit_store_flag (gen_reg_rtx (mode), LT, m, const0_rtx, mode, 0, -1);
2146e4b17023SJohn Marino t = m ? expand_binop (mode, and_optab, m, t, NULL_RTX, 0, OPTAB_DIRECT)
2147e4b17023SJohn Marino : NULL_RTX;
2148e4b17023SJohn Marino
2149e4b17023SJohn Marino if (!t)
2150e4b17023SJohn Marino {
2151e4b17023SJohn Marino end_sequence ();
2152e4b17023SJohn Marino return FALSE;
2153e4b17023SJohn Marino }
2154e4b17023SJohn Marino
2155e4b17023SJohn Marino noce_emit_move_insn (if_info->x, t);
2156e4b17023SJohn Marino
2157e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
2158e4b17023SJohn Marino if (!seq)
2159e4b17023SJohn Marino return FALSE;
2160e4b17023SJohn Marino
2161e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
2162e4b17023SJohn Marino return TRUE;
2163e4b17023SJohn Marino }
2164e4b17023SJohn Marino
2165e4b17023SJohn Marino
2166e4b17023SJohn Marino /* Optimize away "if (x & C) x |= C" and similar bit manipulation
2167e4b17023SJohn Marino transformations. */
2168e4b17023SJohn Marino
2169e4b17023SJohn Marino static int
noce_try_bitop(struct noce_if_info * if_info)2170e4b17023SJohn Marino noce_try_bitop (struct noce_if_info *if_info)
2171e4b17023SJohn Marino {
2172e4b17023SJohn Marino rtx cond, x, a, result, seq;
2173e4b17023SJohn Marino enum machine_mode mode;
2174e4b17023SJohn Marino enum rtx_code code;
2175e4b17023SJohn Marino int bitnum;
2176e4b17023SJohn Marino
2177e4b17023SJohn Marino x = if_info->x;
2178e4b17023SJohn Marino cond = if_info->cond;
2179e4b17023SJohn Marino code = GET_CODE (cond);
2180e4b17023SJohn Marino
2181e4b17023SJohn Marino /* Check for no else condition. */
2182e4b17023SJohn Marino if (! rtx_equal_p (x, if_info->b))
2183e4b17023SJohn Marino return FALSE;
2184e4b17023SJohn Marino
2185e4b17023SJohn Marino /* Check for a suitable condition. */
2186e4b17023SJohn Marino if (code != NE && code != EQ)
2187e4b17023SJohn Marino return FALSE;
2188e4b17023SJohn Marino if (XEXP (cond, 1) != const0_rtx)
2189e4b17023SJohn Marino return FALSE;
2190e4b17023SJohn Marino cond = XEXP (cond, 0);
2191e4b17023SJohn Marino
2192e4b17023SJohn Marino /* ??? We could also handle AND here. */
2193e4b17023SJohn Marino if (GET_CODE (cond) == ZERO_EXTRACT)
2194e4b17023SJohn Marino {
2195e4b17023SJohn Marino if (XEXP (cond, 1) != const1_rtx
2196e4b17023SJohn Marino || !CONST_INT_P (XEXP (cond, 2))
2197e4b17023SJohn Marino || ! rtx_equal_p (x, XEXP (cond, 0)))
2198e4b17023SJohn Marino return FALSE;
2199e4b17023SJohn Marino bitnum = INTVAL (XEXP (cond, 2));
2200e4b17023SJohn Marino mode = GET_MODE (x);
2201e4b17023SJohn Marino if (BITS_BIG_ENDIAN)
2202e4b17023SJohn Marino bitnum = GET_MODE_BITSIZE (mode) - 1 - bitnum;
2203e4b17023SJohn Marino if (bitnum < 0 || bitnum >= HOST_BITS_PER_WIDE_INT)
2204e4b17023SJohn Marino return FALSE;
2205e4b17023SJohn Marino }
2206e4b17023SJohn Marino else
2207e4b17023SJohn Marino return FALSE;
2208e4b17023SJohn Marino
2209e4b17023SJohn Marino a = if_info->a;
2210e4b17023SJohn Marino if (GET_CODE (a) == IOR || GET_CODE (a) == XOR)
2211e4b17023SJohn Marino {
2212e4b17023SJohn Marino /* Check for "if (X & C) x = x op C". */
2213e4b17023SJohn Marino if (! rtx_equal_p (x, XEXP (a, 0))
2214e4b17023SJohn Marino || !CONST_INT_P (XEXP (a, 1))
2215e4b17023SJohn Marino || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
2216e4b17023SJohn Marino != (unsigned HOST_WIDE_INT) 1 << bitnum)
2217e4b17023SJohn Marino return FALSE;
2218e4b17023SJohn Marino
2219e4b17023SJohn Marino /* if ((x & C) == 0) x |= C; is transformed to x |= C. */
2220e4b17023SJohn Marino /* if ((x & C) != 0) x |= C; is transformed to nothing. */
2221e4b17023SJohn Marino if (GET_CODE (a) == IOR)
2222e4b17023SJohn Marino result = (code == NE) ? a : NULL_RTX;
2223e4b17023SJohn Marino else if (code == NE)
2224e4b17023SJohn Marino {
2225e4b17023SJohn Marino /* if ((x & C) == 0) x ^= C; is transformed to x |= C. */
2226e4b17023SJohn Marino result = gen_int_mode ((HOST_WIDE_INT) 1 << bitnum, mode);
2227e4b17023SJohn Marino result = simplify_gen_binary (IOR, mode, x, result);
2228e4b17023SJohn Marino }
2229e4b17023SJohn Marino else
2230e4b17023SJohn Marino {
2231e4b17023SJohn Marino /* if ((x & C) != 0) x ^= C; is transformed to x &= ~C. */
2232e4b17023SJohn Marino result = gen_int_mode (~((HOST_WIDE_INT) 1 << bitnum), mode);
2233e4b17023SJohn Marino result = simplify_gen_binary (AND, mode, x, result);
2234e4b17023SJohn Marino }
2235e4b17023SJohn Marino }
2236e4b17023SJohn Marino else if (GET_CODE (a) == AND)
2237e4b17023SJohn Marino {
2238e4b17023SJohn Marino /* Check for "if (X & C) x &= ~C". */
2239e4b17023SJohn Marino if (! rtx_equal_p (x, XEXP (a, 0))
2240e4b17023SJohn Marino || !CONST_INT_P (XEXP (a, 1))
2241e4b17023SJohn Marino || (INTVAL (XEXP (a, 1)) & GET_MODE_MASK (mode))
2242e4b17023SJohn Marino != (~((HOST_WIDE_INT) 1 << bitnum) & GET_MODE_MASK (mode)))
2243e4b17023SJohn Marino return FALSE;
2244e4b17023SJohn Marino
2245e4b17023SJohn Marino /* if ((x & C) == 0) x &= ~C; is transformed to nothing. */
2246e4b17023SJohn Marino /* if ((x & C) != 0) x &= ~C; is transformed to x &= ~C. */
2247e4b17023SJohn Marino result = (code == EQ) ? a : NULL_RTX;
2248e4b17023SJohn Marino }
2249e4b17023SJohn Marino else
2250e4b17023SJohn Marino return FALSE;
2251e4b17023SJohn Marino
2252e4b17023SJohn Marino if (result)
2253e4b17023SJohn Marino {
2254e4b17023SJohn Marino start_sequence ();
2255e4b17023SJohn Marino noce_emit_move_insn (x, result);
2256e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
2257e4b17023SJohn Marino if (!seq)
2258e4b17023SJohn Marino return FALSE;
2259e4b17023SJohn Marino
2260e4b17023SJohn Marino emit_insn_before_setloc (seq, if_info->jump,
2261e4b17023SJohn Marino INSN_LOCATOR (if_info->insn_a));
2262e4b17023SJohn Marino }
2263e4b17023SJohn Marino return TRUE;
2264e4b17023SJohn Marino }
2265e4b17023SJohn Marino
2266e4b17023SJohn Marino
2267e4b17023SJohn Marino /* Similar to get_condition, only the resulting condition must be
2268e4b17023SJohn Marino valid at JUMP, instead of at EARLIEST.
2269e4b17023SJohn Marino
2270e4b17023SJohn Marino If THEN_ELSE_REVERSED is true, the fallthrough does not go to the
2271e4b17023SJohn Marino THEN block of the caller, and we have to reverse the condition. */
2272e4b17023SJohn Marino
2273e4b17023SJohn Marino static rtx
noce_get_condition(rtx jump,rtx * earliest,bool then_else_reversed)2274e4b17023SJohn Marino noce_get_condition (rtx jump, rtx *earliest, bool then_else_reversed)
2275e4b17023SJohn Marino {
2276e4b17023SJohn Marino rtx cond, set, tmp;
2277e4b17023SJohn Marino bool reverse;
2278e4b17023SJohn Marino
2279e4b17023SJohn Marino if (! any_condjump_p (jump))
2280e4b17023SJohn Marino return NULL_RTX;
2281e4b17023SJohn Marino
2282e4b17023SJohn Marino set = pc_set (jump);
2283e4b17023SJohn Marino
2284e4b17023SJohn Marino /* If this branches to JUMP_LABEL when the condition is false,
2285e4b17023SJohn Marino reverse the condition. */
2286e4b17023SJohn Marino reverse = (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
2287e4b17023SJohn Marino && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump));
2288e4b17023SJohn Marino
2289e4b17023SJohn Marino /* We may have to reverse because the caller's if block is not canonical,
2290e4b17023SJohn Marino i.e. the THEN block isn't the fallthrough block for the TEST block
2291e4b17023SJohn Marino (see find_if_header). */
2292e4b17023SJohn Marino if (then_else_reversed)
2293e4b17023SJohn Marino reverse = !reverse;
2294e4b17023SJohn Marino
2295e4b17023SJohn Marino /* If the condition variable is a register and is MODE_INT, accept it. */
2296e4b17023SJohn Marino
2297e4b17023SJohn Marino cond = XEXP (SET_SRC (set), 0);
2298e4b17023SJohn Marino tmp = XEXP (cond, 0);
2299e4b17023SJohn Marino if (REG_P (tmp) && GET_MODE_CLASS (GET_MODE (tmp)) == MODE_INT
2300e4b17023SJohn Marino && (GET_MODE (tmp) != BImode
2301e4b17023SJohn Marino || !targetm.small_register_classes_for_mode_p (BImode)))
2302e4b17023SJohn Marino {
2303e4b17023SJohn Marino *earliest = jump;
2304e4b17023SJohn Marino
2305e4b17023SJohn Marino if (reverse)
2306e4b17023SJohn Marino cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
2307e4b17023SJohn Marino GET_MODE (cond), tmp, XEXP (cond, 1));
2308e4b17023SJohn Marino return cond;
2309e4b17023SJohn Marino }
2310e4b17023SJohn Marino
2311e4b17023SJohn Marino /* Otherwise, fall back on canonicalize_condition to do the dirty
2312e4b17023SJohn Marino work of manipulating MODE_CC values and COMPARE rtx codes. */
2313e4b17023SJohn Marino tmp = canonicalize_condition (jump, cond, reverse, earliest,
2314e4b17023SJohn Marino NULL_RTX, false, true);
2315e4b17023SJohn Marino
2316e4b17023SJohn Marino /* We don't handle side-effects in the condition, like handling
2317e4b17023SJohn Marino REG_INC notes and making sure no duplicate conditions are emitted. */
2318e4b17023SJohn Marino if (tmp != NULL_RTX && side_effects_p (tmp))
2319e4b17023SJohn Marino return NULL_RTX;
2320e4b17023SJohn Marino
2321e4b17023SJohn Marino return tmp;
2322e4b17023SJohn Marino }
2323e4b17023SJohn Marino
2324e4b17023SJohn Marino /* Return true if OP is ok for if-then-else processing. */
2325e4b17023SJohn Marino
2326e4b17023SJohn Marino static int
noce_operand_ok(const_rtx op)2327e4b17023SJohn Marino noce_operand_ok (const_rtx op)
2328e4b17023SJohn Marino {
2329e4b17023SJohn Marino if (side_effects_p (op))
2330e4b17023SJohn Marino return FALSE;
2331e4b17023SJohn Marino
2332e4b17023SJohn Marino /* We special-case memories, so handle any of them with
2333e4b17023SJohn Marino no address side effects. */
2334e4b17023SJohn Marino if (MEM_P (op))
2335e4b17023SJohn Marino return ! side_effects_p (XEXP (op, 0));
2336e4b17023SJohn Marino
2337e4b17023SJohn Marino return ! may_trap_p (op);
2338e4b17023SJohn Marino }
2339e4b17023SJohn Marino
2340e4b17023SJohn Marino /* Return true if a write into MEM may trap or fault. */
2341e4b17023SJohn Marino
2342e4b17023SJohn Marino static bool
noce_mem_write_may_trap_or_fault_p(const_rtx mem)2343e4b17023SJohn Marino noce_mem_write_may_trap_or_fault_p (const_rtx mem)
2344e4b17023SJohn Marino {
2345e4b17023SJohn Marino rtx addr;
2346e4b17023SJohn Marino
2347e4b17023SJohn Marino if (MEM_READONLY_P (mem))
2348e4b17023SJohn Marino return true;
2349e4b17023SJohn Marino
2350e4b17023SJohn Marino if (may_trap_or_fault_p (mem))
2351e4b17023SJohn Marino return true;
2352e4b17023SJohn Marino
2353e4b17023SJohn Marino addr = XEXP (mem, 0);
2354e4b17023SJohn Marino
2355e4b17023SJohn Marino /* Call target hook to avoid the effects of -fpic etc.... */
2356e4b17023SJohn Marino addr = targetm.delegitimize_address (addr);
2357e4b17023SJohn Marino
2358e4b17023SJohn Marino while (addr)
2359e4b17023SJohn Marino switch (GET_CODE (addr))
2360e4b17023SJohn Marino {
2361e4b17023SJohn Marino case CONST:
2362e4b17023SJohn Marino case PRE_DEC:
2363e4b17023SJohn Marino case PRE_INC:
2364e4b17023SJohn Marino case POST_DEC:
2365e4b17023SJohn Marino case POST_INC:
2366e4b17023SJohn Marino case POST_MODIFY:
2367e4b17023SJohn Marino addr = XEXP (addr, 0);
2368e4b17023SJohn Marino break;
2369e4b17023SJohn Marino case LO_SUM:
2370e4b17023SJohn Marino case PRE_MODIFY:
2371e4b17023SJohn Marino addr = XEXP (addr, 1);
2372e4b17023SJohn Marino break;
2373e4b17023SJohn Marino case PLUS:
2374e4b17023SJohn Marino if (CONST_INT_P (XEXP (addr, 1)))
2375e4b17023SJohn Marino addr = XEXP (addr, 0);
2376e4b17023SJohn Marino else
2377e4b17023SJohn Marino return false;
2378e4b17023SJohn Marino break;
2379e4b17023SJohn Marino case LABEL_REF:
2380e4b17023SJohn Marino return true;
2381e4b17023SJohn Marino case SYMBOL_REF:
2382e4b17023SJohn Marino if (SYMBOL_REF_DECL (addr)
2383e4b17023SJohn Marino && decl_readonly_section (SYMBOL_REF_DECL (addr), 0))
2384e4b17023SJohn Marino return true;
2385e4b17023SJohn Marino return false;
2386e4b17023SJohn Marino default:
2387e4b17023SJohn Marino return false;
2388e4b17023SJohn Marino }
2389e4b17023SJohn Marino
2390e4b17023SJohn Marino return false;
2391e4b17023SJohn Marino }
2392e4b17023SJohn Marino
2393e4b17023SJohn Marino /* Return whether we can use store speculation for MEM. TOP_BB is the
2394e4b17023SJohn Marino basic block above the conditional block where we are considering
2395e4b17023SJohn Marino doing the speculative store. We look for whether MEM is set
2396e4b17023SJohn Marino unconditionally later in the function. */
2397e4b17023SJohn Marino
2398e4b17023SJohn Marino static bool
noce_can_store_speculate_p(basic_block top_bb,const_rtx mem)2399e4b17023SJohn Marino noce_can_store_speculate_p (basic_block top_bb, const_rtx mem)
2400e4b17023SJohn Marino {
2401e4b17023SJohn Marino basic_block dominator;
2402e4b17023SJohn Marino
2403e4b17023SJohn Marino for (dominator = get_immediate_dominator (CDI_POST_DOMINATORS, top_bb);
2404e4b17023SJohn Marino dominator != NULL;
2405e4b17023SJohn Marino dominator = get_immediate_dominator (CDI_POST_DOMINATORS, dominator))
2406e4b17023SJohn Marino {
2407e4b17023SJohn Marino rtx insn;
2408e4b17023SJohn Marino
2409e4b17023SJohn Marino FOR_BB_INSNS (dominator, insn)
2410e4b17023SJohn Marino {
2411e4b17023SJohn Marino /* If we see something that might be a memory barrier, we
2412e4b17023SJohn Marino have to stop looking. Even if the MEM is set later in
2413e4b17023SJohn Marino the function, we still don't want to set it
2414e4b17023SJohn Marino unconditionally before the barrier. */
2415e4b17023SJohn Marino if (INSN_P (insn)
2416e4b17023SJohn Marino && (volatile_insn_p (PATTERN (insn))
2417e4b17023SJohn Marino || (CALL_P (insn) && (!RTL_CONST_CALL_P (insn)))))
2418e4b17023SJohn Marino return false;
2419e4b17023SJohn Marino
2420e4b17023SJohn Marino if (memory_modified_in_insn_p (mem, insn))
2421e4b17023SJohn Marino return true;
2422e4b17023SJohn Marino if (modified_in_p (XEXP (mem, 0), insn))
2423e4b17023SJohn Marino return false;
2424e4b17023SJohn Marino
2425e4b17023SJohn Marino }
2426e4b17023SJohn Marino }
2427e4b17023SJohn Marino
2428e4b17023SJohn Marino return false;
2429e4b17023SJohn Marino }
2430e4b17023SJohn Marino
2431e4b17023SJohn Marino /* Given a simple IF-THEN-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert
2432e4b17023SJohn Marino it without using conditional execution. Return TRUE if we were successful
2433e4b17023SJohn Marino at converting the block. */
2434e4b17023SJohn Marino
2435e4b17023SJohn Marino static int
noce_process_if_block(struct noce_if_info * if_info)2436e4b17023SJohn Marino noce_process_if_block (struct noce_if_info *if_info)
2437e4b17023SJohn Marino {
2438e4b17023SJohn Marino basic_block test_bb = if_info->test_bb; /* test block */
2439e4b17023SJohn Marino basic_block then_bb = if_info->then_bb; /* THEN */
2440e4b17023SJohn Marino basic_block else_bb = if_info->else_bb; /* ELSE or NULL */
2441e4b17023SJohn Marino basic_block join_bb = if_info->join_bb; /* JOIN */
2442e4b17023SJohn Marino rtx jump = if_info->jump;
2443e4b17023SJohn Marino rtx cond = if_info->cond;
2444e4b17023SJohn Marino rtx insn_a, insn_b;
2445e4b17023SJohn Marino rtx set_a, set_b;
2446e4b17023SJohn Marino rtx orig_x, x, a, b;
2447e4b17023SJohn Marino
2448e4b17023SJohn Marino /* We're looking for patterns of the form
2449e4b17023SJohn Marino
2450e4b17023SJohn Marino (1) if (...) x = a; else x = b;
2451e4b17023SJohn Marino (2) x = b; if (...) x = a;
2452e4b17023SJohn Marino (3) if (...) x = a; // as if with an initial x = x.
2453e4b17023SJohn Marino
2454e4b17023SJohn Marino The later patterns require jumps to be more expensive.
2455e4b17023SJohn Marino
2456e4b17023SJohn Marino ??? For future expansion, look for multiple X in such patterns. */
2457e4b17023SJohn Marino
2458e4b17023SJohn Marino /* Look for one of the potential sets. */
2459e4b17023SJohn Marino insn_a = first_active_insn (then_bb);
2460e4b17023SJohn Marino if (! insn_a
2461e4b17023SJohn Marino || insn_a != last_active_insn (then_bb, FALSE)
2462e4b17023SJohn Marino || (set_a = single_set (insn_a)) == NULL_RTX)
2463e4b17023SJohn Marino return FALSE;
2464e4b17023SJohn Marino
2465e4b17023SJohn Marino x = SET_DEST (set_a);
2466e4b17023SJohn Marino a = SET_SRC (set_a);
2467e4b17023SJohn Marino
2468e4b17023SJohn Marino /* Look for the other potential set. Make sure we've got equivalent
2469e4b17023SJohn Marino destinations. */
2470e4b17023SJohn Marino /* ??? This is overconservative. Storing to two different mems is
2471e4b17023SJohn Marino as easy as conditionally computing the address. Storing to a
2472e4b17023SJohn Marino single mem merely requires a scratch memory to use as one of the
2473e4b17023SJohn Marino destination addresses; often the memory immediately below the
2474e4b17023SJohn Marino stack pointer is available for this. */
2475e4b17023SJohn Marino set_b = NULL_RTX;
2476e4b17023SJohn Marino if (else_bb)
2477e4b17023SJohn Marino {
2478e4b17023SJohn Marino insn_b = first_active_insn (else_bb);
2479e4b17023SJohn Marino if (! insn_b
2480e4b17023SJohn Marino || insn_b != last_active_insn (else_bb, FALSE)
2481e4b17023SJohn Marino || (set_b = single_set (insn_b)) == NULL_RTX
2482e4b17023SJohn Marino || ! rtx_equal_p (x, SET_DEST (set_b)))
2483e4b17023SJohn Marino return FALSE;
2484e4b17023SJohn Marino }
2485e4b17023SJohn Marino else
2486e4b17023SJohn Marino {
2487e4b17023SJohn Marino insn_b = prev_nonnote_nondebug_insn (if_info->cond_earliest);
2488e4b17023SJohn Marino /* We're going to be moving the evaluation of B down from above
2489e4b17023SJohn Marino COND_EARLIEST to JUMP. Make sure the relevant data is still
2490e4b17023SJohn Marino intact. */
2491e4b17023SJohn Marino if (! insn_b
2492e4b17023SJohn Marino || BLOCK_FOR_INSN (insn_b) != BLOCK_FOR_INSN (if_info->cond_earliest)
2493e4b17023SJohn Marino || !NONJUMP_INSN_P (insn_b)
2494e4b17023SJohn Marino || (set_b = single_set (insn_b)) == NULL_RTX
2495e4b17023SJohn Marino || ! rtx_equal_p (x, SET_DEST (set_b))
2496e4b17023SJohn Marino || ! noce_operand_ok (SET_SRC (set_b))
2497e4b17023SJohn Marino || reg_overlap_mentioned_p (x, SET_SRC (set_b))
2498e4b17023SJohn Marino || modified_between_p (SET_SRC (set_b), insn_b, jump)
2499e4b17023SJohn Marino /* Likewise with X. In particular this can happen when
2500e4b17023SJohn Marino noce_get_condition looks farther back in the instruction
2501e4b17023SJohn Marino stream than one might expect. */
2502e4b17023SJohn Marino || reg_overlap_mentioned_p (x, cond)
2503e4b17023SJohn Marino || reg_overlap_mentioned_p (x, a)
2504e4b17023SJohn Marino || modified_between_p (x, insn_b, jump))
2505e4b17023SJohn Marino insn_b = set_b = NULL_RTX;
2506e4b17023SJohn Marino }
2507e4b17023SJohn Marino
2508e4b17023SJohn Marino /* If x has side effects then only the if-then-else form is safe to
2509e4b17023SJohn Marino convert. But even in that case we would need to restore any notes
2510e4b17023SJohn Marino (such as REG_INC) at then end. That can be tricky if
2511e4b17023SJohn Marino noce_emit_move_insn expands to more than one insn, so disable the
2512e4b17023SJohn Marino optimization entirely for now if there are side effects. */
2513e4b17023SJohn Marino if (side_effects_p (x))
2514e4b17023SJohn Marino return FALSE;
2515e4b17023SJohn Marino
2516e4b17023SJohn Marino b = (set_b ? SET_SRC (set_b) : x);
2517e4b17023SJohn Marino
2518e4b17023SJohn Marino /* Only operate on register destinations, and even then avoid extending
2519e4b17023SJohn Marino the lifetime of hard registers on small register class machines. */
2520e4b17023SJohn Marino orig_x = x;
2521e4b17023SJohn Marino if (!REG_P (x)
2522e4b17023SJohn Marino || (HARD_REGISTER_P (x)
2523e4b17023SJohn Marino && targetm.small_register_classes_for_mode_p (GET_MODE (x))))
2524e4b17023SJohn Marino {
2525e4b17023SJohn Marino if (GET_MODE (x) == BLKmode)
2526e4b17023SJohn Marino return FALSE;
2527e4b17023SJohn Marino
2528e4b17023SJohn Marino if (GET_CODE (x) == ZERO_EXTRACT
2529e4b17023SJohn Marino && (!CONST_INT_P (XEXP (x, 1))
2530e4b17023SJohn Marino || !CONST_INT_P (XEXP (x, 2))))
2531e4b17023SJohn Marino return FALSE;
2532e4b17023SJohn Marino
2533e4b17023SJohn Marino x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
2534e4b17023SJohn Marino ? XEXP (x, 0) : x));
2535e4b17023SJohn Marino }
2536e4b17023SJohn Marino
2537e4b17023SJohn Marino /* Don't operate on sources that may trap or are volatile. */
2538e4b17023SJohn Marino if (! noce_operand_ok (a) || ! noce_operand_ok (b))
2539e4b17023SJohn Marino return FALSE;
2540e4b17023SJohn Marino
2541e4b17023SJohn Marino retry:
2542e4b17023SJohn Marino /* Set up the info block for our subroutines. */
2543e4b17023SJohn Marino if_info->insn_a = insn_a;
2544e4b17023SJohn Marino if_info->insn_b = insn_b;
2545e4b17023SJohn Marino if_info->x = x;
2546e4b17023SJohn Marino if_info->a = a;
2547e4b17023SJohn Marino if_info->b = b;
2548e4b17023SJohn Marino
2549e4b17023SJohn Marino /* Try optimizations in some approximation of a useful order. */
2550e4b17023SJohn Marino /* ??? Should first look to see if X is live incoming at all. If it
2551e4b17023SJohn Marino isn't, we don't need anything but an unconditional set. */
2552e4b17023SJohn Marino
2553e4b17023SJohn Marino /* Look and see if A and B are really the same. Avoid creating silly
2554e4b17023SJohn Marino cmove constructs that no one will fix up later. */
2555e4b17023SJohn Marino if (rtx_equal_p (a, b))
2556e4b17023SJohn Marino {
2557e4b17023SJohn Marino /* If we have an INSN_B, we don't have to create any new rtl. Just
2558e4b17023SJohn Marino move the instruction that we already have. If we don't have an
2559e4b17023SJohn Marino INSN_B, that means that A == X, and we've got a noop move. In
2560e4b17023SJohn Marino that case don't do anything and let the code below delete INSN_A. */
2561e4b17023SJohn Marino if (insn_b && else_bb)
2562e4b17023SJohn Marino {
2563e4b17023SJohn Marino rtx note;
2564e4b17023SJohn Marino
2565e4b17023SJohn Marino if (else_bb && insn_b == BB_END (else_bb))
2566e4b17023SJohn Marino BB_END (else_bb) = PREV_INSN (insn_b);
2567e4b17023SJohn Marino reorder_insns (insn_b, insn_b, PREV_INSN (jump));
2568e4b17023SJohn Marino
2569e4b17023SJohn Marino /* If there was a REG_EQUAL note, delete it since it may have been
2570e4b17023SJohn Marino true due to this insn being after a jump. */
2571e4b17023SJohn Marino if ((note = find_reg_note (insn_b, REG_EQUAL, NULL_RTX)) != 0)
2572e4b17023SJohn Marino remove_note (insn_b, note);
2573e4b17023SJohn Marino
2574e4b17023SJohn Marino insn_b = NULL_RTX;
2575e4b17023SJohn Marino }
2576e4b17023SJohn Marino /* If we have "x = b; if (...) x = a;", and x has side-effects, then
2577e4b17023SJohn Marino x must be executed twice. */
2578e4b17023SJohn Marino else if (insn_b && side_effects_p (orig_x))
2579e4b17023SJohn Marino return FALSE;
2580e4b17023SJohn Marino
2581e4b17023SJohn Marino x = orig_x;
2582e4b17023SJohn Marino goto success;
2583e4b17023SJohn Marino }
2584e4b17023SJohn Marino
2585e4b17023SJohn Marino if (!set_b && MEM_P (orig_x))
2586e4b17023SJohn Marino {
2587e4b17023SJohn Marino /* Disallow the "if (...) x = a;" form (implicit "else x = x;")
2588e4b17023SJohn Marino for optimizations if writing to x may trap or fault,
2589e4b17023SJohn Marino i.e. it's a memory other than a static var or a stack slot,
2590e4b17023SJohn Marino is misaligned on strict aligned machines or is read-only. If
2591e4b17023SJohn Marino x is a read-only memory, then the program is valid only if we
2592e4b17023SJohn Marino avoid the store into it. If there are stores on both the
2593e4b17023SJohn Marino THEN and ELSE arms, then we can go ahead with the conversion;
2594e4b17023SJohn Marino either the program is broken, or the condition is always
2595e4b17023SJohn Marino false such that the other memory is selected. */
2596e4b17023SJohn Marino if (noce_mem_write_may_trap_or_fault_p (orig_x))
2597e4b17023SJohn Marino return FALSE;
2598e4b17023SJohn Marino
2599e4b17023SJohn Marino /* Avoid store speculation: given "if (...) x = a" where x is a
2600e4b17023SJohn Marino MEM, we only want to do the store if x is always set
2601e4b17023SJohn Marino somewhere in the function. This avoids cases like
2602e4b17023SJohn Marino if (pthread_mutex_trylock(mutex))
2603e4b17023SJohn Marino ++global_variable;
2604e4b17023SJohn Marino where we only want global_variable to be changed if the mutex
2605e4b17023SJohn Marino is held. FIXME: This should ideally be expressed directly in
2606e4b17023SJohn Marino RTL somehow. */
2607e4b17023SJohn Marino if (!noce_can_store_speculate_p (test_bb, orig_x))
2608e4b17023SJohn Marino return FALSE;
2609e4b17023SJohn Marino }
2610e4b17023SJohn Marino
2611e4b17023SJohn Marino if (noce_try_move (if_info))
2612e4b17023SJohn Marino goto success;
2613e4b17023SJohn Marino if (noce_try_store_flag (if_info))
2614e4b17023SJohn Marino goto success;
2615e4b17023SJohn Marino if (noce_try_bitop (if_info))
2616e4b17023SJohn Marino goto success;
2617e4b17023SJohn Marino if (noce_try_minmax (if_info))
2618e4b17023SJohn Marino goto success;
2619e4b17023SJohn Marino if (noce_try_abs (if_info))
2620e4b17023SJohn Marino goto success;
2621e4b17023SJohn Marino if (HAVE_conditional_move
2622e4b17023SJohn Marino && noce_try_cmove (if_info))
2623e4b17023SJohn Marino goto success;
2624e4b17023SJohn Marino if (! targetm.have_conditional_execution ())
2625e4b17023SJohn Marino {
2626e4b17023SJohn Marino if (noce_try_store_flag_constants (if_info))
2627e4b17023SJohn Marino goto success;
2628e4b17023SJohn Marino if (noce_try_addcc (if_info))
2629e4b17023SJohn Marino goto success;
2630e4b17023SJohn Marino if (noce_try_store_flag_mask (if_info))
2631e4b17023SJohn Marino goto success;
2632e4b17023SJohn Marino if (HAVE_conditional_move
2633e4b17023SJohn Marino && noce_try_cmove_arith (if_info))
2634e4b17023SJohn Marino goto success;
2635e4b17023SJohn Marino if (noce_try_sign_mask (if_info))
2636e4b17023SJohn Marino goto success;
2637e4b17023SJohn Marino }
2638e4b17023SJohn Marino
2639e4b17023SJohn Marino if (!else_bb && set_b)
2640e4b17023SJohn Marino {
2641e4b17023SJohn Marino insn_b = set_b = NULL_RTX;
2642e4b17023SJohn Marino b = orig_x;
2643e4b17023SJohn Marino goto retry;
2644e4b17023SJohn Marino }
2645e4b17023SJohn Marino
2646e4b17023SJohn Marino return FALSE;
2647e4b17023SJohn Marino
2648e4b17023SJohn Marino success:
2649e4b17023SJohn Marino
2650e4b17023SJohn Marino /* If we used a temporary, fix it up now. */
2651e4b17023SJohn Marino if (orig_x != x)
2652e4b17023SJohn Marino {
2653e4b17023SJohn Marino rtx seq;
2654e4b17023SJohn Marino
2655e4b17023SJohn Marino start_sequence ();
2656e4b17023SJohn Marino noce_emit_move_insn (orig_x, x);
2657e4b17023SJohn Marino seq = get_insns ();
2658e4b17023SJohn Marino set_used_flags (orig_x);
2659e4b17023SJohn Marino unshare_all_rtl_in_chain (seq);
2660e4b17023SJohn Marino end_sequence ();
2661e4b17023SJohn Marino
2662e4b17023SJohn Marino emit_insn_before_setloc (seq, BB_END (test_bb), INSN_LOCATOR (insn_a));
2663e4b17023SJohn Marino }
2664e4b17023SJohn Marino
2665e4b17023SJohn Marino /* The original THEN and ELSE blocks may now be removed. The test block
2666e4b17023SJohn Marino must now jump to the join block. If the test block and the join block
2667e4b17023SJohn Marino can be merged, do so. */
2668e4b17023SJohn Marino if (else_bb)
2669e4b17023SJohn Marino {
2670e4b17023SJohn Marino delete_basic_block (else_bb);
2671e4b17023SJohn Marino num_true_changes++;
2672e4b17023SJohn Marino }
2673e4b17023SJohn Marino else
2674e4b17023SJohn Marino remove_edge (find_edge (test_bb, join_bb));
2675e4b17023SJohn Marino
2676e4b17023SJohn Marino remove_edge (find_edge (then_bb, join_bb));
2677e4b17023SJohn Marino redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb);
2678e4b17023SJohn Marino delete_basic_block (then_bb);
2679e4b17023SJohn Marino num_true_changes++;
2680e4b17023SJohn Marino
2681e4b17023SJohn Marino if (can_merge_blocks_p (test_bb, join_bb))
2682e4b17023SJohn Marino {
2683e4b17023SJohn Marino merge_blocks (test_bb, join_bb);
2684e4b17023SJohn Marino num_true_changes++;
2685e4b17023SJohn Marino }
2686e4b17023SJohn Marino
2687e4b17023SJohn Marino num_updated_if_blocks++;
2688e4b17023SJohn Marino return TRUE;
2689e4b17023SJohn Marino }
2690e4b17023SJohn Marino
2691e4b17023SJohn Marino /* Check whether a block is suitable for conditional move conversion.
2692e4b17023SJohn Marino Every insn must be a simple set of a register to a constant or a
2693*5ce9237cSJohn Marino register. For each assignment, store the value in the pointer map
2694*5ce9237cSJohn Marino VALS, keyed indexed by register pointer, then store the register
2695*5ce9237cSJohn Marino pointer in REGS. COND is the condition we will test. */
2696e4b17023SJohn Marino
2697e4b17023SJohn Marino static int
check_cond_move_block(basic_block bb,struct pointer_map_t * vals,VEC (rtx,heap)** regs,rtx cond)2698*5ce9237cSJohn Marino check_cond_move_block (basic_block bb,
2699*5ce9237cSJohn Marino struct pointer_map_t *vals,
2700*5ce9237cSJohn Marino VEC (rtx, heap) **regs,
2701e4b17023SJohn Marino rtx cond)
2702e4b17023SJohn Marino {
2703e4b17023SJohn Marino rtx insn;
2704e4b17023SJohn Marino
2705e4b17023SJohn Marino /* We can only handle simple jumps at the end of the basic block.
2706e4b17023SJohn Marino It is almost impossible to update the CFG otherwise. */
2707e4b17023SJohn Marino insn = BB_END (bb);
2708e4b17023SJohn Marino if (JUMP_P (insn) && !onlyjump_p (insn))
2709e4b17023SJohn Marino return FALSE;
2710e4b17023SJohn Marino
2711e4b17023SJohn Marino FOR_BB_INSNS (bb, insn)
2712e4b17023SJohn Marino {
2713e4b17023SJohn Marino rtx set, dest, src;
2714*5ce9237cSJohn Marino void **slot;
2715e4b17023SJohn Marino
2716e4b17023SJohn Marino if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn))
2717e4b17023SJohn Marino continue;
2718e4b17023SJohn Marino set = single_set (insn);
2719e4b17023SJohn Marino if (!set)
2720e4b17023SJohn Marino return FALSE;
2721e4b17023SJohn Marino
2722e4b17023SJohn Marino dest = SET_DEST (set);
2723e4b17023SJohn Marino src = SET_SRC (set);
2724e4b17023SJohn Marino if (!REG_P (dest)
2725e4b17023SJohn Marino || (HARD_REGISTER_P (dest)
2726e4b17023SJohn Marino && targetm.small_register_classes_for_mode_p (GET_MODE (dest))))
2727e4b17023SJohn Marino return FALSE;
2728e4b17023SJohn Marino
2729e4b17023SJohn Marino if (!CONSTANT_P (src) && !register_operand (src, VOIDmode))
2730e4b17023SJohn Marino return FALSE;
2731e4b17023SJohn Marino
2732e4b17023SJohn Marino if (side_effects_p (src) || side_effects_p (dest))
2733e4b17023SJohn Marino return FALSE;
2734e4b17023SJohn Marino
2735e4b17023SJohn Marino if (may_trap_p (src) || may_trap_p (dest))
2736e4b17023SJohn Marino return FALSE;
2737e4b17023SJohn Marino
2738e4b17023SJohn Marino /* Don't try to handle this if the source register was
2739e4b17023SJohn Marino modified earlier in the block. */
2740e4b17023SJohn Marino if ((REG_P (src)
2741*5ce9237cSJohn Marino && pointer_map_contains (vals, src))
2742e4b17023SJohn Marino || (GET_CODE (src) == SUBREG && REG_P (SUBREG_REG (src))
2743*5ce9237cSJohn Marino && pointer_map_contains (vals, SUBREG_REG (src))))
2744e4b17023SJohn Marino return FALSE;
2745e4b17023SJohn Marino
2746e4b17023SJohn Marino /* Don't try to handle this if the destination register was
2747e4b17023SJohn Marino modified earlier in the block. */
2748*5ce9237cSJohn Marino if (pointer_map_contains (vals, dest))
2749e4b17023SJohn Marino return FALSE;
2750e4b17023SJohn Marino
2751e4b17023SJohn Marino /* Don't try to handle this if the condition uses the
2752e4b17023SJohn Marino destination register. */
2753e4b17023SJohn Marino if (reg_overlap_mentioned_p (dest, cond))
2754e4b17023SJohn Marino return FALSE;
2755e4b17023SJohn Marino
2756e4b17023SJohn Marino /* Don't try to handle this if the source register is modified
2757e4b17023SJohn Marino later in the block. */
2758e4b17023SJohn Marino if (!CONSTANT_P (src)
2759e4b17023SJohn Marino && modified_between_p (src, insn, NEXT_INSN (BB_END (bb))))
2760e4b17023SJohn Marino return FALSE;
2761e4b17023SJohn Marino
2762*5ce9237cSJohn Marino slot = pointer_map_insert (vals, (void *) dest);
2763*5ce9237cSJohn Marino *slot = (void *) src;
2764e4b17023SJohn Marino
2765*5ce9237cSJohn Marino VEC_safe_push (rtx, heap, *regs, dest);
2766e4b17023SJohn Marino }
2767e4b17023SJohn Marino
2768e4b17023SJohn Marino return TRUE;
2769e4b17023SJohn Marino }
2770e4b17023SJohn Marino
2771e4b17023SJohn Marino /* Given a basic block BB suitable for conditional move conversion,
2772*5ce9237cSJohn Marino a condition COND, and pointer maps THEN_VALS and ELSE_VALS containing
2773*5ce9237cSJohn Marino the register values depending on COND, emit the insns in the block as
2774e4b17023SJohn Marino conditional moves. If ELSE_BLOCK is true, THEN_BB was already
2775e4b17023SJohn Marino processed. The caller has started a sequence for the conversion.
2776e4b17023SJohn Marino Return true if successful, false if something goes wrong. */
2777e4b17023SJohn Marino
2778e4b17023SJohn Marino static bool
cond_move_convert_if_block(struct noce_if_info * if_infop,basic_block bb,rtx cond,struct pointer_map_t * then_vals,struct pointer_map_t * else_vals,bool else_block_p)2779e4b17023SJohn Marino cond_move_convert_if_block (struct noce_if_info *if_infop,
2780e4b17023SJohn Marino basic_block bb, rtx cond,
2781*5ce9237cSJohn Marino struct pointer_map_t *then_vals,
2782*5ce9237cSJohn Marino struct pointer_map_t *else_vals,
2783e4b17023SJohn Marino bool else_block_p)
2784e4b17023SJohn Marino {
2785e4b17023SJohn Marino enum rtx_code code;
2786e4b17023SJohn Marino rtx insn, cond_arg0, cond_arg1;
2787e4b17023SJohn Marino
2788e4b17023SJohn Marino code = GET_CODE (cond);
2789e4b17023SJohn Marino cond_arg0 = XEXP (cond, 0);
2790e4b17023SJohn Marino cond_arg1 = XEXP (cond, 1);
2791e4b17023SJohn Marino
2792e4b17023SJohn Marino FOR_BB_INSNS (bb, insn)
2793e4b17023SJohn Marino {
2794e4b17023SJohn Marino rtx set, target, dest, t, e;
2795*5ce9237cSJohn Marino void **then_slot, **else_slot;
2796e4b17023SJohn Marino
2797e4b17023SJohn Marino /* ??? Maybe emit conditional debug insn? */
2798e4b17023SJohn Marino if (!NONDEBUG_INSN_P (insn) || JUMP_P (insn))
2799e4b17023SJohn Marino continue;
2800e4b17023SJohn Marino set = single_set (insn);
2801e4b17023SJohn Marino gcc_assert (set && REG_P (SET_DEST (set)));
2802e4b17023SJohn Marino
2803e4b17023SJohn Marino dest = SET_DEST (set);
2804e4b17023SJohn Marino
2805*5ce9237cSJohn Marino then_slot = pointer_map_contains (then_vals, dest);
2806*5ce9237cSJohn Marino else_slot = pointer_map_contains (else_vals, dest);
2807*5ce9237cSJohn Marino t = then_slot ? (rtx) *then_slot : NULL_RTX;
2808*5ce9237cSJohn Marino e = else_slot ? (rtx) *else_slot : NULL_RTX;
2809e4b17023SJohn Marino
2810e4b17023SJohn Marino if (else_block_p)
2811e4b17023SJohn Marino {
2812e4b17023SJohn Marino /* If this register was set in the then block, we already
2813e4b17023SJohn Marino handled this case there. */
2814e4b17023SJohn Marino if (t)
2815e4b17023SJohn Marino continue;
2816e4b17023SJohn Marino t = dest;
2817e4b17023SJohn Marino gcc_assert (e);
2818e4b17023SJohn Marino }
2819e4b17023SJohn Marino else
2820e4b17023SJohn Marino {
2821e4b17023SJohn Marino gcc_assert (t);
2822e4b17023SJohn Marino if (!e)
2823e4b17023SJohn Marino e = dest;
2824e4b17023SJohn Marino }
2825e4b17023SJohn Marino
2826e4b17023SJohn Marino target = noce_emit_cmove (if_infop, dest, code, cond_arg0, cond_arg1,
2827e4b17023SJohn Marino t, e);
2828e4b17023SJohn Marino if (!target)
2829e4b17023SJohn Marino return false;
2830e4b17023SJohn Marino
2831e4b17023SJohn Marino if (target != dest)
2832e4b17023SJohn Marino noce_emit_move_insn (dest, target);
2833e4b17023SJohn Marino }
2834e4b17023SJohn Marino
2835e4b17023SJohn Marino return true;
2836e4b17023SJohn Marino }
2837e4b17023SJohn Marino
2838e4b17023SJohn Marino /* Given a simple IF-THEN-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert
2839e4b17023SJohn Marino it using only conditional moves. Return TRUE if we were successful at
2840e4b17023SJohn Marino converting the block. */
2841e4b17023SJohn Marino
2842e4b17023SJohn Marino static int
cond_move_process_if_block(struct noce_if_info * if_info)2843e4b17023SJohn Marino cond_move_process_if_block (struct noce_if_info *if_info)
2844e4b17023SJohn Marino {
2845e4b17023SJohn Marino basic_block test_bb = if_info->test_bb;
2846e4b17023SJohn Marino basic_block then_bb = if_info->then_bb;
2847e4b17023SJohn Marino basic_block else_bb = if_info->else_bb;
2848e4b17023SJohn Marino basic_block join_bb = if_info->join_bb;
2849e4b17023SJohn Marino rtx jump = if_info->jump;
2850e4b17023SJohn Marino rtx cond = if_info->cond;
2851e4b17023SJohn Marino rtx seq, loc_insn;
2852*5ce9237cSJohn Marino rtx reg;
2853*5ce9237cSJohn Marino int c;
2854*5ce9237cSJohn Marino struct pointer_map_t *then_vals;
2855*5ce9237cSJohn Marino struct pointer_map_t *else_vals;
2856*5ce9237cSJohn Marino VEC (rtx, heap) *then_regs = NULL;
2857*5ce9237cSJohn Marino VEC (rtx, heap) *else_regs = NULL;
2858e4b17023SJohn Marino unsigned int i;
2859*5ce9237cSJohn Marino int success_p = FALSE;
2860e4b17023SJohn Marino
2861e4b17023SJohn Marino /* Build a mapping for each block to the value used for each
2862e4b17023SJohn Marino register. */
2863*5ce9237cSJohn Marino then_vals = pointer_map_create ();
2864*5ce9237cSJohn Marino else_vals = pointer_map_create ();
2865e4b17023SJohn Marino
2866e4b17023SJohn Marino /* Make sure the blocks are suitable. */
2867e4b17023SJohn Marino if (!check_cond_move_block (then_bb, then_vals, &then_regs, cond)
2868e4b17023SJohn Marino || (else_bb
2869e4b17023SJohn Marino && !check_cond_move_block (else_bb, else_vals, &else_regs, cond)))
2870*5ce9237cSJohn Marino goto done;
2871e4b17023SJohn Marino
2872e4b17023SJohn Marino /* Make sure the blocks can be used together. If the same register
2873e4b17023SJohn Marino is set in both blocks, and is not set to a constant in both
2874e4b17023SJohn Marino cases, then both blocks must set it to the same register. We
2875e4b17023SJohn Marino have already verified that if it is set to a register, that the
2876e4b17023SJohn Marino source register does not change after the assignment. Also count
2877e4b17023SJohn Marino the number of registers set in only one of the blocks. */
2878e4b17023SJohn Marino c = 0;
2879*5ce9237cSJohn Marino FOR_EACH_VEC_ELT (rtx, then_regs, i, reg)
2880e4b17023SJohn Marino {
2881*5ce9237cSJohn Marino void **then_slot = pointer_map_contains (then_vals, reg);
2882*5ce9237cSJohn Marino void **else_slot = pointer_map_contains (else_vals, reg);
2883e4b17023SJohn Marino
2884*5ce9237cSJohn Marino gcc_checking_assert (then_slot);
2885*5ce9237cSJohn Marino if (!else_slot)
2886e4b17023SJohn Marino ++c;
2887e4b17023SJohn Marino else
2888e4b17023SJohn Marino {
2889*5ce9237cSJohn Marino rtx then_val = (rtx) *then_slot;
2890*5ce9237cSJohn Marino rtx else_val = (rtx) *else_slot;
2891*5ce9237cSJohn Marino if (!CONSTANT_P (then_val) && !CONSTANT_P (else_val)
2892*5ce9237cSJohn Marino && !rtx_equal_p (then_val, else_val))
2893*5ce9237cSJohn Marino goto done;
2894e4b17023SJohn Marino }
2895e4b17023SJohn Marino }
2896e4b17023SJohn Marino
2897e4b17023SJohn Marino /* Finish off c for MAX_CONDITIONAL_EXECUTE. */
2898*5ce9237cSJohn Marino FOR_EACH_VEC_ELT (rtx, else_regs, i, reg)
2899*5ce9237cSJohn Marino {
2900*5ce9237cSJohn Marino gcc_checking_assert (pointer_map_contains (else_vals, reg));
2901*5ce9237cSJohn Marino if (!pointer_map_contains (then_vals, reg))
2902e4b17023SJohn Marino ++c;
2903*5ce9237cSJohn Marino }
2904e4b17023SJohn Marino
2905e4b17023SJohn Marino /* Make sure it is reasonable to convert this block. What matters
2906e4b17023SJohn Marino is the number of assignments currently made in only one of the
2907e4b17023SJohn Marino branches, since if we convert we are going to always execute
2908e4b17023SJohn Marino them. */
2909e4b17023SJohn Marino if (c > MAX_CONDITIONAL_EXECUTE)
2910*5ce9237cSJohn Marino goto done;
2911e4b17023SJohn Marino
2912e4b17023SJohn Marino /* Try to emit the conditional moves. First do the then block,
2913e4b17023SJohn Marino then do anything left in the else blocks. */
2914e4b17023SJohn Marino start_sequence ();
2915e4b17023SJohn Marino if (!cond_move_convert_if_block (if_info, then_bb, cond,
2916e4b17023SJohn Marino then_vals, else_vals, false)
2917e4b17023SJohn Marino || (else_bb
2918e4b17023SJohn Marino && !cond_move_convert_if_block (if_info, else_bb, cond,
2919e4b17023SJohn Marino then_vals, else_vals, true)))
2920e4b17023SJohn Marino {
2921e4b17023SJohn Marino end_sequence ();
2922*5ce9237cSJohn Marino goto done;
2923e4b17023SJohn Marino }
2924e4b17023SJohn Marino seq = end_ifcvt_sequence (if_info);
2925e4b17023SJohn Marino if (!seq)
2926*5ce9237cSJohn Marino goto done;
2927e4b17023SJohn Marino
2928e4b17023SJohn Marino loc_insn = first_active_insn (then_bb);
2929e4b17023SJohn Marino if (!loc_insn)
2930e4b17023SJohn Marino {
2931e4b17023SJohn Marino loc_insn = first_active_insn (else_bb);
2932e4b17023SJohn Marino gcc_assert (loc_insn);
2933e4b17023SJohn Marino }
2934e4b17023SJohn Marino emit_insn_before_setloc (seq, jump, INSN_LOCATOR (loc_insn));
2935e4b17023SJohn Marino
2936e4b17023SJohn Marino if (else_bb)
2937e4b17023SJohn Marino {
2938e4b17023SJohn Marino delete_basic_block (else_bb);
2939e4b17023SJohn Marino num_true_changes++;
2940e4b17023SJohn Marino }
2941e4b17023SJohn Marino else
2942e4b17023SJohn Marino remove_edge (find_edge (test_bb, join_bb));
2943e4b17023SJohn Marino
2944e4b17023SJohn Marino remove_edge (find_edge (then_bb, join_bb));
2945e4b17023SJohn Marino redirect_edge_and_branch_force (single_succ_edge (test_bb), join_bb);
2946e4b17023SJohn Marino delete_basic_block (then_bb);
2947e4b17023SJohn Marino num_true_changes++;
2948e4b17023SJohn Marino
2949e4b17023SJohn Marino if (can_merge_blocks_p (test_bb, join_bb))
2950e4b17023SJohn Marino {
2951e4b17023SJohn Marino merge_blocks (test_bb, join_bb);
2952e4b17023SJohn Marino num_true_changes++;
2953e4b17023SJohn Marino }
2954e4b17023SJohn Marino
2955e4b17023SJohn Marino num_updated_if_blocks++;
2956e4b17023SJohn Marino
2957*5ce9237cSJohn Marino success_p = TRUE;
2958*5ce9237cSJohn Marino
2959*5ce9237cSJohn Marino done:
2960*5ce9237cSJohn Marino pointer_map_destroy (then_vals);
2961*5ce9237cSJohn Marino pointer_map_destroy (else_vals);
2962*5ce9237cSJohn Marino VEC_free (rtx, heap, then_regs);
2963*5ce9237cSJohn Marino VEC_free (rtx, heap, else_regs);
2964*5ce9237cSJohn Marino return success_p;
2965e4b17023SJohn Marino }
2966e4b17023SJohn Marino
2967e4b17023SJohn Marino
2968e4b17023SJohn Marino /* Determine if a given basic block heads a simple IF-THEN-JOIN or an
2969e4b17023SJohn Marino IF-THEN-ELSE-JOIN block.
2970e4b17023SJohn Marino
2971e4b17023SJohn Marino If so, we'll try to convert the insns to not require the branch,
2972e4b17023SJohn Marino using only transformations that do not require conditional execution.
2973e4b17023SJohn Marino
2974e4b17023SJohn Marino Return TRUE if we were successful at converting the block. */
2975e4b17023SJohn Marino
2976e4b17023SJohn Marino static int
noce_find_if_block(basic_block test_bb,edge then_edge,edge else_edge,int pass)2977e4b17023SJohn Marino noce_find_if_block (basic_block test_bb, edge then_edge, edge else_edge,
2978e4b17023SJohn Marino int pass)
2979e4b17023SJohn Marino {
2980e4b17023SJohn Marino basic_block then_bb, else_bb, join_bb;
2981e4b17023SJohn Marino bool then_else_reversed = false;
2982e4b17023SJohn Marino rtx jump, cond;
2983e4b17023SJohn Marino rtx cond_earliest;
2984e4b17023SJohn Marino struct noce_if_info if_info;
2985e4b17023SJohn Marino
2986e4b17023SJohn Marino /* We only ever should get here before reload. */
2987e4b17023SJohn Marino gcc_assert (!reload_completed);
2988e4b17023SJohn Marino
2989e4b17023SJohn Marino /* Recognize an IF-THEN-ELSE-JOIN block. */
2990e4b17023SJohn Marino if (single_pred_p (then_edge->dest)
2991e4b17023SJohn Marino && single_succ_p (then_edge->dest)
2992e4b17023SJohn Marino && single_pred_p (else_edge->dest)
2993e4b17023SJohn Marino && single_succ_p (else_edge->dest)
2994e4b17023SJohn Marino && single_succ (then_edge->dest) == single_succ (else_edge->dest))
2995e4b17023SJohn Marino {
2996e4b17023SJohn Marino then_bb = then_edge->dest;
2997e4b17023SJohn Marino else_bb = else_edge->dest;
2998e4b17023SJohn Marino join_bb = single_succ (then_bb);
2999e4b17023SJohn Marino }
3000e4b17023SJohn Marino /* Recognize an IF-THEN-JOIN block. */
3001e4b17023SJohn Marino else if (single_pred_p (then_edge->dest)
3002e4b17023SJohn Marino && single_succ_p (then_edge->dest)
3003e4b17023SJohn Marino && single_succ (then_edge->dest) == else_edge->dest)
3004e4b17023SJohn Marino {
3005e4b17023SJohn Marino then_bb = then_edge->dest;
3006e4b17023SJohn Marino else_bb = NULL_BLOCK;
3007e4b17023SJohn Marino join_bb = else_edge->dest;
3008e4b17023SJohn Marino }
3009e4b17023SJohn Marino /* Recognize an IF-ELSE-JOIN block. We can have those because the order
3010e4b17023SJohn Marino of basic blocks in cfglayout mode does not matter, so the fallthrough
3011e4b17023SJohn Marino edge can go to any basic block (and not just to bb->next_bb, like in
3012e4b17023SJohn Marino cfgrtl mode). */
3013e4b17023SJohn Marino else if (single_pred_p (else_edge->dest)
3014e4b17023SJohn Marino && single_succ_p (else_edge->dest)
3015e4b17023SJohn Marino && single_succ (else_edge->dest) == then_edge->dest)
3016e4b17023SJohn Marino {
3017e4b17023SJohn Marino /* The noce transformations do not apply to IF-ELSE-JOIN blocks.
3018e4b17023SJohn Marino To make this work, we have to invert the THEN and ELSE blocks
3019e4b17023SJohn Marino and reverse the jump condition. */
3020e4b17023SJohn Marino then_bb = else_edge->dest;
3021e4b17023SJohn Marino else_bb = NULL_BLOCK;
3022e4b17023SJohn Marino join_bb = single_succ (then_bb);
3023e4b17023SJohn Marino then_else_reversed = true;
3024e4b17023SJohn Marino }
3025e4b17023SJohn Marino else
3026e4b17023SJohn Marino /* Not a form we can handle. */
3027e4b17023SJohn Marino return FALSE;
3028e4b17023SJohn Marino
3029e4b17023SJohn Marino /* The edges of the THEN and ELSE blocks cannot have complex edges. */
3030e4b17023SJohn Marino if (single_succ_edge (then_bb)->flags & EDGE_COMPLEX)
3031e4b17023SJohn Marino return FALSE;
3032e4b17023SJohn Marino if (else_bb
3033e4b17023SJohn Marino && single_succ_edge (else_bb)->flags & EDGE_COMPLEX)
3034e4b17023SJohn Marino return FALSE;
3035e4b17023SJohn Marino
3036e4b17023SJohn Marino num_possible_if_blocks++;
3037e4b17023SJohn Marino
3038e4b17023SJohn Marino if (dump_file)
3039e4b17023SJohn Marino {
3040e4b17023SJohn Marino fprintf (dump_file,
3041e4b17023SJohn Marino "\nIF-THEN%s-JOIN block found, pass %d, test %d, then %d",
3042e4b17023SJohn Marino (else_bb) ? "-ELSE" : "",
3043e4b17023SJohn Marino pass, test_bb->index, then_bb->index);
3044e4b17023SJohn Marino
3045e4b17023SJohn Marino if (else_bb)
3046e4b17023SJohn Marino fprintf (dump_file, ", else %d", else_bb->index);
3047e4b17023SJohn Marino
3048e4b17023SJohn Marino fprintf (dump_file, ", join %d\n", join_bb->index);
3049e4b17023SJohn Marino }
3050e4b17023SJohn Marino
3051e4b17023SJohn Marino /* If the conditional jump is more than just a conditional
3052e4b17023SJohn Marino jump, then we can not do if-conversion on this block. */
3053e4b17023SJohn Marino jump = BB_END (test_bb);
3054e4b17023SJohn Marino if (! onlyjump_p (jump))
3055e4b17023SJohn Marino return FALSE;
3056e4b17023SJohn Marino
3057e4b17023SJohn Marino /* If this is not a standard conditional jump, we can't parse it. */
3058e4b17023SJohn Marino cond = noce_get_condition (jump, &cond_earliest, then_else_reversed);
3059e4b17023SJohn Marino if (!cond)
3060e4b17023SJohn Marino return FALSE;
3061e4b17023SJohn Marino
3062e4b17023SJohn Marino /* We must be comparing objects whose modes imply the size. */
3063e4b17023SJohn Marino if (GET_MODE (XEXP (cond, 0)) == BLKmode)
3064e4b17023SJohn Marino return FALSE;
3065e4b17023SJohn Marino
3066e4b17023SJohn Marino /* Initialize an IF_INFO struct to pass around. */
3067e4b17023SJohn Marino memset (&if_info, 0, sizeof if_info);
3068e4b17023SJohn Marino if_info.test_bb = test_bb;
3069e4b17023SJohn Marino if_info.then_bb = then_bb;
3070e4b17023SJohn Marino if_info.else_bb = else_bb;
3071e4b17023SJohn Marino if_info.join_bb = join_bb;
3072e4b17023SJohn Marino if_info.cond = cond;
3073e4b17023SJohn Marino if_info.cond_earliest = cond_earliest;
3074e4b17023SJohn Marino if_info.jump = jump;
3075e4b17023SJohn Marino if_info.then_else_reversed = then_else_reversed;
3076e4b17023SJohn Marino if_info.branch_cost = BRANCH_COST (optimize_bb_for_speed_p (test_bb),
3077e4b17023SJohn Marino predictable_edge_p (then_edge));
3078e4b17023SJohn Marino
3079e4b17023SJohn Marino /* Do the real work. */
3080e4b17023SJohn Marino
3081e4b17023SJohn Marino if (noce_process_if_block (&if_info))
3082e4b17023SJohn Marino return TRUE;
3083e4b17023SJohn Marino
3084e4b17023SJohn Marino if (HAVE_conditional_move
3085e4b17023SJohn Marino && cond_move_process_if_block (&if_info))
3086e4b17023SJohn Marino return TRUE;
3087e4b17023SJohn Marino
3088e4b17023SJohn Marino return FALSE;
3089e4b17023SJohn Marino }
3090e4b17023SJohn Marino
3091e4b17023SJohn Marino
3092e4b17023SJohn Marino /* Merge the blocks and mark for local life update. */
3093e4b17023SJohn Marino
3094e4b17023SJohn Marino static void
merge_if_block(struct ce_if_block * ce_info)3095e4b17023SJohn Marino merge_if_block (struct ce_if_block * ce_info)
3096e4b17023SJohn Marino {
3097e4b17023SJohn Marino basic_block test_bb = ce_info->test_bb; /* last test block */
3098e4b17023SJohn Marino basic_block then_bb = ce_info->then_bb; /* THEN */
3099e4b17023SJohn Marino basic_block else_bb = ce_info->else_bb; /* ELSE or NULL */
3100e4b17023SJohn Marino basic_block join_bb = ce_info->join_bb; /* join block */
3101e4b17023SJohn Marino basic_block combo_bb;
3102e4b17023SJohn Marino
3103e4b17023SJohn Marino /* All block merging is done into the lower block numbers. */
3104e4b17023SJohn Marino
3105e4b17023SJohn Marino combo_bb = test_bb;
3106e4b17023SJohn Marino df_set_bb_dirty (test_bb);
3107e4b17023SJohn Marino
3108e4b17023SJohn Marino /* Merge any basic blocks to handle && and || subtests. Each of
3109e4b17023SJohn Marino the blocks are on the fallthru path from the predecessor block. */
3110e4b17023SJohn Marino if (ce_info->num_multiple_test_blocks > 0)
3111e4b17023SJohn Marino {
3112e4b17023SJohn Marino basic_block bb = test_bb;
3113e4b17023SJohn Marino basic_block last_test_bb = ce_info->last_test_bb;
3114e4b17023SJohn Marino basic_block fallthru = block_fallthru (bb);
3115e4b17023SJohn Marino
3116e4b17023SJohn Marino do
3117e4b17023SJohn Marino {
3118e4b17023SJohn Marino bb = fallthru;
3119e4b17023SJohn Marino fallthru = block_fallthru (bb);
3120e4b17023SJohn Marino merge_blocks (combo_bb, bb);
3121e4b17023SJohn Marino num_true_changes++;
3122e4b17023SJohn Marino }
3123e4b17023SJohn Marino while (bb != last_test_bb);
3124e4b17023SJohn Marino }
3125e4b17023SJohn Marino
3126e4b17023SJohn Marino /* Merge TEST block into THEN block. Normally the THEN block won't have a
3127e4b17023SJohn Marino label, but it might if there were || tests. That label's count should be
3128e4b17023SJohn Marino zero, and it normally should be removed. */
3129e4b17023SJohn Marino
3130e4b17023SJohn Marino if (then_bb)
3131e4b17023SJohn Marino {
3132e4b17023SJohn Marino merge_blocks (combo_bb, then_bb);
3133e4b17023SJohn Marino num_true_changes++;
3134e4b17023SJohn Marino }
3135e4b17023SJohn Marino
3136e4b17023SJohn Marino /* The ELSE block, if it existed, had a label. That label count
3137e4b17023SJohn Marino will almost always be zero, but odd things can happen when labels
3138e4b17023SJohn Marino get their addresses taken. */
3139e4b17023SJohn Marino if (else_bb)
3140e4b17023SJohn Marino {
3141e4b17023SJohn Marino merge_blocks (combo_bb, else_bb);
3142e4b17023SJohn Marino num_true_changes++;
3143e4b17023SJohn Marino }
3144e4b17023SJohn Marino
3145e4b17023SJohn Marino /* If there was no join block reported, that means it was not adjacent
3146e4b17023SJohn Marino to the others, and so we cannot merge them. */
3147e4b17023SJohn Marino
3148e4b17023SJohn Marino if (! join_bb)
3149e4b17023SJohn Marino {
3150e4b17023SJohn Marino rtx last = BB_END (combo_bb);
3151e4b17023SJohn Marino
3152e4b17023SJohn Marino /* The outgoing edge for the current COMBO block should already
3153e4b17023SJohn Marino be correct. Verify this. */
3154e4b17023SJohn Marino if (EDGE_COUNT (combo_bb->succs) == 0)
3155e4b17023SJohn Marino gcc_assert (find_reg_note (last, REG_NORETURN, NULL)
3156e4b17023SJohn Marino || (NONJUMP_INSN_P (last)
3157e4b17023SJohn Marino && GET_CODE (PATTERN (last)) == TRAP_IF
3158e4b17023SJohn Marino && (TRAP_CONDITION (PATTERN (last))
3159e4b17023SJohn Marino == const_true_rtx)));
3160e4b17023SJohn Marino
3161e4b17023SJohn Marino else
3162e4b17023SJohn Marino /* There should still be something at the end of the THEN or ELSE
3163e4b17023SJohn Marino blocks taking us to our final destination. */
3164e4b17023SJohn Marino gcc_assert (JUMP_P (last)
3165e4b17023SJohn Marino || (EDGE_SUCC (combo_bb, 0)->dest == EXIT_BLOCK_PTR
3166e4b17023SJohn Marino && CALL_P (last)
3167e4b17023SJohn Marino && SIBLING_CALL_P (last))
3168e4b17023SJohn Marino || ((EDGE_SUCC (combo_bb, 0)->flags & EDGE_EH)
3169e4b17023SJohn Marino && can_throw_internal (last)));
3170e4b17023SJohn Marino }
3171e4b17023SJohn Marino
3172e4b17023SJohn Marino /* The JOIN block may have had quite a number of other predecessors too.
3173e4b17023SJohn Marino Since we've already merged the TEST, THEN and ELSE blocks, we should
3174e4b17023SJohn Marino have only one remaining edge from our if-then-else diamond. If there
3175e4b17023SJohn Marino is more than one remaining edge, it must come from elsewhere. There
3176e4b17023SJohn Marino may be zero incoming edges if the THEN block didn't actually join
3177e4b17023SJohn Marino back up (as with a call to a non-return function). */
3178e4b17023SJohn Marino else if (EDGE_COUNT (join_bb->preds) < 2
3179e4b17023SJohn Marino && join_bb != EXIT_BLOCK_PTR)
3180e4b17023SJohn Marino {
3181e4b17023SJohn Marino /* We can merge the JOIN cleanly and update the dataflow try
3182e4b17023SJohn Marino again on this pass.*/
3183e4b17023SJohn Marino merge_blocks (combo_bb, join_bb);
3184e4b17023SJohn Marino num_true_changes++;
3185e4b17023SJohn Marino }
3186e4b17023SJohn Marino else
3187e4b17023SJohn Marino {
3188e4b17023SJohn Marino /* We cannot merge the JOIN. */
3189e4b17023SJohn Marino
3190e4b17023SJohn Marino /* The outgoing edge for the current COMBO block should already
3191e4b17023SJohn Marino be correct. Verify this. */
3192e4b17023SJohn Marino gcc_assert (single_succ_p (combo_bb)
3193e4b17023SJohn Marino && single_succ (combo_bb) == join_bb);
3194e4b17023SJohn Marino
3195e4b17023SJohn Marino /* Remove the jump and cruft from the end of the COMBO block. */
3196e4b17023SJohn Marino if (join_bb != EXIT_BLOCK_PTR)
3197e4b17023SJohn Marino tidy_fallthru_edge (single_succ_edge (combo_bb));
3198e4b17023SJohn Marino }
3199e4b17023SJohn Marino
3200e4b17023SJohn Marino num_updated_if_blocks++;
3201e4b17023SJohn Marino }
3202e4b17023SJohn Marino
3203e4b17023SJohn Marino /* Find a block ending in a simple IF condition and try to transform it
3204e4b17023SJohn Marino in some way. When converting a multi-block condition, put the new code
3205e4b17023SJohn Marino in the first such block and delete the rest. Return a pointer to this
3206e4b17023SJohn Marino first block if some transformation was done. Return NULL otherwise. */
3207e4b17023SJohn Marino
3208e4b17023SJohn Marino static basic_block
find_if_header(basic_block test_bb,int pass)3209e4b17023SJohn Marino find_if_header (basic_block test_bb, int pass)
3210e4b17023SJohn Marino {
3211e4b17023SJohn Marino ce_if_block_t ce_info;
3212e4b17023SJohn Marino edge then_edge;
3213e4b17023SJohn Marino edge else_edge;
3214e4b17023SJohn Marino
3215e4b17023SJohn Marino /* The kind of block we're looking for has exactly two successors. */
3216e4b17023SJohn Marino if (EDGE_COUNT (test_bb->succs) != 2)
3217e4b17023SJohn Marino return NULL;
3218e4b17023SJohn Marino
3219e4b17023SJohn Marino then_edge = EDGE_SUCC (test_bb, 0);
3220e4b17023SJohn Marino else_edge = EDGE_SUCC (test_bb, 1);
3221e4b17023SJohn Marino
3222e4b17023SJohn Marino if (df_get_bb_dirty (then_edge->dest))
3223e4b17023SJohn Marino return NULL;
3224e4b17023SJohn Marino if (df_get_bb_dirty (else_edge->dest))
3225e4b17023SJohn Marino return NULL;
3226e4b17023SJohn Marino
3227e4b17023SJohn Marino /* Neither edge should be abnormal. */
3228e4b17023SJohn Marino if ((then_edge->flags & EDGE_COMPLEX)
3229e4b17023SJohn Marino || (else_edge->flags & EDGE_COMPLEX))
3230e4b17023SJohn Marino return NULL;
3231e4b17023SJohn Marino
3232e4b17023SJohn Marino /* Nor exit the loop. */
3233e4b17023SJohn Marino if ((then_edge->flags & EDGE_LOOP_EXIT)
3234e4b17023SJohn Marino || (else_edge->flags & EDGE_LOOP_EXIT))
3235e4b17023SJohn Marino return NULL;
3236e4b17023SJohn Marino
3237e4b17023SJohn Marino /* The THEN edge is canonically the one that falls through. */
3238e4b17023SJohn Marino if (then_edge->flags & EDGE_FALLTHRU)
3239e4b17023SJohn Marino ;
3240e4b17023SJohn Marino else if (else_edge->flags & EDGE_FALLTHRU)
3241e4b17023SJohn Marino {
3242e4b17023SJohn Marino edge e = else_edge;
3243e4b17023SJohn Marino else_edge = then_edge;
3244e4b17023SJohn Marino then_edge = e;
3245e4b17023SJohn Marino }
3246e4b17023SJohn Marino else
3247e4b17023SJohn Marino /* Otherwise this must be a multiway branch of some sort. */
3248e4b17023SJohn Marino return NULL;
3249e4b17023SJohn Marino
3250e4b17023SJohn Marino memset (&ce_info, 0, sizeof (ce_info));
3251e4b17023SJohn Marino ce_info.test_bb = test_bb;
3252e4b17023SJohn Marino ce_info.then_bb = then_edge->dest;
3253e4b17023SJohn Marino ce_info.else_bb = else_edge->dest;
3254e4b17023SJohn Marino ce_info.pass = pass;
3255e4b17023SJohn Marino
3256e4b17023SJohn Marino #ifdef IFCVT_INIT_EXTRA_FIELDS
3257e4b17023SJohn Marino IFCVT_INIT_EXTRA_FIELDS (&ce_info);
3258e4b17023SJohn Marino #endif
3259e4b17023SJohn Marino
3260e4b17023SJohn Marino if (!reload_completed
3261e4b17023SJohn Marino && noce_find_if_block (test_bb, then_edge, else_edge, pass))
3262e4b17023SJohn Marino goto success;
3263e4b17023SJohn Marino
3264e4b17023SJohn Marino if (reload_completed
3265e4b17023SJohn Marino && targetm.have_conditional_execution ()
3266e4b17023SJohn Marino && cond_exec_find_if_block (&ce_info))
3267e4b17023SJohn Marino goto success;
3268e4b17023SJohn Marino
3269e4b17023SJohn Marino if (HAVE_trap
3270e4b17023SJohn Marino && optab_handler (ctrap_optab, word_mode) != CODE_FOR_nothing
3271e4b17023SJohn Marino && find_cond_trap (test_bb, then_edge, else_edge))
3272e4b17023SJohn Marino goto success;
3273e4b17023SJohn Marino
3274e4b17023SJohn Marino if (dom_info_state (CDI_POST_DOMINATORS) >= DOM_NO_FAST_QUERY
3275e4b17023SJohn Marino && (reload_completed || !targetm.have_conditional_execution ()))
3276e4b17023SJohn Marino {
3277e4b17023SJohn Marino if (find_if_case_1 (test_bb, then_edge, else_edge))
3278e4b17023SJohn Marino goto success;
3279e4b17023SJohn Marino if (find_if_case_2 (test_bb, then_edge, else_edge))
3280e4b17023SJohn Marino goto success;
3281e4b17023SJohn Marino }
3282e4b17023SJohn Marino
3283e4b17023SJohn Marino return NULL;
3284e4b17023SJohn Marino
3285e4b17023SJohn Marino success:
3286e4b17023SJohn Marino if (dump_file)
3287e4b17023SJohn Marino fprintf (dump_file, "Conversion succeeded on pass %d.\n", pass);
3288e4b17023SJohn Marino /* Set this so we continue looking. */
3289e4b17023SJohn Marino cond_exec_changed_p = TRUE;
3290e4b17023SJohn Marino return ce_info.test_bb;
3291e4b17023SJohn Marino }
3292e4b17023SJohn Marino
3293e4b17023SJohn Marino /* Return true if a block has two edges, one of which falls through to the next
3294e4b17023SJohn Marino block, and the other jumps to a specific block, so that we can tell if the
3295e4b17023SJohn Marino block is part of an && test or an || test. Returns either -1 or the number
3296e4b17023SJohn Marino of non-note, non-jump, non-USE/CLOBBER insns in the block. */
3297e4b17023SJohn Marino
3298e4b17023SJohn Marino static int
block_jumps_and_fallthru_p(basic_block cur_bb,basic_block target_bb)3299e4b17023SJohn Marino block_jumps_and_fallthru_p (basic_block cur_bb, basic_block target_bb)
3300e4b17023SJohn Marino {
3301e4b17023SJohn Marino edge cur_edge;
3302e4b17023SJohn Marino int fallthru_p = FALSE;
3303e4b17023SJohn Marino int jump_p = FALSE;
3304e4b17023SJohn Marino rtx insn;
3305e4b17023SJohn Marino rtx end;
3306e4b17023SJohn Marino int n_insns = 0;
3307e4b17023SJohn Marino edge_iterator ei;
3308e4b17023SJohn Marino
3309e4b17023SJohn Marino if (!cur_bb || !target_bb)
3310e4b17023SJohn Marino return -1;
3311e4b17023SJohn Marino
3312e4b17023SJohn Marino /* If no edges, obviously it doesn't jump or fallthru. */
3313e4b17023SJohn Marino if (EDGE_COUNT (cur_bb->succs) == 0)
3314e4b17023SJohn Marino return FALSE;
3315e4b17023SJohn Marino
3316e4b17023SJohn Marino FOR_EACH_EDGE (cur_edge, ei, cur_bb->succs)
3317e4b17023SJohn Marino {
3318e4b17023SJohn Marino if (cur_edge->flags & EDGE_COMPLEX)
3319e4b17023SJohn Marino /* Anything complex isn't what we want. */
3320e4b17023SJohn Marino return -1;
3321e4b17023SJohn Marino
3322e4b17023SJohn Marino else if (cur_edge->flags & EDGE_FALLTHRU)
3323e4b17023SJohn Marino fallthru_p = TRUE;
3324e4b17023SJohn Marino
3325e4b17023SJohn Marino else if (cur_edge->dest == target_bb)
3326e4b17023SJohn Marino jump_p = TRUE;
3327e4b17023SJohn Marino
3328e4b17023SJohn Marino else
3329e4b17023SJohn Marino return -1;
3330e4b17023SJohn Marino }
3331e4b17023SJohn Marino
3332e4b17023SJohn Marino if ((jump_p & fallthru_p) == 0)
3333e4b17023SJohn Marino return -1;
3334e4b17023SJohn Marino
3335e4b17023SJohn Marino /* Don't allow calls in the block, since this is used to group && and ||
3336e4b17023SJohn Marino together for conditional execution support. ??? we should support
3337e4b17023SJohn Marino conditional execution support across calls for IA-64 some day, but
3338e4b17023SJohn Marino for now it makes the code simpler. */
3339e4b17023SJohn Marino end = BB_END (cur_bb);
3340e4b17023SJohn Marino insn = BB_HEAD (cur_bb);
3341e4b17023SJohn Marino
3342e4b17023SJohn Marino while (insn != NULL_RTX)
3343e4b17023SJohn Marino {
3344e4b17023SJohn Marino if (CALL_P (insn))
3345e4b17023SJohn Marino return -1;
3346e4b17023SJohn Marino
3347e4b17023SJohn Marino if (INSN_P (insn)
3348e4b17023SJohn Marino && !JUMP_P (insn)
3349e4b17023SJohn Marino && !DEBUG_INSN_P (insn)
3350e4b17023SJohn Marino && GET_CODE (PATTERN (insn)) != USE
3351e4b17023SJohn Marino && GET_CODE (PATTERN (insn)) != CLOBBER)
3352e4b17023SJohn Marino n_insns++;
3353e4b17023SJohn Marino
3354e4b17023SJohn Marino if (insn == end)
3355e4b17023SJohn Marino break;
3356e4b17023SJohn Marino
3357e4b17023SJohn Marino insn = NEXT_INSN (insn);
3358e4b17023SJohn Marino }
3359e4b17023SJohn Marino
3360e4b17023SJohn Marino return n_insns;
3361e4b17023SJohn Marino }
3362e4b17023SJohn Marino
3363e4b17023SJohn Marino /* Determine if a given basic block heads a simple IF-THEN or IF-THEN-ELSE
3364e4b17023SJohn Marino block. If so, we'll try to convert the insns to not require the branch.
3365e4b17023SJohn Marino Return TRUE if we were successful at converting the block. */
3366e4b17023SJohn Marino
3367e4b17023SJohn Marino static int
cond_exec_find_if_block(struct ce_if_block * ce_info)3368e4b17023SJohn Marino cond_exec_find_if_block (struct ce_if_block * ce_info)
3369e4b17023SJohn Marino {
3370e4b17023SJohn Marino basic_block test_bb = ce_info->test_bb;
3371e4b17023SJohn Marino basic_block then_bb = ce_info->then_bb;
3372e4b17023SJohn Marino basic_block else_bb = ce_info->else_bb;
3373e4b17023SJohn Marino basic_block join_bb = NULL_BLOCK;
3374e4b17023SJohn Marino edge cur_edge;
3375e4b17023SJohn Marino basic_block next;
3376e4b17023SJohn Marino edge_iterator ei;
3377e4b17023SJohn Marino
3378e4b17023SJohn Marino ce_info->last_test_bb = test_bb;
3379e4b17023SJohn Marino
3380e4b17023SJohn Marino /* We only ever should get here after reload,
3381e4b17023SJohn Marino and if we have conditional execution. */
3382e4b17023SJohn Marino gcc_assert (reload_completed && targetm.have_conditional_execution ());
3383e4b17023SJohn Marino
3384e4b17023SJohn Marino /* Discover if any fall through predecessors of the current test basic block
3385e4b17023SJohn Marino were && tests (which jump to the else block) or || tests (which jump to
3386e4b17023SJohn Marino the then block). */
3387e4b17023SJohn Marino if (single_pred_p (test_bb)
3388e4b17023SJohn Marino && single_pred_edge (test_bb)->flags == EDGE_FALLTHRU)
3389e4b17023SJohn Marino {
3390e4b17023SJohn Marino basic_block bb = single_pred (test_bb);
3391e4b17023SJohn Marino basic_block target_bb;
3392e4b17023SJohn Marino int max_insns = MAX_CONDITIONAL_EXECUTE;
3393e4b17023SJohn Marino int n_insns;
3394e4b17023SJohn Marino
3395e4b17023SJohn Marino /* Determine if the preceding block is an && or || block. */
3396e4b17023SJohn Marino if ((n_insns = block_jumps_and_fallthru_p (bb, else_bb)) >= 0)
3397e4b17023SJohn Marino {
3398e4b17023SJohn Marino ce_info->and_and_p = TRUE;
3399e4b17023SJohn Marino target_bb = else_bb;
3400e4b17023SJohn Marino }
3401e4b17023SJohn Marino else if ((n_insns = block_jumps_and_fallthru_p (bb, then_bb)) >= 0)
3402e4b17023SJohn Marino {
3403e4b17023SJohn Marino ce_info->and_and_p = FALSE;
3404e4b17023SJohn Marino target_bb = then_bb;
3405e4b17023SJohn Marino }
3406e4b17023SJohn Marino else
3407e4b17023SJohn Marino target_bb = NULL_BLOCK;
3408e4b17023SJohn Marino
3409e4b17023SJohn Marino if (target_bb && n_insns <= max_insns)
3410e4b17023SJohn Marino {
3411e4b17023SJohn Marino int total_insns = 0;
3412e4b17023SJohn Marino int blocks = 0;
3413e4b17023SJohn Marino
3414e4b17023SJohn Marino ce_info->last_test_bb = test_bb;
3415e4b17023SJohn Marino
3416e4b17023SJohn Marino /* Found at least one && or || block, look for more. */
3417e4b17023SJohn Marino do
3418e4b17023SJohn Marino {
3419e4b17023SJohn Marino ce_info->test_bb = test_bb = bb;
3420e4b17023SJohn Marino total_insns += n_insns;
3421e4b17023SJohn Marino blocks++;
3422e4b17023SJohn Marino
3423e4b17023SJohn Marino if (!single_pred_p (bb))
3424e4b17023SJohn Marino break;
3425e4b17023SJohn Marino
3426e4b17023SJohn Marino bb = single_pred (bb);
3427e4b17023SJohn Marino n_insns = block_jumps_and_fallthru_p (bb, target_bb);
3428e4b17023SJohn Marino }
3429e4b17023SJohn Marino while (n_insns >= 0 && (total_insns + n_insns) <= max_insns);
3430e4b17023SJohn Marino
3431e4b17023SJohn Marino ce_info->num_multiple_test_blocks = blocks;
3432e4b17023SJohn Marino ce_info->num_multiple_test_insns = total_insns;
3433e4b17023SJohn Marino
3434e4b17023SJohn Marino if (ce_info->and_and_p)
3435e4b17023SJohn Marino ce_info->num_and_and_blocks = blocks;
3436e4b17023SJohn Marino else
3437e4b17023SJohn Marino ce_info->num_or_or_blocks = blocks;
3438e4b17023SJohn Marino }
3439e4b17023SJohn Marino }
3440e4b17023SJohn Marino
3441e4b17023SJohn Marino /* The THEN block of an IF-THEN combo must have exactly one predecessor,
3442e4b17023SJohn Marino other than any || blocks which jump to the THEN block. */
3443e4b17023SJohn Marino if ((EDGE_COUNT (then_bb->preds) - ce_info->num_or_or_blocks) != 1)
3444e4b17023SJohn Marino return FALSE;
3445e4b17023SJohn Marino
3446e4b17023SJohn Marino /* The edges of the THEN and ELSE blocks cannot have complex edges. */
3447e4b17023SJohn Marino FOR_EACH_EDGE (cur_edge, ei, then_bb->preds)
3448e4b17023SJohn Marino {
3449e4b17023SJohn Marino if (cur_edge->flags & EDGE_COMPLEX)
3450e4b17023SJohn Marino return FALSE;
3451e4b17023SJohn Marino }
3452e4b17023SJohn Marino
3453e4b17023SJohn Marino FOR_EACH_EDGE (cur_edge, ei, else_bb->preds)
3454e4b17023SJohn Marino {
3455e4b17023SJohn Marino if (cur_edge->flags & EDGE_COMPLEX)
3456e4b17023SJohn Marino return FALSE;
3457e4b17023SJohn Marino }
3458e4b17023SJohn Marino
3459e4b17023SJohn Marino /* The THEN block of an IF-THEN combo must have zero or one successors. */
3460e4b17023SJohn Marino if (EDGE_COUNT (then_bb->succs) > 0
3461e4b17023SJohn Marino && (!single_succ_p (then_bb)
3462e4b17023SJohn Marino || (single_succ_edge (then_bb)->flags & EDGE_COMPLEX)
3463e4b17023SJohn Marino || (epilogue_completed
3464e4b17023SJohn Marino && tablejump_p (BB_END (then_bb), NULL, NULL))))
3465e4b17023SJohn Marino return FALSE;
3466e4b17023SJohn Marino
3467e4b17023SJohn Marino /* If the THEN block has no successors, conditional execution can still
3468e4b17023SJohn Marino make a conditional call. Don't do this unless the ELSE block has
3469e4b17023SJohn Marino only one incoming edge -- the CFG manipulation is too ugly otherwise.
3470e4b17023SJohn Marino Check for the last insn of the THEN block being an indirect jump, which
3471e4b17023SJohn Marino is listed as not having any successors, but confuses the rest of the CE
3472e4b17023SJohn Marino code processing. ??? we should fix this in the future. */
3473e4b17023SJohn Marino if (EDGE_COUNT (then_bb->succs) == 0)
3474e4b17023SJohn Marino {
3475e4b17023SJohn Marino if (single_pred_p (else_bb))
3476e4b17023SJohn Marino {
3477e4b17023SJohn Marino rtx last_insn = BB_END (then_bb);
3478e4b17023SJohn Marino
3479e4b17023SJohn Marino while (last_insn
3480e4b17023SJohn Marino && NOTE_P (last_insn)
3481e4b17023SJohn Marino && last_insn != BB_HEAD (then_bb))
3482e4b17023SJohn Marino last_insn = PREV_INSN (last_insn);
3483e4b17023SJohn Marino
3484e4b17023SJohn Marino if (last_insn
3485e4b17023SJohn Marino && JUMP_P (last_insn)
3486e4b17023SJohn Marino && ! simplejump_p (last_insn))
3487e4b17023SJohn Marino return FALSE;
3488e4b17023SJohn Marino
3489e4b17023SJohn Marino join_bb = else_bb;
3490e4b17023SJohn Marino else_bb = NULL_BLOCK;
3491e4b17023SJohn Marino }
3492e4b17023SJohn Marino else
3493e4b17023SJohn Marino return FALSE;
3494e4b17023SJohn Marino }
3495e4b17023SJohn Marino
3496e4b17023SJohn Marino /* If the THEN block's successor is the other edge out of the TEST block,
3497e4b17023SJohn Marino then we have an IF-THEN combo without an ELSE. */
3498e4b17023SJohn Marino else if (single_succ (then_bb) == else_bb)
3499e4b17023SJohn Marino {
3500e4b17023SJohn Marino join_bb = else_bb;
3501e4b17023SJohn Marino else_bb = NULL_BLOCK;
3502e4b17023SJohn Marino }
3503e4b17023SJohn Marino
3504e4b17023SJohn Marino /* If the THEN and ELSE block meet in a subsequent block, and the ELSE
3505e4b17023SJohn Marino has exactly one predecessor and one successor, and the outgoing edge
3506e4b17023SJohn Marino is not complex, then we have an IF-THEN-ELSE combo. */
3507e4b17023SJohn Marino else if (single_succ_p (else_bb)
3508e4b17023SJohn Marino && single_succ (then_bb) == single_succ (else_bb)
3509e4b17023SJohn Marino && single_pred_p (else_bb)
3510e4b17023SJohn Marino && !(single_succ_edge (else_bb)->flags & EDGE_COMPLEX)
3511e4b17023SJohn Marino && !(epilogue_completed
3512e4b17023SJohn Marino && tablejump_p (BB_END (else_bb), NULL, NULL)))
3513e4b17023SJohn Marino join_bb = single_succ (else_bb);
3514e4b17023SJohn Marino
3515e4b17023SJohn Marino /* Otherwise it is not an IF-THEN or IF-THEN-ELSE combination. */
3516e4b17023SJohn Marino else
3517e4b17023SJohn Marino return FALSE;
3518e4b17023SJohn Marino
3519e4b17023SJohn Marino num_possible_if_blocks++;
3520e4b17023SJohn Marino
3521e4b17023SJohn Marino if (dump_file)
3522e4b17023SJohn Marino {
3523e4b17023SJohn Marino fprintf (dump_file,
3524e4b17023SJohn Marino "\nIF-THEN%s block found, pass %d, start block %d "
3525e4b17023SJohn Marino "[insn %d], then %d [%d]",
3526e4b17023SJohn Marino (else_bb) ? "-ELSE" : "",
3527e4b17023SJohn Marino ce_info->pass,
3528e4b17023SJohn Marino test_bb->index,
3529e4b17023SJohn Marino BB_HEAD (test_bb) ? (int)INSN_UID (BB_HEAD (test_bb)) : -1,
3530e4b17023SJohn Marino then_bb->index,
3531e4b17023SJohn Marino BB_HEAD (then_bb) ? (int)INSN_UID (BB_HEAD (then_bb)) : -1);
3532e4b17023SJohn Marino
3533e4b17023SJohn Marino if (else_bb)
3534e4b17023SJohn Marino fprintf (dump_file, ", else %d [%d]",
3535e4b17023SJohn Marino else_bb->index,
3536e4b17023SJohn Marino BB_HEAD (else_bb) ? (int)INSN_UID (BB_HEAD (else_bb)) : -1);
3537e4b17023SJohn Marino
3538e4b17023SJohn Marino fprintf (dump_file, ", join %d [%d]",
3539e4b17023SJohn Marino join_bb->index,
3540e4b17023SJohn Marino BB_HEAD (join_bb) ? (int)INSN_UID (BB_HEAD (join_bb)) : -1);
3541e4b17023SJohn Marino
3542e4b17023SJohn Marino if (ce_info->num_multiple_test_blocks > 0)
3543e4b17023SJohn Marino fprintf (dump_file, ", %d %s block%s last test %d [%d]",
3544e4b17023SJohn Marino ce_info->num_multiple_test_blocks,
3545e4b17023SJohn Marino (ce_info->and_and_p) ? "&&" : "||",
3546e4b17023SJohn Marino (ce_info->num_multiple_test_blocks == 1) ? "" : "s",
3547e4b17023SJohn Marino ce_info->last_test_bb->index,
3548e4b17023SJohn Marino ((BB_HEAD (ce_info->last_test_bb))
3549e4b17023SJohn Marino ? (int)INSN_UID (BB_HEAD (ce_info->last_test_bb))
3550e4b17023SJohn Marino : -1));
3551e4b17023SJohn Marino
3552e4b17023SJohn Marino fputc ('\n', dump_file);
3553e4b17023SJohn Marino }
3554e4b17023SJohn Marino
3555e4b17023SJohn Marino /* Make sure IF, THEN, and ELSE, blocks are adjacent. Actually, we get the
3556e4b17023SJohn Marino first condition for free, since we've already asserted that there's a
3557e4b17023SJohn Marino fallthru edge from IF to THEN. Likewise for the && and || blocks, since
3558e4b17023SJohn Marino we checked the FALLTHRU flag, those are already adjacent to the last IF
3559e4b17023SJohn Marino block. */
3560e4b17023SJohn Marino /* ??? As an enhancement, move the ELSE block. Have to deal with
3561e4b17023SJohn Marino BLOCK notes, if by no other means than backing out the merge if they
3562e4b17023SJohn Marino exist. Sticky enough I don't want to think about it now. */
3563e4b17023SJohn Marino next = then_bb;
3564e4b17023SJohn Marino if (else_bb && (next = next->next_bb) != else_bb)
3565e4b17023SJohn Marino return FALSE;
3566e4b17023SJohn Marino if ((next = next->next_bb) != join_bb && join_bb != EXIT_BLOCK_PTR)
3567e4b17023SJohn Marino {
3568e4b17023SJohn Marino if (else_bb)
3569e4b17023SJohn Marino join_bb = NULL;
3570e4b17023SJohn Marino else
3571e4b17023SJohn Marino return FALSE;
3572e4b17023SJohn Marino }
3573e4b17023SJohn Marino
3574e4b17023SJohn Marino /* Do the real work. */
3575e4b17023SJohn Marino
3576e4b17023SJohn Marino ce_info->else_bb = else_bb;
3577e4b17023SJohn Marino ce_info->join_bb = join_bb;
3578e4b17023SJohn Marino
3579e4b17023SJohn Marino /* If we have && and || tests, try to first handle combining the && and ||
3580e4b17023SJohn Marino tests into the conditional code, and if that fails, go back and handle
3581e4b17023SJohn Marino it without the && and ||, which at present handles the && case if there
3582e4b17023SJohn Marino was no ELSE block. */
3583e4b17023SJohn Marino if (cond_exec_process_if_block (ce_info, TRUE))
3584e4b17023SJohn Marino return TRUE;
3585e4b17023SJohn Marino
3586e4b17023SJohn Marino if (ce_info->num_multiple_test_blocks)
3587e4b17023SJohn Marino {
3588e4b17023SJohn Marino cancel_changes (0);
3589e4b17023SJohn Marino
3590e4b17023SJohn Marino if (cond_exec_process_if_block (ce_info, FALSE))
3591e4b17023SJohn Marino return TRUE;
3592e4b17023SJohn Marino }
3593e4b17023SJohn Marino
3594e4b17023SJohn Marino return FALSE;
3595e4b17023SJohn Marino }
3596e4b17023SJohn Marino
3597e4b17023SJohn Marino /* Convert a branch over a trap, or a branch
3598e4b17023SJohn Marino to a trap, into a conditional trap. */
3599e4b17023SJohn Marino
3600e4b17023SJohn Marino static int
find_cond_trap(basic_block test_bb,edge then_edge,edge else_edge)3601e4b17023SJohn Marino find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
3602e4b17023SJohn Marino {
3603e4b17023SJohn Marino basic_block then_bb = then_edge->dest;
3604e4b17023SJohn Marino basic_block else_bb = else_edge->dest;
3605e4b17023SJohn Marino basic_block other_bb, trap_bb;
3606e4b17023SJohn Marino rtx trap, jump, cond, cond_earliest, seq;
3607e4b17023SJohn Marino enum rtx_code code;
3608e4b17023SJohn Marino
3609e4b17023SJohn Marino /* Locate the block with the trap instruction. */
3610e4b17023SJohn Marino /* ??? While we look for no successors, we really ought to allow
3611e4b17023SJohn Marino EH successors. Need to fix merge_if_block for that to work. */
3612e4b17023SJohn Marino if ((trap = block_has_only_trap (then_bb)) != NULL)
3613e4b17023SJohn Marino trap_bb = then_bb, other_bb = else_bb;
3614e4b17023SJohn Marino else if ((trap = block_has_only_trap (else_bb)) != NULL)
3615e4b17023SJohn Marino trap_bb = else_bb, other_bb = then_bb;
3616e4b17023SJohn Marino else
3617e4b17023SJohn Marino return FALSE;
3618e4b17023SJohn Marino
3619e4b17023SJohn Marino if (dump_file)
3620e4b17023SJohn Marino {
3621e4b17023SJohn Marino fprintf (dump_file, "\nTRAP-IF block found, start %d, trap %d\n",
3622e4b17023SJohn Marino test_bb->index, trap_bb->index);
3623e4b17023SJohn Marino }
3624e4b17023SJohn Marino
3625e4b17023SJohn Marino /* If this is not a standard conditional jump, we can't parse it. */
3626e4b17023SJohn Marino jump = BB_END (test_bb);
3627e4b17023SJohn Marino cond = noce_get_condition (jump, &cond_earliest, false);
3628e4b17023SJohn Marino if (! cond)
3629e4b17023SJohn Marino return FALSE;
3630e4b17023SJohn Marino
3631e4b17023SJohn Marino /* If the conditional jump is more than just a conditional jump, then
3632e4b17023SJohn Marino we can not do if-conversion on this block. */
3633e4b17023SJohn Marino if (! onlyjump_p (jump))
3634e4b17023SJohn Marino return FALSE;
3635e4b17023SJohn Marino
3636e4b17023SJohn Marino /* We must be comparing objects whose modes imply the size. */
3637e4b17023SJohn Marino if (GET_MODE (XEXP (cond, 0)) == BLKmode)
3638e4b17023SJohn Marino return FALSE;
3639e4b17023SJohn Marino
3640e4b17023SJohn Marino /* Reverse the comparison code, if necessary. */
3641e4b17023SJohn Marino code = GET_CODE (cond);
3642e4b17023SJohn Marino if (then_bb == trap_bb)
3643e4b17023SJohn Marino {
3644e4b17023SJohn Marino code = reversed_comparison_code (cond, jump);
3645e4b17023SJohn Marino if (code == UNKNOWN)
3646e4b17023SJohn Marino return FALSE;
3647e4b17023SJohn Marino }
3648e4b17023SJohn Marino
3649e4b17023SJohn Marino /* Attempt to generate the conditional trap. */
3650e4b17023SJohn Marino seq = gen_cond_trap (code, copy_rtx (XEXP (cond, 0)),
3651e4b17023SJohn Marino copy_rtx (XEXP (cond, 1)),
3652e4b17023SJohn Marino TRAP_CODE (PATTERN (trap)));
3653e4b17023SJohn Marino if (seq == NULL)
3654e4b17023SJohn Marino return FALSE;
3655e4b17023SJohn Marino
3656e4b17023SJohn Marino /* Emit the new insns before cond_earliest. */
3657e4b17023SJohn Marino emit_insn_before_setloc (seq, cond_earliest, INSN_LOCATOR (trap));
3658e4b17023SJohn Marino
3659e4b17023SJohn Marino /* Delete the trap block if possible. */
3660e4b17023SJohn Marino remove_edge (trap_bb == then_bb ? then_edge : else_edge);
3661e4b17023SJohn Marino df_set_bb_dirty (test_bb);
3662e4b17023SJohn Marino df_set_bb_dirty (then_bb);
3663e4b17023SJohn Marino df_set_bb_dirty (else_bb);
3664e4b17023SJohn Marino
3665e4b17023SJohn Marino if (EDGE_COUNT (trap_bb->preds) == 0)
3666e4b17023SJohn Marino {
3667e4b17023SJohn Marino delete_basic_block (trap_bb);
3668e4b17023SJohn Marino num_true_changes++;
3669e4b17023SJohn Marino }
3670e4b17023SJohn Marino
3671e4b17023SJohn Marino /* Wire together the blocks again. */
3672e4b17023SJohn Marino if (current_ir_type () == IR_RTL_CFGLAYOUT)
3673e4b17023SJohn Marino single_succ_edge (test_bb)->flags |= EDGE_FALLTHRU;
3674e4b17023SJohn Marino else
3675e4b17023SJohn Marino {
3676e4b17023SJohn Marino rtx lab, newjump;
3677e4b17023SJohn Marino
3678e4b17023SJohn Marino lab = JUMP_LABEL (jump);
3679e4b17023SJohn Marino newjump = emit_jump_insn_after (gen_jump (lab), jump);
3680e4b17023SJohn Marino LABEL_NUSES (lab) += 1;
3681e4b17023SJohn Marino JUMP_LABEL (newjump) = lab;
3682e4b17023SJohn Marino emit_barrier_after (newjump);
3683e4b17023SJohn Marino }
3684e4b17023SJohn Marino delete_insn (jump);
3685e4b17023SJohn Marino
3686e4b17023SJohn Marino if (can_merge_blocks_p (test_bb, other_bb))
3687e4b17023SJohn Marino {
3688e4b17023SJohn Marino merge_blocks (test_bb, other_bb);
3689e4b17023SJohn Marino num_true_changes++;
3690e4b17023SJohn Marino }
3691e4b17023SJohn Marino
3692e4b17023SJohn Marino num_updated_if_blocks++;
3693e4b17023SJohn Marino return TRUE;
3694e4b17023SJohn Marino }
3695e4b17023SJohn Marino
3696e4b17023SJohn Marino /* Subroutine of find_cond_trap: if BB contains only a trap insn,
3697e4b17023SJohn Marino return it. */
3698e4b17023SJohn Marino
3699e4b17023SJohn Marino static rtx
block_has_only_trap(basic_block bb)3700e4b17023SJohn Marino block_has_only_trap (basic_block bb)
3701e4b17023SJohn Marino {
3702e4b17023SJohn Marino rtx trap;
3703e4b17023SJohn Marino
3704e4b17023SJohn Marino /* We're not the exit block. */
3705e4b17023SJohn Marino if (bb == EXIT_BLOCK_PTR)
3706e4b17023SJohn Marino return NULL_RTX;
3707e4b17023SJohn Marino
3708e4b17023SJohn Marino /* The block must have no successors. */
3709e4b17023SJohn Marino if (EDGE_COUNT (bb->succs) > 0)
3710e4b17023SJohn Marino return NULL_RTX;
3711e4b17023SJohn Marino
3712e4b17023SJohn Marino /* The only instruction in the THEN block must be the trap. */
3713e4b17023SJohn Marino trap = first_active_insn (bb);
3714e4b17023SJohn Marino if (! (trap == BB_END (bb)
3715e4b17023SJohn Marino && GET_CODE (PATTERN (trap)) == TRAP_IF
3716e4b17023SJohn Marino && TRAP_CONDITION (PATTERN (trap)) == const_true_rtx))
3717e4b17023SJohn Marino return NULL_RTX;
3718e4b17023SJohn Marino
3719e4b17023SJohn Marino return trap;
3720e4b17023SJohn Marino }
3721e4b17023SJohn Marino
3722e4b17023SJohn Marino /* Look for IF-THEN-ELSE cases in which one of THEN or ELSE is
3723e4b17023SJohn Marino transformable, but not necessarily the other. There need be no
3724e4b17023SJohn Marino JOIN block.
3725e4b17023SJohn Marino
3726e4b17023SJohn Marino Return TRUE if we were successful at converting the block.
3727e4b17023SJohn Marino
3728e4b17023SJohn Marino Cases we'd like to look at:
3729e4b17023SJohn Marino
3730e4b17023SJohn Marino (1)
3731e4b17023SJohn Marino if (test) goto over; // x not live
3732e4b17023SJohn Marino x = a;
3733e4b17023SJohn Marino goto label;
3734e4b17023SJohn Marino over:
3735e4b17023SJohn Marino
3736e4b17023SJohn Marino becomes
3737e4b17023SJohn Marino
3738e4b17023SJohn Marino x = a;
3739e4b17023SJohn Marino if (! test) goto label;
3740e4b17023SJohn Marino
3741e4b17023SJohn Marino (2)
3742e4b17023SJohn Marino if (test) goto E; // x not live
3743e4b17023SJohn Marino x = big();
3744e4b17023SJohn Marino goto L;
3745e4b17023SJohn Marino E:
3746e4b17023SJohn Marino x = b;
3747e4b17023SJohn Marino goto M;
3748e4b17023SJohn Marino
3749e4b17023SJohn Marino becomes
3750e4b17023SJohn Marino
3751e4b17023SJohn Marino x = b;
3752e4b17023SJohn Marino if (test) goto M;
3753e4b17023SJohn Marino x = big();
3754e4b17023SJohn Marino goto L;
3755e4b17023SJohn Marino
3756e4b17023SJohn Marino (3) // This one's really only interesting for targets that can do
3757e4b17023SJohn Marino // multiway branching, e.g. IA-64 BBB bundles. For other targets
3758e4b17023SJohn Marino // it results in multiple branches on a cache line, which often
3759e4b17023SJohn Marino // does not sit well with predictors.
3760e4b17023SJohn Marino
3761e4b17023SJohn Marino if (test1) goto E; // predicted not taken
3762e4b17023SJohn Marino x = a;
3763e4b17023SJohn Marino if (test2) goto F;
3764e4b17023SJohn Marino ...
3765e4b17023SJohn Marino E:
3766e4b17023SJohn Marino x = b;
3767e4b17023SJohn Marino J:
3768e4b17023SJohn Marino
3769e4b17023SJohn Marino becomes
3770e4b17023SJohn Marino
3771e4b17023SJohn Marino x = a;
3772e4b17023SJohn Marino if (test1) goto E;
3773e4b17023SJohn Marino if (test2) goto F;
3774e4b17023SJohn Marino
3775e4b17023SJohn Marino Notes:
3776e4b17023SJohn Marino
3777e4b17023SJohn Marino (A) Don't do (2) if the branch is predicted against the block we're
3778e4b17023SJohn Marino eliminating. Do it anyway if we can eliminate a branch; this requires
3779e4b17023SJohn Marino that the sole successor of the eliminated block postdominate the other
3780e4b17023SJohn Marino side of the if.
3781e4b17023SJohn Marino
3782e4b17023SJohn Marino (B) With CE, on (3) we can steal from both sides of the if, creating
3783e4b17023SJohn Marino
3784e4b17023SJohn Marino if (test1) x = a;
3785e4b17023SJohn Marino if (!test1) x = b;
3786e4b17023SJohn Marino if (test1) goto J;
3787e4b17023SJohn Marino if (test2) goto F;
3788e4b17023SJohn Marino ...
3789e4b17023SJohn Marino J:
3790e4b17023SJohn Marino
3791e4b17023SJohn Marino Again, this is most useful if J postdominates.
3792e4b17023SJohn Marino
3793e4b17023SJohn Marino (C) CE substitutes for helpful life information.
3794e4b17023SJohn Marino
3795e4b17023SJohn Marino (D) These heuristics need a lot of work. */
3796e4b17023SJohn Marino
3797e4b17023SJohn Marino /* Tests for case 1 above. */
3798e4b17023SJohn Marino
3799e4b17023SJohn Marino static int
find_if_case_1(basic_block test_bb,edge then_edge,edge else_edge)3800e4b17023SJohn Marino find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
3801e4b17023SJohn Marino {
3802e4b17023SJohn Marino basic_block then_bb = then_edge->dest;
3803e4b17023SJohn Marino basic_block else_bb = else_edge->dest;
3804e4b17023SJohn Marino basic_block new_bb;
3805e4b17023SJohn Marino int then_bb_index, then_prob;
3806e4b17023SJohn Marino rtx else_target = NULL_RTX;
3807e4b17023SJohn Marino
3808e4b17023SJohn Marino /* If we are partitioning hot/cold basic blocks, we don't want to
3809e4b17023SJohn Marino mess up unconditional or indirect jumps that cross between hot
3810e4b17023SJohn Marino and cold sections.
3811e4b17023SJohn Marino
3812e4b17023SJohn Marino Basic block partitioning may result in some jumps that appear to
3813e4b17023SJohn Marino be optimizable (or blocks that appear to be mergeable), but which really
3814e4b17023SJohn Marino must be left untouched (they are required to make it safely across
3815e4b17023SJohn Marino partition boundaries). See the comments at the top of
3816e4b17023SJohn Marino bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
3817e4b17023SJohn Marino
3818e4b17023SJohn Marino if ((BB_END (then_bb)
3819e4b17023SJohn Marino && find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
3820e4b17023SJohn Marino || (BB_END (test_bb)
3821e4b17023SJohn Marino && find_reg_note (BB_END (test_bb), REG_CROSSING_JUMP, NULL_RTX))
3822e4b17023SJohn Marino || (BB_END (else_bb)
3823e4b17023SJohn Marino && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
3824e4b17023SJohn Marino NULL_RTX)))
3825e4b17023SJohn Marino return FALSE;
3826e4b17023SJohn Marino
3827e4b17023SJohn Marino /* THEN has one successor. */
3828e4b17023SJohn Marino if (!single_succ_p (then_bb))
3829e4b17023SJohn Marino return FALSE;
3830e4b17023SJohn Marino
3831e4b17023SJohn Marino /* THEN does not fall through, but is not strange either. */
3832e4b17023SJohn Marino if (single_succ_edge (then_bb)->flags & (EDGE_COMPLEX | EDGE_FALLTHRU))
3833e4b17023SJohn Marino return FALSE;
3834e4b17023SJohn Marino
3835e4b17023SJohn Marino /* THEN has one predecessor. */
3836e4b17023SJohn Marino if (!single_pred_p (then_bb))
3837e4b17023SJohn Marino return FALSE;
3838e4b17023SJohn Marino
3839e4b17023SJohn Marino /* THEN must do something. */
3840e4b17023SJohn Marino if (forwarder_block_p (then_bb))
3841e4b17023SJohn Marino return FALSE;
3842e4b17023SJohn Marino
3843e4b17023SJohn Marino num_possible_if_blocks++;
3844e4b17023SJohn Marino if (dump_file)
3845e4b17023SJohn Marino fprintf (dump_file,
3846e4b17023SJohn Marino "\nIF-CASE-1 found, start %d, then %d\n",
3847e4b17023SJohn Marino test_bb->index, then_bb->index);
3848e4b17023SJohn Marino
3849e4b17023SJohn Marino if (then_edge->probability)
3850e4b17023SJohn Marino then_prob = REG_BR_PROB_BASE - then_edge->probability;
3851e4b17023SJohn Marino else
3852e4b17023SJohn Marino then_prob = REG_BR_PROB_BASE / 2;
3853e4b17023SJohn Marino
3854e4b17023SJohn Marino /* We're speculating from the THEN path, we want to make sure the cost
3855e4b17023SJohn Marino of speculation is within reason. */
3856e4b17023SJohn Marino if (! cheap_bb_rtx_cost_p (then_bb, then_prob,
3857e4b17023SJohn Marino COSTS_N_INSNS (BRANCH_COST (optimize_bb_for_speed_p (then_edge->src),
3858e4b17023SJohn Marino predictable_edge_p (then_edge)))))
3859e4b17023SJohn Marino return FALSE;
3860e4b17023SJohn Marino
3861e4b17023SJohn Marino if (else_bb == EXIT_BLOCK_PTR)
3862e4b17023SJohn Marino {
3863e4b17023SJohn Marino rtx jump = BB_END (else_edge->src);
3864e4b17023SJohn Marino gcc_assert (JUMP_P (jump));
3865e4b17023SJohn Marino else_target = JUMP_LABEL (jump);
3866e4b17023SJohn Marino }
3867e4b17023SJohn Marino
3868e4b17023SJohn Marino /* Registers set are dead, or are predicable. */
3869e4b17023SJohn Marino if (! dead_or_predicable (test_bb, then_bb, else_bb,
3870e4b17023SJohn Marino single_succ_edge (then_bb), 1))
3871e4b17023SJohn Marino return FALSE;
3872e4b17023SJohn Marino
3873e4b17023SJohn Marino /* Conversion went ok, including moving the insns and fixing up the
3874e4b17023SJohn Marino jump. Adjust the CFG to match. */
3875e4b17023SJohn Marino
3876e4b17023SJohn Marino /* We can avoid creating a new basic block if then_bb is immediately
3877e4b17023SJohn Marino followed by else_bb, i.e. deleting then_bb allows test_bb to fall
3878e4b17023SJohn Marino thru to else_bb. */
3879e4b17023SJohn Marino
3880e4b17023SJohn Marino if (then_bb->next_bb == else_bb
3881e4b17023SJohn Marino && then_bb->prev_bb == test_bb
3882e4b17023SJohn Marino && else_bb != EXIT_BLOCK_PTR)
3883e4b17023SJohn Marino {
3884e4b17023SJohn Marino redirect_edge_succ (FALLTHRU_EDGE (test_bb), else_bb);
3885e4b17023SJohn Marino new_bb = 0;
3886e4b17023SJohn Marino }
3887e4b17023SJohn Marino else if (else_bb == EXIT_BLOCK_PTR)
3888e4b17023SJohn Marino new_bb = force_nonfallthru_and_redirect (FALLTHRU_EDGE (test_bb),
3889e4b17023SJohn Marino else_bb, else_target);
3890e4b17023SJohn Marino else
3891e4b17023SJohn Marino new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb),
3892e4b17023SJohn Marino else_bb);
3893e4b17023SJohn Marino
3894e4b17023SJohn Marino df_set_bb_dirty (test_bb);
3895e4b17023SJohn Marino df_set_bb_dirty (else_bb);
3896e4b17023SJohn Marino
3897e4b17023SJohn Marino then_bb_index = then_bb->index;
3898e4b17023SJohn Marino delete_basic_block (then_bb);
3899e4b17023SJohn Marino
3900e4b17023SJohn Marino /* Make rest of code believe that the newly created block is the THEN_BB
3901e4b17023SJohn Marino block we removed. */
3902e4b17023SJohn Marino if (new_bb)
3903e4b17023SJohn Marino {
3904e4b17023SJohn Marino df_bb_replace (then_bb_index, new_bb);
3905e4b17023SJohn Marino /* Since the fallthru edge was redirected from test_bb to new_bb,
3906e4b17023SJohn Marino we need to ensure that new_bb is in the same partition as
3907e4b17023SJohn Marino test bb (you can not fall through across section boundaries). */
3908e4b17023SJohn Marino BB_COPY_PARTITION (new_bb, test_bb);
3909e4b17023SJohn Marino }
3910e4b17023SJohn Marino
3911e4b17023SJohn Marino num_true_changes++;
3912e4b17023SJohn Marino num_updated_if_blocks++;
3913e4b17023SJohn Marino
3914e4b17023SJohn Marino return TRUE;
3915e4b17023SJohn Marino }
3916e4b17023SJohn Marino
3917e4b17023SJohn Marino /* Test for case 2 above. */
3918e4b17023SJohn Marino
3919e4b17023SJohn Marino static int
find_if_case_2(basic_block test_bb,edge then_edge,edge else_edge)3920e4b17023SJohn Marino find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
3921e4b17023SJohn Marino {
3922e4b17023SJohn Marino basic_block then_bb = then_edge->dest;
3923e4b17023SJohn Marino basic_block else_bb = else_edge->dest;
3924e4b17023SJohn Marino edge else_succ;
3925e4b17023SJohn Marino int then_prob, else_prob;
3926e4b17023SJohn Marino
3927e4b17023SJohn Marino /* If we are partitioning hot/cold basic blocks, we don't want to
3928e4b17023SJohn Marino mess up unconditional or indirect jumps that cross between hot
3929e4b17023SJohn Marino and cold sections.
3930e4b17023SJohn Marino
3931e4b17023SJohn Marino Basic block partitioning may result in some jumps that appear to
3932e4b17023SJohn Marino be optimizable (or blocks that appear to be mergeable), but which really
3933e4b17023SJohn Marino must be left untouched (they are required to make it safely across
3934e4b17023SJohn Marino partition boundaries). See the comments at the top of
3935e4b17023SJohn Marino bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
3936e4b17023SJohn Marino
3937e4b17023SJohn Marino if ((BB_END (then_bb)
3938e4b17023SJohn Marino && find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
3939e4b17023SJohn Marino || (BB_END (test_bb)
3940e4b17023SJohn Marino && find_reg_note (BB_END (test_bb), REG_CROSSING_JUMP, NULL_RTX))
3941e4b17023SJohn Marino || (BB_END (else_bb)
3942e4b17023SJohn Marino && find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
3943e4b17023SJohn Marino NULL_RTX)))
3944e4b17023SJohn Marino return FALSE;
3945e4b17023SJohn Marino
3946e4b17023SJohn Marino /* ELSE has one successor. */
3947e4b17023SJohn Marino if (!single_succ_p (else_bb))
3948e4b17023SJohn Marino return FALSE;
3949e4b17023SJohn Marino else
3950e4b17023SJohn Marino else_succ = single_succ_edge (else_bb);
3951e4b17023SJohn Marino
3952e4b17023SJohn Marino /* ELSE outgoing edge is not complex. */
3953e4b17023SJohn Marino if (else_succ->flags & EDGE_COMPLEX)
3954e4b17023SJohn Marino return FALSE;
3955e4b17023SJohn Marino
3956e4b17023SJohn Marino /* ELSE has one predecessor. */
3957e4b17023SJohn Marino if (!single_pred_p (else_bb))
3958e4b17023SJohn Marino return FALSE;
3959e4b17023SJohn Marino
3960e4b17023SJohn Marino /* THEN is not EXIT. */
3961e4b17023SJohn Marino if (then_bb->index < NUM_FIXED_BLOCKS)
3962e4b17023SJohn Marino return FALSE;
3963e4b17023SJohn Marino
3964e4b17023SJohn Marino if (else_edge->probability)
3965e4b17023SJohn Marino {
3966e4b17023SJohn Marino else_prob = else_edge->probability;
3967e4b17023SJohn Marino then_prob = REG_BR_PROB_BASE - else_prob;
3968e4b17023SJohn Marino }
3969e4b17023SJohn Marino else
3970e4b17023SJohn Marino {
3971e4b17023SJohn Marino else_prob = REG_BR_PROB_BASE / 2;
3972e4b17023SJohn Marino then_prob = REG_BR_PROB_BASE / 2;
3973e4b17023SJohn Marino }
3974e4b17023SJohn Marino
3975e4b17023SJohn Marino /* ELSE is predicted or SUCC(ELSE) postdominates THEN. */
3976e4b17023SJohn Marino if (else_prob > then_prob)
3977e4b17023SJohn Marino ;
3978e4b17023SJohn Marino else if (else_succ->dest->index < NUM_FIXED_BLOCKS
3979e4b17023SJohn Marino || dominated_by_p (CDI_POST_DOMINATORS, then_bb,
3980e4b17023SJohn Marino else_succ->dest))
3981e4b17023SJohn Marino ;
3982e4b17023SJohn Marino else
3983e4b17023SJohn Marino return FALSE;
3984e4b17023SJohn Marino
3985e4b17023SJohn Marino num_possible_if_blocks++;
3986e4b17023SJohn Marino if (dump_file)
3987e4b17023SJohn Marino fprintf (dump_file,
3988e4b17023SJohn Marino "\nIF-CASE-2 found, start %d, else %d\n",
3989e4b17023SJohn Marino test_bb->index, else_bb->index);
3990e4b17023SJohn Marino
3991e4b17023SJohn Marino /* We're speculating from the ELSE path, we want to make sure the cost
3992e4b17023SJohn Marino of speculation is within reason. */
3993e4b17023SJohn Marino if (! cheap_bb_rtx_cost_p (else_bb, else_prob,
3994e4b17023SJohn Marino COSTS_N_INSNS (BRANCH_COST (optimize_bb_for_speed_p (else_edge->src),
3995e4b17023SJohn Marino predictable_edge_p (else_edge)))))
3996e4b17023SJohn Marino return FALSE;
3997e4b17023SJohn Marino
3998e4b17023SJohn Marino /* Registers set are dead, or are predicable. */
3999e4b17023SJohn Marino if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ, 0))
4000e4b17023SJohn Marino return FALSE;
4001e4b17023SJohn Marino
4002e4b17023SJohn Marino /* Conversion went ok, including moving the insns and fixing up the
4003e4b17023SJohn Marino jump. Adjust the CFG to match. */
4004e4b17023SJohn Marino
4005e4b17023SJohn Marino df_set_bb_dirty (test_bb);
4006e4b17023SJohn Marino df_set_bb_dirty (then_bb);
4007e4b17023SJohn Marino delete_basic_block (else_bb);
4008e4b17023SJohn Marino
4009e4b17023SJohn Marino num_true_changes++;
4010e4b17023SJohn Marino num_updated_if_blocks++;
4011e4b17023SJohn Marino
4012e4b17023SJohn Marino /* ??? We may now fallthru from one of THEN's successors into a join
4013e4b17023SJohn Marino block. Rerun cleanup_cfg? Examine things manually? Wait? */
4014e4b17023SJohn Marino
4015e4b17023SJohn Marino return TRUE;
4016e4b17023SJohn Marino }
4017e4b17023SJohn Marino
4018e4b17023SJohn Marino /* Used by the code above to perform the actual rtl transformations.
4019e4b17023SJohn Marino Return TRUE if successful.
4020e4b17023SJohn Marino
4021e4b17023SJohn Marino TEST_BB is the block containing the conditional branch. MERGE_BB
4022e4b17023SJohn Marino is the block containing the code to manipulate. DEST_EDGE is an
4023e4b17023SJohn Marino edge representing a jump to the join block; after the conversion,
4024e4b17023SJohn Marino TEST_BB should be branching to its destination.
4025e4b17023SJohn Marino REVERSEP is true if the sense of the branch should be reversed. */
4026e4b17023SJohn Marino
4027e4b17023SJohn Marino static int
dead_or_predicable(basic_block test_bb,basic_block merge_bb,basic_block other_bb,edge dest_edge,int reversep)4028e4b17023SJohn Marino dead_or_predicable (basic_block test_bb, basic_block merge_bb,
4029e4b17023SJohn Marino basic_block other_bb, edge dest_edge, int reversep)
4030e4b17023SJohn Marino {
4031e4b17023SJohn Marino basic_block new_dest = dest_edge->dest;
4032e4b17023SJohn Marino rtx head, end, jump, earliest = NULL_RTX, old_dest;
4033e4b17023SJohn Marino bitmap merge_set = NULL;
4034e4b17023SJohn Marino /* Number of pending changes. */
4035e4b17023SJohn Marino int n_validated_changes = 0;
4036e4b17023SJohn Marino rtx new_dest_label = NULL_RTX;
4037e4b17023SJohn Marino
4038e4b17023SJohn Marino jump = BB_END (test_bb);
4039e4b17023SJohn Marino
4040e4b17023SJohn Marino /* Find the extent of the real code in the merge block. */
4041e4b17023SJohn Marino head = BB_HEAD (merge_bb);
4042e4b17023SJohn Marino end = BB_END (merge_bb);
4043e4b17023SJohn Marino
4044e4b17023SJohn Marino while (DEBUG_INSN_P (end) && end != head)
4045e4b17023SJohn Marino end = PREV_INSN (end);
4046e4b17023SJohn Marino
4047e4b17023SJohn Marino /* If merge_bb ends with a tablejump, predicating/moving insn's
4048e4b17023SJohn Marino into test_bb and then deleting merge_bb will result in the jumptable
4049e4b17023SJohn Marino that follows merge_bb being removed along with merge_bb and then we
4050e4b17023SJohn Marino get an unresolved reference to the jumptable. */
4051e4b17023SJohn Marino if (tablejump_p (end, NULL, NULL))
4052e4b17023SJohn Marino return FALSE;
4053e4b17023SJohn Marino
4054e4b17023SJohn Marino if (LABEL_P (head))
4055e4b17023SJohn Marino head = NEXT_INSN (head);
4056e4b17023SJohn Marino while (DEBUG_INSN_P (head) && head != end)
4057e4b17023SJohn Marino head = NEXT_INSN (head);
4058e4b17023SJohn Marino if (NOTE_P (head))
4059e4b17023SJohn Marino {
4060e4b17023SJohn Marino if (head == end)
4061e4b17023SJohn Marino {
4062e4b17023SJohn Marino head = end = NULL_RTX;
4063e4b17023SJohn Marino goto no_body;
4064e4b17023SJohn Marino }
4065e4b17023SJohn Marino head = NEXT_INSN (head);
4066e4b17023SJohn Marino while (DEBUG_INSN_P (head) && head != end)
4067e4b17023SJohn Marino head = NEXT_INSN (head);
4068e4b17023SJohn Marino }
4069e4b17023SJohn Marino
4070e4b17023SJohn Marino if (JUMP_P (end))
4071e4b17023SJohn Marino {
4072e4b17023SJohn Marino if (head == end)
4073e4b17023SJohn Marino {
4074e4b17023SJohn Marino head = end = NULL_RTX;
4075e4b17023SJohn Marino goto no_body;
4076e4b17023SJohn Marino }
4077e4b17023SJohn Marino end = PREV_INSN (end);
4078e4b17023SJohn Marino while (DEBUG_INSN_P (end) && end != head)
4079e4b17023SJohn Marino end = PREV_INSN (end);
4080e4b17023SJohn Marino }
4081e4b17023SJohn Marino
4082e4b17023SJohn Marino /* Disable handling dead code by conditional execution if the machine needs
4083e4b17023SJohn Marino to do anything funny with the tests, etc. */
4084e4b17023SJohn Marino #ifndef IFCVT_MODIFY_TESTS
4085e4b17023SJohn Marino if (targetm.have_conditional_execution ())
4086e4b17023SJohn Marino {
4087e4b17023SJohn Marino /* In the conditional execution case, we have things easy. We know
4088e4b17023SJohn Marino the condition is reversible. We don't have to check life info
4089e4b17023SJohn Marino because we're going to conditionally execute the code anyway.
4090e4b17023SJohn Marino All that's left is making sure the insns involved can actually
4091e4b17023SJohn Marino be predicated. */
4092e4b17023SJohn Marino
4093e4b17023SJohn Marino rtx cond, prob_val;
4094e4b17023SJohn Marino
4095e4b17023SJohn Marino cond = cond_exec_get_condition (jump);
4096e4b17023SJohn Marino if (! cond)
4097e4b17023SJohn Marino return FALSE;
4098e4b17023SJohn Marino
4099e4b17023SJohn Marino prob_val = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
4100e4b17023SJohn Marino if (prob_val)
4101e4b17023SJohn Marino prob_val = XEXP (prob_val, 0);
4102e4b17023SJohn Marino
4103e4b17023SJohn Marino if (reversep)
4104e4b17023SJohn Marino {
4105e4b17023SJohn Marino enum rtx_code rev = reversed_comparison_code (cond, jump);
4106e4b17023SJohn Marino if (rev == UNKNOWN)
4107e4b17023SJohn Marino return FALSE;
4108e4b17023SJohn Marino cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
4109e4b17023SJohn Marino XEXP (cond, 1));
4110e4b17023SJohn Marino if (prob_val)
4111e4b17023SJohn Marino prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
4112e4b17023SJohn Marino }
4113e4b17023SJohn Marino
4114e4b17023SJohn Marino if (cond_exec_process_insns (NULL, head, end, cond, prob_val, 0)
4115e4b17023SJohn Marino && verify_changes (0))
4116e4b17023SJohn Marino n_validated_changes = num_validated_changes ();
4117e4b17023SJohn Marino else
4118e4b17023SJohn Marino cancel_changes (0);
4119e4b17023SJohn Marino
4120e4b17023SJohn Marino earliest = jump;
4121e4b17023SJohn Marino }
4122e4b17023SJohn Marino #endif
4123e4b17023SJohn Marino
4124e4b17023SJohn Marino /* If we allocated new pseudos (e.g. in the conditional move
4125e4b17023SJohn Marino expander called from noce_emit_cmove), we must resize the
4126e4b17023SJohn Marino array first. */
4127e4b17023SJohn Marino if (max_regno < max_reg_num ())
4128e4b17023SJohn Marino max_regno = max_reg_num ();
4129e4b17023SJohn Marino
4130e4b17023SJohn Marino /* Try the NCE path if the CE path did not result in any changes. */
4131e4b17023SJohn Marino if (n_validated_changes == 0)
4132e4b17023SJohn Marino {
4133e4b17023SJohn Marino rtx cond, insn;
4134e4b17023SJohn Marino regset live;
4135e4b17023SJohn Marino bool success;
4136e4b17023SJohn Marino
4137e4b17023SJohn Marino /* In the non-conditional execution case, we have to verify that there
4138e4b17023SJohn Marino are no trapping operations, no calls, no references to memory, and
4139e4b17023SJohn Marino that any registers modified are dead at the branch site. */
4140e4b17023SJohn Marino
4141e4b17023SJohn Marino if (!any_condjump_p (jump))
4142e4b17023SJohn Marino return FALSE;
4143e4b17023SJohn Marino
4144e4b17023SJohn Marino /* Find the extent of the conditional. */
4145e4b17023SJohn Marino cond = noce_get_condition (jump, &earliest, false);
4146e4b17023SJohn Marino if (!cond)
4147e4b17023SJohn Marino return FALSE;
4148e4b17023SJohn Marino
4149e4b17023SJohn Marino live = BITMAP_ALLOC (®_obstack);
4150e4b17023SJohn Marino simulate_backwards_to_point (merge_bb, live, end);
4151e4b17023SJohn Marino success = can_move_insns_across (head, end, earliest, jump,
4152e4b17023SJohn Marino merge_bb, live,
4153e4b17023SJohn Marino df_get_live_in (other_bb), NULL);
4154e4b17023SJohn Marino BITMAP_FREE (live);
4155e4b17023SJohn Marino if (!success)
4156e4b17023SJohn Marino return FALSE;
4157e4b17023SJohn Marino
4158e4b17023SJohn Marino /* Collect the set of registers set in MERGE_BB. */
4159e4b17023SJohn Marino merge_set = BITMAP_ALLOC (®_obstack);
4160e4b17023SJohn Marino
4161e4b17023SJohn Marino FOR_BB_INSNS (merge_bb, insn)
4162e4b17023SJohn Marino if (NONDEBUG_INSN_P (insn))
4163e4b17023SJohn Marino df_simulate_find_defs (insn, merge_set);
4164e4b17023SJohn Marino
4165e4b17023SJohn Marino #ifdef HAVE_simple_return
4166e4b17023SJohn Marino /* If shrink-wrapping, disable this optimization when test_bb is
4167e4b17023SJohn Marino the first basic block and merge_bb exits. The idea is to not
4168e4b17023SJohn Marino move code setting up a return register as that may clobber a
4169e4b17023SJohn Marino register used to pass function parameters, which then must be
4170e4b17023SJohn Marino saved in caller-saved regs. A caller-saved reg requires the
4171e4b17023SJohn Marino prologue, killing a shrink-wrap opportunity. */
4172e4b17023SJohn Marino if ((flag_shrink_wrap && HAVE_simple_return && !epilogue_completed)
4173e4b17023SJohn Marino && ENTRY_BLOCK_PTR->next_bb == test_bb
4174e4b17023SJohn Marino && single_succ_p (new_dest)
4175e4b17023SJohn Marino && single_succ (new_dest) == EXIT_BLOCK_PTR
4176e4b17023SJohn Marino && bitmap_intersect_p (df_get_live_in (new_dest), merge_set))
4177e4b17023SJohn Marino {
4178e4b17023SJohn Marino regset return_regs;
4179e4b17023SJohn Marino unsigned int i;
4180e4b17023SJohn Marino
4181e4b17023SJohn Marino return_regs = BITMAP_ALLOC (®_obstack);
4182e4b17023SJohn Marino
4183e4b17023SJohn Marino /* Start off with the intersection of regs used to pass
4184e4b17023SJohn Marino params and regs used to return values. */
4185e4b17023SJohn Marino for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4186e4b17023SJohn Marino if (FUNCTION_ARG_REGNO_P (i)
4187e4b17023SJohn Marino && targetm.calls.function_value_regno_p (i))
4188e4b17023SJohn Marino bitmap_set_bit (return_regs, INCOMING_REGNO (i));
4189e4b17023SJohn Marino
4190e4b17023SJohn Marino bitmap_and_into (return_regs, df_get_live_out (ENTRY_BLOCK_PTR));
4191e4b17023SJohn Marino bitmap_and_into (return_regs, df_get_live_in (EXIT_BLOCK_PTR));
4192e4b17023SJohn Marino if (!bitmap_empty_p (return_regs))
4193e4b17023SJohn Marino {
4194e4b17023SJohn Marino FOR_BB_INSNS_REVERSE (new_dest, insn)
4195e4b17023SJohn Marino if (NONDEBUG_INSN_P (insn))
4196e4b17023SJohn Marino {
4197e4b17023SJohn Marino df_ref *def_rec;
4198e4b17023SJohn Marino unsigned int uid = INSN_UID (insn);
4199e4b17023SJohn Marino
4200e4b17023SJohn Marino /* If this insn sets any reg in return_regs.. */
4201e4b17023SJohn Marino for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
4202e4b17023SJohn Marino {
4203e4b17023SJohn Marino df_ref def = *def_rec;
4204e4b17023SJohn Marino unsigned r = DF_REF_REGNO (def);
4205e4b17023SJohn Marino
4206e4b17023SJohn Marino if (bitmap_bit_p (return_regs, r))
4207e4b17023SJohn Marino break;
4208e4b17023SJohn Marino }
4209e4b17023SJohn Marino /* ..then add all reg uses to the set of regs
4210e4b17023SJohn Marino we're interested in. */
4211e4b17023SJohn Marino if (*def_rec)
4212e4b17023SJohn Marino df_simulate_uses (insn, return_regs);
4213e4b17023SJohn Marino }
4214e4b17023SJohn Marino if (bitmap_intersect_p (merge_set, return_regs))
4215e4b17023SJohn Marino {
4216e4b17023SJohn Marino BITMAP_FREE (return_regs);
4217e4b17023SJohn Marino BITMAP_FREE (merge_set);
4218e4b17023SJohn Marino return FALSE;
4219e4b17023SJohn Marino }
4220e4b17023SJohn Marino }
4221e4b17023SJohn Marino BITMAP_FREE (return_regs);
4222e4b17023SJohn Marino }
4223e4b17023SJohn Marino #endif
4224e4b17023SJohn Marino }
4225e4b17023SJohn Marino
4226e4b17023SJohn Marino no_body:
4227e4b17023SJohn Marino /* We don't want to use normal invert_jump or redirect_jump because
4228e4b17023SJohn Marino we don't want to delete_insn called. Also, we want to do our own
4229e4b17023SJohn Marino change group management. */
4230e4b17023SJohn Marino
4231e4b17023SJohn Marino old_dest = JUMP_LABEL (jump);
4232e4b17023SJohn Marino if (other_bb != new_dest)
4233e4b17023SJohn Marino {
4234e4b17023SJohn Marino if (JUMP_P (BB_END (dest_edge->src)))
4235e4b17023SJohn Marino new_dest_label = JUMP_LABEL (BB_END (dest_edge->src));
4236e4b17023SJohn Marino else if (new_dest == EXIT_BLOCK_PTR)
4237e4b17023SJohn Marino new_dest_label = ret_rtx;
4238e4b17023SJohn Marino else
4239e4b17023SJohn Marino new_dest_label = block_label (new_dest);
4240e4b17023SJohn Marino
4241e4b17023SJohn Marino if (reversep
4242e4b17023SJohn Marino ? ! invert_jump_1 (jump, new_dest_label)
4243e4b17023SJohn Marino : ! redirect_jump_1 (jump, new_dest_label))
4244e4b17023SJohn Marino goto cancel;
4245e4b17023SJohn Marino }
4246e4b17023SJohn Marino
4247e4b17023SJohn Marino if (verify_changes (n_validated_changes))
4248e4b17023SJohn Marino confirm_change_group ();
4249e4b17023SJohn Marino else
4250e4b17023SJohn Marino goto cancel;
4251e4b17023SJohn Marino
4252e4b17023SJohn Marino if (other_bb != new_dest)
4253e4b17023SJohn Marino {
4254e4b17023SJohn Marino redirect_jump_2 (jump, old_dest, new_dest_label, 0, reversep);
4255e4b17023SJohn Marino
4256e4b17023SJohn Marino redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
4257e4b17023SJohn Marino if (reversep)
4258e4b17023SJohn Marino {
4259e4b17023SJohn Marino gcov_type count, probability;
4260e4b17023SJohn Marino count = BRANCH_EDGE (test_bb)->count;
4261e4b17023SJohn Marino BRANCH_EDGE (test_bb)->count = FALLTHRU_EDGE (test_bb)->count;
4262e4b17023SJohn Marino FALLTHRU_EDGE (test_bb)->count = count;
4263e4b17023SJohn Marino probability = BRANCH_EDGE (test_bb)->probability;
4264e4b17023SJohn Marino BRANCH_EDGE (test_bb)->probability
4265e4b17023SJohn Marino = FALLTHRU_EDGE (test_bb)->probability;
4266e4b17023SJohn Marino FALLTHRU_EDGE (test_bb)->probability = probability;
4267e4b17023SJohn Marino update_br_prob_note (test_bb);
4268e4b17023SJohn Marino }
4269e4b17023SJohn Marino }
4270e4b17023SJohn Marino
4271e4b17023SJohn Marino /* Move the insns out of MERGE_BB to before the branch. */
4272e4b17023SJohn Marino if (head != NULL)
4273e4b17023SJohn Marino {
4274e4b17023SJohn Marino rtx insn;
4275e4b17023SJohn Marino
4276e4b17023SJohn Marino if (end == BB_END (merge_bb))
4277e4b17023SJohn Marino BB_END (merge_bb) = PREV_INSN (head);
4278e4b17023SJohn Marino
4279e4b17023SJohn Marino /* PR 21767: when moving insns above a conditional branch, the REG_EQUAL
4280e4b17023SJohn Marino notes being moved might become invalid. */
4281e4b17023SJohn Marino insn = head;
4282e4b17023SJohn Marino do
4283e4b17023SJohn Marino {
4284e4b17023SJohn Marino rtx note, set;
4285e4b17023SJohn Marino
4286e4b17023SJohn Marino if (! INSN_P (insn))
4287e4b17023SJohn Marino continue;
4288e4b17023SJohn Marino note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
4289e4b17023SJohn Marino if (! note)
4290e4b17023SJohn Marino continue;
4291e4b17023SJohn Marino set = single_set (insn);
4292e4b17023SJohn Marino if (!set || !function_invariant_p (SET_SRC (set))
4293e4b17023SJohn Marino || !function_invariant_p (XEXP (note, 0)))
4294e4b17023SJohn Marino remove_note (insn, note);
4295e4b17023SJohn Marino } while (insn != end && (insn = NEXT_INSN (insn)));
4296e4b17023SJohn Marino
4297e4b17023SJohn Marino /* PR46315: when moving insns above a conditional branch, the REG_EQUAL
4298e4b17023SJohn Marino notes referring to the registers being set might become invalid. */
4299e4b17023SJohn Marino if (merge_set)
4300e4b17023SJohn Marino {
4301e4b17023SJohn Marino unsigned i;
4302e4b17023SJohn Marino bitmap_iterator bi;
4303e4b17023SJohn Marino
4304e4b17023SJohn Marino EXECUTE_IF_SET_IN_BITMAP (merge_set, 0, i, bi)
4305e4b17023SJohn Marino remove_reg_equal_equiv_notes_for_regno (i);
4306e4b17023SJohn Marino
4307e4b17023SJohn Marino BITMAP_FREE (merge_set);
4308e4b17023SJohn Marino }
4309e4b17023SJohn Marino
4310e4b17023SJohn Marino reorder_insns (head, end, PREV_INSN (earliest));
4311e4b17023SJohn Marino }
4312e4b17023SJohn Marino
4313e4b17023SJohn Marino /* Remove the jump and edge if we can. */
4314e4b17023SJohn Marino if (other_bb == new_dest)
4315e4b17023SJohn Marino {
4316e4b17023SJohn Marino delete_insn (jump);
4317e4b17023SJohn Marino remove_edge (BRANCH_EDGE (test_bb));
4318e4b17023SJohn Marino /* ??? Can't merge blocks here, as then_bb is still in use.
4319e4b17023SJohn Marino At minimum, the merge will get done just before bb-reorder. */
4320e4b17023SJohn Marino }
4321e4b17023SJohn Marino
4322e4b17023SJohn Marino return TRUE;
4323e4b17023SJohn Marino
4324e4b17023SJohn Marino cancel:
4325e4b17023SJohn Marino cancel_changes (0);
4326e4b17023SJohn Marino
4327e4b17023SJohn Marino if (merge_set)
4328e4b17023SJohn Marino BITMAP_FREE (merge_set);
4329e4b17023SJohn Marino
4330e4b17023SJohn Marino return FALSE;
4331e4b17023SJohn Marino }
4332e4b17023SJohn Marino
4333e4b17023SJohn Marino /* Main entry point for all if-conversion. */
4334e4b17023SJohn Marino
4335e4b17023SJohn Marino static void
if_convert(void)4336e4b17023SJohn Marino if_convert (void)
4337e4b17023SJohn Marino {
4338e4b17023SJohn Marino basic_block bb;
4339e4b17023SJohn Marino int pass;
4340e4b17023SJohn Marino
4341e4b17023SJohn Marino if (optimize == 1)
4342e4b17023SJohn Marino {
4343e4b17023SJohn Marino df_live_add_problem ();
4344e4b17023SJohn Marino df_live_set_all_dirty ();
4345e4b17023SJohn Marino }
4346e4b17023SJohn Marino
4347e4b17023SJohn Marino num_possible_if_blocks = 0;
4348e4b17023SJohn Marino num_updated_if_blocks = 0;
4349e4b17023SJohn Marino num_true_changes = 0;
4350e4b17023SJohn Marino
4351e4b17023SJohn Marino loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
4352e4b17023SJohn Marino mark_loop_exit_edges ();
4353e4b17023SJohn Marino loop_optimizer_finalize ();
4354e4b17023SJohn Marino free_dominance_info (CDI_DOMINATORS);
4355e4b17023SJohn Marino
4356e4b17023SJohn Marino /* Compute postdominators. */
4357e4b17023SJohn Marino calculate_dominance_info (CDI_POST_DOMINATORS);
4358e4b17023SJohn Marino
4359e4b17023SJohn Marino df_set_flags (DF_LR_RUN_DCE);
4360e4b17023SJohn Marino
4361e4b17023SJohn Marino /* Go through each of the basic blocks looking for things to convert. If we
4362e4b17023SJohn Marino have conditional execution, we make multiple passes to allow us to handle
4363e4b17023SJohn Marino IF-THEN{-ELSE} blocks within other IF-THEN{-ELSE} blocks. */
4364e4b17023SJohn Marino pass = 0;
4365e4b17023SJohn Marino do
4366e4b17023SJohn Marino {
4367e4b17023SJohn Marino df_analyze ();
4368e4b17023SJohn Marino /* Only need to do dce on the first pass. */
4369e4b17023SJohn Marino df_clear_flags (DF_LR_RUN_DCE);
4370e4b17023SJohn Marino cond_exec_changed_p = FALSE;
4371e4b17023SJohn Marino pass++;
4372e4b17023SJohn Marino
4373e4b17023SJohn Marino #ifdef IFCVT_MULTIPLE_DUMPS
4374e4b17023SJohn Marino if (dump_file && pass > 1)
4375e4b17023SJohn Marino fprintf (dump_file, "\n\n========== Pass %d ==========\n", pass);
4376e4b17023SJohn Marino #endif
4377e4b17023SJohn Marino
4378e4b17023SJohn Marino FOR_EACH_BB (bb)
4379e4b17023SJohn Marino {
4380e4b17023SJohn Marino basic_block new_bb;
4381e4b17023SJohn Marino while (!df_get_bb_dirty (bb)
4382e4b17023SJohn Marino && (new_bb = find_if_header (bb, pass)) != NULL)
4383e4b17023SJohn Marino bb = new_bb;
4384e4b17023SJohn Marino }
4385e4b17023SJohn Marino
4386e4b17023SJohn Marino #ifdef IFCVT_MULTIPLE_DUMPS
4387e4b17023SJohn Marino if (dump_file && cond_exec_changed_p)
4388e4b17023SJohn Marino {
4389e4b17023SJohn Marino if (dump_flags & TDF_SLIM)
4390e4b17023SJohn Marino print_rtl_slim_with_bb (dump_file, get_insns (), dump_flags);
4391e4b17023SJohn Marino else
4392e4b17023SJohn Marino print_rtl_with_bb (dump_file, get_insns ());
4393e4b17023SJohn Marino }
4394e4b17023SJohn Marino #endif
4395e4b17023SJohn Marino }
4396e4b17023SJohn Marino while (cond_exec_changed_p);
4397e4b17023SJohn Marino
4398e4b17023SJohn Marino #ifdef IFCVT_MULTIPLE_DUMPS
4399e4b17023SJohn Marino if (dump_file)
4400e4b17023SJohn Marino fprintf (dump_file, "\n\n========== no more changes\n");
4401e4b17023SJohn Marino #endif
4402e4b17023SJohn Marino
4403e4b17023SJohn Marino free_dominance_info (CDI_POST_DOMINATORS);
4404e4b17023SJohn Marino
4405e4b17023SJohn Marino if (dump_file)
4406e4b17023SJohn Marino fflush (dump_file);
4407e4b17023SJohn Marino
4408e4b17023SJohn Marino clear_aux_for_blocks ();
4409e4b17023SJohn Marino
4410e4b17023SJohn Marino /* If we allocated new pseudos, we must resize the array for sched1. */
4411e4b17023SJohn Marino if (max_regno < max_reg_num ())
4412e4b17023SJohn Marino max_regno = max_reg_num ();
4413e4b17023SJohn Marino
4414e4b17023SJohn Marino /* Write the final stats. */
4415e4b17023SJohn Marino if (dump_file && num_possible_if_blocks > 0)
4416e4b17023SJohn Marino {
4417e4b17023SJohn Marino fprintf (dump_file,
4418e4b17023SJohn Marino "\n%d possible IF blocks searched.\n",
4419e4b17023SJohn Marino num_possible_if_blocks);
4420e4b17023SJohn Marino fprintf (dump_file,
4421e4b17023SJohn Marino "%d IF blocks converted.\n",
4422e4b17023SJohn Marino num_updated_if_blocks);
4423e4b17023SJohn Marino fprintf (dump_file,
4424e4b17023SJohn Marino "%d true changes made.\n\n\n",
4425e4b17023SJohn Marino num_true_changes);
4426e4b17023SJohn Marino }
4427e4b17023SJohn Marino
4428e4b17023SJohn Marino if (optimize == 1)
4429e4b17023SJohn Marino df_remove_problem (df_live);
4430e4b17023SJohn Marino
4431e4b17023SJohn Marino #ifdef ENABLE_CHECKING
4432e4b17023SJohn Marino verify_flow_info ();
4433e4b17023SJohn Marino #endif
4434e4b17023SJohn Marino }
4435e4b17023SJohn Marino
4436e4b17023SJohn Marino static bool
gate_handle_if_conversion(void)4437e4b17023SJohn Marino gate_handle_if_conversion (void)
4438e4b17023SJohn Marino {
4439e4b17023SJohn Marino return (optimize > 0)
4440e4b17023SJohn Marino && dbg_cnt (if_conversion);
4441e4b17023SJohn Marino }
4442e4b17023SJohn Marino
4443e4b17023SJohn Marino /* If-conversion and CFG cleanup. */
4444e4b17023SJohn Marino static unsigned int
rest_of_handle_if_conversion(void)4445e4b17023SJohn Marino rest_of_handle_if_conversion (void)
4446e4b17023SJohn Marino {
4447e4b17023SJohn Marino if (flag_if_conversion)
4448e4b17023SJohn Marino {
4449e4b17023SJohn Marino if (dump_file)
4450e4b17023SJohn Marino dump_flow_info (dump_file, dump_flags);
4451e4b17023SJohn Marino cleanup_cfg (CLEANUP_EXPENSIVE);
4452e4b17023SJohn Marino if_convert ();
4453e4b17023SJohn Marino }
4454e4b17023SJohn Marino
4455e4b17023SJohn Marino cleanup_cfg (0);
4456e4b17023SJohn Marino return 0;
4457e4b17023SJohn Marino }
4458e4b17023SJohn Marino
4459e4b17023SJohn Marino struct rtl_opt_pass pass_rtl_ifcvt =
4460e4b17023SJohn Marino {
4461e4b17023SJohn Marino {
4462e4b17023SJohn Marino RTL_PASS,
4463e4b17023SJohn Marino "ce1", /* name */
4464e4b17023SJohn Marino gate_handle_if_conversion, /* gate */
4465e4b17023SJohn Marino rest_of_handle_if_conversion, /* execute */
4466e4b17023SJohn Marino NULL, /* sub */
4467e4b17023SJohn Marino NULL, /* next */
4468e4b17023SJohn Marino 0, /* static_pass_number */
4469e4b17023SJohn Marino TV_IFCVT, /* tv_id */
4470e4b17023SJohn Marino 0, /* properties_required */
4471e4b17023SJohn Marino 0, /* properties_provided */
4472e4b17023SJohn Marino 0, /* properties_destroyed */
4473e4b17023SJohn Marino 0, /* todo_flags_start */
4474e4b17023SJohn Marino TODO_df_finish | TODO_verify_rtl_sharing |
4475e4b17023SJohn Marino 0 /* todo_flags_finish */
4476e4b17023SJohn Marino }
4477e4b17023SJohn Marino };
4478e4b17023SJohn Marino
4479e4b17023SJohn Marino static bool
gate_handle_if_after_combine(void)4480e4b17023SJohn Marino gate_handle_if_after_combine (void)
4481e4b17023SJohn Marino {
4482e4b17023SJohn Marino return optimize > 0 && flag_if_conversion
4483e4b17023SJohn Marino && dbg_cnt (if_after_combine);
4484e4b17023SJohn Marino }
4485e4b17023SJohn Marino
4486e4b17023SJohn Marino
4487e4b17023SJohn Marino /* Rerun if-conversion, as combine may have simplified things enough
4488e4b17023SJohn Marino to now meet sequence length restrictions. */
4489e4b17023SJohn Marino static unsigned int
rest_of_handle_if_after_combine(void)4490e4b17023SJohn Marino rest_of_handle_if_after_combine (void)
4491e4b17023SJohn Marino {
4492e4b17023SJohn Marino if_convert ();
4493e4b17023SJohn Marino return 0;
4494e4b17023SJohn Marino }
4495e4b17023SJohn Marino
4496e4b17023SJohn Marino struct rtl_opt_pass pass_if_after_combine =
4497e4b17023SJohn Marino {
4498e4b17023SJohn Marino {
4499e4b17023SJohn Marino RTL_PASS,
4500e4b17023SJohn Marino "ce2", /* name */
4501e4b17023SJohn Marino gate_handle_if_after_combine, /* gate */
4502e4b17023SJohn Marino rest_of_handle_if_after_combine, /* execute */
4503e4b17023SJohn Marino NULL, /* sub */
4504e4b17023SJohn Marino NULL, /* next */
4505e4b17023SJohn Marino 0, /* static_pass_number */
4506e4b17023SJohn Marino TV_IFCVT, /* tv_id */
4507e4b17023SJohn Marino 0, /* properties_required */
4508e4b17023SJohn Marino 0, /* properties_provided */
4509e4b17023SJohn Marino 0, /* properties_destroyed */
4510e4b17023SJohn Marino 0, /* todo_flags_start */
4511e4b17023SJohn Marino TODO_df_finish | TODO_verify_rtl_sharing |
4512e4b17023SJohn Marino TODO_ggc_collect /* todo_flags_finish */
4513e4b17023SJohn Marino }
4514e4b17023SJohn Marino };
4515e4b17023SJohn Marino
4516e4b17023SJohn Marino
4517e4b17023SJohn Marino static bool
gate_handle_if_after_reload(void)4518e4b17023SJohn Marino gate_handle_if_after_reload (void)
4519e4b17023SJohn Marino {
4520e4b17023SJohn Marino return optimize > 0 && flag_if_conversion2
4521e4b17023SJohn Marino && dbg_cnt (if_after_reload);
4522e4b17023SJohn Marino }
4523e4b17023SJohn Marino
4524e4b17023SJohn Marino static unsigned int
rest_of_handle_if_after_reload(void)4525e4b17023SJohn Marino rest_of_handle_if_after_reload (void)
4526e4b17023SJohn Marino {
4527e4b17023SJohn Marino if_convert ();
4528e4b17023SJohn Marino return 0;
4529e4b17023SJohn Marino }
4530e4b17023SJohn Marino
4531e4b17023SJohn Marino
4532e4b17023SJohn Marino struct rtl_opt_pass pass_if_after_reload =
4533e4b17023SJohn Marino {
4534e4b17023SJohn Marino {
4535e4b17023SJohn Marino RTL_PASS,
4536e4b17023SJohn Marino "ce3", /* name */
4537e4b17023SJohn Marino gate_handle_if_after_reload, /* gate */
4538e4b17023SJohn Marino rest_of_handle_if_after_reload, /* execute */
4539e4b17023SJohn Marino NULL, /* sub */
4540e4b17023SJohn Marino NULL, /* next */
4541e4b17023SJohn Marino 0, /* static_pass_number */
4542e4b17023SJohn Marino TV_IFCVT2, /* tv_id */
4543e4b17023SJohn Marino 0, /* properties_required */
4544e4b17023SJohn Marino 0, /* properties_provided */
4545e4b17023SJohn Marino 0, /* properties_destroyed */
4546e4b17023SJohn Marino 0, /* todo_flags_start */
4547e4b17023SJohn Marino TODO_df_finish | TODO_verify_rtl_sharing |
4548e4b17023SJohn Marino TODO_ggc_collect /* todo_flags_finish */
4549e4b17023SJohn Marino }
4550e4b17023SJohn Marino };
4551