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