xref: /dragonfly/contrib/gcc-4.7/gcc/ifcvt.c (revision 5ce9237c)
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, &REG_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 (&reg_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 (&reg_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 (&reg_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