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