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