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