1 | /* CPU mode switching |
2 | Copyright (C) 1998-2024 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 | commit_mode_sets (struct edge_list *edge_list, int e, struct bb_info *info) |
105 | { |
106 | bool need_commit = false; |
107 | |
108 | for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--) |
109 | { |
110 | edge eg = INDEX_EDGE (edge_list, ed); |
111 | |
112 | if (eg->aux) |
113 | { |
114 | int mode = (int) (intptr_t) eg->aux - 1; |
115 | HARD_REG_SET live_at_edge; |
116 | basic_block src_bb = eg->src; |
117 | int cur_mode = info[src_bb->index].mode_out; |
118 | rtx_insn *mode_set; |
119 | |
120 | REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb)); |
121 | |
122 | rtl_profile_for_edge (eg); |
123 | start_sequence (); |
124 | |
125 | targetm.mode_switching.emit (e, mode, cur_mode, live_at_edge); |
126 | |
127 | mode_set = get_insns (); |
128 | end_sequence (); |
129 | default_rtl_profile (); |
130 | |
131 | /* Do not bother to insert empty sequence. */ |
132 | if (mode_set == NULL) |
133 | continue; |
134 | |
135 | /* We should not get an abnormal edge here. */ |
136 | gcc_assert (! (eg->flags & EDGE_ABNORMAL)); |
137 | |
138 | need_commit = true; |
139 | insert_insn_on_edge (mode_set, eg); |
140 | } |
141 | } |
142 | |
143 | 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 | new_seginfo (int prev_mode, int mode, rtx_insn *insn, |
154 | const HARD_REG_SET ®s_live) |
155 | { |
156 | struct seginfo *ptr; |
157 | |
158 | gcc_assert (!NOTE_INSN_BASIC_BLOCK_P (insn) |
159 | || insn == BB_END (NOTE_BASIC_BLOCK (insn))); |
160 | ptr = XNEW (struct seginfo); |
161 | ptr->prev_mode = prev_mode; |
162 | ptr->mode = mode; |
163 | ptr->insn_ptr = insn; |
164 | ptr->next = NULL; |
165 | ptr->regs_live = regs_live; |
166 | 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 | add_seginfo (struct seginfo ***tail_ptr, struct seginfo *info) |
175 | { |
176 | **tail_ptr = info; |
177 | *tail_ptr = &info->next; |
178 | } |
179 | |
180 | /* Record in LIVE that register REG died. */ |
181 | |
182 | static void |
183 | reg_dies (rtx reg, HARD_REG_SET *live) |
184 | { |
185 | int regno; |
186 | |
187 | if (!REG_P (reg)) |
188 | return; |
189 | |
190 | regno = REGNO (reg); |
191 | if (regno < FIRST_PSEUDO_REGISTER) |
192 | remove_from_hard_reg_set (regs: 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 | reg_becomes_live (rtx reg, const_rtx setter ATTRIBUTE_UNUSED, void *live) |
200 | { |
201 | int regno; |
202 | |
203 | if (GET_CODE (reg) == SUBREG) |
204 | reg = SUBREG_REG (reg); |
205 | |
206 | if (!REG_P (reg)) |
207 | return; |
208 | |
209 | regno = REGNO (reg); |
210 | if (regno < FIRST_PSEUDO_REGISTER) |
211 | add_to_hard_reg_set (regs: (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 | create_pre_exit (int n_entities, int *entity_map, const int *num_modes) |
220 | { |
221 | edge eg; |
222 | edge_iterator ei; |
223 | 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 | pre_exit = 0; |
229 | FOR_EACH_EDGE (eg, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) |
230 | if (eg->flags & EDGE_FALLTHRU) |
231 | { |
232 | basic_block src_bb = eg->src; |
233 | rtx_insn *last_insn; |
234 | rtx ret_reg; |
235 | |
236 | 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 | if (!reload_completed |
254 | && EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) == 1 |
255 | && NONJUMP_INSN_P ((last_insn = BB_END (src_bb))) |
256 | && GET_CODE (PATTERN (last_insn)) == USE |
257 | && GET_CODE ((ret_reg = XEXP (PATTERN (last_insn), 0))) == REG) |
258 | { |
259 | auto_bitmap live; |
260 | df_simulate_initialize_backwards (src_bb, live); |
261 | |
262 | int ret_start = REGNO (ret_reg); |
263 | int nregs = REG_NREGS (ret_reg); |
264 | int ret_end = ret_start + nregs; |
265 | bool short_block = false; |
266 | bool multi_reg_return = false; |
267 | bool forced_late_switch = false; |
268 | rtx_insn *before_return_copy; |
269 | |
270 | df_simulate_one_insn_backwards (src_bb, last_insn, live); |
271 | |
272 | do |
273 | { |
274 | rtx_insn *return_copy = PREV_INSN (insn: last_insn); |
275 | rtx return_copy_pat, copy_reg; |
276 | int copy_start, copy_num; |
277 | int j; |
278 | |
279 | df_simulate_one_insn_backwards (src_bb, return_copy, live); |
280 | |
281 | 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 | if (CALL_P (return_copy)) |
290 | { |
291 | short_block = true; |
292 | break; |
293 | } |
294 | return_copy_pat = PATTERN (insn: return_copy); |
295 | switch (GET_CODE (return_copy_pat)) |
296 | { |
297 | case USE: |
298 | /* Skip USEs of multiple return registers. |
299 | __builtin_apply pattern is also handled here. */ |
300 | if (GET_CODE (XEXP (return_copy_pat, 0)) == REG |
301 | && (targetm.calls.function_value_regno_p |
302 | (REGNO (XEXP (return_copy_pat, 0))))) |
303 | { |
304 | multi_reg_return = true; |
305 | last_insn = return_copy; |
306 | continue; |
307 | } |
308 | break; |
309 | |
310 | case ASM_OPERANDS: |
311 | /* Skip barrier insns. */ |
312 | if (!MEM_VOLATILE_P (return_copy_pat)) |
313 | break; |
314 | |
315 | /* Fall through. */ |
316 | |
317 | case ASM_INPUT: |
318 | case UNSPEC_VOLATILE: |
319 | last_insn = return_copy; |
320 | continue; |
321 | |
322 | default: |
323 | break; |
324 | } |
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 | return_copy_pat = single_set (insn: return_copy); |
330 | if (!return_copy_pat) |
331 | { |
332 | return_copy_pat = PATTERN (insn: return_copy); |
333 | if (GET_CODE (return_copy_pat) != CLOBBER) |
334 | break; |
335 | 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 | copy_reg = SET_DEST (return_copy_pat); |
342 | if (GET_CODE (copy_reg) == REG |
343 | && !HARD_REGISTER_NUM_P (REGNO (copy_reg))) |
344 | { |
345 | if (INSN_P (PREV_INSN (return_copy))) |
346 | { |
347 | return_copy = PREV_INSN (insn: return_copy); |
348 | return_copy_pat = PATTERN (insn: return_copy); |
349 | if (GET_CODE (return_copy_pat) != CLOBBER) |
350 | break; |
351 | } |
352 | } |
353 | } |
354 | } |
355 | copy_reg = SET_DEST (return_copy_pat); |
356 | if (GET_CODE (copy_reg) == REG) |
357 | copy_start = REGNO (copy_reg); |
358 | else if (GET_CODE (copy_reg) == SUBREG |
359 | && GET_CODE (SUBREG_REG (copy_reg)) == REG) |
360 | 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 | if (ret_start + nregs == ret_end) |
367 | short_block = true; |
368 | break; |
369 | } |
370 | if (!targetm.calls.function_value_regno_p (copy_start)) |
371 | copy_num = 0; |
372 | else |
373 | copy_num = hard_regno_nregs (regno: copy_start, |
374 | 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 | HARD_REG_SET hard_regs_live; |
381 | REG_SET_TO_HARD_REG_SET (hard_regs_live, live); |
382 | for (j = n_entities - 1; j >= 0; j--) |
383 | { |
384 | int e = entity_map[j]; |
385 | int mode = |
386 | targetm.mode_switching.needed (e, return_copy, |
387 | hard_regs_live); |
388 | |
389 | if (mode != num_modes[e] |
390 | && mode != targetm.mode_switching.exit (e)) |
391 | break; |
392 | } |
393 | 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 | if (multi_reg_return |
401 | && targetm.calls.function_value_regno_p |
402 | (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 | if (copy_start >= ret_start |
411 | && copy_start + copy_num <= ret_end |
412 | && GET_CODE (return_copy_pat) == SET |
413 | && OBJECT_P (SET_SRC (return_copy_pat))) |
414 | forced_late_switch = true; |
415 | break; |
416 | } |
417 | if (copy_num == 0) |
418 | { |
419 | last_insn = return_copy; |
420 | continue; |
421 | } |
422 | |
423 | if (copy_start >= ret_start |
424 | && copy_start + copy_num <= ret_end) |
425 | nregs -= copy_num; |
426 | else if (!multi_reg_return |
427 | || !targetm.calls.function_value_regno_p |
428 | (copy_start)) |
429 | break; |
430 | 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 | if (return_copy == BB_HEAD (src_bb)) |
439 | { |
440 | short_block = true; |
441 | break; |
442 | } |
443 | last_insn = return_copy; |
444 | } |
445 | 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 | 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 | if (!NOTE_INSN_BASIC_BLOCK_P (last_insn)) |
467 | { |
468 | before_return_copy |
469 | = 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 | src_bb = split_block (src_bb, |
475 | PREV_INSN (insn: before_return_copy))->dest; |
476 | } |
477 | else |
478 | before_return_copy = last_insn; |
479 | pre_exit = split_block (src_bb, before_return_copy)->src; |
480 | } |
481 | else |
482 | { |
483 | pre_exit = split_edge (eg); |
484 | } |
485 | } |
486 | |
487 | 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 | mode_confluence (int entity, int mode1, int mode2, int no_mode) |
496 | { |
497 | if (mode1 == mode2) |
498 | return mode1; |
499 | |
500 | if (mode1 != no_mode |
501 | && mode2 != no_mode |
502 | && targetm.mode_switching.confluence) |
503 | 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 | forward_confluence_n (edge e) |
532 | { |
533 | /* The entry and exit blocks have no useful mode information. */ |
534 | 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 | 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 | struct bb_info *bb_info = confluence_info.bb_info; |
545 | int no_mode = confluence_info.no_mode; |
546 | int src_mode = bb_info[e->src->index].mode_out; |
547 | if (e->aux) |
548 | src_mode = (int) (intptr_t) e->aux - 1; |
549 | if (src_mode == no_mode + 1) |
550 | return false; |
551 | |
552 | int dest_mode = bb_info[e->dest->index].mode_in; |
553 | if (dest_mode == no_mode + 1) |
554 | { |
555 | bb_info[e->dest->index].mode_in = src_mode; |
556 | return true; |
557 | } |
558 | |
559 | int entity = confluence_info.entity; |
560 | int new_mode = mode_confluence (entity, mode1: src_mode, mode2: dest_mode, no_mode); |
561 | if (dest_mode == new_mode) |
562 | return false; |
563 | |
564 | bb_info[e->dest->index].mode_in = new_mode; |
565 | 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 | forward_transfer (int bb_index) |
573 | { |
574 | /* The entry and exit blocks have no useful mode information. */ |
575 | 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 | struct bb_info *bb_info = confluence_info.bb_info; |
580 | if (bb_info[bb_index].computing != confluence_info.no_mode |
581 | || bb_info[bb_index].mode_out == bb_info[bb_index].mode_in) |
582 | return false; |
583 | |
584 | bb_info[bb_index].mode_out = bb_info[bb_index].mode_in; |
585 | 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 | single_succ_confluence_n (edge e) |
598 | { |
599 | /* The entry block has no associated mode information. */ |
600 | if (e->src->index == ENTRY_BLOCK) |
601 | return false; |
602 | |
603 | /* We don't control mode changes across abnormal edges. */ |
604 | if (e->flags & EDGE_ABNORMAL) |
605 | return false; |
606 | |
607 | /* Do nothing if we've already found a conflict. */ |
608 | struct bb_info *bb_info = confluence_info.bb_info; |
609 | int no_mode = confluence_info.no_mode; |
610 | int src_mode = bb_info[e->src->index].single_succ; |
611 | if (src_mode == no_mode) |
612 | return false; |
613 | |
614 | /* Work out what mode the destination block (or its successors) require. */ |
615 | int dest_mode; |
616 | if (e->dest->index == EXIT_BLOCK) |
617 | dest_mode = no_mode; |
618 | else if (bitmap_bit_p (map: confluence_info.transp, bitno: e->dest->index)) |
619 | dest_mode = bb_info[e->dest->index].single_succ; |
620 | else |
621 | dest_mode = bb_info[e->dest->index].seginfo->mode; |
622 | |
623 | /* Do nothing if the destination block has no new information. */ |
624 | if (dest_mode == no_mode + 1 || dest_mode == src_mode) |
625 | return false; |
626 | |
627 | /* Detect conflicting modes. */ |
628 | if (src_mode != no_mode + 1) |
629 | dest_mode = no_mode; |
630 | |
631 | bb_info[e->src->index].single_succ = dest_mode; |
632 | 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 | 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 | return bitmap_bit_p (map: confluence_info.transp, bitno: 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 | backprop_confluence_n (edge e) |
653 | { |
654 | /* The entry and exit blocks have no useful mode information. */ |
655 | 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 | 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 | if (!bitmap_bit_p (map: confluence_info.transp, bitno: 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 | struct bb_info *bb_info = confluence_info.bb_info; |
670 | int no_mode = confluence_info.no_mode; |
671 | int src_mode = bb_info[e->src->index].mode_out; |
672 | int dest_mode = bb_info[e->dest->index].mode_in; |
673 | if (dest_mode == no_mode || src_mode == dest_mode) |
674 | return false; |
675 | |
676 | /* See what the target thinks about this transition. */ |
677 | int entity = confluence_info.entity; |
678 | int new_mode = targetm.mode_switching.backprop (entity, src_mode, |
679 | dest_mode); |
680 | 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 | int old_mode = bb_info[e->src->index].computing; |
696 | if (bb_info[e->src->index].single_succ != no_mode) |
697 | new_mode = bb_info[e->src->index].single_succ; |
698 | else if (old_mode != no_mode + 1) |
699 | new_mode = mode_confluence (entity, mode1: old_mode, mode2: new_mode, no_mode); |
700 | |
701 | if (old_mode == new_mode) |
702 | return false; |
703 | |
704 | bb_info[e->src->index].computing = new_mode; |
705 | 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 | backprop_transfer (int bb_index) |
744 | { |
745 | /* The entry and exit blocks have no useful mode information. */ |
746 | 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 | if (!bitmap_bit_p (map: confluence_info.transp, bitno: bb_index)) |
752 | return false; |
753 | |
754 | struct bb_info *bb_info = confluence_info.bb_info; |
755 | basic_block bb = BASIC_BLOCK_FOR_FN (cfun, bb_index); |
756 | int no_mode = confluence_info.no_mode; |
757 | int mode_in = bb_info[bb_index].mode_in; |
758 | int mode_out = bb_info[bb_index].computing; |
759 | 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 | mode_out = bb_info[bb_index].single_succ; |
765 | 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 | unsigned int moved = 0; |
771 | for (edge e : bb->succs) |
772 | if (e->dest->index != EXIT_BLOCK |
773 | && mode_out == bb_info[e->dest->index].seginfo->mode) |
774 | 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 | if (moved < EDGE_COUNT (bb->preds)) |
779 | return false; |
780 | |
781 | bb_info[bb_index].mode_out = mode_out; |
782 | bb_info[bb_index].computing = mode_out; |
783 | } |
784 | else if (mode_out == mode_in) |
785 | return false; |
786 | |
787 | bb_info[bb_index].mode_in = mode_out; |
788 | bb_info[bb_index].seginfo->mode = mode_out; |
789 | 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 | optimize_mode_switching (void) |
797 | { |
798 | int e; |
799 | basic_block bb; |
800 | bool need_commit = false; |
801 | static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING; |
802 | #define N_ENTITIES ARRAY_SIZE (num_modes) |
803 | int entity_map[N_ENTITIES] = {}; |
804 | struct bb_info *bb_info[N_ENTITIES] = {}; |
805 | int i, j; |
806 | int n_entities = 0; |
807 | int max_num_modes = 0; |
808 | bool emitted ATTRIBUTE_UNUSED = false; |
809 | basic_block post_entry = 0; |
810 | basic_block pre_exit = 0; |
811 | struct edge_list *edge_list = 0; |
812 | |
813 | /* These bitmaps are used for the LCM algorithm. */ |
814 | sbitmap *kill, *del, *insert, *antic, *transp, *comp; |
815 | sbitmap *avin, *avout; |
816 | |
817 | for (e = N_ENTITIES - 1; e >= 0; e--) |
818 | if (OPTIMIZE_MODE_SWITCHING (e)) |
819 | { |
820 | int = 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 | if (targetm.mode_switching.entry && targetm.mode_switching.exit) |
826 | entry_exit_extra = 3; |
827 | |
828 | bb_info[n_entities] |
829 | = XCNEWVEC (struct bb_info, |
830 | last_basic_block_for_fn (cfun) + entry_exit_extra); |
831 | entity_map[n_entities++] = e; |
832 | if (num_modes[e] > max_num_modes) |
833 | max_num_modes = num_modes[e]; |
834 | } |
835 | |
836 | if (! n_entities) |
837 | return 0; |
838 | |
839 | /* Make sure if MODE_ENTRY is defined MODE_EXIT is defined. */ |
840 | gcc_assert ((targetm.mode_switching.entry && targetm.mode_switching.exit) |
841 | || (!targetm.mode_switching.entry |
842 | && !targetm.mode_switching.exit)); |
843 | |
844 | 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 | post_entry = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))); |
849 | pre_exit = create_pre_exit (n_entities, entity_map, num_modes); |
850 | } |
851 | |
852 | df_note_add_problem (); |
853 | df_analyze (); |
854 | |
855 | /* Create the bitmap vectors. */ |
856 | antic = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), |
857 | n_entities * max_num_modes); |
858 | transp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), |
859 | n_entities * max_num_modes); |
860 | comp = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), |
861 | n_entities * max_num_modes); |
862 | avin = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), |
863 | n_entities * max_num_modes); |
864 | avout = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), |
865 | n_entities * max_num_modes); |
866 | kill = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), |
867 | n_entities * max_num_modes); |
868 | |
869 | bitmap_vector_ones (transp, last_basic_block_for_fn (cfun)); |
870 | bitmap_vector_clear (antic, last_basic_block_for_fn (cfun)); |
871 | bitmap_vector_clear (comp, last_basic_block_for_fn (cfun)); |
872 | |
873 | auto_sbitmap transp_all (last_basic_block_for_fn (cfun)); |
874 | |
875 | 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 | 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 | FOR_EACH_BB_FN (bb, cfun) |
885 | { |
886 | if (bb_has_abnormal_pred (bb)) |
887 | info[bb->index].mode_in = info[bb->index].seginfo->mode; |
888 | else |
889 | info[bb->index].mode_in = no_mode + 1; |
890 | if (info[bb->index].computing != no_mode) |
891 | info[bb->index].mode_out = info[bb->index].computing; |
892 | else |
893 | info[bb->index].mode_out = no_mode + 1; |
894 | } |
895 | |
896 | confluence_info.bb_info = info; |
897 | confluence_info.transp = nullptr; |
898 | confluence_info.entity = entity; |
899 | confluence_info.no_mode = no_mode; |
900 | |
901 | bitmap_set_range (blocks, 0, last_basic_block_for_fn (cfun)); |
902 | 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 | }; |
908 | |
909 | if (targetm.mode_switching.backprop) |
910 | clear_aux_for_edges (); |
911 | |
912 | for (j = n_entities - 1; j >= 0; j--) |
913 | { |
914 | int e = entity_map[j]; |
915 | int no_mode = num_modes[e]; |
916 | struct bb_info *info = bb_info[j]; |
917 | rtx_insn *insn; |
918 | |
919 | 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 | FOR_EACH_BB_FN (bb, cfun) |
925 | { |
926 | struct seginfo **tail_ptr = &info[bb->index].seginfo; |
927 | struct seginfo *ptr; |
928 | int last_mode = no_mode; |
929 | bool any_set_required = false; |
930 | HARD_REG_SET live_now; |
931 | |
932 | info[bb->index].mode_out = info[bb->index].mode_in = no_mode; |
933 | |
934 | REG_SET_TO_HARD_REG_SET (live_now, df_get_live_in (bb)); |
935 | |
936 | /* Pretend the mode is clobbered across abnormal edges. */ |
937 | { |
938 | edge_iterator ei; |
939 | edge eg; |
940 | FOR_EACH_EDGE (eg, ei, bb->preds) |
941 | if (eg->flags & EDGE_COMPLEX) |
942 | break; |
943 | if (eg) |
944 | { |
945 | rtx_insn *ins_pos = BB_HEAD (bb); |
946 | if (LABEL_P (ins_pos)) |
947 | ins_pos = NEXT_INSN (insn: ins_pos); |
948 | gcc_assert (NOTE_INSN_BASIC_BLOCK_P (ins_pos)); |
949 | if (ins_pos != BB_END (bb)) |
950 | ins_pos = NEXT_INSN (insn: ins_pos); |
951 | if (bb_has_eh_pred (bb) |
952 | && targetm.mode_switching.eh_handler) |
953 | last_mode = targetm.mode_switching.eh_handler (e); |
954 | ptr = new_seginfo (prev_mode: no_mode, mode: last_mode, insn: ins_pos, regs_live: live_now); |
955 | add_seginfo (tail_ptr: &tail_ptr, info: ptr); |
956 | bitmap_clear_bit (map: transp_all, bitno: bb->index); |
957 | } |
958 | } |
959 | |
960 | FOR_BB_INSNS (bb, insn) |
961 | { |
962 | if (NONDEBUG_INSN_P (insn)) |
963 | { |
964 | int mode = targetm.mode_switching.needed (e, insn, live_now); |
965 | rtx link; |
966 | |
967 | if (mode != no_mode && mode != last_mode) |
968 | { |
969 | ptr = new_seginfo (prev_mode: last_mode, mode, insn, regs_live: live_now); |
970 | add_seginfo (tail_ptr: &tail_ptr, info: ptr); |
971 | bitmap_clear_bit (map: transp_all, bitno: bb->index); |
972 | any_set_required = true; |
973 | last_mode = mode; |
974 | } |
975 | |
976 | /* Update LIVE_NOW. */ |
977 | for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) |
978 | if (REG_NOTE_KIND (link) == REG_DEAD) |
979 | reg_dies (XEXP (link, 0), live: &live_now); |
980 | |
981 | note_stores (insn, reg_becomes_live, &live_now); |
982 | for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) |
983 | if (REG_NOTE_KIND (link) == REG_UNUSED) |
984 | reg_dies (XEXP (link, 0), live: &live_now); |
985 | |
986 | if (targetm.mode_switching.after) |
987 | last_mode = targetm.mode_switching.after (e, last_mode, |
988 | insn, live_now); |
989 | } |
990 | } |
991 | |
992 | 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 | if (!any_set_required) |
998 | { |
999 | ptr = new_seginfo (prev_mode: last_mode, mode: no_mode, BB_END (bb), regs_live: live_now); |
1000 | add_seginfo (tail_ptr: &tail_ptr, info: ptr); |
1001 | if (last_mode != no_mode) |
1002 | bitmap_clear_bit (map: transp_all, bitno: bb->index); |
1003 | } |
1004 | } |
1005 | if (targetm.mode_switching.entry && targetm.mode_switching.exit) |
1006 | { |
1007 | info[post_entry->index].mode_out = |
1008 | info[post_entry->index].mode_in = no_mode; |
1009 | |
1010 | int mode = targetm.mode_switching.entry (e); |
1011 | 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 | info[post_entry->index].computing = mode; |
1017 | bitmap_clear_bit (map: transp_all, bitno: post_entry->index); |
1018 | } |
1019 | |
1020 | if (pre_exit) |
1021 | { |
1022 | info[pre_exit->index].mode_out = |
1023 | info[pre_exit->index].mode_in = no_mode; |
1024 | |
1025 | int mode = targetm.mode_switching.exit (e); |
1026 | if (mode != no_mode) |
1027 | { |
1028 | info[pre_exit->index].seginfo->mode = mode; |
1029 | bitmap_clear_bit (map: transp_all, bitno: pre_exit->index); |
1030 | } |
1031 | } |
1032 | } |
1033 | |
1034 | /* If the target requests it, back-propagate selected mode requirements |
1035 | through transparent blocks. */ |
1036 | if (targetm.mode_switching.backprop) |
1037 | { |
1038 | /* First work out the mode on entry to and exit from each block. */ |
1039 | forwprop_mode_info (info, e, no_mode); |
1040 | |
1041 | /* Compute the single_succ fields, as described above |
1042 | single_succ_confluence. */ |
1043 | FOR_EACH_BB_FN (bb, cfun) |
1044 | info[bb->index].single_succ = no_mode + 1; |
1045 | |
1046 | confluence_info.transp = transp_all; |
1047 | bitmap_set_range (blocks, 0, last_basic_block_for_fn (cfun)); |
1048 | 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 | 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 | if (info[bb->index].seginfo->mode != no_mode) |
1059 | 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 | if (info[bb->index].computing == no_mode) |
1064 | info[bb->index].computing = no_mode + 1; |
1065 | } |
1066 | |
1067 | bitmap_set_range (blocks, 0, last_basic_block_for_fn (cfun)); |
1068 | 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 | FOR_EACH_BB_FN (bb, cfun) |
1075 | if (info[bb->index].computing == no_mode + 1) |
1076 | info[bb->index].computing = no_mode; |
1077 | else if (info[bb->index].computing != no_mode) |
1078 | bitmap_clear_bit (map: transp_all, bitno: bb->index); |
1079 | } |
1080 | |
1081 | /* Set the anticipatable and computing arrays. */ |
1082 | for (i = 0; i < no_mode; i++) |
1083 | { |
1084 | int m = targetm.mode_switching.priority (entity_map[j], i); |
1085 | |
1086 | FOR_EACH_BB_FN (bb, cfun) |
1087 | { |
1088 | if (!bitmap_bit_p (map: transp_all, bitno: bb->index)) |
1089 | clear_mode_bit (transp[bb->index], j, m); |
1090 | |
1091 | if (info[bb->index].seginfo->mode == m) |
1092 | set_mode_bit (antic[bb->index], j, m); |
1093 | |
1094 | if (info[bb->index].computing == m) |
1095 | 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 | FOR_EACH_BB_FN (bb, cfun) |
1104 | bitmap_not (kill[bb->index], transp[bb->index]); |
1105 | |
1106 | edge_list = pre_edge_lcm_avs (n_entities * max_num_modes, transp, comp, antic, |
1107 | kill, avin, avout, &insert, &del); |
1108 | |
1109 | auto_sbitmap jumping_blocks (last_basic_block_for_fn (cfun)); |
1110 | bitmap_clear (jumping_blocks); |
1111 | for (j = n_entities - 1; j >= 0; j--) |
1112 | { |
1113 | int no_mode = num_modes[entity_map[j]]; |
1114 | struct bb_info *info = bb_info[j]; |
1115 | |
1116 | /* Insert all mode sets that have been inserted by lcm. */ |
1117 | |
1118 | for (int ed = NUM_EDGES (edge_list) - 1; ed >= 0; ed--) |
1119 | { |
1120 | edge eg = INDEX_EDGE (edge_list, ed); |
1121 | |
1122 | eg->aux = (void *) (intptr_t) 0; |
1123 | |
1124 | for (i = 0; i < no_mode; i++) |
1125 | { |
1126 | int m = targetm.mode_switching.priority (entity_map[j], i); |
1127 | if (mode_bit_p (insert[ed], j, m)) |
1128 | { |
1129 | eg->aux = (void *) (intptr_t) (m + 1); |
1130 | 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 | if (targetm.mode_switching.confluence) |
1139 | forwprop_mode_info (info, entity_map[j], no_mode); |
1140 | |
1141 | FOR_EACH_BB_FN (bb, cfun) |
1142 | { |
1143 | auto modes_confluence = [&](sbitmap *av) |
1144 | { |
1145 | for (int i = 0; i < no_mode; ++i) |
1146 | if (mode_bit_p (av[bb->index], j, i)) |
1147 | { |
1148 | for (int i2 = i + 1; i2 < no_mode; ++i2) |
1149 | if (mode_bit_p (av[bb->index], j, i2)) |
1150 | return no_mode; |
1151 | return i; |
1152 | } |
1153 | return no_mode; |
1154 | }; |
1155 | |
1156 | /* intialize mode in/out availability for bb. */ |
1157 | if (!targetm.mode_switching.confluence) |
1158 | { |
1159 | info[bb->index].mode_out = modes_confluence (avout); |
1160 | info[bb->index].mode_in = modes_confluence (avin); |
1161 | } |
1162 | |
1163 | for (i = 0; i < no_mode; i++) |
1164 | if (mode_bit_p (del[bb->index], j, i)) |
1165 | 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 | if (targetm.mode_switching.backprop) |
1171 | { |
1172 | int from_mode = info[bb->index].mode_in; |
1173 | int to_mode = info[bb->index].seginfo->mode; |
1174 | if (targetm.mode_switching.backprop (entity_map[j], from_mode, |
1175 | to_mode) != no_mode) |
1176 | { |
1177 | for (edge e : bb->preds) |
1178 | e->aux = (void *) (intptr_t) (to_mode + 1); |
1179 | 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 | need_commit |= commit_mode_sets (edge_list, e: entity_map[j], info: bb_info[j]); |
1190 | |
1191 | /* Reset modes for next entity. */ |
1192 | clear_aux_for_edges (); |
1193 | |
1194 | FOR_EACH_BB_FN (bb, cfun) |
1195 | { |
1196 | struct seginfo *ptr, *next; |
1197 | struct seginfo *first = bb_info[j][bb->index].seginfo; |
1198 | |
1199 | for (ptr = first; ptr; ptr = next) |
1200 | { |
1201 | next = ptr->next; |
1202 | if (ptr->mode != no_mode) |
1203 | { |
1204 | rtx_insn *mode_set; |
1205 | |
1206 | rtl_profile_for_bb (bb); |
1207 | start_sequence (); |
1208 | |
1209 | int cur_mode = (ptr == first && ptr->prev_mode == no_mode |
1210 | ? bb_info[j][bb->index].mode_in |
1211 | : ptr->prev_mode); |
1212 | |
1213 | targetm.mode_switching.emit (entity_map[j], ptr->mode, |
1214 | cur_mode, ptr->regs_live); |
1215 | mode_set = get_insns (); |
1216 | end_sequence (); |
1217 | |
1218 | /* Insert MODE_SET only if it is nonempty. */ |
1219 | if (mode_set != NULL_RTX) |
1220 | { |
1221 | for (auto insn = mode_set; insn; insn = NEXT_INSN (insn)) |
1222 | if (JUMP_P (insn)) |
1223 | { |
1224 | rebuild_jump_labels_chain (mode_set); |
1225 | bitmap_set_bit (map: jumping_blocks, bitno: bb->index); |
1226 | break; |
1227 | } |
1228 | emitted = true; |
1229 | 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 | emit_insn_after |
1238 | (mode_set, BB_END (NOTE_BASIC_BLOCK (ptr->insn_ptr))); |
1239 | else |
1240 | emit_insn_before (mode_set, ptr->insn_ptr); |
1241 | } |
1242 | |
1243 | default_rtl_profile (); |
1244 | } |
1245 | |
1246 | free (ptr: ptr); |
1247 | } |
1248 | } |
1249 | |
1250 | free (ptr: bb_info[j]); |
1251 | } |
1252 | |
1253 | free_edge_list (edge_list); |
1254 | |
1255 | /* Finished. Free up all the things we've allocated. */ |
1256 | sbitmap_vector_free (vec: del); |
1257 | sbitmap_vector_free (vec: insert); |
1258 | sbitmap_vector_free (vec: kill); |
1259 | sbitmap_vector_free (vec: antic); |
1260 | sbitmap_vector_free (vec: transp); |
1261 | sbitmap_vector_free (vec: comp); |
1262 | sbitmap_vector_free (vec: avin); |
1263 | sbitmap_vector_free (vec: avout); |
1264 | |
1265 | gcc_assert (SBITMAP_SIZE ((sbitmap) jumping_blocks) |
1266 | == (unsigned int) last_basic_block_for_fn (cfun)); |
1267 | if (!bitmap_empty_p (jumping_blocks)) |
1268 | find_many_sub_basic_blocks (jumping_blocks); |
1269 | |
1270 | if (need_commit) |
1271 | commit_edge_insertions (); |
1272 | |
1273 | if (targetm.mode_switching.entry && targetm.mode_switching.exit) |
1274 | { |
1275 | free_dominance_info (CDI_DOMINATORS); |
1276 | cleanup_cfg (CLEANUP_NO_INSN_DEL); |
1277 | } |
1278 | else if (!need_commit && !emitted) |
1279 | return 0; |
1280 | |
1281 | return 1; |
1282 | } |
1283 | |
1284 | #endif /* OPTIMIZE_MODE_SWITCHING */ |
1285 | |
1286 | namespace { |
1287 | |
1288 | const pass_data pass_data_mode_switching = |
1289 | { |
1290 | .type: RTL_PASS, /* type */ |
1291 | .name: "mode_sw" , /* name */ |
1292 | .optinfo_flags: OPTGROUP_NONE, /* optinfo_flags */ |
1293 | .tv_id: TV_MODE_SWITCH, /* tv_id */ |
1294 | .properties_required: 0, /* properties_required */ |
1295 | .properties_provided: 0, /* properties_provided */ |
1296 | .properties_destroyed: 0, /* properties_destroyed */ |
1297 | .todo_flags_start: 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 | pass_mode_switching (gcc::context *ctxt) |
1305 | : 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 | opt_pass * clone () final override { return new pass_mode_switching (m_ctxt); } |
1312 | bool gate (function *) final override |
1313 | { |
1314 | #ifdef OPTIMIZE_MODE_SWITCHING |
1315 | return true; |
1316 | #else |
1317 | return false; |
1318 | #endif |
1319 | } |
1320 | |
1321 | unsigned int execute (function *) final override |
1322 | { |
1323 | #ifdef OPTIMIZE_MODE_SWITCHING |
1324 | optimize_mode_switching (); |
1325 | #endif /* OPTIMIZE_MODE_SWITCHING */ |
1326 | return 0; |
1327 | } |
1328 | |
1329 | }; // class pass_mode_switching |
1330 | |
1331 | } // anon namespace |
1332 | |
1333 | rtl_opt_pass * |
1334 | make_pass_mode_switching (gcc::context *ctxt) |
1335 | { |
1336 | return new pass_mode_switching (ctxt); |
1337 | } |
1338 | |