1/* CPU mode switching
2 Copyright (C) 1998-2023 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along 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
38/* We want target macros for the mode switching code to be able to refer
39 to instruction attribute values. */
40#include "insn-attr.h"
41
42#ifdef OPTIMIZE_MODE_SWITCHING
43
44/* The algorithm for setting the modes consists of scanning the insn list
45 and finding all the insns which require a specific mode. Each insn gets
46 a unique struct seginfo element. These structures are inserted into a list
47 for each basic block. For each entity, there is an array of bb_info over
48 the flow graph basic blocks (local var 'bb_info'), which contains a list
49 of all insns within that basic block, in the order they are encountered.
50
51 For each entity, any basic block WITHOUT any insns requiring a specific
52 mode are given a single entry without a mode (each basic block in the
53 flow graph must have at least one entry in the segment table).
54
55 The LCM algorithm is then run over the flow graph to determine where to
56 place the sets to the highest-priority mode with respect to the first
57 insn in any one block. Any adjustments required to the transparency
58 vectors are made, then the next iteration starts for the next-lower
59 priority mode, till for each entity all modes are exhausted.
60
61 More details can be found in the code of optimize_mode_switching. */
62
63/* This structure contains the information for each insn which requires
64 either single or double mode to be set.
65 MODE is the mode this insn must be executed in.
66 INSN_PTR is the insn to be executed (may be the note that marks the
67 beginning of a basic block).
68 NEXT is the next insn in the same basic block. */
69struct seginfo
70{
71 int mode;
72 rtx_insn *insn_ptr;
73 struct seginfo *next;
74 HARD_REG_SET regs_live;
75};
76
77struct bb_info
78{
79 struct seginfo *seginfo;
80 int computing;
81 int mode_out;
82 int mode_in;
83};
84
85/* Clear ode I from entity J in bitmap B. */
86#define clear_mode_bit(b, j, i) \
87 bitmap_clear_bit (b, (j * max_num_modes) + i)
88
89/* Test mode I from entity J in bitmap B. */
90#define mode_bit_p(b, j, i) \
91 bitmap_bit_p (b, (j * max_num_modes) + i)
92
93/* Set mode I from entity J in bitmal B. */
94#define set_mode_bit(b, j, i) \
95 bitmap_set_bit (b, (j * max_num_modes) + i)
96
97/* Emit modes segments from EDGE_LIST associated with entity E.
98 INFO gives mode availability for each mode. */
99
100static bool
101commit_mode_sets (struct edge_list *edge_list, int e, struct bb_info *info)
102{
103 bool need_commit = false;
104
105 for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
106 {
107 edge eg = INDEX_EDGE (edge_list, ed);
108 int mode;
109
110 if ((mode = (int)(intptr_t)(eg->aux)) != -1)
111 {
112 HARD_REG_SET live_at_edge;
113 basic_block src_bb = eg->src;
114 int cur_mode = info[src_bb->index].mode_out;
115 rtx_insn *mode_set;
116
117 REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb));
118
119 rtl_profile_for_edge (eg);
120 start_sequence ();
121
122 targetm.mode_switching.emit (e, mode, cur_mode, live_at_edge);
123
124 mode_set = get_insns ();
125 end_sequence ();
126 default_rtl_profile ();
127
128 /* Do not bother to insert empty sequence. */
129 if (mode_set == NULL)
130 continue;
131
132 /* We should not get an abnormal edge here. */
133 gcc_assert (! (eg->flags & EDGE_ABNORMAL));
134
135 need_commit = true;
136 insert_insn_on_edge (mode_set, eg);
137 }
138 }
139
140 return need_commit;
141}
142
143/* Allocate a new BBINFO structure, initialized with the MODE, INSN,
144 and REGS_LIVE parameters.
145 INSN may not be a NOTE_INSN_BASIC_BLOCK, unless it is an empty
146 basic block; that allows us later to insert instructions in a FIFO-like
147 manner. */
148
149static struct seginfo *
150new_seginfo (int mode, rtx_insn *insn, const HARD_REG_SET &regs_live)
151{
152 struct seginfo *ptr;
153
154 gcc_assert (!NOTE_INSN_BASIC_BLOCK_P (insn)
155 || insn == BB_END (NOTE_BASIC_BLOCK (insn)));
156 ptr = XNEW (struct seginfo);
157 ptr->mode = mode;
158 ptr->insn_ptr = insn;
159 ptr->next = NULL;
160 ptr->regs_live = regs_live;
161 return ptr;
162}
163
164/* Add a seginfo element to the end of a list.
165 HEAD is a pointer to the list beginning.
166 INFO is the structure to be linked in. */
167
168static void
169add_seginfo (struct bb_info *head, struct seginfo *info)
170{
171 struct seginfo *ptr;
172
173 if (head->seginfo == NULL)
174 head->seginfo = info;
175 else
176 {
177 ptr = head->seginfo;
178 while (ptr->next != NULL)
179 ptr = ptr->next;
180 ptr->next = info;
181 }
182}
183
184/* Record in LIVE that register REG died. */
185
186static void
187reg_dies (rtx reg, HARD_REG_SET *live)
188{
189 int regno;
190
191 if (!REG_P (reg))
192 return;
193
194 regno = REGNO (reg);
195 if (regno < FIRST_PSEUDO_REGISTER)
196 remove_from_hard_reg_set (regs: live, GET_MODE (reg), regno);
197}
198
199/* Record in LIVE that register REG became live.
200 This is called via note_stores. */
201
202static void
203reg_becomes_live (rtx reg, const_rtx setter ATTRIBUTE_UNUSED, void *live)
204{
205 int regno;
206
207 if (GET_CODE (reg) == SUBREG)
208 reg = SUBREG_REG (reg);
209
210 if (!REG_P (reg))
211 return;
212
213 regno = REGNO (reg);
214 if (regno < FIRST_PSEUDO_REGISTER)
215 add_to_hard_reg_set (regs: (HARD_REG_SET *) live, GET_MODE (reg), regno);
216}
217
218/* Split the fallthrough edge to the exit block, so that we can note
219 that there NORMAL_MODE is required. Return the new block if it's
220 inserted before the exit block. Otherwise return null. */
221
222static basic_block
223create_pre_exit (int n_entities, int *entity_map, const int *num_modes)
224{
225 edge eg;
226 edge_iterator ei;
227 basic_block pre_exit;
228
229 /* The only non-call predecessor at this stage is a block with a
230 fallthrough edge; there can be at most one, but there could be
231 none at all, e.g. when exit is called. */
232 pre_exit = 0;
233 FOR_EACH_EDGE (eg, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
234 if (eg->flags & EDGE_FALLTHRU)
235 {
236 basic_block src_bb = eg->src;
237 rtx_insn *last_insn;
238 rtx ret_reg;
239
240 gcc_assert (!pre_exit);
241 /* If this function returns a value at the end, we have to
242 insert the final mode switch before the return value copy
243 to its hard register.
244
245 x86 targets use mode-switching infrastructure to
246 conditionally insert vzeroupper instruction at the exit
247 from the function where there is no need to switch the
248 mode before the return value copy. The vzeroupper insertion
249 pass runs after reload, so use !reload_completed as a stand-in
250 for x86 to skip the search for the return value copy insn.
251
252 N.b.: the code below assumes that the return copy insn
253 immediately precedes its corresponding use insn. This
254 assumption does not hold after reload, since sched1 pass
255 can schedule the return copy insn away from its
256 corresponding use insn. */
257 if (!reload_completed
258 && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) == 1
259 && NONJUMP_INSN_P ((last_insn = BB_END (src_bb)))
260 && GET_CODE (PATTERN (last_insn)) == USE
261 && GET_CODE ((ret_reg = XEXP (PATTERN (last_insn), 0))) == REG)
262 {
263 int ret_start = REGNO (ret_reg);
264 int nregs = REG_NREGS (ret_reg);
265 int ret_end = ret_start + nregs;
266 bool short_block = false;
267 bool multi_reg_return = false;
268 bool forced_late_switch = false;
269 rtx_insn *before_return_copy;
270
271 do
272 {
273 rtx_insn *return_copy = PREV_INSN (insn: last_insn);
274 rtx return_copy_pat, copy_reg;
275 int copy_start, copy_num;
276 int j;
277
278 if (NONDEBUG_INSN_P (return_copy))
279 {
280 /* When using SJLJ exceptions, the call to the
281 unregister function is inserted between the
282 clobber of the return value and the copy.
283 We do not want to split the block before this
284 or any other call; if we have not found the
285 copy yet, the copy must have been deleted. */
286 if (CALL_P (return_copy))
287 {
288 short_block = true;
289 break;
290 }
291 return_copy_pat = PATTERN (insn: return_copy);
292 switch (GET_CODE (return_copy_pat))
293 {
294 case USE:
295 /* Skip USEs of multiple return registers.
296 __builtin_apply pattern is also handled here. */
297 if (GET_CODE (XEXP (return_copy_pat, 0)) == REG
298 && (targetm.calls.function_value_regno_p
299 (REGNO (XEXP (return_copy_pat, 0)))))
300 {
301 multi_reg_return = true;
302 last_insn = return_copy;
303 continue;
304 }
305 break;
306
307 case ASM_OPERANDS:
308 /* Skip barrier insns. */
309 if (!MEM_VOLATILE_P (return_copy_pat))
310 break;
311
312 /* Fall through. */
313
314 case ASM_INPUT:
315 case UNSPEC_VOLATILE:
316 last_insn = return_copy;
317 continue;
318
319 default:
320 break;
321 }
322
323 /* If the return register is not (in its entirety)
324 likely spilled, the return copy might be
325 partially or completely optimized away. */
326 return_copy_pat = single_set (insn: return_copy);
327 if (!return_copy_pat)
328 {
329 return_copy_pat = PATTERN (insn: return_copy);
330 if (GET_CODE (return_copy_pat) != CLOBBER)
331 break;
332 else if (!optimize)
333 {
334 /* This might be (clobber (reg [<result>]))
335 when not optimizing. Then check if
336 the previous insn is the clobber for
337 the return register. */
338 copy_reg = SET_DEST (return_copy_pat);
339 if (GET_CODE (copy_reg) == REG
340 && !HARD_REGISTER_NUM_P (REGNO (copy_reg)))
341 {
342 if (INSN_P (PREV_INSN (return_copy)))
343 {
344 return_copy = PREV_INSN (insn: return_copy);
345 return_copy_pat = PATTERN (insn: return_copy);
346 if (GET_CODE (return_copy_pat) != CLOBBER)
347 break;
348 }
349 }
350 }
351 }
352 copy_reg = SET_DEST (return_copy_pat);
353 if (GET_CODE (copy_reg) == REG)
354 copy_start = REGNO (copy_reg);
355 else if (GET_CODE (copy_reg) == SUBREG
356 && GET_CODE (SUBREG_REG (copy_reg)) == REG)
357 copy_start = REGNO (SUBREG_REG (copy_reg));
358 else
359 {
360 /* When control reaches end of non-void function,
361 there are no return copy insns at all. This
362 avoids an ice on that invalid function. */
363 if (ret_start + nregs == ret_end)
364 short_block = true;
365 break;
366 }
367 if (!targetm.calls.function_value_regno_p (copy_start))
368 copy_num = 0;
369 else
370 copy_num = hard_regno_nregs (regno: copy_start,
371 GET_MODE (copy_reg));
372
373 /* If the return register is not likely spilled, - as is
374 the case for floating point on SH4 - then it might
375 be set by an arithmetic operation that needs a
376 different mode than the exit block. */
377 for (j = n_entities - 1; j >= 0; j--)
378 {
379 int e = entity_map[j];
380 int mode =
381 targetm.mode_switching.needed (e, return_copy);
382
383 if (mode != num_modes[e]
384 && mode != targetm.mode_switching.exit (e))
385 break;
386 }
387 if (j >= 0)
388 {
389 /* __builtin_return emits a sequence of loads to all
390 return registers. One of them might require
391 another mode than MODE_EXIT, even if it is
392 unrelated to the return value, so we want to put
393 the final mode switch after it. */
394 if (multi_reg_return
395 && targetm.calls.function_value_regno_p
396 (copy_start))
397 forced_late_switch = true;
398
399 /* For the SH4, floating point loads depend on fpscr,
400 thus we might need to put the final mode switch
401 after the return value copy. That is still OK,
402 because a floating point return value does not
403 conflict with address reloads. */
404 if (copy_start >= ret_start
405 && copy_start + copy_num <= ret_end
406 && GET_CODE (return_copy_pat) == SET
407 && OBJECT_P (SET_SRC (return_copy_pat)))
408 forced_late_switch = true;
409 break;
410 }
411 if (copy_num == 0)
412 {
413 last_insn = return_copy;
414 continue;
415 }
416
417 if (copy_start >= ret_start
418 && copy_start + copy_num <= ret_end)
419 nregs -= copy_num;
420 else if (!multi_reg_return
421 || !targetm.calls.function_value_regno_p
422 (copy_start))
423 break;
424 last_insn = return_copy;
425 }
426 /* ??? Exception handling can lead to the return value
427 copy being already separated from the return value use,
428 as in unwind-dw2.c .
429 Similarly, conditionally returning without a value,
430 and conditionally using builtin_return can lead to an
431 isolated use. */
432 if (return_copy == BB_HEAD (src_bb))
433 {
434 short_block = true;
435 break;
436 }
437 last_insn = return_copy;
438 }
439 while (nregs);
440
441 /* If we didn't see a full return value copy, verify that there
442 is a plausible reason for this. If some, but not all of the
443 return register is likely spilled, we can expect that there
444 is a copy for the likely spilled part. */
445 gcc_assert (!nregs
446 || forced_late_switch
447 || short_block
448 || !(targetm.class_likely_spilled_p
449 (REGNO_REG_CLASS (ret_start)))
450 || nregs != REG_NREGS (ret_reg)
451 /* For multi-hard-register floating point
452 values, sometimes the likely-spilled part
453 is ordinarily copied first, then the other
454 part is set with an arithmetic operation.
455 This doesn't actually cause reload
456 failures, so let it pass. */
457 || (GET_MODE_CLASS (GET_MODE (ret_reg)) != MODE_INT
458 && nregs != 1));
459
460 if (!NOTE_INSN_BASIC_BLOCK_P (last_insn))
461 {
462 before_return_copy
463 = emit_note_before (NOTE_INSN_DELETED, last_insn);
464 /* Instructions preceding LAST_INSN in the same block might
465 require a different mode than MODE_EXIT, so if we might
466 have such instructions, keep them in a separate block
467 from pre_exit. */
468 src_bb = split_block (src_bb,
469 PREV_INSN (insn: before_return_copy))->dest;
470 }
471 else
472 before_return_copy = last_insn;
473 pre_exit = split_block (src_bb, before_return_copy)->src;
474 }
475 else
476 {
477 pre_exit = split_edge (eg);
478 }
479 }
480
481 return pre_exit;
482}
483
484/* Find all insns that need a particular mode setting, and insert the
485 necessary mode switches. Return true if we did work. */
486
487static int
488optimize_mode_switching (void)
489{
490 int e;
491 basic_block bb;
492 bool need_commit = false;
493 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
494#define N_ENTITIES ARRAY_SIZE (num_modes)
495 int entity_map[N_ENTITIES] = {};
496 struct bb_info *bb_info[N_ENTITIES] = {};
497 int i, j;
498 int n_entities = 0;
499 int max_num_modes = 0;
500 bool emitted ATTRIBUTE_UNUSED = false;
501 basic_block post_entry = 0;
502 basic_block pre_exit = 0;
503 struct edge_list *edge_list = 0;
504
505 /* These bitmaps are used for the LCM algorithm. */
506 sbitmap *kill, *del, *insert, *antic, *transp, *comp;
507 sbitmap *avin, *avout;
508
509 for (e = N_ENTITIES - 1; e >= 0; e--)
510 if (OPTIMIZE_MODE_SWITCHING (e))
511 {
512 int entry_exit_extra = 0;
513
514 /* Create the list of segments within each basic block.
515 If NORMAL_MODE is defined, allow for two extra
516 blocks split from the entry and exit block. */
517 if (targetm.mode_switching.entry && targetm.mode_switching.exit)
518 entry_exit_extra = 3;
519
520 bb_info[n_entities]
521 = XCNEWVEC (struct bb_info,
522 last_basic_block_for_fn (cfun) + entry_exit_extra);
523 entity_map[n_entities++] = e;
524 if (num_modes[e] > max_num_modes)
525 max_num_modes = num_modes[e];
526 }
527
528 if (! n_entities)
529 return 0;
530
531 /* Make sure if MODE_ENTRY is defined MODE_EXIT is defined. */
532 gcc_assert ((targetm.mode_switching.entry && targetm.mode_switching.exit)
533 || (!targetm.mode_switching.entry
534 && !targetm.mode_switching.exit));
535
536 if (targetm.mode_switching.entry && targetm.mode_switching.exit)
537 {
538 /* Split the edge from the entry block, so that we can note that
539 there NORMAL_MODE is supplied. */
540 post_entry = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
541 pre_exit = create_pre_exit (n_entities, entity_map, num_modes);
542 }
543
544 df_analyze ();
545
546 /* Create the bitmap vectors. */
547 antic = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
548 n_entities * max_num_modes);
549 transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
550 n_entities * max_num_modes);
551 comp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
552 n_entities * max_num_modes);
553 avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
554 n_entities * max_num_modes);
555 avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
556 n_entities * max_num_modes);
557 kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun),
558 n_entities * max_num_modes);
559
560 bitmap_vector_ones (transp, last_basic_block_for_fn (cfun));
561 bitmap_vector_clear (antic, last_basic_block_for_fn (cfun));
562 bitmap_vector_clear (comp, last_basic_block_for_fn (cfun));
563
564 for (j = n_entities - 1; j >= 0; j--)
565 {
566 int e = entity_map[j];
567 int no_mode = num_modes[e];
568 struct bb_info *info = bb_info[j];
569 rtx_insn *insn;
570
571 /* Determine what the first use (if any) need for a mode of entity E is.
572 This will be the mode that is anticipatable for this block.
573 Also compute the initial transparency settings. */
574 FOR_EACH_BB_FN (bb, cfun)
575 {
576 struct seginfo *ptr;
577 int last_mode = no_mode;
578 bool any_set_required = false;
579 HARD_REG_SET live_now;
580
581 info[bb->index].mode_out = info[bb->index].mode_in = no_mode;
582
583 REG_SET_TO_HARD_REG_SET (live_now, df_get_live_in (bb));
584
585 /* Pretend the mode is clobbered across abnormal edges. */
586 {
587 edge_iterator ei;
588 edge eg;
589 FOR_EACH_EDGE (eg, ei, bb->preds)
590 if (eg->flags & EDGE_COMPLEX)
591 break;
592 if (eg)
593 {
594 rtx_insn *ins_pos = BB_HEAD (bb);
595 if (LABEL_P (ins_pos))
596 ins_pos = NEXT_INSN (insn: ins_pos);
597 gcc_assert (NOTE_INSN_BASIC_BLOCK_P (ins_pos));
598 if (ins_pos != BB_END (bb))
599 ins_pos = NEXT_INSN (insn: ins_pos);
600 ptr = new_seginfo (mode: no_mode, insn: ins_pos, regs_live: live_now);
601 add_seginfo (head: info + bb->index, info: ptr);
602 for (i = 0; i < no_mode; i++)
603 clear_mode_bit (transp[bb->index], j, i);
604 }
605 }
606
607 FOR_BB_INSNS (bb, insn)
608 {
609 if (INSN_P (insn))
610 {
611 int mode = targetm.mode_switching.needed (e, insn);
612 rtx link;
613
614 if (mode != no_mode && mode != last_mode)
615 {
616 any_set_required = true;
617 last_mode = mode;
618 ptr = new_seginfo (mode, insn, regs_live: live_now);
619 add_seginfo (head: info + bb->index, info: ptr);
620 for (i = 0; i < no_mode; i++)
621 clear_mode_bit (transp[bb->index], j, i);
622 }
623
624 if (targetm.mode_switching.after)
625 last_mode = targetm.mode_switching.after (e, last_mode,
626 insn);
627
628 /* Update LIVE_NOW. */
629 for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
630 if (REG_NOTE_KIND (link) == REG_DEAD)
631 reg_dies (XEXP (link, 0), live: &live_now);
632
633 note_stores (insn, reg_becomes_live, &live_now);
634 for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
635 if (REG_NOTE_KIND (link) == REG_UNUSED)
636 reg_dies (XEXP (link, 0), live: &live_now);
637 }
638 }
639
640 info[bb->index].computing = last_mode;
641 /* Check for blocks without ANY mode requirements.
642 N.B. because of MODE_AFTER, last_mode might still
643 be different from no_mode, in which case we need to
644 mark the block as nontransparent. */
645 if (!any_set_required)
646 {
647 ptr = new_seginfo (mode: no_mode, BB_END (bb), regs_live: live_now);
648 add_seginfo (head: info + bb->index, info: ptr);
649 if (last_mode != no_mode)
650 for (i = 0; i < no_mode; i++)
651 clear_mode_bit (transp[bb->index], j, i);
652 }
653 }
654 if (targetm.mode_switching.entry && targetm.mode_switching.exit)
655 {
656 int mode = targetm.mode_switching.entry (e);
657
658 info[post_entry->index].mode_out =
659 info[post_entry->index].mode_in = no_mode;
660 if (pre_exit)
661 {
662 info[pre_exit->index].mode_out =
663 info[pre_exit->index].mode_in = no_mode;
664 }
665
666 if (mode != no_mode)
667 {
668 bb = post_entry;
669
670 /* By always making this nontransparent, we save
671 an extra check in make_preds_opaque. We also
672 need this to avoid confusing pre_edge_lcm when
673 antic is cleared but transp and comp are set. */
674 for (i = 0; i < no_mode; i++)
675 clear_mode_bit (transp[bb->index], j, i);
676
677 /* Insert a fake computing definition of MODE into entry
678 blocks which compute no mode. This represents the mode on
679 entry. */
680 info[bb->index].computing = mode;
681
682 if (pre_exit)
683 info[pre_exit->index].seginfo->mode =
684 targetm.mode_switching.exit (e);
685 }
686 }
687
688 /* Set the anticipatable and computing arrays. */
689 for (i = 0; i < no_mode; i++)
690 {
691 int m = targetm.mode_switching.priority (entity_map[j], i);
692
693 FOR_EACH_BB_FN (bb, cfun)
694 {
695 if (info[bb->index].seginfo->mode == m)
696 set_mode_bit (antic[bb->index], j, m);
697
698 if (info[bb->index].computing == m)
699 set_mode_bit (comp[bb->index], j, m);
700 }
701 }
702 }
703
704 /* Calculate the optimal locations for the
705 placement mode switches to modes with priority I. */
706
707 FOR_EACH_BB_FN (bb, cfun)
708 bitmap_not (kill[bb->index], transp[bb->index]);
709
710 edge_list = pre_edge_lcm_avs (n_entities * max_num_modes, transp, comp, antic,
711 kill, avin, avout, &insert, &del);
712
713 for (j = n_entities - 1; j >= 0; j--)
714 {
715 int no_mode = num_modes[entity_map[j]];
716
717 /* Insert all mode sets that have been inserted by lcm. */
718
719 for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--)
720 {
721 edge eg = INDEX_EDGE (edge_list, ed);
722
723 eg->aux = (void *)(intptr_t)-1;
724
725 for (i = 0; i < no_mode; i++)
726 {
727 int m = targetm.mode_switching.priority (entity_map[j], i);
728 if (mode_bit_p (insert[ed], j, m))
729 {
730 eg->aux = (void *)(intptr_t)m;
731 break;
732 }
733 }
734 }
735
736 FOR_EACH_BB_FN (bb, cfun)
737 {
738 struct bb_info *info = bb_info[j];
739 int last_mode = no_mode;
740
741 /* intialize mode in availability for bb. */
742 for (i = 0; i < no_mode; i++)
743 if (mode_bit_p (avout[bb->index], j, i))
744 {
745 if (last_mode == no_mode)
746 last_mode = i;
747 if (last_mode != i)
748 {
749 last_mode = no_mode;
750 break;
751 }
752 }
753 info[bb->index].mode_out = last_mode;
754
755 /* intialize mode out availability for bb. */
756 last_mode = no_mode;
757 for (i = 0; i < no_mode; i++)
758 if (mode_bit_p (avin[bb->index], j, i))
759 {
760 if (last_mode == no_mode)
761 last_mode = i;
762 if (last_mode != i)
763 {
764 last_mode = no_mode;
765 break;
766 }
767 }
768 info[bb->index].mode_in = last_mode;
769
770 for (i = 0; i < no_mode; i++)
771 if (mode_bit_p (del[bb->index], j, i))
772 info[bb->index].seginfo->mode = no_mode;
773 }
774
775 /* Now output the remaining mode sets in all the segments. */
776
777 /* In case there was no mode inserted. the mode information on the edge
778 might not be complete.
779 Update mode info on edges and commit pending mode sets. */
780 need_commit |= commit_mode_sets (edge_list, e: entity_map[j], info: bb_info[j]);
781
782 /* Reset modes for next entity. */
783 clear_aux_for_edges ();
784
785 FOR_EACH_BB_FN (bb, cfun)
786 {
787 struct seginfo *ptr, *next;
788 int cur_mode = bb_info[j][bb->index].mode_in;
789
790 for (ptr = bb_info[j][bb->index].seginfo; ptr; ptr = next)
791 {
792 next = ptr->next;
793 if (ptr->mode != no_mode)
794 {
795 rtx_insn *mode_set;
796
797 rtl_profile_for_bb (bb);
798 start_sequence ();
799
800 targetm.mode_switching.emit (entity_map[j], ptr->mode,
801 cur_mode, ptr->regs_live);
802 mode_set = get_insns ();
803 end_sequence ();
804
805 /* modes kill each other inside a basic block. */
806 cur_mode = ptr->mode;
807
808 /* Insert MODE_SET only if it is nonempty. */
809 if (mode_set != NULL_RTX)
810 {
811 emitted = true;
812 if (NOTE_INSN_BASIC_BLOCK_P (ptr->insn_ptr))
813 /* We need to emit the insns in a FIFO-like manner,
814 i.e. the first to be emitted at our insertion
815 point ends up first in the instruction steam.
816 Because we made sure that NOTE_INSN_BASIC_BLOCK is
817 only used for initially empty basic blocks, we
818 can achieve this by appending at the end of
819 the block. */
820 emit_insn_after
821 (mode_set, BB_END (NOTE_BASIC_BLOCK (ptr->insn_ptr)));
822 else
823 emit_insn_before (mode_set, ptr->insn_ptr);
824 }
825
826 default_rtl_profile ();
827 }
828
829 free (ptr: ptr);
830 }
831 }
832
833 free (ptr: bb_info[j]);
834 }
835
836 free_edge_list (edge_list);
837
838 /* Finished. Free up all the things we've allocated. */
839 sbitmap_vector_free (vec: del);
840 sbitmap_vector_free (vec: insert);
841 sbitmap_vector_free (vec: kill);
842 sbitmap_vector_free (vec: antic);
843 sbitmap_vector_free (vec: transp);
844 sbitmap_vector_free (vec: comp);
845 sbitmap_vector_free (vec: avin);
846 sbitmap_vector_free (vec: avout);
847
848 if (need_commit)
849 commit_edge_insertions ();
850
851 if (targetm.mode_switching.entry && targetm.mode_switching.exit)
852 {
853 free_dominance_info (CDI_DOMINATORS);
854 cleanup_cfg (CLEANUP_NO_INSN_DEL);
855 }
856 else if (!need_commit && !emitted)
857 return 0;
858
859 return 1;
860}
861
862#endif /* OPTIMIZE_MODE_SWITCHING */
863
864namespace {
865
866const pass_data pass_data_mode_switching =
867{
868 .type: RTL_PASS, /* type */
869 .name: "mode_sw", /* name */
870 .optinfo_flags: OPTGROUP_NONE, /* optinfo_flags */
871 .tv_id: TV_MODE_SWITCH, /* tv_id */
872 .properties_required: 0, /* properties_required */
873 .properties_provided: 0, /* properties_provided */
874 .properties_destroyed: 0, /* properties_destroyed */
875 .todo_flags_start: 0, /* todo_flags_start */
876 TODO_df_finish, /* todo_flags_finish */
877};
878
879class pass_mode_switching : public rtl_opt_pass
880{
881public:
882 pass_mode_switching (gcc::context *ctxt)
883 : rtl_opt_pass (pass_data_mode_switching, ctxt)
884 {}
885
886 /* opt_pass methods: */
887 /* The epiphany backend creates a second instance of this pass, so we need
888 a clone method. */
889 opt_pass * clone () final override { return new pass_mode_switching (m_ctxt); }
890 bool gate (function *) final override
891 {
892#ifdef OPTIMIZE_MODE_SWITCHING
893 return true;
894#else
895 return false;
896#endif
897 }
898
899 unsigned int execute (function *) final override
900 {
901#ifdef OPTIMIZE_MODE_SWITCHING
902 optimize_mode_switching ();
903#endif /* OPTIMIZE_MODE_SWITCHING */
904 return 0;
905 }
906
907}; // class pass_mode_switching
908
909} // anon namespace
910
911rtl_opt_pass *
912make_pass_mode_switching (gcc::context *ctxt)
913{
914 return new pass_mode_switching (ctxt);
915}
916

source code of gcc/mode-switching.cc