Branch data Line data Source code
1 : : /* CPU mode switching
2 : : Copyright (C) 1998-2025 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 under
7 : : the terms of the GNU General Public License as published by the Free
8 : : Software Foundation; either version 3, or (at your option) any later
9 : : version.
10 : :
11 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : : 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 "cfghooks.h"
27 : : #include "df.h"
28 : : #include "memmodel.h"
29 : : #include "tm_p.h"
30 : : #include "regs.h"
31 : : #include "emit-rtl.h"
32 : : #include "cfgrtl.h"
33 : : #include "cfganal.h"
34 : : #include "lcm.h"
35 : : #include "cfgcleanup.h"
36 : : #include "tree-pass.h"
37 : : #include "cfgbuild.h"
38 : :
39 : : /* We want target macros for the mode switching code to be able to refer
40 : : to instruction attribute values. */
41 : : #include "insn-attr.h"
42 : :
43 : : #ifdef OPTIMIZE_MODE_SWITCHING
44 : :
45 : : /* The algorithm for setting the modes consists of scanning the insn list
46 : : and finding all the insns which require a specific mode. Each insn gets
47 : : a unique struct seginfo element. These structures are inserted into a list
48 : : for each basic block. For each entity, there is an array of bb_info over
49 : : the flow graph basic blocks (local var 'bb_info'), which contains a list
50 : : of all insns within that basic block, in the order they are encountered.
51 : :
52 : : For each entity, any basic block WITHOUT any insns requiring a specific
53 : : mode are given a single entry without a mode (each basic block in the
54 : : flow graph must have at least one entry in the segment table).
55 : :
56 : : The LCM algorithm is then run over the flow graph to determine where to
57 : : place the sets to the highest-priority mode with respect to the first
58 : : insn in any one block. Any adjustments required to the transparency
59 : : vectors are made, then the next iteration starts for the next-lower
60 : : priority mode, till for each entity all modes are exhausted.
61 : :
62 : : More details can be found in the code of optimize_mode_switching. */
63 : :
64 : : /* This structure contains the information for each insn which requires
65 : : either single or double mode to be set.
66 : : MODE is the mode this insn must be executed in.
67 : : INSN_PTR is the insn to be executed (may be the note that marks the
68 : : beginning of a basic block).
69 : : NEXT is the next insn in the same basic block. */
70 : : struct seginfo
71 : : {
72 : : int prev_mode;
73 : : int mode;
74 : : rtx_insn *insn_ptr;
75 : : struct seginfo *next;
76 : : HARD_REG_SET regs_live;
77 : : };
78 : :
79 : : struct bb_info
80 : : {
81 : : struct seginfo *seginfo;
82 : : int computing;
83 : : int mode_out;
84 : : int mode_in;
85 : : int single_succ;
86 : : };
87 : :
88 : : /* Clear ode I from entity J in bitmap B. */
89 : : #define clear_mode_bit(b, j, i) \
90 : : bitmap_clear_bit (b, (j * max_num_modes) + i)
91 : :
92 : : /* Test mode I from entity J in bitmap B. */
93 : : #define mode_bit_p(b, j, i) \
94 : : bitmap_bit_p (b, (j * max_num_modes) + i)
95 : :
96 : : /* Set mode I from entity J in bitmal B. */
97 : : #define set_mode_bit(b, j, i) \
98 : : bitmap_set_bit (b, (j * max_num_modes) + i)
99 : :
100 : : /* Emit modes segments from EDGE_LIST associated with entity E.
101 : : INFO gives mode availability for each mode. */
102 : :
103 : : static bool
104 : 76487 : commit_mode_sets (struct edge_list *edge_list, int e, struct bb_info *info)
105 : : {
106 : 76487 : bool need_commit = false;
107 : :
108 : 884359 : for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
109 : : {
110 : 807872 : edge eg = INDEX_EDGE (edge_list, ed);
111 : :
112 : 807872 : if (eg->aux)
113 : : {
114 : 9309 : int mode = (int) (intptr_t) eg->aux - 1;
115 : 9309 : HARD_REG_SET live_at_edge;
116 : 9309 : basic_block src_bb = eg->src;
117 : 9309 : int cur_mode = info[src_bb->index].mode_out;
118 : 9309 : rtx_insn *mode_set;
119 : :
120 : 18618 : REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb));
121 : :
122 : 9309 : rtl_profile_for_edge (eg);
123 : 9309 : start_sequence ();
124 : :
125 : 9309 : targetm.mode_switching.emit (e, mode, cur_mode, live_at_edge);
126 : :
127 : 9309 : mode_set = get_insns ();
128 : 9309 : end_sequence ();
129 : 9309 : default_rtl_profile ();
130 : :
131 : : /* Do not bother to insert empty sequence. */
132 : 9309 : if (mode_set == NULL)
133 : 3394 : continue;
134 : :
135 : : /* We should not get an abnormal edge here. */
136 : 5915 : gcc_assert (! (eg->flags & EDGE_ABNORMAL));
137 : :
138 : 5915 : need_commit = true;
139 : 5915 : insert_insn_on_edge (mode_set, eg);
140 : : }
141 : : }
142 : :
143 : 76487 : return need_commit;
144 : : }
145 : :
146 : : /* Allocate a new BBINFO structure, initialized with the PREV_MODE, MODE,
147 : : INSN, and REGS_LIVE parameters.
148 : : INSN may not be a NOTE_INSN_BASIC_BLOCK, unless it is an empty
149 : : basic block; that allows us later to insert instructions in a FIFO-like
150 : : manner. */
151 : :
152 : : static struct seginfo *
153 : 555924 : new_seginfo (int prev_mode, int mode, rtx_insn *insn,
154 : : const HARD_REG_SET ®s_live)
155 : : {
156 : 555924 : struct seginfo *ptr;
157 : :
158 : 555924 : gcc_assert (!NOTE_INSN_BASIC_BLOCK_P (insn)
159 : : || insn == BB_END (NOTE_BASIC_BLOCK (insn)));
160 : 555924 : ptr = XNEW (struct seginfo);
161 : 555924 : ptr->prev_mode = prev_mode;
162 : 555924 : ptr->mode = mode;
163 : 555924 : ptr->insn_ptr = insn;
164 : 555924 : ptr->next = NULL;
165 : 555924 : ptr->regs_live = regs_live;
166 : 555924 : return ptr;
167 : : }
168 : :
169 : : /* Add a seginfo element to the end of a list.
170 : : TAIL is a pointer to the list's null terminator.
171 : : INFO is the structure to be linked in. */
172 : :
173 : : static void
174 : 555924 : add_seginfo (struct seginfo ***tail_ptr, struct seginfo *info)
175 : : {
176 : 555924 : **tail_ptr = info;
177 : 555924 : *tail_ptr = &info->next;
178 : 0 : }
179 : :
180 : : /* Record in LIVE that register REG died. */
181 : :
182 : : static void
183 : 1591312 : reg_dies (rtx reg, HARD_REG_SET *live)
184 : : {
185 : 1591312 : int regno;
186 : :
187 : 1591312 : if (!REG_P (reg))
188 : : return;
189 : :
190 : 1591312 : regno = REGNO (reg);
191 : 1591312 : if (regno < FIRST_PSEUDO_REGISTER)
192 : 1389901 : remove_from_hard_reg_set (live, GET_MODE (reg), regno);
193 : : }
194 : :
195 : : /* Record in LIVE that register REG became live.
196 : : This is called via note_stores. */
197 : :
198 : : static void
199 : 2744042 : reg_becomes_live (rtx reg, const_rtx setter ATTRIBUTE_UNUSED, void *live)
200 : : {
201 : 2744042 : int regno;
202 : :
203 : 2744042 : if (GET_CODE (reg) == SUBREG)
204 : 29 : reg = SUBREG_REG (reg);
205 : :
206 : 2744042 : if (!REG_P (reg))
207 : : return;
208 : :
209 : 2137479 : regno = REGNO (reg);
210 : 2137479 : if (regno < FIRST_PSEUDO_REGISTER)
211 : 1917952 : add_to_hard_reg_set ((HARD_REG_SET *) live, GET_MODE (reg), regno);
212 : : }
213 : :
214 : : /* Split the fallthrough edge to the exit block, so that we can note
215 : : that there NORMAL_MODE is required. Return the new block if it's
216 : : inserted before the exit block. Otherwise return null. */
217 : :
218 : : static basic_block
219 : 76471 : create_pre_exit (int n_entities, int *entity_map, const int *num_modes)
220 : : {
221 : 76471 : edge eg;
222 : 76471 : edge_iterator ei;
223 : 76471 : basic_block pre_exit;
224 : :
225 : : /* The only non-call predecessor at this stage is a block with a
226 : : fallthrough edge; there can be at most one, but there could be
227 : : none at all, e.g. when exit is called. */
228 : 76471 : pre_exit = 0;
229 : 152881 : FOR_EACH_EDGE (eg, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
230 : 76410 : if (eg->flags & EDGE_FALLTHRU)
231 : : {
232 : 75144 : basic_block src_bb = eg->src;
233 : 75144 : rtx_insn *last_insn;
234 : 75144 : rtx ret_reg;
235 : :
236 : 75144 : gcc_assert (!pre_exit);
237 : : /* If this function returns a value at the end, we have to
238 : : insert the final mode switch before the return value copy
239 : : to its hard register.
240 : :
241 : : x86 targets use mode-switching infrastructure to
242 : : conditionally insert vzeroupper instruction at the exit
243 : : from the function where there is no need to switch the
244 : : mode before the return value copy. The vzeroupper insertion
245 : : pass runs after reload, so use !reload_completed as a stand-in
246 : : for x86 to skip the search for the return value copy insn.
247 : :
248 : : N.b.: the code below assumes that the return copy insn
249 : : immediately precedes its corresponding use insn. This
250 : : assumption does not hold after reload, since sched1 pass
251 : : can schedule the return copy insn away from its
252 : : corresponding use insn. */
253 : 75144 : if (!reload_completed
254 : 1109 : && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) == 1
255 : 1091 : && NONJUMP_INSN_P ((last_insn = BB_END (src_bb)))
256 : 942 : && GET_CODE (PATTERN (last_insn)) == USE
257 : 75982 : && GET_CODE ((ret_reg = XEXP (PATTERN (last_insn), 0))) == REG)
258 : : {
259 : 838 : auto_bitmap live;
260 : 838 : df_simulate_initialize_backwards (src_bb, live);
261 : :
262 : 838 : int ret_start = REGNO (ret_reg);
263 : 838 : int nregs = REG_NREGS (ret_reg);
264 : 838 : int ret_end = ret_start + nregs;
265 : 838 : bool short_block = false;
266 : 838 : bool multi_reg_return = false;
267 : 838 : bool forced_late_switch = false;
268 : 838 : rtx_insn *before_return_copy;
269 : :
270 : 838 : df_simulate_one_insn_backwards (src_bb, last_insn, live);
271 : :
272 : 933 : do
273 : : {
274 : 933 : rtx_insn *return_copy = PREV_INSN (last_insn);
275 : 933 : rtx return_copy_pat, copy_reg;
276 : 933 : int copy_start, copy_num;
277 : 933 : int j;
278 : :
279 : 933 : df_simulate_one_insn_backwards (src_bb, return_copy, live);
280 : :
281 : 933 : if (NONDEBUG_INSN_P (return_copy))
282 : : {
283 : : /* When using SJLJ exceptions, the call to the
284 : : unregister function is inserted between the
285 : : clobber of the return value and the copy.
286 : : We do not want to split the block before this
287 : : or any other call; if we have not found the
288 : : copy yet, the copy must have been deleted. */
289 : 933 : if (CALL_P (return_copy))
290 : : {
291 : : short_block = true;
292 : 0 : break;
293 : : }
294 : 933 : return_copy_pat = PATTERN (return_copy);
295 : 933 : switch (GET_CODE (return_copy_pat))
296 : : {
297 : 0 : case USE:
298 : : /* Skip USEs of multiple return registers.
299 : : __builtin_apply pattern is also handled here. */
300 : 0 : if (GET_CODE (XEXP (return_copy_pat, 0)) == REG
301 : 0 : && (targetm.calls.function_value_regno_p
302 : 0 : (REGNO (XEXP (return_copy_pat, 0)))))
303 : : {
304 : 0 : multi_reg_return = true;
305 : 0 : last_insn = return_copy;
306 : 95 : continue;
307 : : }
308 : : break;
309 : :
310 : 0 : case ASM_OPERANDS:
311 : : /* Skip barrier insns. */
312 : 0 : if (!MEM_VOLATILE_P (return_copy_pat))
313 : : break;
314 : :
315 : : /* Fall through. */
316 : :
317 : 95 : case ASM_INPUT:
318 : 95 : case UNSPEC_VOLATILE:
319 : 95 : last_insn = return_copy;
320 : 95 : continue;
321 : :
322 : : default:
323 : : break;
324 : 95 : }
325 : :
326 : : /* If the return register is not (in its entirety)
327 : : likely spilled, the return copy might be
328 : : partially or completely optimized away. */
329 : 838 : return_copy_pat = single_set (return_copy);
330 : 838 : if (!return_copy_pat)
331 : : {
332 : 0 : return_copy_pat = PATTERN (return_copy);
333 : 0 : if (GET_CODE (return_copy_pat) != CLOBBER)
334 : : break;
335 : 0 : else if (!optimize)
336 : : {
337 : : /* This might be (clobber (reg [<result>]))
338 : : when not optimizing. Then check if
339 : : the previous insn is the clobber for
340 : : the return register. */
341 : 0 : copy_reg = SET_DEST (return_copy_pat);
342 : 0 : if (GET_CODE (copy_reg) == REG
343 : 0 : && !HARD_REGISTER_NUM_P (REGNO (copy_reg)))
344 : : {
345 : 0 : if (INSN_P (PREV_INSN (return_copy)))
346 : : {
347 : 0 : return_copy = PREV_INSN (return_copy);
348 : 0 : return_copy_pat = PATTERN (return_copy);
349 : 0 : if (GET_CODE (return_copy_pat) != CLOBBER)
350 : : break;
351 : : }
352 : : }
353 : : }
354 : : }
355 : 838 : copy_reg = SET_DEST (return_copy_pat);
356 : 838 : if (GET_CODE (copy_reg) == REG)
357 : 838 : copy_start = REGNO (copy_reg);
358 : 0 : else if (GET_CODE (copy_reg) == SUBREG
359 : 0 : && GET_CODE (SUBREG_REG (copy_reg)) == REG)
360 : 0 : copy_start = REGNO (SUBREG_REG (copy_reg));
361 : : else
362 : : {
363 : : /* When control reaches end of non-void function,
364 : : there are no return copy insns at all. This
365 : : avoids an ice on that invalid function. */
366 : 0 : if (ret_start + nregs == ret_end)
367 : 0 : short_block = true;
368 : : break;
369 : : }
370 : 838 : if (!targetm.calls.function_value_regno_p (copy_start))
371 : : copy_num = 0;
372 : : else
373 : 838 : copy_num = hard_regno_nregs (copy_start,
374 : 838 : GET_MODE (copy_reg));
375 : :
376 : : /* If the return register is not likely spilled, - as is
377 : : the case for floating point on SH4 - then it might
378 : : be set by an arithmetic operation that needs a
379 : : different mode than the exit block. */
380 : 838 : HARD_REG_SET hard_regs_live;
381 : 1676 : REG_SET_TO_HARD_REG_SET (hard_regs_live, live);
382 : 1690 : for (j = n_entities - 1; j >= 0; j--)
383 : : {
384 : 852 : int e = entity_map[j];
385 : 852 : int mode =
386 : 852 : targetm.mode_switching.needed (e, return_copy,
387 : : hard_regs_live);
388 : :
389 : 852 : if (mode != num_modes[e]
390 : 852 : && mode != targetm.mode_switching.exit (e))
391 : : break;
392 : : }
393 : 838 : if (j >= 0)
394 : : {
395 : : /* __builtin_return emits a sequence of loads to all
396 : : return registers. One of them might require
397 : : another mode than MODE_EXIT, even if it is
398 : : unrelated to the return value, so we want to put
399 : : the final mode switch after it. */
400 : 0 : if (multi_reg_return
401 : 0 : && targetm.calls.function_value_regno_p
402 : 0 : (copy_start))
403 : : forced_late_switch = true;
404 : :
405 : : /* For the SH4, floating point loads depend on fpscr,
406 : : thus we might need to put the final mode switch
407 : : after the return value copy. That is still OK,
408 : : because a floating point return value does not
409 : : conflict with address reloads. */
410 : 0 : if (copy_start >= ret_start
411 : 0 : && copy_start + copy_num <= ret_end
412 : 0 : && GET_CODE (return_copy_pat) == SET
413 : 0 : && OBJECT_P (SET_SRC (return_copy_pat)))
414 : 0 : forced_late_switch = true;
415 : : break;
416 : : }
417 : 838 : if (copy_num == 0)
418 : : {
419 : 0 : last_insn = return_copy;
420 : 0 : continue;
421 : : }
422 : :
423 : 838 : if (copy_start >= ret_start
424 : 838 : && copy_start + copy_num <= ret_end)
425 : 838 : nregs -= copy_num;
426 : 0 : else if (!multi_reg_return
427 : 0 : || !targetm.calls.function_value_regno_p
428 : 0 : (copy_start))
429 : : break;
430 : 838 : last_insn = return_copy;
431 : : }
432 : : /* ??? Exception handling can lead to the return value
433 : : copy being already separated from the return value use,
434 : : as in unwind-dw2.c .
435 : : Similarly, conditionally returning without a value,
436 : : and conditionally using builtin_return can lead to an
437 : : isolated use. */
438 : 838 : if (return_copy == BB_HEAD (src_bb))
439 : : {
440 : : short_block = true;
441 : : break;
442 : : }
443 : : last_insn = return_copy;
444 : : }
445 : 933 : while (nregs);
446 : :
447 : : /* If we didn't see a full return value copy, verify that there
448 : : is a plausible reason for this. If some, but not all of the
449 : : return register is likely spilled, we can expect that there
450 : : is a copy for the likely spilled part. */
451 : 838 : gcc_assert (!nregs
452 : : || forced_late_switch
453 : : || short_block
454 : : || !(targetm.class_likely_spilled_p
455 : : (REGNO_REG_CLASS (ret_start)))
456 : : || nregs != REG_NREGS (ret_reg)
457 : : /* For multi-hard-register floating point
458 : : values, sometimes the likely-spilled part
459 : : is ordinarily copied first, then the other
460 : : part is set with an arithmetic operation.
461 : : This doesn't actually cause reload
462 : : failures, so let it pass. */
463 : : || (GET_MODE_CLASS (GET_MODE (ret_reg)) != MODE_INT
464 : : && nregs != 1));
465 : :
466 : 838 : if (!NOTE_INSN_BASIC_BLOCK_P (last_insn))
467 : : {
468 : 838 : before_return_copy
469 : 838 : = emit_note_before (NOTE_INSN_DELETED, last_insn);
470 : : /* Instructions preceding LAST_INSN in the same block might
471 : : require a different mode than MODE_EXIT, so if we might
472 : : have such instructions, keep them in a separate block
473 : : from pre_exit. */
474 : 1676 : src_bb = split_block (src_bb,
475 : 838 : PREV_INSN (before_return_copy))->dest;
476 : : }
477 : : else
478 : : before_return_copy = last_insn;
479 : 838 : pre_exit = split_block (src_bb, before_return_copy)->src;
480 : 838 : }
481 : : else
482 : : {
483 : 74306 : pre_exit = split_edge (eg);
484 : : }
485 : : }
486 : :
487 : 76471 : return pre_exit;
488 : : }
489 : :
490 : : /* Return the confluence of modes MODE1 and MODE2 for entity ENTITY,
491 : : using NO_MODE to represent an unknown mode if nothing more precise
492 : : is available. */
493 : :
494 : : int
495 : 0 : mode_confluence (int entity, int mode1, int mode2, int no_mode)
496 : : {
497 : 0 : if (mode1 == mode2)
498 : : return mode1;
499 : :
500 : 0 : if (mode1 != no_mode
501 : 0 : && mode2 != no_mode
502 : 0 : && targetm.mode_switching.confluence)
503 : 0 : return targetm.mode_switching.confluence (entity, mode1, mode2);
504 : :
505 : : return no_mode;
506 : : }
507 : :
508 : : /* Information for the dataflow problems below. */
509 : : struct
510 : : {
511 : : /* Information about each basic block, indexed by block id. */
512 : : struct bb_info *bb_info;
513 : :
514 : : /* A bitmap of blocks for which the current entity is transparent. */
515 : : sbitmap transp;
516 : :
517 : : /* The entity that we're processing. */
518 : : int entity;
519 : :
520 : : /* The number of modes defined for the entity, and thus the identifier
521 : : of the "don't know" mode. */
522 : : int no_mode;
523 : : } confluence_info;
524 : :
525 : : /* Propagate information about any mode change on edge E to the
526 : : destination block's mode_in. Return true if something changed.
527 : :
528 : : The mode_in and mode_out fields use no_mode + 1 to mean "not yet set". */
529 : :
530 : : static bool
531 : 0 : forward_confluence_n (edge e)
532 : : {
533 : : /* The entry and exit blocks have no useful mode information. */
534 : 0 : if (e->src->index == ENTRY_BLOCK || e->dest->index == EXIT_BLOCK)
535 : : return false;
536 : :
537 : : /* We don't control mode changes across abnormal edges. */
538 : 0 : if (e->flags & EDGE_ABNORMAL)
539 : : return false;
540 : :
541 : : /* E->aux is nonzero if we have computed the LCM problem and scheduled
542 : : E to change the mode to E->aux - 1. Otherwise model the change
543 : : from the source to the destination. */
544 : 0 : struct bb_info *bb_info = confluence_info.bb_info;
545 : 0 : int no_mode = confluence_info.no_mode;
546 : 0 : int src_mode = bb_info[e->src->index].mode_out;
547 : 0 : if (e->aux)
548 : 0 : src_mode = (int) (intptr_t) e->aux - 1;
549 : 0 : if (src_mode == no_mode + 1)
550 : : return false;
551 : :
552 : 0 : int dest_mode = bb_info[e->dest->index].mode_in;
553 : 0 : if (dest_mode == no_mode + 1)
554 : : {
555 : 0 : bb_info[e->dest->index].mode_in = src_mode;
556 : 0 : return true;
557 : : }
558 : :
559 : 0 : int entity = confluence_info.entity;
560 : 0 : int new_mode = mode_confluence (entity, src_mode, dest_mode, no_mode);
561 : 0 : if (dest_mode == new_mode)
562 : : return false;
563 : :
564 : 0 : bb_info[e->dest->index].mode_in = new_mode;
565 : 0 : return true;
566 : : }
567 : :
568 : : /* Update block BB_INDEX's mode_out based on its mode_in. Return true if
569 : : something changed. */
570 : :
571 : : static bool
572 : 0 : forward_transfer (int bb_index)
573 : : {
574 : : /* The entry and exit blocks have no useful mode information. */
575 : 0 : if (bb_index == ENTRY_BLOCK || bb_index == EXIT_BLOCK)
576 : : return false;
577 : :
578 : : /* Only propagate through a block if the entity is transparent. */
579 : 0 : struct bb_info *bb_info = confluence_info.bb_info;
580 : 0 : if (bb_info[bb_index].computing != confluence_info.no_mode
581 : 0 : || bb_info[bb_index].mode_out == bb_info[bb_index].mode_in)
582 : : return false;
583 : :
584 : 0 : bb_info[bb_index].mode_out = bb_info[bb_index].mode_in;
585 : 0 : return true;
586 : : }
587 : :
588 : : /* A backwards confluence function. Update the bb_info single_succ
589 : : field for E's source block, based on changes to E's destination block.
590 : : At the end of the dataflow problem, single_succ is the single mode
591 : : that all successors require (directly or indirectly), or no_mode
592 : : if there are conflicting requirements.
593 : :
594 : : Initially, a value of no_mode + 1 means "don't know". */
595 : :
596 : : static bool
597 : 0 : single_succ_confluence_n (edge e)
598 : : {
599 : : /* The entry block has no associated mode information. */
600 : 0 : if (e->src->index == ENTRY_BLOCK)
601 : : return false;
602 : :
603 : : /* We don't control mode changes across abnormal edges. */
604 : 0 : if (e->flags & EDGE_ABNORMAL)
605 : : return false;
606 : :
607 : : /* Do nothing if we've already found a conflict. */
608 : 0 : struct bb_info *bb_info = confluence_info.bb_info;
609 : 0 : int no_mode = confluence_info.no_mode;
610 : 0 : int src_mode = bb_info[e->src->index].single_succ;
611 : 0 : if (src_mode == no_mode)
612 : : return false;
613 : :
614 : : /* Work out what mode the destination block (or its successors) require. */
615 : 0 : int dest_mode;
616 : 0 : if (e->dest->index == EXIT_BLOCK)
617 : : dest_mode = no_mode;
618 : 0 : else if (bitmap_bit_p (confluence_info.transp, e->dest->index))
619 : 0 : dest_mode = bb_info[e->dest->index].single_succ;
620 : : else
621 : 0 : dest_mode = bb_info[e->dest->index].seginfo->mode;
622 : :
623 : : /* Do nothing if the destination block has no new information. */
624 : 0 : if (dest_mode == no_mode + 1 || dest_mode == src_mode)
625 : : return false;
626 : :
627 : : /* Detect conflicting modes. */
628 : 0 : if (src_mode != no_mode + 1)
629 : 0 : dest_mode = no_mode;
630 : :
631 : 0 : bb_info[e->src->index].single_succ = dest_mode;
632 : 0 : return true;
633 : : }
634 : :
635 : : /* A backward transfer function for computing the bb_info single_succ
636 : : fields, as described above single_succ_confluence. */
637 : :
638 : : static bool
639 : 0 : single_succ_transfer (int bb_index)
640 : : {
641 : : /* We don't have any field to transfer to. Assume that, after the
642 : : first iteration, we are only called if single_succ has changed.
643 : : We should then process incoming edges if the entity is transparent. */
644 : 0 : return bitmap_bit_p (confluence_info.transp, bb_index);
645 : : }
646 : :
647 : : /* Check whether the target wants to back-propagate a mode change across
648 : : edge E, and update the source block's computed mode if so. Return true
649 : : if something changed. */
650 : :
651 : : static bool
652 : 0 : backprop_confluence_n (edge e)
653 : : {
654 : : /* The entry and exit blocks have no useful mode information. */
655 : 0 : if (e->src->index == ENTRY_BLOCK || e->dest->index == EXIT_BLOCK)
656 : : return false;
657 : :
658 : : /* We don't control mode changes across abnormal edges. */
659 : 0 : if (e->flags & EDGE_ABNORMAL)
660 : : return false;
661 : :
662 : : /* We can only require a new mode in the source block if the entity
663 : : was originally transparent there. */
664 : 0 : if (!bitmap_bit_p (confluence_info.transp, e->src->index))
665 : : return false;
666 : :
667 : : /* Exit now if there is no required mode, or if all paths into the
668 : : source block leave the entity in the required mode. */
669 : 0 : struct bb_info *bb_info = confluence_info.bb_info;
670 : 0 : int no_mode = confluence_info.no_mode;
671 : 0 : int src_mode = bb_info[e->src->index].mode_out;
672 : 0 : int dest_mode = bb_info[e->dest->index].mode_in;
673 : 0 : if (dest_mode == no_mode || src_mode == dest_mode)
674 : : return false;
675 : :
676 : : /* See what the target thinks about this transition. */
677 : 0 : int entity = confluence_info.entity;
678 : 0 : int new_mode = targetm.mode_switching.backprop (entity, src_mode,
679 : : dest_mode);
680 : 0 : if (new_mode == no_mode)
681 : : return false;
682 : :
683 : : /* The target doesn't like the current transition, but would be happy
684 : : with a transition from NEW_MODE.
685 : :
686 : : If we force the source block to use NEW_MODE, we might introduce a
687 : : double transition on at least one path through the function (one to
688 : : NEW_MODE and then one to DEST_MODE). Therefore, if all destination
689 : : blocks require the same mode, it is usually better to bring that
690 : : mode requirement forward.
691 : :
692 : : If that isn't possible, merge the preference for this edge with
693 : : the preferences for other edges. no_mode + 1 indicates that there
694 : : was no previous preference. */
695 : 0 : int old_mode = bb_info[e->src->index].computing;
696 : 0 : if (bb_info[e->src->index].single_succ != no_mode)
697 : : new_mode = bb_info[e->src->index].single_succ;
698 : 0 : else if (old_mode != no_mode + 1)
699 : 0 : new_mode = mode_confluence (entity, old_mode, new_mode, no_mode);
700 : :
701 : 0 : if (old_mode == new_mode)
702 : : return false;
703 : :
704 : 0 : bb_info[e->src->index].computing = new_mode;
705 : 0 : return true;
706 : : }
707 : :
708 : : /* If the current entity was originally transparent in block BB_INDEX,
709 : : update the incoming mode to match the outgoing mode. Register a mode
710 : : change if the entity is no longer transparent.
711 : :
712 : : Also, as an on-the-fly optimization, check whether the entity was
713 : : originally transparent in BB_INDEX and if all successor blocks require
714 : : the same mode. If so, anticipate the mode change in BB_INDEX if
715 : : doing it on the incoming edges would require no more mode changes than
716 : : doing it on the outgoing edges. The aim is to reduce the total number
717 : : of mode changes emitted for the function (and thus reduce code size and
718 : : cfg complexity) without increasing the number of mode changes on any
719 : : given path through the function. A typical case where it helps is:
720 : :
721 : : T
722 : : / \
723 : : T M
724 : : \ /
725 : : M
726 : :
727 : : where the entity is transparent in the T blocks and is required to have
728 : : mode M in the M blocks. If there are no redundancies leading up to this,
729 : : there will be two mutually-exclusive changes to mode M, one on each of
730 : : the T->M edges. The optimization instead converts it to:
731 : :
732 : : T T M
733 : : / \ / \ / \
734 : : T M -> M M -> M M
735 : : \ / \ / \ /
736 : : M M M
737 : :
738 : : which creates a single transition to M for both paths through the diamond.
739 : :
740 : : Return true if something changed. */
741 : :
742 : : static bool
743 : 0 : backprop_transfer (int bb_index)
744 : : {
745 : : /* The entry and exit blocks have no useful mode information. */
746 : 0 : if (bb_index == ENTRY_BLOCK || bb_index == EXIT_BLOCK)
747 : : return false;
748 : :
749 : : /* We can only require a new mode if the entity was previously
750 : : transparent. */
751 : 0 : if (!bitmap_bit_p (confluence_info.transp, bb_index))
752 : : return false;
753 : :
754 : 0 : struct bb_info *bb_info = confluence_info.bb_info;
755 : 0 : basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index);
756 : 0 : int no_mode = confluence_info.no_mode;
757 : 0 : int mode_in = bb_info[bb_index].mode_in;
758 : 0 : int mode_out = bb_info[bb_index].computing;
759 : 0 : if (mode_out == no_mode + 1)
760 : : {
761 : : /* The entity is still transparent for this block. See whether
762 : : all successor blocks need the same mode, either directly or
763 : : indirectly. */
764 : 0 : mode_out = bb_info[bb_index].single_succ;
765 : 0 : if (mode_out == no_mode)
766 : : return false;
767 : :
768 : : /* Get a minimum bound on the number of transitions that would be
769 : : removed if BB itself required MODE_OUT. */
770 : 0 : unsigned int moved = 0;
771 : 0 : for (edge e : bb->succs)
772 : 0 : if (e->dest->index != EXIT_BLOCK
773 : 0 : && mode_out == bb_info[e->dest->index].seginfo->mode)
774 : 0 : moved += 1;
775 : :
776 : : /* See whether making the mode change on all incoming edges would
777 : : be no worse than making it on MOVED outgoing edges. */
778 : 0 : if (moved < EDGE_COUNT (bb->preds))
779 : : return false;
780 : :
781 : 0 : bb_info[bb_index].mode_out = mode_out;
782 : 0 : bb_info[bb_index].computing = mode_out;
783 : : }
784 : 0 : else if (mode_out == mode_in)
785 : : return false;
786 : :
787 : 0 : bb_info[bb_index].mode_in = mode_out;
788 : 0 : bb_info[bb_index].seginfo->mode = mode_out;
789 : 0 : return true;
790 : : }
791 : :
792 : : /* Find all insns that need a particular mode setting, and insert the
793 : : necessary mode switches. Return true if we did work. */
794 : :
795 : : static int
796 : 1511061 : optimize_mode_switching (void)
797 : : {
798 : 1511061 : int e;
799 : 1511061 : basic_block bb;
800 : 1511061 : bool need_commit = false;
801 : 1511061 : static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
802 : : #define N_ENTITIES ARRAY_SIZE (num_modes)
803 : 1511061 : int entity_map[N_ENTITIES] = {};
804 : 1511061 : struct bb_info *bb_info[N_ENTITIES] = {};
805 : 1511061 : int i, j;
806 : 1511061 : int n_entities = 0;
807 : 1511061 : int max_num_modes = 0;
808 : 1511061 : bool emitted ATTRIBUTE_UNUSED = false;
809 : 1511061 : basic_block post_entry = 0;
810 : 1511061 : basic_block pre_exit = 0;
811 : 1511061 : struct edge_list *edge_list = 0;
812 : :
813 : : /* These bitmaps are used for the LCM algorithm. */
814 : 1511061 : sbitmap *kill, *del, *insert, *antic, *transp, *comp;
815 : 1511061 : sbitmap *avin, *avout;
816 : :
817 : 10577427 : for (e = N_ENTITIES - 1; e >= 0; e--)
818 : 9066366 : if (OPTIMIZE_MODE_SWITCHING (e))
819 : : {
820 : 76487 : int entry_exit_extra = 0;
821 : :
822 : : /* Create the list of segments within each basic block.
823 : : If NORMAL_MODE is defined, allow for two extra
824 : : blocks split from the entry and exit block. */
825 : 76487 : if (targetm.mode_switching.entry && targetm.mode_switching.exit)
826 : 76487 : entry_exit_extra = 3;
827 : :
828 : 76487 : bb_info[n_entities]
829 : 76487 : = XCNEWVEC (struct bb_info,
830 : : last_basic_block_for_fn (cfun) + entry_exit_extra);
831 : 76487 : entity_map[n_entities++] = e;
832 : 76487 : if (num_modes[e] > max_num_modes)
833 : 76471 : max_num_modes = num_modes[e];
834 : : }
835 : :
836 : 1511061 : if (! n_entities)
837 : : return 0;
838 : :
839 : : /* Make sure if MODE_ENTRY is defined MODE_EXIT is defined. */
840 : 76471 : gcc_assert ((targetm.mode_switching.entry && targetm.mode_switching.exit)
841 : : || (!targetm.mode_switching.entry
842 : : && !targetm.mode_switching.exit));
843 : :
844 : 76471 : if (targetm.mode_switching.entry && targetm.mode_switching.exit)
845 : : {
846 : : /* Split the edge from the entry block, so that we can note that
847 : : there NORMAL_MODE is supplied. */
848 : 76471 : post_entry = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
849 : 76471 : pre_exit = create_pre_exit (n_entities, entity_map, num_modes);
850 : : }
851 : :
852 : 76471 : df_note_add_problem ();
853 : 76471 : df_analyze ();
854 : :
855 : : /* Create the bitmap vectors. */
856 : 152942 : antic = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
857 : 76471 : n_entities * max_num_modes);
858 : 152942 : transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
859 : 76471 : n_entities * max_num_modes);
860 : 152942 : comp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
861 : 76471 : n_entities * max_num_modes);
862 : 152942 : avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
863 : 76471 : n_entities * max_num_modes);
864 : 152942 : avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
865 : 76471 : n_entities * max_num_modes);
866 : 152942 : kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
867 : 76471 : n_entities * max_num_modes);
868 : :
869 : 76471 : bitmap_vector_ones (transp, last_basic_block_for_fn (cfun));
870 : 76471 : bitmap_vector_clear (antic, last_basic_block_for_fn (cfun));
871 : 76471 : bitmap_vector_clear (comp, last_basic_block_for_fn (cfun));
872 : :
873 : 76471 : auto_sbitmap transp_all (last_basic_block_for_fn (cfun));
874 : :
875 : 76471 : auto_bitmap blocks;
876 : :
877 : : /* Forward-propagate mode information through blocks where the entity
878 : : is transparent, so that mode_in describes the mode on entry to each
879 : : block and mode_out describes the mode on exit from each block. */
880 : 76471 : auto forwprop_mode_info = [&](struct bb_info *info,
881 : : int entity, int no_mode)
882 : : {
883 : : /* Use no_mode + 1 to mean "not yet set". */
884 : 0 : FOR_EACH_BB_FN (bb, cfun)
885 : : {
886 : 0 : if (bb_has_abnormal_pred (bb))
887 : 0 : info[bb->index].mode_in = info[bb->index].seginfo->mode;
888 : : else
889 : 0 : info[bb->index].mode_in = no_mode + 1;
890 : 0 : if (info[bb->index].computing != no_mode)
891 : 0 : info[bb->index].mode_out = info[bb->index].computing;
892 : : else
893 : 0 : info[bb->index].mode_out = no_mode + 1;
894 : : }
895 : :
896 : 0 : confluence_info.bb_info = info;
897 : 0 : confluence_info.transp = nullptr;
898 : 0 : confluence_info.entity = entity;
899 : 0 : confluence_info.no_mode = no_mode;
900 : :
901 : 0 : bitmap_set_range (blocks, 0, last_basic_block_for_fn (cfun));
902 : 0 : df_simple_dataflow (DF_FORWARD, NULL, NULL, forward_confluence_n,
903 : : forward_transfer, blocks,
904 : : df_get_postorder (DF_FORWARD),
905 : : df_get_n_blocks (DF_FORWARD));
906 : :
907 : 76471 : };
908 : :
909 : 76471 : if (targetm.mode_switching.backprop)
910 : 0 : clear_aux_for_edges ();
911 : :
912 : 152958 : for (j = n_entities - 1; j >= 0; j--)
913 : : {
914 : 76487 : int e = entity_map[j];
915 : 76487 : int no_mode = num_modes[e];
916 : 76487 : struct bb_info *info = bb_info[j];
917 : 76487 : rtx_insn *insn;
918 : :
919 : 76487 : bitmap_ones (transp_all);
920 : :
921 : : /* Determine what the first use (if any) need for a mode of entity E is.
922 : : This will be the mode that is anticipatable for this block.
923 : : Also compute the initial transparency settings. */
924 : 623615 : FOR_EACH_BB_FN (bb, cfun)
925 : : {
926 : 547128 : struct seginfo **tail_ptr = &info[bb->index].seginfo;
927 : 547128 : struct seginfo *ptr;
928 : 547128 : int last_mode = no_mode;
929 : 547128 : bool any_set_required = false;
930 : 547128 : HARD_REG_SET live_now;
931 : :
932 : 547128 : info[bb->index].mode_out = info[bb->index].mode_in = no_mode;
933 : :
934 : 1094256 : REG_SET_TO_HARD_REG_SET (live_now, df_get_live_in (bb));
935 : :
936 : : /* Pretend the mode is clobbered across abnormal edges. */
937 : 547128 : {
938 : 547128 : edge_iterator ei;
939 : 547128 : edge eg;
940 : 1275595 : FOR_EACH_EDGE (eg, ei, bb->preds)
941 : 729154 : if (eg->flags & EDGE_COMPLEX)
942 : : break;
943 : 547128 : if (eg)
944 : : {
945 : 687 : rtx_insn *ins_pos = BB_HEAD (bb);
946 : 687 : if (LABEL_P (ins_pos))
947 : 687 : ins_pos = NEXT_INSN (ins_pos);
948 : 687 : gcc_assert (NOTE_INSN_BASIC_BLOCK_P (ins_pos));
949 : 687 : if (ins_pos != BB_END (bb))
950 : 681 : ins_pos = NEXT_INSN (ins_pos);
951 : 687 : if (bb_has_eh_pred (bb)
952 : 687 : && targetm.mode_switching.eh_handler)
953 : 0 : last_mode = targetm.mode_switching.eh_handler (e);
954 : 687 : ptr = new_seginfo (no_mode, last_mode, ins_pos, live_now);
955 : 687 : add_seginfo (&tail_ptr, ptr);
956 : 687 : bitmap_clear_bit (transp_all, bb->index);
957 : : }
958 : : }
959 : :
960 : 5287066 : FOR_BB_INSNS (bb, insn)
961 : : {
962 : 4739938 : if (NONDEBUG_INSN_P (insn))
963 : : {
964 : 2463645 : int mode = targetm.mode_switching.needed (e, insn, live_now);
965 : 2463645 : rtx link;
966 : :
967 : 2463645 : if (mode != no_mode && mode != last_mode)
968 : : {
969 : 102019 : ptr = new_seginfo (last_mode, mode, insn, live_now);
970 : 102019 : add_seginfo (&tail_ptr, ptr);
971 : 102019 : bitmap_clear_bit (transp_all, bb->index);
972 : 102019 : any_set_required = true;
973 : 102019 : last_mode = mode;
974 : : }
975 : :
976 : : /* Update LIVE_NOW. */
977 : 4632724 : for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
978 : 2169079 : if (REG_NOTE_KIND (link) == REG_DEAD)
979 : 1217147 : reg_dies (XEXP (link, 0), &live_now);
980 : :
981 : 2463645 : note_stores (insn, reg_becomes_live, &live_now);
982 : 4632724 : for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
983 : 2169079 : if (REG_NOTE_KIND (link) == REG_UNUSED)
984 : 374165 : reg_dies (XEXP (link, 0), &live_now);
985 : :
986 : 2463645 : if (targetm.mode_switching.after)
987 : 2463645 : last_mode = targetm.mode_switching.after (e, last_mode,
988 : : insn, live_now);
989 : : }
990 : : }
991 : :
992 : 547128 : info[bb->index].computing = last_mode;
993 : : /* Check for blocks without ANY mode requirements.
994 : : N.B. because of MODE_AFTER, last_mode might still
995 : : be different from no_mode, in which case we need to
996 : : mark the block as nontransparent. */
997 : 547128 : if (!any_set_required)
998 : : {
999 : 453218 : ptr = new_seginfo (last_mode, no_mode, BB_END (bb), live_now);
1000 : 453218 : add_seginfo (&tail_ptr, ptr);
1001 : 453218 : if (last_mode != no_mode)
1002 : 11 : bitmap_clear_bit (transp_all, bb->index);
1003 : : }
1004 : : }
1005 : 76487 : if (targetm.mode_switching.entry && targetm.mode_switching.exit)
1006 : : {
1007 : 76487 : info[post_entry->index].mode_out =
1008 : 76487 : info[post_entry->index].mode_in = no_mode;
1009 : :
1010 : 76487 : int mode = targetm.mode_switching.entry (e);
1011 : 76487 : if (mode != no_mode)
1012 : : {
1013 : : /* Insert a fake computing definition of MODE into entry
1014 : : blocks which compute no mode. This represents the mode on
1015 : : entry. */
1016 : 75221 : info[post_entry->index].computing = mode;
1017 : 75221 : bitmap_clear_bit (transp_all, post_entry->index);
1018 : : }
1019 : :
1020 : 76487 : if (pre_exit)
1021 : : {
1022 : 75160 : info[pre_exit->index].mode_out =
1023 : 75160 : info[pre_exit->index].mode_in = no_mode;
1024 : :
1025 : 75160 : int mode = targetm.mode_switching.exit (e);
1026 : 75160 : if (mode != no_mode)
1027 : : {
1028 : 74035 : info[pre_exit->index].seginfo->mode = mode;
1029 : 74035 : bitmap_clear_bit (transp_all, pre_exit->index);
1030 : : }
1031 : : }
1032 : : }
1033 : :
1034 : : /* If the target requests it, back-propagate selected mode requirements
1035 : : through transparent blocks. */
1036 : 76487 : if (targetm.mode_switching.backprop)
1037 : : {
1038 : : /* First work out the mode on entry to and exit from each block. */
1039 : 0 : forwprop_mode_info (info, e, no_mode);
1040 : :
1041 : : /* Compute the single_succ fields, as described above
1042 : : single_succ_confluence. */
1043 : 0 : FOR_EACH_BB_FN (bb, cfun)
1044 : 0 : info[bb->index].single_succ = no_mode + 1;
1045 : :
1046 : 0 : confluence_info.transp = transp_all;
1047 : 0 : bitmap_set_range (blocks, 0, last_basic_block_for_fn (cfun));
1048 : 0 : df_simple_dataflow (DF_BACKWARD, NULL, NULL,
1049 : : single_succ_confluence_n,
1050 : : single_succ_transfer, blocks,
1051 : : df_get_postorder (DF_BACKWARD),
1052 : : df_get_n_blocks (DF_BACKWARD));
1053 : :
1054 : 0 : FOR_EACH_BB_FN (bb, cfun)
1055 : : {
1056 : : /* Repurpose mode_in as the first mode required by the block,
1057 : : or the output mode if none. */
1058 : 0 : if (info[bb->index].seginfo->mode != no_mode)
1059 : 0 : info[bb->index].mode_in = info[bb->index].seginfo->mode;
1060 : :
1061 : : /* In transparent blocks, use computing == no_mode + 1
1062 : : to indicate that no propagation has taken place. */
1063 : 0 : if (info[bb->index].computing == no_mode)
1064 : 0 : info[bb->index].computing = no_mode + 1;
1065 : : }
1066 : :
1067 : 0 : bitmap_set_range (blocks, 0, last_basic_block_for_fn (cfun));
1068 : 0 : df_simple_dataflow (DF_BACKWARD, NULL, NULL, backprop_confluence_n,
1069 : : backprop_transfer, blocks,
1070 : : df_get_postorder (DF_BACKWARD),
1071 : : df_get_n_blocks (DF_BACKWARD));
1072 : :
1073 : : /* Any block that now computes a mode is no longer transparent. */
1074 : 0 : FOR_EACH_BB_FN (bb, cfun)
1075 : 0 : if (info[bb->index].computing == no_mode + 1)
1076 : 0 : info[bb->index].computing = no_mode;
1077 : 0 : else if (info[bb->index].computing != no_mode)
1078 : 0 : bitmap_clear_bit (transp_all, bb->index);
1079 : : }
1080 : :
1081 : : /* Set the anticipatable and computing arrays. */
1082 : 232787 : for (i = 0; i < no_mode; i++)
1083 : : {
1084 : 156300 : int m = targetm.mode_switching.priority (entity_map[j], i);
1085 : :
1086 : 1510944 : FOR_EACH_BB_FN (bb, cfun)
1087 : : {
1088 : 1354644 : if (!bitmap_bit_p (transp_all, bb->index))
1089 : 548078 : clear_mode_bit (transp[bb->index], j, m);
1090 : :
1091 : 1354644 : if (info[bb->index].seginfo->mode == m)
1092 : 167639 : set_mode_bit (antic[bb->index], j, m);
1093 : :
1094 : 1354644 : if (info[bb->index].computing == m)
1095 : 167193 : set_mode_bit (comp[bb->index], j, m);
1096 : : }
1097 : : }
1098 : : }
1099 : :
1100 : : /* Calculate the optimal locations for the
1101 : : placement mode switches to modes with priority I. */
1102 : :
1103 : 623207 : FOR_EACH_BB_FN (bb, cfun)
1104 : 546736 : bitmap_not (kill[bb->index], transp[bb->index]);
1105 : :
1106 : 76471 : edge_list = pre_edge_lcm_avs (n_entities * max_num_modes, transp, comp, antic,
1107 : : kill, avin, avout, &insert, &del);
1108 : :
1109 : 76471 : auto_sbitmap jumping_blocks (last_basic_block_for_fn (cfun));
1110 : 76471 : bitmap_clear (jumping_blocks);
1111 : 152958 : for (j = n_entities - 1; j >= 0; j--)
1112 : : {
1113 : 76487 : int no_mode = num_modes[entity_map[j]];
1114 : 76487 : struct bb_info *info = bb_info[j];
1115 : :
1116 : : /* Insert all mode sets that have been inserted by lcm. */
1117 : :
1118 : 884359 : for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
1119 : : {
1120 : 807872 : edge eg = INDEX_EDGE (edge_list, ed);
1121 : :
1122 : 807872 : eg->aux = (void *) (intptr_t) 0;
1123 : :
1124 : 2836439 : for (i = 0; i < no_mode; i++)
1125 : : {
1126 : 2037876 : int m = targetm.mode_switching.priority (entity_map[j], i);
1127 : 2037876 : if (mode_bit_p (insert[ed], j, m))
1128 : : {
1129 : 9309 : eg->aux = (void *) (intptr_t) (m + 1);
1130 : 9309 : break;
1131 : : }
1132 : : }
1133 : : }
1134 : :
1135 : : /* mode_in and mode_out can be calculated directly from avin and
1136 : : avout if all the modes are mutually exclusive. Use the target-
1137 : : provided confluence function otherwise. */
1138 : 76487 : if (targetm.mode_switching.confluence)
1139 : 0 : forwprop_mode_info (info, entity_map[j], no_mode);
1140 : :
1141 : 623615 : FOR_EACH_BB_FN (bb, cfun)
1142 : : {
1143 : 1641384 : auto modes_confluence = [&](sbitmap *av)
1144 : : {
1145 : 2325315 : for (int i = 0; i < no_mode; ++i)
1146 : 2106489 : if (mode_bit_p (av[bb->index], j, i))
1147 : : {
1148 : 1478229 : for (int i2 = i + 1; i2 < no_mode; ++i2)
1149 : 602799 : if (mode_bit_p (av[bb->index], j, i2))
1150 : : return no_mode;
1151 : : return i;
1152 : : }
1153 : : return no_mode;
1154 : 547128 : };
1155 : :
1156 : : /* intialize mode in/out availability for bb. */
1157 : 547128 : if (!targetm.mode_switching.confluence)
1158 : : {
1159 : 547128 : info[bb->index].mode_out = modes_confluence (avout);
1160 : 547128 : info[bb->index].mode_in = modes_confluence (avin);
1161 : : }
1162 : :
1163 : 1901772 : for (i = 0; i < no_mode; i++)
1164 : 1354644 : if (mode_bit_p (del[bb->index], j, i))
1165 : 139852 : info[bb->index].seginfo->mode = no_mode;
1166 : :
1167 : : /* See whether the target can perform the first transition.
1168 : : If not, push it onto the incoming edges. The earlier backprop
1169 : : pass should ensure that the resulting transitions are valid. */
1170 : 547128 : if (targetm.mode_switching.backprop)
1171 : : {
1172 : 0 : int from_mode = info[bb->index].mode_in;
1173 : 0 : int to_mode = info[bb->index].seginfo->mode;
1174 : 0 : if (targetm.mode_switching.backprop (entity_map[j], from_mode,
1175 : 0 : to_mode) != no_mode)
1176 : : {
1177 : 0 : for (edge e : bb->preds)
1178 : 0 : e->aux = (void *) (intptr_t) (to_mode + 1);
1179 : 0 : info[bb->index].mode_in = to_mode;
1180 : : }
1181 : : }
1182 : : }
1183 : :
1184 : : /* Now output the remaining mode sets in all the segments. */
1185 : :
1186 : : /* In case there was no mode inserted. the mode information on the edge
1187 : : might not be complete.
1188 : : Update mode info on edges and commit pending mode sets. */
1189 : 76487 : need_commit |= commit_mode_sets (edge_list, entity_map[j], bb_info[j]);
1190 : :
1191 : : /* Reset modes for next entity. */
1192 : 76487 : clear_aux_for_edges ();
1193 : :
1194 : 623615 : FOR_EACH_BB_FN (bb, cfun)
1195 : : {
1196 : 547128 : struct seginfo *ptr, *next;
1197 : 547128 : struct seginfo *first = bb_info[j][bb->index].seginfo;
1198 : :
1199 : 1103052 : for (ptr = first; ptr; ptr = next)
1200 : : {
1201 : 555924 : next = ptr->next;
1202 : 555924 : if (ptr->mode != no_mode)
1203 : : {
1204 : 36202 : rtx_insn *mode_set;
1205 : :
1206 : 36202 : rtl_profile_for_bb (bb);
1207 : 36202 : start_sequence ();
1208 : :
1209 : 27787 : int cur_mode = (ptr == first && ptr->prev_mode == no_mode
1210 : 63989 : ? bb_info[j][bb->index].mode_in
1211 : : : ptr->prev_mode);
1212 : :
1213 : 36202 : targetm.mode_switching.emit (entity_map[j], ptr->mode,
1214 : : cur_mode, ptr->regs_live);
1215 : 36202 : mode_set = get_insns ();
1216 : 36202 : end_sequence ();
1217 : :
1218 : : /* Insert MODE_SET only if it is nonempty. */
1219 : 36202 : if (mode_set != NULL_RTX)
1220 : : {
1221 : 34500 : for (auto insn = mode_set; insn; insn = NEXT_INSN (insn))
1222 : 19519 : if (JUMP_P (insn))
1223 : : {
1224 : 0 : rebuild_jump_labels_chain (mode_set);
1225 : 0 : bitmap_set_bit (jumping_blocks, bb->index);
1226 : 0 : break;
1227 : : }
1228 : 14981 : emitted = true;
1229 : 14981 : if (NOTE_INSN_BASIC_BLOCK_P (ptr->insn_ptr))
1230 : : /* We need to emit the insns in a FIFO-like manner,
1231 : : i.e. the first to be emitted at our insertion
1232 : : point ends up first in the instruction steam.
1233 : : Because we made sure that NOTE_INSN_BASIC_BLOCK is
1234 : : only used for initially empty basic blocks, we
1235 : : can achieve this by appending at the end of
1236 : : the block. */
1237 : 5513 : emit_insn_after
1238 : 5513 : (mode_set, BB_END (NOTE_BASIC_BLOCK (ptr->insn_ptr)));
1239 : : else
1240 : 9468 : emit_insn_before (mode_set, ptr->insn_ptr);
1241 : : }
1242 : :
1243 : 36202 : default_rtl_profile ();
1244 : : }
1245 : :
1246 : 555924 : free (ptr);
1247 : : }
1248 : : }
1249 : :
1250 : 76487 : free (bb_info[j]);
1251 : : }
1252 : :
1253 : 76471 : free_edge_list (edge_list);
1254 : :
1255 : : /* Finished. Free up all the things we've allocated. */
1256 : 76471 : sbitmap_vector_free (del);
1257 : 76471 : sbitmap_vector_free (insert);
1258 : 76471 : sbitmap_vector_free (kill);
1259 : 76471 : sbitmap_vector_free (antic);
1260 : 76471 : sbitmap_vector_free (transp);
1261 : 76471 : sbitmap_vector_free (comp);
1262 : 76471 : sbitmap_vector_free (avin);
1263 : 76471 : sbitmap_vector_free (avout);
1264 : :
1265 : 76471 : gcc_assert (SBITMAP_SIZE ((sbitmap) jumping_blocks)
1266 : : == (unsigned int) last_basic_block_for_fn (cfun));
1267 : 76471 : if (!bitmap_empty_p (jumping_blocks))
1268 : 0 : find_many_sub_basic_blocks (jumping_blocks);
1269 : :
1270 : 76471 : if (need_commit)
1271 : 1207 : commit_edge_insertions ();
1272 : :
1273 : 76471 : if (targetm.mode_switching.entry && targetm.mode_switching.exit)
1274 : : {
1275 : 76471 : free_dominance_info (CDI_DOMINATORS);
1276 : 76471 : cleanup_cfg (CLEANUP_NO_INSN_DEL);
1277 : : }
1278 : 0 : else if (!need_commit && !emitted)
1279 : : return 0;
1280 : :
1281 : : return 1;
1282 : 76471 : }
1283 : :
1284 : : #endif /* OPTIMIZE_MODE_SWITCHING */
1285 : :
1286 : : namespace {
1287 : :
1288 : : const pass_data pass_data_mode_switching =
1289 : : {
1290 : : RTL_PASS, /* type */
1291 : : "mode_sw", /* name */
1292 : : OPTGROUP_NONE, /* optinfo_flags */
1293 : : TV_MODE_SWITCH, /* tv_id */
1294 : : 0, /* properties_required */
1295 : : 0, /* properties_provided */
1296 : : 0, /* properties_destroyed */
1297 : : 0, /* todo_flags_start */
1298 : : TODO_df_finish, /* todo_flags_finish */
1299 : : };
1300 : :
1301 : : class pass_mode_switching : public rtl_opt_pass
1302 : : {
1303 : : public:
1304 : 283157 : pass_mode_switching (gcc::context *ctxt)
1305 : 566314 : : rtl_opt_pass (pass_data_mode_switching, ctxt)
1306 : : {}
1307 : :
1308 : : /* opt_pass methods: */
1309 : : /* The epiphany backend creates a second instance of this pass, so we need
1310 : : a clone method. */
1311 : 0 : opt_pass * clone () final override { return new pass_mode_switching (m_ctxt); }
1312 : 1435849 : bool gate (function *) final override
1313 : : {
1314 : : #ifdef OPTIMIZE_MODE_SWITCHING
1315 : 1435849 : return true;
1316 : : #else
1317 : : return false;
1318 : : #endif
1319 : : }
1320 : :
1321 : 1511061 : unsigned int execute (function *) final override
1322 : : {
1323 : : #ifdef OPTIMIZE_MODE_SWITCHING
1324 : 1511061 : optimize_mode_switching ();
1325 : : #endif /* OPTIMIZE_MODE_SWITCHING */
1326 : 1511061 : return 0;
1327 : : }
1328 : :
1329 : : }; // class pass_mode_switching
1330 : :
1331 : : } // anon namespace
1332 : :
1333 : : rtl_opt_pass *
1334 : 283157 : make_pass_mode_switching (gcc::context *ctxt)
1335 : : {
1336 : 283157 : return new pass_mode_switching (ctxt);
1337 : : }
|