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