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