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