0
|
1 /* CPU mode switching
|
|
2 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008,
|
|
3 2009 Free Software Foundation, Inc.
|
|
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"
|
|
25 #include "rtl.h"
|
|
26 #include "regs.h"
|
|
27 #include "hard-reg-set.h"
|
|
28 #include "flags.h"
|
|
29 #include "real.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"
|
|
39
|
|
40 /* We want target macros for the mode switching code to be able to refer
|
|
41 to instruction attribute values. */
|
|
42 #include "insn-attr.h"
|
|
43
|
|
44 #ifdef OPTIMIZE_MODE_SWITCHING
|
|
45
|
|
46 /* The algorithm for setting the modes consists of scanning the insn list
|
|
47 and finding all the insns which require a specific mode. Each insn gets
|
|
48 a unique struct seginfo element. These structures are inserted into a list
|
|
49 for each basic block. For each entity, there is an array of bb_info over
|
|
50 the flow graph basic blocks (local var 'bb_info'), and contains a list
|
|
51 of all insns within that basic block, in the order they are encountered.
|
|
52
|
|
53 For each entity, any basic block WITHOUT any insns requiring a specific
|
|
54 mode are given a single entry, without a mode. (Each basic block
|
|
55 in the flow graph must have at least one entry in the segment table.)
|
|
56
|
|
57 The LCM algorithm is then run over the flow graph to determine where to
|
|
58 place the sets to the highest-priority value in respect of first the first
|
|
59 insn in any one block. Any adjustments required to the transparency
|
|
60 vectors are made, then the next iteration starts for the next-lower
|
|
61 priority mode, till for each entity all modes are exhausted.
|
|
62
|
|
63 More details are located in the code for optimize_mode_switching(). */
|
|
64
|
|
65 /* This structure contains the information for each insn which requires
|
|
66 either single or double mode to be set.
|
|
67 MODE is the mode this insn must be executed in.
|
|
68 INSN_PTR is the insn to be executed (may be the note that marks the
|
|
69 beginning of a basic block).
|
|
70 BBNUM is the flow graph basic block this insn occurs in.
|
|
71 NEXT is the next insn in the same basic block. */
|
|
72 struct seginfo
|
|
73 {
|
|
74 int mode;
|
|
75 rtx insn_ptr;
|
|
76 int bbnum;
|
|
77 struct seginfo *next;
|
|
78 HARD_REG_SET regs_live;
|
|
79 };
|
|
80
|
|
81 struct bb_info
|
|
82 {
|
|
83 struct seginfo *seginfo;
|
|
84 int computing;
|
|
85 };
|
|
86
|
|
87 /* These bitmaps are used for the LCM algorithm. */
|
|
88
|
|
89 static sbitmap *antic;
|
|
90 static sbitmap *transp;
|
|
91 static sbitmap *comp;
|
|
92
|
|
93 static struct seginfo * new_seginfo (int, rtx, int, HARD_REG_SET);
|
|
94 static void add_seginfo (struct bb_info *, struct seginfo *);
|
|
95 static void reg_dies (rtx, HARD_REG_SET *);
|
|
96 static void reg_becomes_live (rtx, const_rtx, void *);
|
|
97 static void make_preds_opaque (basic_block, int);
|
|
98
|
|
99
|
|
100 /* This function will allocate a new BBINFO structure, initialized
|
|
101 with the MODE, INSN, and basic block BB parameters. */
|
|
102
|
|
103 static struct seginfo *
|
|
104 new_seginfo (int mode, rtx insn, int bb, HARD_REG_SET regs_live)
|
|
105 {
|
|
106 struct seginfo *ptr;
|
|
107 ptr = XNEW (struct seginfo);
|
|
108 ptr->mode = mode;
|
|
109 ptr->insn_ptr = insn;
|
|
110 ptr->bbnum = bb;
|
|
111 ptr->next = NULL;
|
|
112 COPY_HARD_REG_SET (ptr->regs_live, regs_live);
|
|
113 return ptr;
|
|
114 }
|
|
115
|
|
116 /* Add a seginfo element to the end of a list.
|
|
117 HEAD is a pointer to the list beginning.
|
|
118 INFO is the structure to be linked in. */
|
|
119
|
|
120 static void
|
|
121 add_seginfo (struct bb_info *head, struct seginfo *info)
|
|
122 {
|
|
123 struct seginfo *ptr;
|
|
124
|
|
125 if (head->seginfo == NULL)
|
|
126 head->seginfo = info;
|
|
127 else
|
|
128 {
|
|
129 ptr = head->seginfo;
|
|
130 while (ptr->next != NULL)
|
|
131 ptr = ptr->next;
|
|
132 ptr->next = info;
|
|
133 }
|
|
134 }
|
|
135
|
|
136 /* Make all predecessors of basic block B opaque, recursively, till we hit
|
|
137 some that are already non-transparent, or an edge where aux is set; that
|
|
138 denotes that a mode set is to be done on that edge.
|
|
139 J is the bit number in the bitmaps that corresponds to the entity that
|
|
140 we are currently handling mode-switching for. */
|
|
141
|
|
142 static void
|
|
143 make_preds_opaque (basic_block b, int j)
|
|
144 {
|
|
145 edge e;
|
|
146 edge_iterator ei;
|
|
147
|
|
148 FOR_EACH_EDGE (e, ei, b->preds)
|
|
149 {
|
|
150 basic_block pb = e->src;
|
|
151
|
|
152 if (e->aux || ! TEST_BIT (transp[pb->index], j))
|
|
153 continue;
|
|
154
|
|
155 RESET_BIT (transp[pb->index], j);
|
|
156 make_preds_opaque (pb, j);
|
|
157 }
|
|
158 }
|
|
159
|
|
160 /* Record in LIVE that register REG died. */
|
|
161
|
|
162 static void
|
|
163 reg_dies (rtx reg, HARD_REG_SET *live)
|
|
164 {
|
|
165 int regno;
|
|
166
|
|
167 if (!REG_P (reg))
|
|
168 return;
|
|
169
|
|
170 regno = REGNO (reg);
|
|
171 if (regno < FIRST_PSEUDO_REGISTER)
|
|
172 remove_from_hard_reg_set (live, GET_MODE (reg), regno);
|
|
173 }
|
|
174
|
|
175 /* Record in LIVE that register REG became live.
|
|
176 This is called via note_stores. */
|
|
177
|
|
178 static void
|
|
179 reg_becomes_live (rtx reg, const_rtx setter ATTRIBUTE_UNUSED, void *live)
|
|
180 {
|
|
181 int regno;
|
|
182
|
|
183 if (GET_CODE (reg) == SUBREG)
|
|
184 reg = SUBREG_REG (reg);
|
|
185
|
|
186 if (!REG_P (reg))
|
|
187 return;
|
|
188
|
|
189 regno = REGNO (reg);
|
|
190 if (regno < FIRST_PSEUDO_REGISTER)
|
|
191 add_to_hard_reg_set ((HARD_REG_SET *) live, GET_MODE (reg), regno);
|
|
192 }
|
|
193
|
|
194 /* Make sure if MODE_ENTRY is defined the MODE_EXIT is defined
|
|
195 and vice versa. */
|
|
196 #if defined (MODE_ENTRY) != defined (MODE_EXIT)
|
|
197 #error "Both MODE_ENTRY and MODE_EXIT must be defined"
|
|
198 #endif
|
|
199
|
|
200 #if defined (MODE_ENTRY) && defined (MODE_EXIT)
|
|
201 /* Split the fallthrough edge to the exit block, so that we can note
|
|
202 that there NORMAL_MODE is required. Return the new block if it's
|
|
203 inserted before the exit block. Otherwise return null. */
|
|
204
|
|
205 static basic_block
|
|
206 create_pre_exit (int n_entities, int *entity_map, const int *num_modes)
|
|
207 {
|
|
208 edge eg;
|
|
209 edge_iterator ei;
|
|
210 basic_block pre_exit;
|
|
211
|
|
212 /* The only non-call predecessor at this stage is a block with a
|
|
213 fallthrough edge; there can be at most one, but there could be
|
|
214 none at all, e.g. when exit is called. */
|
|
215 pre_exit = 0;
|
|
216 FOR_EACH_EDGE (eg, ei, EXIT_BLOCK_PTR->preds)
|
|
217 if (eg->flags & EDGE_FALLTHRU)
|
|
218 {
|
|
219 basic_block src_bb = eg->src;
|
|
220 rtx last_insn, ret_reg;
|
|
221
|
|
222 gcc_assert (!pre_exit);
|
|
223 /* If this function returns a value at the end, we have to
|
|
224 insert the final mode switch before the return value copy
|
|
225 to its hard register. */
|
|
226 if (EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 1
|
|
227 && NONJUMP_INSN_P ((last_insn = BB_END (src_bb)))
|
|
228 && GET_CODE (PATTERN (last_insn)) == USE
|
|
229 && GET_CODE ((ret_reg = XEXP (PATTERN (last_insn), 0))) == REG)
|
|
230 {
|
|
231 int ret_start = REGNO (ret_reg);
|
|
232 int nregs = hard_regno_nregs[ret_start][GET_MODE (ret_reg)];
|
|
233 int ret_end = ret_start + nregs;
|
|
234 int short_block = 0;
|
|
235 int maybe_builtin_apply = 0;
|
|
236 int forced_late_switch = 0;
|
|
237 rtx before_return_copy;
|
|
238
|
|
239 do
|
|
240 {
|
|
241 rtx return_copy = PREV_INSN (last_insn);
|
|
242 rtx return_copy_pat, copy_reg;
|
|
243 int copy_start, copy_num;
|
|
244 int j;
|
|
245
|
|
246 if (INSN_P (return_copy))
|
|
247 {
|
|
248 /* When using SJLJ exceptions, the call to the
|
|
249 unregister function is inserted between the
|
|
250 clobber of the return value and the copy.
|
|
251 We do not want to split the block before this
|
|
252 or any other call; if we have not found the
|
|
253 copy yet, the copy must have been deleted. */
|
|
254 if (CALL_P (return_copy))
|
|
255 {
|
|
256 short_block = 1;
|
|
257 break;
|
|
258 }
|
|
259 return_copy_pat = PATTERN (return_copy);
|
|
260 switch (GET_CODE (return_copy_pat))
|
|
261 {
|
|
262 case USE:
|
|
263 /* Skip __builtin_apply pattern. */
|
|
264 if (GET_CODE (XEXP (return_copy_pat, 0)) == REG
|
|
265 && (FUNCTION_VALUE_REGNO_P
|
|
266 (REGNO (XEXP (return_copy_pat, 0)))))
|
|
267 {
|
|
268 maybe_builtin_apply = 1;
|
|
269 last_insn = return_copy;
|
|
270 continue;
|
|
271 }
|
|
272 break;
|
|
273
|
|
274 case ASM_OPERANDS:
|
|
275 /* Skip barrier insns. */
|
|
276 if (!MEM_VOLATILE_P (return_copy_pat))
|
|
277 break;
|
|
278
|
|
279 /* Fall through. */
|
|
280
|
|
281 case ASM_INPUT:
|
|
282 case UNSPEC_VOLATILE:
|
|
283 last_insn = return_copy;
|
|
284 continue;
|
|
285
|
|
286 default:
|
|
287 break;
|
|
288 }
|
|
289
|
|
290 /* If the return register is not (in its entirety)
|
|
291 likely spilled, the return copy might be
|
|
292 partially or completely optimized away. */
|
|
293 return_copy_pat = single_set (return_copy);
|
|
294 if (!return_copy_pat)
|
|
295 {
|
|
296 return_copy_pat = PATTERN (return_copy);
|
|
297 if (GET_CODE (return_copy_pat) != CLOBBER)
|
|
298 break;
|
|
299 else if (!optimize)
|
|
300 {
|
|
301 /* This might be (clobber (reg [<result>]))
|
|
302 when not optimizing. Then check if
|
|
303 the previous insn is the clobber for
|
|
304 the return register. */
|
|
305 copy_reg = SET_DEST (return_copy_pat);
|
|
306 if (GET_CODE (copy_reg) == REG
|
|
307 && !HARD_REGISTER_NUM_P (REGNO (copy_reg)))
|
|
308 {
|
|
309 if (INSN_P (PREV_INSN (return_copy)))
|
|
310 {
|
|
311 return_copy = PREV_INSN (return_copy);
|
|
312 return_copy_pat = PATTERN (return_copy);
|
|
313 if (GET_CODE (return_copy_pat) != CLOBBER)
|
|
314 break;
|
|
315 }
|
|
316 }
|
|
317 }
|
|
318 }
|
|
319 copy_reg = SET_DEST (return_copy_pat);
|
|
320 if (GET_CODE (copy_reg) == REG)
|
|
321 copy_start = REGNO (copy_reg);
|
|
322 else if (GET_CODE (copy_reg) == SUBREG
|
|
323 && GET_CODE (SUBREG_REG (copy_reg)) == REG)
|
|
324 copy_start = REGNO (SUBREG_REG (copy_reg));
|
|
325 else
|
|
326 break;
|
|
327 if (copy_start >= FIRST_PSEUDO_REGISTER)
|
|
328 break;
|
|
329 copy_num
|
|
330 = hard_regno_nregs[copy_start][GET_MODE (copy_reg)];
|
|
331
|
|
332 /* If the return register is not likely spilled, - as is
|
|
333 the case for floating point on SH4 - then it might
|
|
334 be set by an arithmetic operation that needs a
|
|
335 different mode than the exit block. */
|
|
336 for (j = n_entities - 1; j >= 0; j--)
|
|
337 {
|
|
338 int e = entity_map[j];
|
|
339 int mode = MODE_NEEDED (e, return_copy);
|
|
340
|
|
341 if (mode != num_modes[e] && mode != MODE_EXIT (e))
|
|
342 break;
|
|
343 }
|
|
344 if (j >= 0)
|
|
345 {
|
|
346 /* For the SH4, floating point loads depend on fpscr,
|
|
347 thus we might need to put the final mode switch
|
|
348 after the return value copy. That is still OK,
|
|
349 because a floating point return value does not
|
|
350 conflict with address reloads. */
|
|
351 if (copy_start >= ret_start
|
|
352 && copy_start + copy_num <= ret_end
|
|
353 && OBJECT_P (SET_SRC (return_copy_pat)))
|
|
354 forced_late_switch = 1;
|
|
355 break;
|
|
356 }
|
|
357
|
|
358 if (copy_start >= ret_start
|
|
359 && copy_start + copy_num <= ret_end)
|
|
360 nregs -= copy_num;
|
|
361 else if (!maybe_builtin_apply
|
|
362 || !FUNCTION_VALUE_REGNO_P (copy_start))
|
|
363 break;
|
|
364 last_insn = return_copy;
|
|
365 }
|
|
366 /* ??? Exception handling can lead to the return value
|
|
367 copy being already separated from the return value use,
|
|
368 as in unwind-dw2.c .
|
|
369 Similarly, conditionally returning without a value,
|
|
370 and conditionally using builtin_return can lead to an
|
|
371 isolated use. */
|
|
372 if (return_copy == BB_HEAD (src_bb))
|
|
373 {
|
|
374 short_block = 1;
|
|
375 break;
|
|
376 }
|
|
377 last_insn = return_copy;
|
|
378 }
|
|
379 while (nregs);
|
|
380
|
|
381 /* If we didn't see a full return value copy, verify that there
|
|
382 is a plausible reason for this. If some, but not all of the
|
|
383 return register is likely spilled, we can expect that there
|
|
384 is a copy for the likely spilled part. */
|
|
385 gcc_assert (!nregs
|
|
386 || forced_late_switch
|
|
387 || short_block
|
|
388 || !(CLASS_LIKELY_SPILLED_P
|
|
389 (REGNO_REG_CLASS (ret_start)))
|
|
390 || (nregs
|
|
391 != hard_regno_nregs[ret_start][GET_MODE (ret_reg)])
|
|
392 /* For multi-hard-register floating point
|
|
393 values, sometimes the likely-spilled part
|
|
394 is ordinarily copied first, then the other
|
|
395 part is set with an arithmetic operation.
|
|
396 This doesn't actually cause reload
|
|
397 failures, so let it pass. */
|
|
398 || (GET_MODE_CLASS (GET_MODE (ret_reg)) != MODE_INT
|
|
399 && nregs != 1));
|
|
400
|
|
401 if (INSN_P (last_insn))
|
|
402 {
|
|
403 before_return_copy
|
|
404 = emit_note_before (NOTE_INSN_DELETED, last_insn);
|
|
405 /* Instructions preceding LAST_INSN in the same block might
|
|
406 require a different mode than MODE_EXIT, so if we might
|
|
407 have such instructions, keep them in a separate block
|
|
408 from pre_exit. */
|
|
409 if (last_insn != BB_HEAD (src_bb))
|
|
410 src_bb = split_block (src_bb,
|
|
411 PREV_INSN (before_return_copy))->dest;
|
|
412 }
|
|
413 else
|
|
414 before_return_copy = last_insn;
|
|
415 pre_exit = split_block (src_bb, before_return_copy)->src;
|
|
416 }
|
|
417 else
|
|
418 {
|
|
419 pre_exit = split_edge (eg);
|
|
420 }
|
|
421 }
|
|
422
|
|
423 return pre_exit;
|
|
424 }
|
|
425 #endif
|
|
426
|
|
427 /* Find all insns that need a particular mode setting, and insert the
|
|
428 necessary mode switches. Return true if we did work. */
|
|
429
|
|
430 static int
|
|
431 optimize_mode_switching (void)
|
|
432 {
|
|
433 rtx insn;
|
|
434 int e;
|
|
435 basic_block bb;
|
|
436 int need_commit = 0;
|
|
437 sbitmap *kill;
|
|
438 struct edge_list *edge_list;
|
|
439 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
|
|
440 #define N_ENTITIES ARRAY_SIZE (num_modes)
|
|
441 int entity_map[N_ENTITIES];
|
|
442 struct bb_info *bb_info[N_ENTITIES];
|
|
443 int i, j;
|
|
444 int n_entities;
|
|
445 int max_num_modes = 0;
|
|
446 bool emited = false;
|
|
447 basic_block post_entry ATTRIBUTE_UNUSED, pre_exit ATTRIBUTE_UNUSED;
|
|
448
|
|
449 for (e = N_ENTITIES - 1, n_entities = 0; e >= 0; e--)
|
|
450 if (OPTIMIZE_MODE_SWITCHING (e))
|
|
451 {
|
|
452 int entry_exit_extra = 0;
|
|
453
|
|
454 /* Create the list of segments within each basic block.
|
|
455 If NORMAL_MODE is defined, allow for two extra
|
|
456 blocks split from the entry and exit block. */
|
|
457 #if defined (MODE_ENTRY) && defined (MODE_EXIT)
|
|
458 entry_exit_extra = 3;
|
|
459 #endif
|
|
460 bb_info[n_entities]
|
|
461 = XCNEWVEC (struct bb_info, last_basic_block + entry_exit_extra);
|
|
462 entity_map[n_entities++] = e;
|
|
463 if (num_modes[e] > max_num_modes)
|
|
464 max_num_modes = num_modes[e];
|
|
465 }
|
|
466
|
|
467 if (! n_entities)
|
|
468 return 0;
|
|
469
|
|
470 #if defined (MODE_ENTRY) && defined (MODE_EXIT)
|
|
471 /* Split the edge from the entry block, so that we can note that
|
|
472 there NORMAL_MODE is supplied. */
|
|
473 post_entry = split_edge (single_succ_edge (ENTRY_BLOCK_PTR));
|
|
474 pre_exit = create_pre_exit (n_entities, entity_map, num_modes);
|
|
475 #endif
|
|
476
|
|
477 df_analyze ();
|
|
478
|
|
479 /* Create the bitmap vectors. */
|
|
480
|
|
481 antic = sbitmap_vector_alloc (last_basic_block, n_entities);
|
|
482 transp = sbitmap_vector_alloc (last_basic_block, n_entities);
|
|
483 comp = sbitmap_vector_alloc (last_basic_block, n_entities);
|
|
484
|
|
485 sbitmap_vector_ones (transp, last_basic_block);
|
|
486
|
|
487 for (j = n_entities - 1; j >= 0; j--)
|
|
488 {
|
|
489 int e = entity_map[j];
|
|
490 int no_mode = num_modes[e];
|
|
491 struct bb_info *info = bb_info[j];
|
|
492
|
|
493 /* Determine what the first use (if any) need for a mode of entity E is.
|
|
494 This will be the mode that is anticipatable for this block.
|
|
495 Also compute the initial transparency settings. */
|
|
496 FOR_EACH_BB (bb)
|
|
497 {
|
|
498 struct seginfo *ptr;
|
|
499 int last_mode = no_mode;
|
|
500 HARD_REG_SET live_now;
|
|
501
|
|
502 REG_SET_TO_HARD_REG_SET (live_now, df_get_live_in (bb));
|
|
503
|
|
504 /* Pretend the mode is clobbered across abnormal edges. */
|
|
505 {
|
|
506 edge_iterator ei;
|
|
507 edge e;
|
|
508 FOR_EACH_EDGE (e, ei, bb->preds)
|
|
509 if (e->flags & EDGE_COMPLEX)
|
|
510 break;
|
|
511 if (e)
|
|
512 {
|
|
513 ptr = new_seginfo (no_mode, BB_HEAD (bb), bb->index, live_now);
|
|
514 add_seginfo (info + bb->index, ptr);
|
|
515 RESET_BIT (transp[bb->index], j);
|
|
516 }
|
|
517 }
|
|
518
|
|
519 for (insn = BB_HEAD (bb);
|
|
520 insn != NULL && insn != NEXT_INSN (BB_END (bb));
|
|
521 insn = NEXT_INSN (insn))
|
|
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 };
|