Mercurial > hg > CbC > CbC_gcc
annotate gcc/mode-switching.c @ 67:f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 22 Mar 2011 17:18:12 +0900 |
parents | b7f97abdc517 |
children | 04ced10e8804 |
rev | line source |
---|---|
0 | 1 /* CPU mode switching |
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, | |
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
|
3 2009, 2010 Free Software Foundation, Inc. |
0 | 4 |
5 This file is part of GCC. | |
6 | |
7 GCC is free software; you can redistribute it and/or modify it under | |
8 the terms of the GNU General Public License as published by the Free | |
9 Software Foundation; either version 3, or (at your option) any later | |
10 version. | |
11 | |
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with GCC; see the file COPYING3. If not see | |
19 <http://www.gnu.org/licenses/>. */ | |
20 | |
21 #include "config.h" | |
22 #include "system.h" | |
23 #include "coretypes.h" | |
24 #include "tm.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
|
25 #include "target.h" |
0 | 26 #include "rtl.h" |
27 #include "regs.h" | |
28 #include "hard-reg-set.h" | |
29 #include "flags.h" | |
30 #include "insn-config.h" | |
31 #include "recog.h" | |
32 #include "basic-block.h" | |
33 #include "output.h" | |
34 #include "tm_p.h" | |
35 #include "function.h" | |
36 #include "tree-pass.h" | |
37 #include "timevar.h" | |
38 #include "df.h" | |
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
|
39 #include "emit-rtl.h" |
0 | 40 |
41 /* We want target macros for the mode switching code to be able to refer | |
42 to instruction attribute values. */ | |
43 #include "insn-attr.h" | |
44 | |
45 #ifdef OPTIMIZE_MODE_SWITCHING | |
46 | |
47 /* The algorithm for setting the modes consists of scanning the insn list | |
48 and finding all the insns which require a specific mode. Each insn gets | |
49 a unique struct seginfo element. These structures are inserted into a list | |
50 for each basic block. For each entity, there is an array of bb_info over | |
51 the flow graph basic blocks (local var 'bb_info'), and contains a list | |
52 of all insns within that basic block, in the order they are encountered. | |
53 | |
54 For each entity, any basic block WITHOUT any insns requiring a specific | |
55 mode are given a single entry, without a mode. (Each basic block | |
56 in the flow graph must have at least one entry in the segment table.) | |
57 | |
58 The LCM algorithm is then run over the flow graph to determine where to | |
59 place the sets to the highest-priority value in respect of first the first | |
60 insn in any one block. Any adjustments required to the transparency | |
61 vectors are made, then the next iteration starts for the next-lower | |
62 priority mode, till for each entity all modes are exhausted. | |
63 | |
64 More details are located in the code for optimize_mode_switching(). */ | |
65 | |
66 /* This structure contains the information for each insn which requires | |
67 either single or double mode to be set. | |
68 MODE is the mode this insn must be executed in. | |
69 INSN_PTR is the insn to be executed (may be the note that marks the | |
70 beginning of a basic block). | |
71 BBNUM is the flow graph basic block this insn occurs in. | |
72 NEXT is the next insn in the same basic block. */ | |
73 struct seginfo | |
74 { | |
75 int mode; | |
76 rtx insn_ptr; | |
77 int bbnum; | |
78 struct seginfo *next; | |
79 HARD_REG_SET regs_live; | |
80 }; | |
81 | |
82 struct bb_info | |
83 { | |
84 struct seginfo *seginfo; | |
85 int computing; | |
86 }; | |
87 | |
88 /* These bitmaps are used for the LCM algorithm. */ | |
89 | |
90 static sbitmap *antic; | |
91 static sbitmap *transp; | |
92 static sbitmap *comp; | |
93 | |
94 static struct seginfo * new_seginfo (int, rtx, int, HARD_REG_SET); | |
95 static void add_seginfo (struct bb_info *, struct seginfo *); | |
96 static void reg_dies (rtx, HARD_REG_SET *); | |
97 static void reg_becomes_live (rtx, const_rtx, void *); | |
98 static void make_preds_opaque (basic_block, int); | |
99 | |
100 | |
101 /* This function will allocate a new BBINFO structure, initialized | |
102 with the MODE, INSN, and basic block BB parameters. */ | |
103 | |
104 static struct seginfo * | |
105 new_seginfo (int mode, rtx insn, int bb, HARD_REG_SET regs_live) | |
106 { | |
107 struct seginfo *ptr; | |
108 ptr = XNEW (struct seginfo); | |
109 ptr->mode = mode; | |
110 ptr->insn_ptr = insn; | |
111 ptr->bbnum = bb; | |
112 ptr->next = NULL; | |
113 COPY_HARD_REG_SET (ptr->regs_live, regs_live); | |
114 return ptr; | |
115 } | |
116 | |
117 /* Add a seginfo element to the end of a list. | |
118 HEAD is a pointer to the list beginning. | |
119 INFO is the structure to be linked in. */ | |
120 | |
121 static void | |
122 add_seginfo (struct bb_info *head, struct seginfo *info) | |
123 { | |
124 struct seginfo *ptr; | |
125 | |
126 if (head->seginfo == NULL) | |
127 head->seginfo = info; | |
128 else | |
129 { | |
130 ptr = head->seginfo; | |
131 while (ptr->next != NULL) | |
132 ptr = ptr->next; | |
133 ptr->next = info; | |
134 } | |
135 } | |
136 | |
137 /* Make all predecessors of basic block B opaque, recursively, till we hit | |
138 some that are already non-transparent, or an edge where aux is set; that | |
139 denotes that a mode set is to be done on that edge. | |
140 J is the bit number in the bitmaps that corresponds to the entity that | |
141 we are currently handling mode-switching for. */ | |
142 | |
143 static void | |
144 make_preds_opaque (basic_block b, int j) | |
145 { | |
146 edge e; | |
147 edge_iterator ei; | |
148 | |
149 FOR_EACH_EDGE (e, ei, b->preds) | |
150 { | |
151 basic_block pb = e->src; | |
152 | |
153 if (e->aux || ! TEST_BIT (transp[pb->index], j)) | |
154 continue; | |
155 | |
156 RESET_BIT (transp[pb->index], j); | |
157 make_preds_opaque (pb, j); | |
158 } | |
159 } | |
160 | |
161 /* Record in LIVE that register REG died. */ | |
162 | |
163 static void | |
164 reg_dies (rtx reg, HARD_REG_SET *live) | |
165 { | |
166 int regno; | |
167 | |
168 if (!REG_P (reg)) | |
169 return; | |
170 | |
171 regno = REGNO (reg); | |
172 if (regno < FIRST_PSEUDO_REGISTER) | |
173 remove_from_hard_reg_set (live, GET_MODE (reg), regno); | |
174 } | |
175 | |
176 /* Record in LIVE that register REG became live. | |
177 This is called via note_stores. */ | |
178 | |
179 static void | |
180 reg_becomes_live (rtx reg, const_rtx setter ATTRIBUTE_UNUSED, void *live) | |
181 { | |
182 int regno; | |
183 | |
184 if (GET_CODE (reg) == SUBREG) | |
185 reg = SUBREG_REG (reg); | |
186 | |
187 if (!REG_P (reg)) | |
188 return; | |
189 | |
190 regno = REGNO (reg); | |
191 if (regno < FIRST_PSEUDO_REGISTER) | |
192 add_to_hard_reg_set ((HARD_REG_SET *) live, GET_MODE (reg), regno); | |
193 } | |
194 | |
195 /* Make sure if MODE_ENTRY is defined the MODE_EXIT is defined | |
196 and vice versa. */ | |
197 #if defined (MODE_ENTRY) != defined (MODE_EXIT) | |
198 #error "Both MODE_ENTRY and MODE_EXIT must be defined" | |
199 #endif | |
200 | |
201 #if defined (MODE_ENTRY) && defined (MODE_EXIT) | |
202 /* Split the fallthrough edge to the exit block, so that we can note | |
203 that there NORMAL_MODE is required. Return the new block if it's | |
204 inserted before the exit block. Otherwise return null. */ | |
205 | |
206 static basic_block | |
207 create_pre_exit (int n_entities, int *entity_map, const int *num_modes) | |
208 { | |
209 edge eg; | |
210 edge_iterator ei; | |
211 basic_block pre_exit; | |
212 | |
213 /* The only non-call predecessor at this stage is a block with a | |
214 fallthrough edge; there can be at most one, but there could be | |
215 none at all, e.g. when exit is called. */ | |
216 pre_exit = 0; | |
217 FOR_EACH_EDGE (eg, ei, EXIT_BLOCK_PTR->preds) | |
218 if (eg->flags & EDGE_FALLTHRU) | |
219 { | |
220 basic_block src_bb = eg->src; | |
221 rtx last_insn, ret_reg; | |
222 | |
223 gcc_assert (!pre_exit); | |
224 /* If this function returns a value at the end, we have to | |
225 insert the final mode switch before the return value copy | |
226 to its hard register. */ | |
227 if (EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 1 | |
228 && NONJUMP_INSN_P ((last_insn = BB_END (src_bb))) | |
229 && GET_CODE (PATTERN (last_insn)) == USE | |
230 && GET_CODE ((ret_reg = XEXP (PATTERN (last_insn), 0))) == REG) | |
231 { | |
232 int ret_start = REGNO (ret_reg); | |
233 int nregs = hard_regno_nregs[ret_start][GET_MODE (ret_reg)]; | |
234 int ret_end = ret_start + nregs; | |
235 int short_block = 0; | |
236 int maybe_builtin_apply = 0; | |
237 int forced_late_switch = 0; | |
238 rtx before_return_copy; | |
239 | |
240 do | |
241 { | |
242 rtx return_copy = PREV_INSN (last_insn); | |
243 rtx return_copy_pat, copy_reg; | |
244 int copy_start, copy_num; | |
245 int j; | |
246 | |
247 if (INSN_P (return_copy)) | |
248 { | |
249 /* When using SJLJ exceptions, the call to the | |
250 unregister function is inserted between the | |
251 clobber of the return value and the copy. | |
252 We do not want to split the block before this | |
253 or any other call; if we have not found the | |
254 copy yet, the copy must have been deleted. */ | |
255 if (CALL_P (return_copy)) | |
256 { | |
257 short_block = 1; | |
258 break; | |
259 } | |
260 return_copy_pat = PATTERN (return_copy); | |
261 switch (GET_CODE (return_copy_pat)) | |
262 { | |
263 case USE: | |
264 /* Skip __builtin_apply pattern. */ | |
265 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
|
266 && (targetm.calls.function_value_regno_p |
0 | 267 (REGNO (XEXP (return_copy_pat, 0))))) |
268 { | |
269 maybe_builtin_apply = 1; | |
270 last_insn = return_copy; | |
271 continue; | |
272 } | |
273 break; | |
274 | |
275 case ASM_OPERANDS: | |
276 /* Skip barrier insns. */ | |
277 if (!MEM_VOLATILE_P (return_copy_pat)) | |
278 break; | |
279 | |
280 /* Fall through. */ | |
281 | |
282 case ASM_INPUT: | |
283 case UNSPEC_VOLATILE: | |
284 last_insn = return_copy; | |
285 continue; | |
286 | |
287 default: | |
288 break; | |
289 } | |
290 | |
291 /* If the return register is not (in its entirety) | |
292 likely spilled, the return copy might be | |
293 partially or completely optimized away. */ | |
294 return_copy_pat = single_set (return_copy); | |
295 if (!return_copy_pat) | |
296 { | |
297 return_copy_pat = PATTERN (return_copy); | |
298 if (GET_CODE (return_copy_pat) != CLOBBER) | |
299 break; | |
300 else if (!optimize) | |
301 { | |
302 /* This might be (clobber (reg [<result>])) | |
303 when not optimizing. Then check if | |
304 the previous insn is the clobber for | |
305 the return register. */ | |
306 copy_reg = SET_DEST (return_copy_pat); | |
307 if (GET_CODE (copy_reg) == REG | |
308 && !HARD_REGISTER_NUM_P (REGNO (copy_reg))) | |
309 { | |
310 if (INSN_P (PREV_INSN (return_copy))) | |
311 { | |
312 return_copy = PREV_INSN (return_copy); | |
313 return_copy_pat = PATTERN (return_copy); | |
314 if (GET_CODE (return_copy_pat) != CLOBBER) | |
315 break; | |
316 } | |
317 } | |
318 } | |
319 } | |
320 copy_reg = SET_DEST (return_copy_pat); | |
321 if (GET_CODE (copy_reg) == REG) | |
322 copy_start = REGNO (copy_reg); | |
323 else if (GET_CODE (copy_reg) == SUBREG | |
324 && GET_CODE (SUBREG_REG (copy_reg)) == REG) | |
325 copy_start = REGNO (SUBREG_REG (copy_reg)); | |
326 else | |
327 break; | |
328 if (copy_start >= FIRST_PSEUDO_REGISTER) | |
329 break; | |
330 copy_num | |
331 = hard_regno_nregs[copy_start][GET_MODE (copy_reg)]; | |
332 | |
333 /* If the return register is not likely spilled, - as is | |
334 the case for floating point on SH4 - then it might | |
335 be set by an arithmetic operation that needs a | |
336 different mode than the exit block. */ | |
337 for (j = n_entities - 1; j >= 0; j--) | |
338 { | |
339 int e = entity_map[j]; | |
340 int mode = MODE_NEEDED (e, return_copy); | |
341 | |
342 if (mode != num_modes[e] && mode != MODE_EXIT (e)) | |
343 break; | |
344 } | |
345 if (j >= 0) | |
346 { | |
347 /* For the SH4, floating point loads depend on fpscr, | |
348 thus we might need to put the final mode switch | |
349 after the return value copy. That is still OK, | |
350 because a floating point return value does not | |
351 conflict with address reloads. */ | |
352 if (copy_start >= ret_start | |
353 && copy_start + copy_num <= ret_end | |
354 && OBJECT_P (SET_SRC (return_copy_pat))) | |
355 forced_late_switch = 1; | |
356 break; | |
357 } | |
358 | |
359 if (copy_start >= ret_start | |
360 && copy_start + copy_num <= ret_end) | |
361 nregs -= copy_num; | |
362 else if (!maybe_builtin_apply | |
63
b7f97abdc517
update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
363 || !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
|
364 (copy_start)) |
0 | 365 break; |
366 last_insn = return_copy; | |
367 } | |
368 /* ??? Exception handling can lead to the return value | |
369 copy being already separated from the return value use, | |
370 as in unwind-dw2.c . | |
371 Similarly, conditionally returning without a value, | |
372 and conditionally using builtin_return can lead to an | |
373 isolated use. */ | |
374 if (return_copy == BB_HEAD (src_bb)) | |
375 { | |
376 short_block = 1; | |
377 break; | |
378 } | |
379 last_insn = return_copy; | |
380 } | |
381 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
|
382 |
0 | 383 /* If we didn't see a full return value copy, verify that there |
384 is a plausible reason for this. If some, but not all of the | |
385 return register is likely spilled, we can expect that there | |
386 is a copy for the likely spilled part. */ | |
387 gcc_assert (!nregs | |
388 || forced_late_switch | |
389 || 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
|
390 || !(targetm.class_likely_spilled_p |
0 | 391 (REGNO_REG_CLASS (ret_start))) |
392 || (nregs | |
393 != hard_regno_nregs[ret_start][GET_MODE (ret_reg)]) | |
394 /* For multi-hard-register floating point | |
395 values, sometimes the likely-spilled part | |
396 is ordinarily copied first, then the other | |
397 part is set with an arithmetic operation. | |
398 This doesn't actually cause reload | |
399 failures, so let it pass. */ | |
400 || (GET_MODE_CLASS (GET_MODE (ret_reg)) != MODE_INT | |
401 && 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
|
402 |
0 | 403 if (INSN_P (last_insn)) |
404 { | |
405 before_return_copy | |
406 = emit_note_before (NOTE_INSN_DELETED, last_insn); | |
407 /* Instructions preceding LAST_INSN in the same block might | |
408 require a different mode than MODE_EXIT, so if we might | |
409 have such instructions, keep them in a separate block | |
410 from pre_exit. */ | |
411 if (last_insn != BB_HEAD (src_bb)) | |
412 src_bb = split_block (src_bb, | |
413 PREV_INSN (before_return_copy))->dest; | |
414 } | |
415 else | |
416 before_return_copy = last_insn; | |
417 pre_exit = split_block (src_bb, before_return_copy)->src; | |
418 } | |
419 else | |
420 { | |
421 pre_exit = split_edge (eg); | |
422 } | |
423 } | |
424 | |
425 return pre_exit; | |
426 } | |
427 #endif | |
428 | |
429 /* Find all insns that need a particular mode setting, and insert the | |
430 necessary mode switches. Return true if we did work. */ | |
431 | |
432 static int | |
433 optimize_mode_switching (void) | |
434 { | |
435 rtx insn; | |
436 int e; | |
437 basic_block bb; | |
438 int need_commit = 0; | |
439 sbitmap *kill; | |
440 struct edge_list *edge_list; | |
441 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING; | |
442 #define N_ENTITIES ARRAY_SIZE (num_modes) | |
443 int entity_map[N_ENTITIES]; | |
444 struct bb_info *bb_info[N_ENTITIES]; | |
445 int i, j; | |
446 int n_entities; | |
447 int max_num_modes = 0; | |
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
|
448 bool emited ATTRIBUTE_UNUSED = false; |
0 | 449 basic_block post_entry ATTRIBUTE_UNUSED, pre_exit ATTRIBUTE_UNUSED; |
450 | |
451 for (e = N_ENTITIES - 1, n_entities = 0; e >= 0; e--) | |
452 if (OPTIMIZE_MODE_SWITCHING (e)) | |
453 { | |
454 int entry_exit_extra = 0; | |
455 | |
456 /* Create the list of segments within each basic block. | |
457 If NORMAL_MODE is defined, allow for two extra | |
458 blocks split from the entry and exit block. */ | |
459 #if defined (MODE_ENTRY) && defined (MODE_EXIT) | |
460 entry_exit_extra = 3; | |
461 #endif | |
462 bb_info[n_entities] | |
463 = XCNEWVEC (struct bb_info, last_basic_block + entry_exit_extra); | |
464 entity_map[n_entities++] = e; | |
465 if (num_modes[e] > max_num_modes) | |
466 max_num_modes = num_modes[e]; | |
467 } | |
468 | |
469 if (! n_entities) | |
470 return 0; | |
471 | |
472 #if defined (MODE_ENTRY) && defined (MODE_EXIT) | |
473 /* Split the edge from the entry block, so that we can note that | |
474 there NORMAL_MODE is supplied. */ | |
475 post_entry = split_edge (single_succ_edge (ENTRY_BLOCK_PTR)); | |
476 pre_exit = create_pre_exit (n_entities, entity_map, num_modes); | |
477 #endif | |
478 | |
479 df_analyze (); | |
480 | |
481 /* Create the bitmap vectors. */ | |
482 | |
483 antic = sbitmap_vector_alloc (last_basic_block, n_entities); | |
484 transp = sbitmap_vector_alloc (last_basic_block, n_entities); | |
485 comp = sbitmap_vector_alloc (last_basic_block, n_entities); | |
486 | |
487 sbitmap_vector_ones (transp, last_basic_block); | |
488 | |
489 for (j = n_entities - 1; j >= 0; j--) | |
490 { | |
491 int e = entity_map[j]; | |
492 int no_mode = num_modes[e]; | |
493 struct bb_info *info = bb_info[j]; | |
494 | |
495 /* Determine what the first use (if any) need for a mode of entity E is. | |
496 This will be the mode that is anticipatable for this block. | |
497 Also compute the initial transparency settings. */ | |
498 FOR_EACH_BB (bb) | |
499 { | |
500 struct seginfo *ptr; | |
501 int last_mode = no_mode; | |
502 HARD_REG_SET live_now; | |
503 | |
504 REG_SET_TO_HARD_REG_SET (live_now, df_get_live_in (bb)); | |
505 | |
506 /* Pretend the mode is clobbered across abnormal edges. */ | |
507 { | |
508 edge_iterator ei; | |
509 edge e; | |
510 FOR_EACH_EDGE (e, ei, bb->preds) | |
511 if (e->flags & EDGE_COMPLEX) | |
512 break; | |
513 if (e) | |
514 { | |
515 ptr = new_seginfo (no_mode, BB_HEAD (bb), bb->index, live_now); | |
516 add_seginfo (info + bb->index, ptr); | |
517 RESET_BIT (transp[bb->index], j); | |
518 } | |
519 } | |
520 | |
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
|
521 FOR_BB_INSNS (bb, insn) |
0 | 522 { |
523 if (INSN_P (insn)) | |
524 { | |
525 int mode = MODE_NEEDED (e, insn); | |
526 rtx link; | |
527 | |
528 if (mode != no_mode && mode != last_mode) | |
529 { | |
530 last_mode = mode; | |
531 ptr = new_seginfo (mode, insn, bb->index, live_now); | |
532 add_seginfo (info + bb->index, ptr); | |
533 RESET_BIT (transp[bb->index], j); | |
534 } | |
535 #ifdef MODE_AFTER | |
536 last_mode = MODE_AFTER (last_mode, insn); | |
537 #endif | |
538 /* Update LIVE_NOW. */ | |
539 for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) | |
540 if (REG_NOTE_KIND (link) == REG_DEAD) | |
541 reg_dies (XEXP (link, 0), &live_now); | |
542 | |
543 note_stores (PATTERN (insn), reg_becomes_live, &live_now); | |
544 for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) | |
545 if (REG_NOTE_KIND (link) == REG_UNUSED) | |
546 reg_dies (XEXP (link, 0), &live_now); | |
547 } | |
548 } | |
549 | |
550 info[bb->index].computing = last_mode; | |
551 /* Check for blocks without ANY mode requirements. */ | |
552 if (last_mode == no_mode) | |
553 { | |
554 ptr = new_seginfo (no_mode, BB_END (bb), bb->index, live_now); | |
555 add_seginfo (info + bb->index, ptr); | |
556 } | |
557 } | |
558 #if defined (MODE_ENTRY) && defined (MODE_EXIT) | |
559 { | |
560 int mode = MODE_ENTRY (e); | |
561 | |
562 if (mode != no_mode) | |
563 { | |
564 bb = post_entry; | |
565 | |
566 /* By always making this nontransparent, we save | |
567 an extra check in make_preds_opaque. We also | |
568 need this to avoid confusing pre_edge_lcm when | |
569 antic is cleared but transp and comp are set. */ | |
570 RESET_BIT (transp[bb->index], j); | |
571 | |
572 /* Insert a fake computing definition of MODE into entry | |
573 blocks which compute no mode. This represents the mode on | |
574 entry. */ | |
575 info[bb->index].computing = mode; | |
576 | |
577 if (pre_exit) | |
578 info[pre_exit->index].seginfo->mode = MODE_EXIT (e); | |
579 } | |
580 } | |
581 #endif /* NORMAL_MODE */ | |
582 } | |
583 | |
584 kill = sbitmap_vector_alloc (last_basic_block, n_entities); | |
585 for (i = 0; i < max_num_modes; i++) | |
586 { | |
587 int current_mode[N_ENTITIES]; | |
588 sbitmap *del; | |
589 sbitmap *insert; | |
590 | |
591 /* Set the anticipatable and computing arrays. */ | |
592 sbitmap_vector_zero (antic, last_basic_block); | |
593 sbitmap_vector_zero (comp, last_basic_block); | |
594 for (j = n_entities - 1; j >= 0; j--) | |
595 { | |
596 int m = current_mode[j] = MODE_PRIORITY_TO_MODE (entity_map[j], i); | |
597 struct bb_info *info = bb_info[j]; | |
598 | |
599 FOR_EACH_BB (bb) | |
600 { | |
601 if (info[bb->index].seginfo->mode == m) | |
602 SET_BIT (antic[bb->index], j); | |
603 | |
604 if (info[bb->index].computing == m) | |
605 SET_BIT (comp[bb->index], j); | |
606 } | |
607 } | |
608 | |
609 /* Calculate the optimal locations for the | |
610 placement mode switches to modes with priority I. */ | |
611 | |
612 FOR_EACH_BB (bb) | |
613 sbitmap_not (kill[bb->index], transp[bb->index]); | |
614 edge_list = pre_edge_lcm (n_entities, transp, comp, antic, | |
615 kill, &insert, &del); | |
616 | |
617 for (j = n_entities - 1; j >= 0; j--) | |
618 { | |
619 /* Insert all mode sets that have been inserted by lcm. */ | |
620 int no_mode = num_modes[entity_map[j]]; | |
621 | |
622 /* Wherever we have moved a mode setting upwards in the flow graph, | |
623 the blocks between the new setting site and the now redundant | |
624 computation ceases to be transparent for any lower-priority | |
625 mode of the same entity. First set the aux field of each | |
626 insertion site edge non-transparent, then propagate the new | |
627 non-transparency from the redundant computation upwards till | |
628 we hit an insertion site or an already non-transparent block. */ | |
629 for (e = NUM_EDGES (edge_list) - 1; e >= 0; e--) | |
630 { | |
631 edge eg = INDEX_EDGE (edge_list, e); | |
632 int mode; | |
633 basic_block src_bb; | |
634 HARD_REG_SET live_at_edge; | |
635 rtx mode_set; | |
636 | |
637 eg->aux = 0; | |
638 | |
639 if (! TEST_BIT (insert[e], j)) | |
640 continue; | |
641 | |
642 eg->aux = (void *)1; | |
643 | |
644 mode = current_mode[j]; | |
645 src_bb = eg->src; | |
646 | |
647 REG_SET_TO_HARD_REG_SET (live_at_edge, df_get_live_out (src_bb)); | |
648 | |
649 start_sequence (); | |
650 EMIT_MODE_SET (entity_map[j], mode, live_at_edge); | |
651 mode_set = get_insns (); | |
652 end_sequence (); | |
653 | |
654 /* Do not bother to insert empty sequence. */ | |
655 if (mode_set == NULL_RTX) | |
656 continue; | |
657 | |
658 /* We should not get an abnormal edge here. */ | |
659 gcc_assert (! (eg->flags & EDGE_ABNORMAL)); | |
660 | |
661 need_commit = 1; | |
662 insert_insn_on_edge (mode_set, eg); | |
663 } | |
664 | |
665 FOR_EACH_BB_REVERSE (bb) | |
666 if (TEST_BIT (del[bb->index], j)) | |
667 { | |
668 make_preds_opaque (bb, j); | |
669 /* Cancel the 'deleted' mode set. */ | |
670 bb_info[j][bb->index].seginfo->mode = no_mode; | |
671 } | |
672 } | |
673 | |
674 sbitmap_vector_free (del); | |
675 sbitmap_vector_free (insert); | |
676 clear_aux_for_edges (); | |
677 free_edge_list (edge_list); | |
678 } | |
679 | |
680 /* Now output the remaining mode sets in all the segments. */ | |
681 for (j = n_entities - 1; j >= 0; j--) | |
682 { | |
683 int no_mode = num_modes[entity_map[j]]; | |
684 | |
685 FOR_EACH_BB_REVERSE (bb) | |
686 { | |
687 struct seginfo *ptr, *next; | |
688 for (ptr = bb_info[j][bb->index].seginfo; ptr; ptr = next) | |
689 { | |
690 next = ptr->next; | |
691 if (ptr->mode != no_mode) | |
692 { | |
693 rtx mode_set; | |
694 | |
695 start_sequence (); | |
696 EMIT_MODE_SET (entity_map[j], ptr->mode, ptr->regs_live); | |
697 mode_set = get_insns (); | |
698 end_sequence (); | |
699 | |
700 /* Insert MODE_SET only if it is nonempty. */ | |
701 if (mode_set != NULL_RTX) | |
702 { | |
703 emited = true; | |
704 if (NOTE_INSN_BASIC_BLOCK_P (ptr->insn_ptr)) | |
705 emit_insn_after (mode_set, ptr->insn_ptr); | |
706 else | |
707 emit_insn_before (mode_set, ptr->insn_ptr); | |
708 } | |
709 } | |
710 | |
711 free (ptr); | |
712 } | |
713 } | |
714 | |
715 free (bb_info[j]); | |
716 } | |
717 | |
718 /* Finished. Free up all the things we've allocated. */ | |
719 sbitmap_vector_free (kill); | |
720 sbitmap_vector_free (antic); | |
721 sbitmap_vector_free (transp); | |
722 sbitmap_vector_free (comp); | |
723 | |
724 if (need_commit) | |
725 commit_edge_insertions (); | |
726 | |
727 #if defined (MODE_ENTRY) && defined (MODE_EXIT) | |
728 cleanup_cfg (CLEANUP_NO_INSN_DEL); | |
729 #else | |
730 if (!need_commit && !emited) | |
731 return 0; | |
732 #endif | |
733 | |
734 return 1; | |
735 } | |
736 | |
737 #endif /* OPTIMIZE_MODE_SWITCHING */ | |
738 | |
739 static bool | |
740 gate_mode_switching (void) | |
741 { | |
742 #ifdef OPTIMIZE_MODE_SWITCHING | |
743 return true; | |
744 #else | |
745 return false; | |
746 #endif | |
747 } | |
748 | |
749 static unsigned int | |
750 rest_of_handle_mode_switching (void) | |
751 { | |
752 #ifdef OPTIMIZE_MODE_SWITCHING | |
753 optimize_mode_switching (); | |
754 #endif /* OPTIMIZE_MODE_SWITCHING */ | |
755 return 0; | |
756 } | |
757 | |
758 | |
759 struct rtl_opt_pass pass_mode_switching = | |
760 { | |
761 { | |
762 RTL_PASS, | |
763 "mode_sw", /* name */ | |
764 gate_mode_switching, /* gate */ | |
765 rest_of_handle_mode_switching, /* execute */ | |
766 NULL, /* sub */ | |
767 NULL, /* next */ | |
768 0, /* static_pass_number */ | |
769 TV_MODE_SWITCH, /* tv_id */ | |
770 0, /* properties_required */ | |
771 0, /* properties_provided */ | |
772 0, /* properties_destroyed */ | |
773 0, /* todo_flags_start */ | |
774 TODO_df_finish | TODO_verify_rtl_sharing | | |
775 TODO_dump_func /* todo_flags_finish */ | |
776 } | |
777 }; |