1*e4b17023SJohn Marino /* RTL-based forward propagation pass for GNU compiler.
2*e4b17023SJohn Marino Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
3*e4b17023SJohn Marino Free Software Foundation, Inc.
4*e4b17023SJohn Marino Contributed by Paolo Bonzini and Steven Bosscher.
5*e4b17023SJohn Marino
6*e4b17023SJohn Marino This file is part of GCC.
7*e4b17023SJohn Marino
8*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
9*e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
10*e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
11*e4b17023SJohn Marino version.
12*e4b17023SJohn Marino
13*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14*e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
15*e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16*e4b17023SJohn Marino for more details.
17*e4b17023SJohn Marino
18*e4b17023SJohn Marino You should have received a copy of the GNU General Public License
19*e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
20*e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
21*e4b17023SJohn Marino
22*e4b17023SJohn Marino #include "config.h"
23*e4b17023SJohn Marino #include "system.h"
24*e4b17023SJohn Marino #include "coretypes.h"
25*e4b17023SJohn Marino #include "tm.h"
26*e4b17023SJohn Marino #include "diagnostic-core.h"
27*e4b17023SJohn Marino
28*e4b17023SJohn Marino #include "sparseset.h"
29*e4b17023SJohn Marino #include "timevar.h"
30*e4b17023SJohn Marino #include "rtl.h"
31*e4b17023SJohn Marino #include "tm_p.h"
32*e4b17023SJohn Marino #include "insn-config.h"
33*e4b17023SJohn Marino #include "recog.h"
34*e4b17023SJohn Marino #include "flags.h"
35*e4b17023SJohn Marino #include "obstack.h"
36*e4b17023SJohn Marino #include "basic-block.h"
37*e4b17023SJohn Marino #include "output.h"
38*e4b17023SJohn Marino #include "df.h"
39*e4b17023SJohn Marino #include "target.h"
40*e4b17023SJohn Marino #include "cfgloop.h"
41*e4b17023SJohn Marino #include "tree-pass.h"
42*e4b17023SJohn Marino #include "domwalk.h"
43*e4b17023SJohn Marino #include "emit-rtl.h"
44*e4b17023SJohn Marino
45*e4b17023SJohn Marino
46*e4b17023SJohn Marino /* This pass does simple forward propagation and simplification when an
47*e4b17023SJohn Marino operand of an insn can only come from a single def. This pass uses
48*e4b17023SJohn Marino df.c, so it is global. However, we only do limited analysis of
49*e4b17023SJohn Marino available expressions.
50*e4b17023SJohn Marino
51*e4b17023SJohn Marino 1) The pass tries to propagate the source of the def into the use,
52*e4b17023SJohn Marino and checks if the result is independent of the substituted value.
53*e4b17023SJohn Marino For example, the high word of a (zero_extend:DI (reg:SI M)) is always
54*e4b17023SJohn Marino zero, independent of the source register.
55*e4b17023SJohn Marino
56*e4b17023SJohn Marino In particular, we propagate constants into the use site. Sometimes
57*e4b17023SJohn Marino RTL expansion did not put the constant in the same insn on purpose,
58*e4b17023SJohn Marino to satisfy a predicate, and the result will fail to be recognized;
59*e4b17023SJohn Marino but this happens rarely and in this case we can still create a
60*e4b17023SJohn Marino REG_EQUAL note. For multi-word operations, this
61*e4b17023SJohn Marino
62*e4b17023SJohn Marino (set (subreg:SI (reg:DI 120) 0) (const_int 0))
63*e4b17023SJohn Marino (set (subreg:SI (reg:DI 120) 4) (const_int -1))
64*e4b17023SJohn Marino (set (subreg:SI (reg:DI 122) 0)
65*e4b17023SJohn Marino (ior:SI (subreg:SI (reg:DI 119) 0) (subreg:SI (reg:DI 120) 0)))
66*e4b17023SJohn Marino (set (subreg:SI (reg:DI 122) 4)
67*e4b17023SJohn Marino (ior:SI (subreg:SI (reg:DI 119) 4) (subreg:SI (reg:DI 120) 4)))
68*e4b17023SJohn Marino
69*e4b17023SJohn Marino can be simplified to the much simpler
70*e4b17023SJohn Marino
71*e4b17023SJohn Marino (set (subreg:SI (reg:DI 122) 0) (subreg:SI (reg:DI 119)))
72*e4b17023SJohn Marino (set (subreg:SI (reg:DI 122) 4) (const_int -1))
73*e4b17023SJohn Marino
74*e4b17023SJohn Marino This particular propagation is also effective at putting together
75*e4b17023SJohn Marino complex addressing modes. We are more aggressive inside MEMs, in
76*e4b17023SJohn Marino that all definitions are propagated if the use is in a MEM; if the
77*e4b17023SJohn Marino result is a valid memory address we check address_cost to decide
78*e4b17023SJohn Marino whether the substitution is worthwhile.
79*e4b17023SJohn Marino
80*e4b17023SJohn Marino 2) The pass propagates register copies. This is not as effective as
81*e4b17023SJohn Marino the copy propagation done by CSE's canon_reg, which works by walking
82*e4b17023SJohn Marino the instruction chain, it can help the other transformations.
83*e4b17023SJohn Marino
84*e4b17023SJohn Marino We should consider removing this optimization, and instead reorder the
85*e4b17023SJohn Marino RTL passes, because GCSE does this transformation too. With some luck,
86*e4b17023SJohn Marino the CSE pass at the end of rest_of_handle_gcse could also go away.
87*e4b17023SJohn Marino
88*e4b17023SJohn Marino 3) The pass looks for paradoxical subregs that are actually unnecessary.
89*e4b17023SJohn Marino Things like this:
90*e4b17023SJohn Marino
91*e4b17023SJohn Marino (set (reg:QI 120) (subreg:QI (reg:SI 118) 0))
92*e4b17023SJohn Marino (set (reg:QI 121) (subreg:QI (reg:SI 119) 0))
93*e4b17023SJohn Marino (set (reg:SI 122) (plus:SI (subreg:SI (reg:QI 120) 0)
94*e4b17023SJohn Marino (subreg:SI (reg:QI 121) 0)))
95*e4b17023SJohn Marino
96*e4b17023SJohn Marino are very common on machines that can only do word-sized operations.
97*e4b17023SJohn Marino For each use of a paradoxical subreg (subreg:WIDER (reg:NARROW N) 0),
98*e4b17023SJohn Marino if it has a single def and it is (subreg:NARROW (reg:WIDE M) 0),
99*e4b17023SJohn Marino we can replace the paradoxical subreg with simply (reg:WIDE M). The
100*e4b17023SJohn Marino above will simplify this to
101*e4b17023SJohn Marino
102*e4b17023SJohn Marino (set (reg:QI 120) (subreg:QI (reg:SI 118) 0))
103*e4b17023SJohn Marino (set (reg:QI 121) (subreg:QI (reg:SI 119) 0))
104*e4b17023SJohn Marino (set (reg:SI 122) (plus:SI (reg:SI 118) (reg:SI 119)))
105*e4b17023SJohn Marino
106*e4b17023SJohn Marino where the first two insns are now dead.
107*e4b17023SJohn Marino
108*e4b17023SJohn Marino We used to use reaching definitions to find which uses have a
109*e4b17023SJohn Marino single reaching definition (sounds obvious...), but this is too
110*e4b17023SJohn Marino complex a problem in nasty testcases like PR33928. Now we use the
111*e4b17023SJohn Marino multiple definitions problem in df-problems.c. The similarity
112*e4b17023SJohn Marino between that problem and SSA form creation is taken further, in
113*e4b17023SJohn Marino that fwprop does a dominator walk to create its chains; however,
114*e4b17023SJohn Marino instead of creating a PHI function where multiple definitions meet
115*e4b17023SJohn Marino I just punt and record only singleton use-def chains, which is
116*e4b17023SJohn Marino all that is needed by fwprop. */
117*e4b17023SJohn Marino
118*e4b17023SJohn Marino
119*e4b17023SJohn Marino static int num_changes;
120*e4b17023SJohn Marino
121*e4b17023SJohn Marino DEF_VEC_P(df_ref);
122*e4b17023SJohn Marino DEF_VEC_ALLOC_P(df_ref,heap);
123*e4b17023SJohn Marino static VEC(df_ref,heap) *use_def_ref;
124*e4b17023SJohn Marino static VEC(df_ref,heap) *reg_defs;
125*e4b17023SJohn Marino static VEC(df_ref,heap) *reg_defs_stack;
126*e4b17023SJohn Marino
127*e4b17023SJohn Marino /* The MD bitmaps are trimmed to include only live registers to cut
128*e4b17023SJohn Marino memory usage on testcases like insn-recog.c. Track live registers
129*e4b17023SJohn Marino in the basic block and do not perform forward propagation if the
130*e4b17023SJohn Marino destination is a dead pseudo occurring in a note. */
131*e4b17023SJohn Marino static bitmap local_md;
132*e4b17023SJohn Marino static bitmap local_lr;
133*e4b17023SJohn Marino
134*e4b17023SJohn Marino /* Return the only def in USE's use-def chain, or NULL if there is
135*e4b17023SJohn Marino more than one def in the chain. */
136*e4b17023SJohn Marino
137*e4b17023SJohn Marino static inline df_ref
get_def_for_use(df_ref use)138*e4b17023SJohn Marino get_def_for_use (df_ref use)
139*e4b17023SJohn Marino {
140*e4b17023SJohn Marino return VEC_index (df_ref, use_def_ref, DF_REF_ID (use));
141*e4b17023SJohn Marino }
142*e4b17023SJohn Marino
143*e4b17023SJohn Marino
144*e4b17023SJohn Marino /* Update the reg_defs vector with non-partial definitions in DEF_REC.
145*e4b17023SJohn Marino TOP_FLAG says which artificials uses should be used, when DEF_REC
146*e4b17023SJohn Marino is an artificial def vector. LOCAL_MD is modified as after a
147*e4b17023SJohn Marino df_md_simulate_* function; we do more or less the same processing
148*e4b17023SJohn Marino done there, so we do not use those functions. */
149*e4b17023SJohn Marino
150*e4b17023SJohn Marino #define DF_MD_GEN_FLAGS \
151*e4b17023SJohn Marino (DF_REF_PARTIAL | DF_REF_CONDITIONAL | DF_REF_MAY_CLOBBER)
152*e4b17023SJohn Marino
153*e4b17023SJohn Marino static void
process_defs(df_ref * def_rec,int top_flag)154*e4b17023SJohn Marino process_defs (df_ref *def_rec, int top_flag)
155*e4b17023SJohn Marino {
156*e4b17023SJohn Marino df_ref def;
157*e4b17023SJohn Marino while ((def = *def_rec++) != NULL)
158*e4b17023SJohn Marino {
159*e4b17023SJohn Marino df_ref curr_def = VEC_index (df_ref, reg_defs, DF_REF_REGNO (def));
160*e4b17023SJohn Marino unsigned int dregno;
161*e4b17023SJohn Marino
162*e4b17023SJohn Marino if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) != top_flag)
163*e4b17023SJohn Marino continue;
164*e4b17023SJohn Marino
165*e4b17023SJohn Marino dregno = DF_REF_REGNO (def);
166*e4b17023SJohn Marino if (curr_def)
167*e4b17023SJohn Marino VEC_safe_push (df_ref, heap, reg_defs_stack, curr_def);
168*e4b17023SJohn Marino else
169*e4b17023SJohn Marino {
170*e4b17023SJohn Marino /* Do not store anything if "transitioning" from NULL to NULL. But
171*e4b17023SJohn Marino otherwise, push a special entry on the stack to tell the
172*e4b17023SJohn Marino leave_block callback that the entry in reg_defs was NULL. */
173*e4b17023SJohn Marino if (DF_REF_FLAGS (def) & DF_MD_GEN_FLAGS)
174*e4b17023SJohn Marino ;
175*e4b17023SJohn Marino else
176*e4b17023SJohn Marino VEC_safe_push (df_ref, heap, reg_defs_stack, def);
177*e4b17023SJohn Marino }
178*e4b17023SJohn Marino
179*e4b17023SJohn Marino if (DF_REF_FLAGS (def) & DF_MD_GEN_FLAGS)
180*e4b17023SJohn Marino {
181*e4b17023SJohn Marino bitmap_set_bit (local_md, dregno);
182*e4b17023SJohn Marino VEC_replace (df_ref, reg_defs, dregno, NULL);
183*e4b17023SJohn Marino }
184*e4b17023SJohn Marino else
185*e4b17023SJohn Marino {
186*e4b17023SJohn Marino bitmap_clear_bit (local_md, dregno);
187*e4b17023SJohn Marino VEC_replace (df_ref, reg_defs, dregno, def);
188*e4b17023SJohn Marino }
189*e4b17023SJohn Marino }
190*e4b17023SJohn Marino }
191*e4b17023SJohn Marino
192*e4b17023SJohn Marino
193*e4b17023SJohn Marino /* Fill the use_def_ref vector with values for the uses in USE_REC,
194*e4b17023SJohn Marino taking reaching definitions info from LOCAL_MD and REG_DEFS.
195*e4b17023SJohn Marino TOP_FLAG says which artificials uses should be used, when USE_REC
196*e4b17023SJohn Marino is an artificial use vector. */
197*e4b17023SJohn Marino
198*e4b17023SJohn Marino static void
process_uses(df_ref * use_rec,int top_flag)199*e4b17023SJohn Marino process_uses (df_ref *use_rec, int top_flag)
200*e4b17023SJohn Marino {
201*e4b17023SJohn Marino df_ref use;
202*e4b17023SJohn Marino while ((use = *use_rec++) != NULL)
203*e4b17023SJohn Marino if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == top_flag)
204*e4b17023SJohn Marino {
205*e4b17023SJohn Marino unsigned int uregno = DF_REF_REGNO (use);
206*e4b17023SJohn Marino if (VEC_index (df_ref, reg_defs, uregno)
207*e4b17023SJohn Marino && !bitmap_bit_p (local_md, uregno)
208*e4b17023SJohn Marino && bitmap_bit_p (local_lr, uregno))
209*e4b17023SJohn Marino VEC_replace (df_ref, use_def_ref, DF_REF_ID (use),
210*e4b17023SJohn Marino VEC_index (df_ref, reg_defs, uregno));
211*e4b17023SJohn Marino }
212*e4b17023SJohn Marino }
213*e4b17023SJohn Marino
214*e4b17023SJohn Marino
215*e4b17023SJohn Marino static void
single_def_use_enter_block(struct dom_walk_data * walk_data ATTRIBUTE_UNUSED,basic_block bb)216*e4b17023SJohn Marino single_def_use_enter_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
217*e4b17023SJohn Marino basic_block bb)
218*e4b17023SJohn Marino {
219*e4b17023SJohn Marino int bb_index = bb->index;
220*e4b17023SJohn Marino struct df_md_bb_info *md_bb_info = df_md_get_bb_info (bb_index);
221*e4b17023SJohn Marino struct df_lr_bb_info *lr_bb_info = df_lr_get_bb_info (bb_index);
222*e4b17023SJohn Marino rtx insn;
223*e4b17023SJohn Marino
224*e4b17023SJohn Marino bitmap_copy (local_md, &md_bb_info->in);
225*e4b17023SJohn Marino bitmap_copy (local_lr, &lr_bb_info->in);
226*e4b17023SJohn Marino
227*e4b17023SJohn Marino /* Push a marker for the leave_block callback. */
228*e4b17023SJohn Marino VEC_safe_push (df_ref, heap, reg_defs_stack, NULL);
229*e4b17023SJohn Marino
230*e4b17023SJohn Marino process_uses (df_get_artificial_uses (bb_index), DF_REF_AT_TOP);
231*e4b17023SJohn Marino process_defs (df_get_artificial_defs (bb_index), DF_REF_AT_TOP);
232*e4b17023SJohn Marino
233*e4b17023SJohn Marino /* We don't call df_simulate_initialize_forwards, as it may overestimate
234*e4b17023SJohn Marino the live registers if there are unused artificial defs. We prefer
235*e4b17023SJohn Marino liveness to be underestimated. */
236*e4b17023SJohn Marino
237*e4b17023SJohn Marino FOR_BB_INSNS (bb, insn)
238*e4b17023SJohn Marino if (INSN_P (insn))
239*e4b17023SJohn Marino {
240*e4b17023SJohn Marino unsigned int uid = INSN_UID (insn);
241*e4b17023SJohn Marino process_uses (DF_INSN_UID_USES (uid), 0);
242*e4b17023SJohn Marino process_uses (DF_INSN_UID_EQ_USES (uid), 0);
243*e4b17023SJohn Marino process_defs (DF_INSN_UID_DEFS (uid), 0);
244*e4b17023SJohn Marino df_simulate_one_insn_forwards (bb, insn, local_lr);
245*e4b17023SJohn Marino }
246*e4b17023SJohn Marino
247*e4b17023SJohn Marino process_uses (df_get_artificial_uses (bb_index), 0);
248*e4b17023SJohn Marino process_defs (df_get_artificial_defs (bb_index), 0);
249*e4b17023SJohn Marino }
250*e4b17023SJohn Marino
251*e4b17023SJohn Marino /* Pop the definitions created in this basic block when leaving its
252*e4b17023SJohn Marino dominated parts. */
253*e4b17023SJohn Marino
254*e4b17023SJohn Marino static void
single_def_use_leave_block(struct dom_walk_data * walk_data ATTRIBUTE_UNUSED,basic_block bb ATTRIBUTE_UNUSED)255*e4b17023SJohn Marino single_def_use_leave_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
256*e4b17023SJohn Marino basic_block bb ATTRIBUTE_UNUSED)
257*e4b17023SJohn Marino {
258*e4b17023SJohn Marino df_ref saved_def;
259*e4b17023SJohn Marino while ((saved_def = VEC_pop (df_ref, reg_defs_stack)) != NULL)
260*e4b17023SJohn Marino {
261*e4b17023SJohn Marino unsigned int dregno = DF_REF_REGNO (saved_def);
262*e4b17023SJohn Marino
263*e4b17023SJohn Marino /* See also process_defs. */
264*e4b17023SJohn Marino if (saved_def == VEC_index (df_ref, reg_defs, dregno))
265*e4b17023SJohn Marino VEC_replace (df_ref, reg_defs, dregno, NULL);
266*e4b17023SJohn Marino else
267*e4b17023SJohn Marino VEC_replace (df_ref, reg_defs, dregno, saved_def);
268*e4b17023SJohn Marino }
269*e4b17023SJohn Marino }
270*e4b17023SJohn Marino
271*e4b17023SJohn Marino
272*e4b17023SJohn Marino /* Build a vector holding the reaching definitions of uses reached by a
273*e4b17023SJohn Marino single dominating definition. */
274*e4b17023SJohn Marino
275*e4b17023SJohn Marino static void
build_single_def_use_links(void)276*e4b17023SJohn Marino build_single_def_use_links (void)
277*e4b17023SJohn Marino {
278*e4b17023SJohn Marino struct dom_walk_data walk_data;
279*e4b17023SJohn Marino
280*e4b17023SJohn Marino /* We use the multiple definitions problem to compute our restricted
281*e4b17023SJohn Marino use-def chains. */
282*e4b17023SJohn Marino df_set_flags (DF_EQ_NOTES);
283*e4b17023SJohn Marino df_md_add_problem ();
284*e4b17023SJohn Marino df_note_add_problem ();
285*e4b17023SJohn Marino df_analyze ();
286*e4b17023SJohn Marino df_maybe_reorganize_use_refs (DF_REF_ORDER_BY_INSN_WITH_NOTES);
287*e4b17023SJohn Marino
288*e4b17023SJohn Marino use_def_ref = VEC_alloc (df_ref, heap, DF_USES_TABLE_SIZE ());
289*e4b17023SJohn Marino VEC_safe_grow_cleared (df_ref, heap, use_def_ref, DF_USES_TABLE_SIZE ());
290*e4b17023SJohn Marino
291*e4b17023SJohn Marino reg_defs = VEC_alloc (df_ref, heap, max_reg_num ());
292*e4b17023SJohn Marino VEC_safe_grow_cleared (df_ref, heap, reg_defs, max_reg_num ());
293*e4b17023SJohn Marino
294*e4b17023SJohn Marino reg_defs_stack = VEC_alloc (df_ref, heap, n_basic_blocks * 10);
295*e4b17023SJohn Marino local_md = BITMAP_ALLOC (NULL);
296*e4b17023SJohn Marino local_lr = BITMAP_ALLOC (NULL);
297*e4b17023SJohn Marino
298*e4b17023SJohn Marino /* Walk the dominator tree looking for single reaching definitions
299*e4b17023SJohn Marino dominating the uses. This is similar to how SSA form is built. */
300*e4b17023SJohn Marino walk_data.dom_direction = CDI_DOMINATORS;
301*e4b17023SJohn Marino walk_data.initialize_block_local_data = NULL;
302*e4b17023SJohn Marino walk_data.before_dom_children = single_def_use_enter_block;
303*e4b17023SJohn Marino walk_data.after_dom_children = single_def_use_leave_block;
304*e4b17023SJohn Marino
305*e4b17023SJohn Marino init_walk_dominator_tree (&walk_data);
306*e4b17023SJohn Marino walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
307*e4b17023SJohn Marino fini_walk_dominator_tree (&walk_data);
308*e4b17023SJohn Marino
309*e4b17023SJohn Marino BITMAP_FREE (local_lr);
310*e4b17023SJohn Marino BITMAP_FREE (local_md);
311*e4b17023SJohn Marino VEC_free (df_ref, heap, reg_defs);
312*e4b17023SJohn Marino VEC_free (df_ref, heap, reg_defs_stack);
313*e4b17023SJohn Marino }
314*e4b17023SJohn Marino
315*e4b17023SJohn Marino
316*e4b17023SJohn Marino /* Do not try to replace constant addresses or addresses of local and
317*e4b17023SJohn Marino argument slots. These MEM expressions are made only once and inserted
318*e4b17023SJohn Marino in many instructions, as well as being used to control symbol table
319*e4b17023SJohn Marino output. It is not safe to clobber them.
320*e4b17023SJohn Marino
321*e4b17023SJohn Marino There are some uncommon cases where the address is already in a register
322*e4b17023SJohn Marino for some reason, but we cannot take advantage of that because we have
323*e4b17023SJohn Marino no easy way to unshare the MEM. In addition, looking up all stack
324*e4b17023SJohn Marino addresses is costly. */
325*e4b17023SJohn Marino
326*e4b17023SJohn Marino static bool
can_simplify_addr(rtx addr)327*e4b17023SJohn Marino can_simplify_addr (rtx addr)
328*e4b17023SJohn Marino {
329*e4b17023SJohn Marino rtx reg;
330*e4b17023SJohn Marino
331*e4b17023SJohn Marino if (CONSTANT_ADDRESS_P (addr))
332*e4b17023SJohn Marino return false;
333*e4b17023SJohn Marino
334*e4b17023SJohn Marino if (GET_CODE (addr) == PLUS)
335*e4b17023SJohn Marino reg = XEXP (addr, 0);
336*e4b17023SJohn Marino else
337*e4b17023SJohn Marino reg = addr;
338*e4b17023SJohn Marino
339*e4b17023SJohn Marino return (!REG_P (reg)
340*e4b17023SJohn Marino || (REGNO (reg) != FRAME_POINTER_REGNUM
341*e4b17023SJohn Marino && REGNO (reg) != HARD_FRAME_POINTER_REGNUM
342*e4b17023SJohn Marino && REGNO (reg) != ARG_POINTER_REGNUM));
343*e4b17023SJohn Marino }
344*e4b17023SJohn Marino
345*e4b17023SJohn Marino /* Returns a canonical version of X for the address, from the point of view,
346*e4b17023SJohn Marino that all multiplications are represented as MULT instead of the multiply
347*e4b17023SJohn Marino by a power of 2 being represented as ASHIFT.
348*e4b17023SJohn Marino
349*e4b17023SJohn Marino Every ASHIFT we find has been made by simplify_gen_binary and was not
350*e4b17023SJohn Marino there before, so it is not shared. So we can do this in place. */
351*e4b17023SJohn Marino
352*e4b17023SJohn Marino static void
canonicalize_address(rtx x)353*e4b17023SJohn Marino canonicalize_address (rtx x)
354*e4b17023SJohn Marino {
355*e4b17023SJohn Marino for (;;)
356*e4b17023SJohn Marino switch (GET_CODE (x))
357*e4b17023SJohn Marino {
358*e4b17023SJohn Marino case ASHIFT:
359*e4b17023SJohn Marino if (CONST_INT_P (XEXP (x, 1))
360*e4b17023SJohn Marino && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (GET_MODE (x))
361*e4b17023SJohn Marino && INTVAL (XEXP (x, 1)) >= 0)
362*e4b17023SJohn Marino {
363*e4b17023SJohn Marino HOST_WIDE_INT shift = INTVAL (XEXP (x, 1));
364*e4b17023SJohn Marino PUT_CODE (x, MULT);
365*e4b17023SJohn Marino XEXP (x, 1) = gen_int_mode ((HOST_WIDE_INT) 1 << shift,
366*e4b17023SJohn Marino GET_MODE (x));
367*e4b17023SJohn Marino }
368*e4b17023SJohn Marino
369*e4b17023SJohn Marino x = XEXP (x, 0);
370*e4b17023SJohn Marino break;
371*e4b17023SJohn Marino
372*e4b17023SJohn Marino case PLUS:
373*e4b17023SJohn Marino if (GET_CODE (XEXP (x, 0)) == PLUS
374*e4b17023SJohn Marino || GET_CODE (XEXP (x, 0)) == ASHIFT
375*e4b17023SJohn Marino || GET_CODE (XEXP (x, 0)) == CONST)
376*e4b17023SJohn Marino canonicalize_address (XEXP (x, 0));
377*e4b17023SJohn Marino
378*e4b17023SJohn Marino x = XEXP (x, 1);
379*e4b17023SJohn Marino break;
380*e4b17023SJohn Marino
381*e4b17023SJohn Marino case CONST:
382*e4b17023SJohn Marino x = XEXP (x, 0);
383*e4b17023SJohn Marino break;
384*e4b17023SJohn Marino
385*e4b17023SJohn Marino default:
386*e4b17023SJohn Marino return;
387*e4b17023SJohn Marino }
388*e4b17023SJohn Marino }
389*e4b17023SJohn Marino
390*e4b17023SJohn Marino /* OLD is a memory address. Return whether it is good to use NEW instead,
391*e4b17023SJohn Marino for a memory access in the given MODE. */
392*e4b17023SJohn Marino
393*e4b17023SJohn Marino static bool
should_replace_address(rtx old_rtx,rtx new_rtx,enum machine_mode mode,addr_space_t as,bool speed)394*e4b17023SJohn Marino should_replace_address (rtx old_rtx, rtx new_rtx, enum machine_mode mode,
395*e4b17023SJohn Marino addr_space_t as, bool speed)
396*e4b17023SJohn Marino {
397*e4b17023SJohn Marino int gain;
398*e4b17023SJohn Marino
399*e4b17023SJohn Marino if (rtx_equal_p (old_rtx, new_rtx)
400*e4b17023SJohn Marino || !memory_address_addr_space_p (mode, new_rtx, as))
401*e4b17023SJohn Marino return false;
402*e4b17023SJohn Marino
403*e4b17023SJohn Marino /* Copy propagation is always ok. */
404*e4b17023SJohn Marino if (REG_P (old_rtx) && REG_P (new_rtx))
405*e4b17023SJohn Marino return true;
406*e4b17023SJohn Marino
407*e4b17023SJohn Marino /* Prefer the new address if it is less expensive. */
408*e4b17023SJohn Marino gain = (address_cost (old_rtx, mode, as, speed)
409*e4b17023SJohn Marino - address_cost (new_rtx, mode, as, speed));
410*e4b17023SJohn Marino
411*e4b17023SJohn Marino /* If the addresses have equivalent cost, prefer the new address
412*e4b17023SJohn Marino if it has the highest `set_src_cost'. That has the potential of
413*e4b17023SJohn Marino eliminating the most insns without additional costs, and it
414*e4b17023SJohn Marino is the same that cse.c used to do. */
415*e4b17023SJohn Marino if (gain == 0)
416*e4b17023SJohn Marino gain = set_src_cost (new_rtx, speed) - set_src_cost (old_rtx, speed);
417*e4b17023SJohn Marino
418*e4b17023SJohn Marino return (gain > 0);
419*e4b17023SJohn Marino }
420*e4b17023SJohn Marino
421*e4b17023SJohn Marino
422*e4b17023SJohn Marino /* Flags for the last parameter of propagate_rtx_1. */
423*e4b17023SJohn Marino
424*e4b17023SJohn Marino enum {
425*e4b17023SJohn Marino /* If PR_CAN_APPEAR is true, propagate_rtx_1 always returns true;
426*e4b17023SJohn Marino if it is false, propagate_rtx_1 returns false if, for at least
427*e4b17023SJohn Marino one occurrence OLD, it failed to collapse the result to a constant.
428*e4b17023SJohn Marino For example, (mult:M (reg:M A) (minus:M (reg:M B) (reg:M A))) may
429*e4b17023SJohn Marino collapse to zero if replacing (reg:M B) with (reg:M A).
430*e4b17023SJohn Marino
431*e4b17023SJohn Marino PR_CAN_APPEAR is disregarded inside MEMs: in that case,
432*e4b17023SJohn Marino propagate_rtx_1 just tries to make cheaper and valid memory
433*e4b17023SJohn Marino addresses. */
434*e4b17023SJohn Marino PR_CAN_APPEAR = 1,
435*e4b17023SJohn Marino
436*e4b17023SJohn Marino /* If PR_HANDLE_MEM is not set, propagate_rtx_1 won't attempt any replacement
437*e4b17023SJohn Marino outside memory addresses. This is needed because propagate_rtx_1 does
438*e4b17023SJohn Marino not do any analysis on memory; thus it is very conservative and in general
439*e4b17023SJohn Marino it will fail if non-read-only MEMs are found in the source expression.
440*e4b17023SJohn Marino
441*e4b17023SJohn Marino PR_HANDLE_MEM is set when the source of the propagation was not
442*e4b17023SJohn Marino another MEM. Then, it is safe not to treat non-read-only MEMs as
443*e4b17023SJohn Marino ``opaque'' objects. */
444*e4b17023SJohn Marino PR_HANDLE_MEM = 2,
445*e4b17023SJohn Marino
446*e4b17023SJohn Marino /* Set when costs should be optimized for speed. */
447*e4b17023SJohn Marino PR_OPTIMIZE_FOR_SPEED = 4
448*e4b17023SJohn Marino };
449*e4b17023SJohn Marino
450*e4b17023SJohn Marino
451*e4b17023SJohn Marino /* Replace all occurrences of OLD in *PX with NEW and try to simplify the
452*e4b17023SJohn Marino resulting expression. Replace *PX with a new RTL expression if an
453*e4b17023SJohn Marino occurrence of OLD was found.
454*e4b17023SJohn Marino
455*e4b17023SJohn Marino This is only a wrapper around simplify-rtx.c: do not add any pattern
456*e4b17023SJohn Marino matching code here. (The sole exception is the handling of LO_SUM, but
457*e4b17023SJohn Marino that is because there is no simplify_gen_* function for LO_SUM). */
458*e4b17023SJohn Marino
459*e4b17023SJohn Marino static bool
propagate_rtx_1(rtx * px,rtx old_rtx,rtx new_rtx,int flags)460*e4b17023SJohn Marino propagate_rtx_1 (rtx *px, rtx old_rtx, rtx new_rtx, int flags)
461*e4b17023SJohn Marino {
462*e4b17023SJohn Marino rtx x = *px, tem = NULL_RTX, op0, op1, op2;
463*e4b17023SJohn Marino enum rtx_code code = GET_CODE (x);
464*e4b17023SJohn Marino enum machine_mode mode = GET_MODE (x);
465*e4b17023SJohn Marino enum machine_mode op_mode;
466*e4b17023SJohn Marino bool can_appear = (flags & PR_CAN_APPEAR) != 0;
467*e4b17023SJohn Marino bool valid_ops = true;
468*e4b17023SJohn Marino
469*e4b17023SJohn Marino if (!(flags & PR_HANDLE_MEM) && MEM_P (x) && !MEM_READONLY_P (x))
470*e4b17023SJohn Marino {
471*e4b17023SJohn Marino /* If unsafe, change MEMs to CLOBBERs or SCRATCHes (to preserve whether
472*e4b17023SJohn Marino they have side effects or not). */
473*e4b17023SJohn Marino *px = (side_effects_p (x)
474*e4b17023SJohn Marino ? gen_rtx_CLOBBER (GET_MODE (x), const0_rtx)
475*e4b17023SJohn Marino : gen_rtx_SCRATCH (GET_MODE (x)));
476*e4b17023SJohn Marino return false;
477*e4b17023SJohn Marino }
478*e4b17023SJohn Marino
479*e4b17023SJohn Marino /* If X is OLD_RTX, return NEW_RTX. But not if replacing only within an
480*e4b17023SJohn Marino address, and we are *not* inside one. */
481*e4b17023SJohn Marino if (x == old_rtx)
482*e4b17023SJohn Marino {
483*e4b17023SJohn Marino *px = new_rtx;
484*e4b17023SJohn Marino return can_appear;
485*e4b17023SJohn Marino }
486*e4b17023SJohn Marino
487*e4b17023SJohn Marino /* If this is an expression, try recursive substitution. */
488*e4b17023SJohn Marino switch (GET_RTX_CLASS (code))
489*e4b17023SJohn Marino {
490*e4b17023SJohn Marino case RTX_UNARY:
491*e4b17023SJohn Marino op0 = XEXP (x, 0);
492*e4b17023SJohn Marino op_mode = GET_MODE (op0);
493*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags);
494*e4b17023SJohn Marino if (op0 == XEXP (x, 0))
495*e4b17023SJohn Marino return true;
496*e4b17023SJohn Marino tem = simplify_gen_unary (code, mode, op0, op_mode);
497*e4b17023SJohn Marino break;
498*e4b17023SJohn Marino
499*e4b17023SJohn Marino case RTX_BIN_ARITH:
500*e4b17023SJohn Marino case RTX_COMM_ARITH:
501*e4b17023SJohn Marino op0 = XEXP (x, 0);
502*e4b17023SJohn Marino op1 = XEXP (x, 1);
503*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags);
504*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags);
505*e4b17023SJohn Marino if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
506*e4b17023SJohn Marino return true;
507*e4b17023SJohn Marino tem = simplify_gen_binary (code, mode, op0, op1);
508*e4b17023SJohn Marino break;
509*e4b17023SJohn Marino
510*e4b17023SJohn Marino case RTX_COMPARE:
511*e4b17023SJohn Marino case RTX_COMM_COMPARE:
512*e4b17023SJohn Marino op0 = XEXP (x, 0);
513*e4b17023SJohn Marino op1 = XEXP (x, 1);
514*e4b17023SJohn Marino op_mode = GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1);
515*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags);
516*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags);
517*e4b17023SJohn Marino if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
518*e4b17023SJohn Marino return true;
519*e4b17023SJohn Marino tem = simplify_gen_relational (code, mode, op_mode, op0, op1);
520*e4b17023SJohn Marino break;
521*e4b17023SJohn Marino
522*e4b17023SJohn Marino case RTX_TERNARY:
523*e4b17023SJohn Marino case RTX_BITFIELD_OPS:
524*e4b17023SJohn Marino op0 = XEXP (x, 0);
525*e4b17023SJohn Marino op1 = XEXP (x, 1);
526*e4b17023SJohn Marino op2 = XEXP (x, 2);
527*e4b17023SJohn Marino op_mode = GET_MODE (op0);
528*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags);
529*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags);
530*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&op2, old_rtx, new_rtx, flags);
531*e4b17023SJohn Marino if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1) && op2 == XEXP (x, 2))
532*e4b17023SJohn Marino return true;
533*e4b17023SJohn Marino if (op_mode == VOIDmode)
534*e4b17023SJohn Marino op_mode = GET_MODE (op0);
535*e4b17023SJohn Marino tem = simplify_gen_ternary (code, mode, op_mode, op0, op1, op2);
536*e4b17023SJohn Marino break;
537*e4b17023SJohn Marino
538*e4b17023SJohn Marino case RTX_EXTRA:
539*e4b17023SJohn Marino /* The only case we try to handle is a SUBREG. */
540*e4b17023SJohn Marino if (code == SUBREG)
541*e4b17023SJohn Marino {
542*e4b17023SJohn Marino op0 = XEXP (x, 0);
543*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&op0, old_rtx, new_rtx, flags);
544*e4b17023SJohn Marino if (op0 == XEXP (x, 0))
545*e4b17023SJohn Marino return true;
546*e4b17023SJohn Marino tem = simplify_gen_subreg (mode, op0, GET_MODE (SUBREG_REG (x)),
547*e4b17023SJohn Marino SUBREG_BYTE (x));
548*e4b17023SJohn Marino }
549*e4b17023SJohn Marino break;
550*e4b17023SJohn Marino
551*e4b17023SJohn Marino case RTX_OBJ:
552*e4b17023SJohn Marino if (code == MEM && x != new_rtx)
553*e4b17023SJohn Marino {
554*e4b17023SJohn Marino rtx new_op0;
555*e4b17023SJohn Marino op0 = XEXP (x, 0);
556*e4b17023SJohn Marino
557*e4b17023SJohn Marino /* There are some addresses that we cannot work on. */
558*e4b17023SJohn Marino if (!can_simplify_addr (op0))
559*e4b17023SJohn Marino return true;
560*e4b17023SJohn Marino
561*e4b17023SJohn Marino op0 = new_op0 = targetm.delegitimize_address (op0);
562*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&new_op0, old_rtx, new_rtx,
563*e4b17023SJohn Marino flags | PR_CAN_APPEAR);
564*e4b17023SJohn Marino
565*e4b17023SJohn Marino /* Dismiss transformation that we do not want to carry on. */
566*e4b17023SJohn Marino if (!valid_ops
567*e4b17023SJohn Marino || new_op0 == op0
568*e4b17023SJohn Marino || !(GET_MODE (new_op0) == GET_MODE (op0)
569*e4b17023SJohn Marino || GET_MODE (new_op0) == VOIDmode))
570*e4b17023SJohn Marino return true;
571*e4b17023SJohn Marino
572*e4b17023SJohn Marino canonicalize_address (new_op0);
573*e4b17023SJohn Marino
574*e4b17023SJohn Marino /* Copy propagations are always ok. Otherwise check the costs. */
575*e4b17023SJohn Marino if (!(REG_P (old_rtx) && REG_P (new_rtx))
576*e4b17023SJohn Marino && !should_replace_address (op0, new_op0, GET_MODE (x),
577*e4b17023SJohn Marino MEM_ADDR_SPACE (x),
578*e4b17023SJohn Marino flags & PR_OPTIMIZE_FOR_SPEED))
579*e4b17023SJohn Marino return true;
580*e4b17023SJohn Marino
581*e4b17023SJohn Marino tem = replace_equiv_address_nv (x, new_op0);
582*e4b17023SJohn Marino }
583*e4b17023SJohn Marino
584*e4b17023SJohn Marino else if (code == LO_SUM)
585*e4b17023SJohn Marino {
586*e4b17023SJohn Marino op0 = XEXP (x, 0);
587*e4b17023SJohn Marino op1 = XEXP (x, 1);
588*e4b17023SJohn Marino
589*e4b17023SJohn Marino /* The only simplification we do attempts to remove references to op0
590*e4b17023SJohn Marino or make it constant -- in both cases, op0's invalidity will not
591*e4b17023SJohn Marino make the result invalid. */
592*e4b17023SJohn Marino propagate_rtx_1 (&op0, old_rtx, new_rtx, flags | PR_CAN_APPEAR);
593*e4b17023SJohn Marino valid_ops &= propagate_rtx_1 (&op1, old_rtx, new_rtx, flags);
594*e4b17023SJohn Marino if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
595*e4b17023SJohn Marino return true;
596*e4b17023SJohn Marino
597*e4b17023SJohn Marino /* (lo_sum (high x) x) -> x */
598*e4b17023SJohn Marino if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1))
599*e4b17023SJohn Marino tem = op1;
600*e4b17023SJohn Marino else
601*e4b17023SJohn Marino tem = gen_rtx_LO_SUM (mode, op0, op1);
602*e4b17023SJohn Marino
603*e4b17023SJohn Marino /* OP1 is likely not a legitimate address, otherwise there would have
604*e4b17023SJohn Marino been no LO_SUM. We want it to disappear if it is invalid, return
605*e4b17023SJohn Marino false in that case. */
606*e4b17023SJohn Marino return memory_address_p (mode, tem);
607*e4b17023SJohn Marino }
608*e4b17023SJohn Marino
609*e4b17023SJohn Marino else if (code == REG)
610*e4b17023SJohn Marino {
611*e4b17023SJohn Marino if (rtx_equal_p (x, old_rtx))
612*e4b17023SJohn Marino {
613*e4b17023SJohn Marino *px = new_rtx;
614*e4b17023SJohn Marino return can_appear;
615*e4b17023SJohn Marino }
616*e4b17023SJohn Marino }
617*e4b17023SJohn Marino break;
618*e4b17023SJohn Marino
619*e4b17023SJohn Marino default:
620*e4b17023SJohn Marino break;
621*e4b17023SJohn Marino }
622*e4b17023SJohn Marino
623*e4b17023SJohn Marino /* No change, no trouble. */
624*e4b17023SJohn Marino if (tem == NULL_RTX)
625*e4b17023SJohn Marino return true;
626*e4b17023SJohn Marino
627*e4b17023SJohn Marino *px = tem;
628*e4b17023SJohn Marino
629*e4b17023SJohn Marino /* The replacement we made so far is valid, if all of the recursive
630*e4b17023SJohn Marino replacements were valid, or we could simplify everything to
631*e4b17023SJohn Marino a constant. */
632*e4b17023SJohn Marino return valid_ops || can_appear || CONSTANT_P (tem);
633*e4b17023SJohn Marino }
634*e4b17023SJohn Marino
635*e4b17023SJohn Marino
636*e4b17023SJohn Marino /* for_each_rtx traversal function that returns 1 if BODY points to
637*e4b17023SJohn Marino a non-constant mem. */
638*e4b17023SJohn Marino
639*e4b17023SJohn Marino static int
varying_mem_p(rtx * body,void * data ATTRIBUTE_UNUSED)640*e4b17023SJohn Marino varying_mem_p (rtx *body, void *data ATTRIBUTE_UNUSED)
641*e4b17023SJohn Marino {
642*e4b17023SJohn Marino rtx x = *body;
643*e4b17023SJohn Marino return MEM_P (x) && !MEM_READONLY_P (x);
644*e4b17023SJohn Marino }
645*e4b17023SJohn Marino
646*e4b17023SJohn Marino
647*e4b17023SJohn Marino /* Replace all occurrences of OLD in X with NEW and try to simplify the
648*e4b17023SJohn Marino resulting expression (in mode MODE). Return a new expression if it is
649*e4b17023SJohn Marino a constant, otherwise X.
650*e4b17023SJohn Marino
651*e4b17023SJohn Marino Simplifications where occurrences of NEW collapse to a constant are always
652*e4b17023SJohn Marino accepted. All simplifications are accepted if NEW is a pseudo too.
653*e4b17023SJohn Marino Otherwise, we accept simplifications that have a lower or equal cost. */
654*e4b17023SJohn Marino
655*e4b17023SJohn Marino static rtx
propagate_rtx(rtx x,enum machine_mode mode,rtx old_rtx,rtx new_rtx,bool speed)656*e4b17023SJohn Marino propagate_rtx (rtx x, enum machine_mode mode, rtx old_rtx, rtx new_rtx,
657*e4b17023SJohn Marino bool speed)
658*e4b17023SJohn Marino {
659*e4b17023SJohn Marino rtx tem;
660*e4b17023SJohn Marino bool collapsed;
661*e4b17023SJohn Marino int flags;
662*e4b17023SJohn Marino
663*e4b17023SJohn Marino if (REG_P (new_rtx) && REGNO (new_rtx) < FIRST_PSEUDO_REGISTER)
664*e4b17023SJohn Marino return NULL_RTX;
665*e4b17023SJohn Marino
666*e4b17023SJohn Marino flags = 0;
667*e4b17023SJohn Marino if (REG_P (new_rtx) || CONSTANT_P (new_rtx))
668*e4b17023SJohn Marino flags |= PR_CAN_APPEAR;
669*e4b17023SJohn Marino if (!for_each_rtx (&new_rtx, varying_mem_p, NULL))
670*e4b17023SJohn Marino flags |= PR_HANDLE_MEM;
671*e4b17023SJohn Marino
672*e4b17023SJohn Marino if (speed)
673*e4b17023SJohn Marino flags |= PR_OPTIMIZE_FOR_SPEED;
674*e4b17023SJohn Marino
675*e4b17023SJohn Marino tem = x;
676*e4b17023SJohn Marino collapsed = propagate_rtx_1 (&tem, old_rtx, copy_rtx (new_rtx), flags);
677*e4b17023SJohn Marino if (tem == x || !collapsed)
678*e4b17023SJohn Marino return NULL_RTX;
679*e4b17023SJohn Marino
680*e4b17023SJohn Marino /* gen_lowpart_common will not be able to process VOIDmode entities other
681*e4b17023SJohn Marino than CONST_INTs. */
682*e4b17023SJohn Marino if (GET_MODE (tem) == VOIDmode && !CONST_INT_P (tem))
683*e4b17023SJohn Marino return NULL_RTX;
684*e4b17023SJohn Marino
685*e4b17023SJohn Marino if (GET_MODE (tem) == VOIDmode)
686*e4b17023SJohn Marino tem = rtl_hooks.gen_lowpart_no_emit (mode, tem);
687*e4b17023SJohn Marino else
688*e4b17023SJohn Marino gcc_assert (GET_MODE (tem) == mode);
689*e4b17023SJohn Marino
690*e4b17023SJohn Marino return tem;
691*e4b17023SJohn Marino }
692*e4b17023SJohn Marino
693*e4b17023SJohn Marino
694*e4b17023SJohn Marino
695*e4b17023SJohn Marino
696*e4b17023SJohn Marino /* Return true if the register from reference REF is killed
697*e4b17023SJohn Marino between FROM to (but not including) TO. */
698*e4b17023SJohn Marino
699*e4b17023SJohn Marino static bool
local_ref_killed_between_p(df_ref ref,rtx from,rtx to)700*e4b17023SJohn Marino local_ref_killed_between_p (df_ref ref, rtx from, rtx to)
701*e4b17023SJohn Marino {
702*e4b17023SJohn Marino rtx insn;
703*e4b17023SJohn Marino
704*e4b17023SJohn Marino for (insn = from; insn != to; insn = NEXT_INSN (insn))
705*e4b17023SJohn Marino {
706*e4b17023SJohn Marino df_ref *def_rec;
707*e4b17023SJohn Marino if (!INSN_P (insn))
708*e4b17023SJohn Marino continue;
709*e4b17023SJohn Marino
710*e4b17023SJohn Marino for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
711*e4b17023SJohn Marino {
712*e4b17023SJohn Marino df_ref def = *def_rec;
713*e4b17023SJohn Marino if (DF_REF_REGNO (ref) == DF_REF_REGNO (def))
714*e4b17023SJohn Marino return true;
715*e4b17023SJohn Marino }
716*e4b17023SJohn Marino }
717*e4b17023SJohn Marino return false;
718*e4b17023SJohn Marino }
719*e4b17023SJohn Marino
720*e4b17023SJohn Marino
721*e4b17023SJohn Marino /* Check if the given DEF is available in INSN. This would require full
722*e4b17023SJohn Marino computation of available expressions; we check only restricted conditions:
723*e4b17023SJohn Marino - if DEF is the sole definition of its register, go ahead;
724*e4b17023SJohn Marino - in the same basic block, we check for no definitions killing the
725*e4b17023SJohn Marino definition of DEF_INSN;
726*e4b17023SJohn Marino - if USE's basic block has DEF's basic block as the sole predecessor,
727*e4b17023SJohn Marino we check if the definition is killed after DEF_INSN or before
728*e4b17023SJohn Marino TARGET_INSN insn, in their respective basic blocks. */
729*e4b17023SJohn Marino static bool
use_killed_between(df_ref use,rtx def_insn,rtx target_insn)730*e4b17023SJohn Marino use_killed_between (df_ref use, rtx def_insn, rtx target_insn)
731*e4b17023SJohn Marino {
732*e4b17023SJohn Marino basic_block def_bb = BLOCK_FOR_INSN (def_insn);
733*e4b17023SJohn Marino basic_block target_bb = BLOCK_FOR_INSN (target_insn);
734*e4b17023SJohn Marino int regno;
735*e4b17023SJohn Marino df_ref def;
736*e4b17023SJohn Marino
737*e4b17023SJohn Marino /* We used to have a def reaching a use that is _before_ the def,
738*e4b17023SJohn Marino with the def not dominating the use even though the use and def
739*e4b17023SJohn Marino are in the same basic block, when a register may be used
740*e4b17023SJohn Marino uninitialized in a loop. This should not happen anymore since
741*e4b17023SJohn Marino we do not use reaching definitions, but still we test for such
742*e4b17023SJohn Marino cases and assume that DEF is not available. */
743*e4b17023SJohn Marino if (def_bb == target_bb
744*e4b17023SJohn Marino ? DF_INSN_LUID (def_insn) >= DF_INSN_LUID (target_insn)
745*e4b17023SJohn Marino : !dominated_by_p (CDI_DOMINATORS, target_bb, def_bb))
746*e4b17023SJohn Marino return true;
747*e4b17023SJohn Marino
748*e4b17023SJohn Marino /* Check if the reg in USE has only one definition. We already
749*e4b17023SJohn Marino know that this definition reaches use, or we wouldn't be here.
750*e4b17023SJohn Marino However, this is invalid for hard registers because if they are
751*e4b17023SJohn Marino live at the beginning of the function it does not mean that we
752*e4b17023SJohn Marino have an uninitialized access. */
753*e4b17023SJohn Marino regno = DF_REF_REGNO (use);
754*e4b17023SJohn Marino def = DF_REG_DEF_CHAIN (regno);
755*e4b17023SJohn Marino if (def
756*e4b17023SJohn Marino && DF_REF_NEXT_REG (def) == NULL
757*e4b17023SJohn Marino && regno >= FIRST_PSEUDO_REGISTER)
758*e4b17023SJohn Marino return false;
759*e4b17023SJohn Marino
760*e4b17023SJohn Marino /* Check locally if we are in the same basic block. */
761*e4b17023SJohn Marino if (def_bb == target_bb)
762*e4b17023SJohn Marino return local_ref_killed_between_p (use, def_insn, target_insn);
763*e4b17023SJohn Marino
764*e4b17023SJohn Marino /* Finally, if DEF_BB is the sole predecessor of TARGET_BB. */
765*e4b17023SJohn Marino if (single_pred_p (target_bb)
766*e4b17023SJohn Marino && single_pred (target_bb) == def_bb)
767*e4b17023SJohn Marino {
768*e4b17023SJohn Marino df_ref x;
769*e4b17023SJohn Marino
770*e4b17023SJohn Marino /* See if USE is killed between DEF_INSN and the last insn in the
771*e4b17023SJohn Marino basic block containing DEF_INSN. */
772*e4b17023SJohn Marino x = df_bb_regno_last_def_find (def_bb, regno);
773*e4b17023SJohn Marino if (x && DF_INSN_LUID (DF_REF_INSN (x)) >= DF_INSN_LUID (def_insn))
774*e4b17023SJohn Marino return true;
775*e4b17023SJohn Marino
776*e4b17023SJohn Marino /* See if USE is killed between TARGET_INSN and the first insn in the
777*e4b17023SJohn Marino basic block containing TARGET_INSN. */
778*e4b17023SJohn Marino x = df_bb_regno_first_def_find (target_bb, regno);
779*e4b17023SJohn Marino if (x && DF_INSN_LUID (DF_REF_INSN (x)) < DF_INSN_LUID (target_insn))
780*e4b17023SJohn Marino return true;
781*e4b17023SJohn Marino
782*e4b17023SJohn Marino return false;
783*e4b17023SJohn Marino }
784*e4b17023SJohn Marino
785*e4b17023SJohn Marino /* Otherwise assume the worst case. */
786*e4b17023SJohn Marino return true;
787*e4b17023SJohn Marino }
788*e4b17023SJohn Marino
789*e4b17023SJohn Marino
790*e4b17023SJohn Marino /* Check if all uses in DEF_INSN can be used in TARGET_INSN. This
791*e4b17023SJohn Marino would require full computation of available expressions;
792*e4b17023SJohn Marino we check only restricted conditions, see use_killed_between. */
793*e4b17023SJohn Marino static bool
all_uses_available_at(rtx def_insn,rtx target_insn)794*e4b17023SJohn Marino all_uses_available_at (rtx def_insn, rtx target_insn)
795*e4b17023SJohn Marino {
796*e4b17023SJohn Marino df_ref *use_rec;
797*e4b17023SJohn Marino struct df_insn_info *insn_info = DF_INSN_INFO_GET (def_insn);
798*e4b17023SJohn Marino rtx def_set = single_set (def_insn);
799*e4b17023SJohn Marino
800*e4b17023SJohn Marino gcc_assert (def_set);
801*e4b17023SJohn Marino
802*e4b17023SJohn Marino /* If target_insn comes right after def_insn, which is very common
803*e4b17023SJohn Marino for addresses, we can use a quicker test. */
804*e4b17023SJohn Marino if (NEXT_INSN (def_insn) == target_insn
805*e4b17023SJohn Marino && REG_P (SET_DEST (def_set)))
806*e4b17023SJohn Marino {
807*e4b17023SJohn Marino rtx def_reg = SET_DEST (def_set);
808*e4b17023SJohn Marino
809*e4b17023SJohn Marino /* If the insn uses the reg that it defines, the substitution is
810*e4b17023SJohn Marino invalid. */
811*e4b17023SJohn Marino for (use_rec = DF_INSN_INFO_USES (insn_info); *use_rec; use_rec++)
812*e4b17023SJohn Marino {
813*e4b17023SJohn Marino df_ref use = *use_rec;
814*e4b17023SJohn Marino if (rtx_equal_p (DF_REF_REG (use), def_reg))
815*e4b17023SJohn Marino return false;
816*e4b17023SJohn Marino }
817*e4b17023SJohn Marino for (use_rec = DF_INSN_INFO_EQ_USES (insn_info); *use_rec; use_rec++)
818*e4b17023SJohn Marino {
819*e4b17023SJohn Marino df_ref use = *use_rec;
820*e4b17023SJohn Marino if (rtx_equal_p (DF_REF_REG (use), def_reg))
821*e4b17023SJohn Marino return false;
822*e4b17023SJohn Marino }
823*e4b17023SJohn Marino }
824*e4b17023SJohn Marino else
825*e4b17023SJohn Marino {
826*e4b17023SJohn Marino rtx def_reg = REG_P (SET_DEST (def_set)) ? SET_DEST (def_set) : NULL_RTX;
827*e4b17023SJohn Marino
828*e4b17023SJohn Marino /* Look at all the uses of DEF_INSN, and see if they are not
829*e4b17023SJohn Marino killed between DEF_INSN and TARGET_INSN. */
830*e4b17023SJohn Marino for (use_rec = DF_INSN_INFO_USES (insn_info); *use_rec; use_rec++)
831*e4b17023SJohn Marino {
832*e4b17023SJohn Marino df_ref use = *use_rec;
833*e4b17023SJohn Marino if (def_reg && rtx_equal_p (DF_REF_REG (use), def_reg))
834*e4b17023SJohn Marino return false;
835*e4b17023SJohn Marino if (use_killed_between (use, def_insn, target_insn))
836*e4b17023SJohn Marino return false;
837*e4b17023SJohn Marino }
838*e4b17023SJohn Marino for (use_rec = DF_INSN_INFO_EQ_USES (insn_info); *use_rec; use_rec++)
839*e4b17023SJohn Marino {
840*e4b17023SJohn Marino df_ref use = *use_rec;
841*e4b17023SJohn Marino if (def_reg && rtx_equal_p (DF_REF_REG (use), def_reg))
842*e4b17023SJohn Marino return false;
843*e4b17023SJohn Marino if (use_killed_between (use, def_insn, target_insn))
844*e4b17023SJohn Marino return false;
845*e4b17023SJohn Marino }
846*e4b17023SJohn Marino }
847*e4b17023SJohn Marino
848*e4b17023SJohn Marino return true;
849*e4b17023SJohn Marino }
850*e4b17023SJohn Marino
851*e4b17023SJohn Marino
852*e4b17023SJohn Marino static df_ref *active_defs;
853*e4b17023SJohn Marino #ifdef ENABLE_CHECKING
854*e4b17023SJohn Marino static sparseset active_defs_check;
855*e4b17023SJohn Marino #endif
856*e4b17023SJohn Marino
857*e4b17023SJohn Marino /* Fill the ACTIVE_DEFS array with the use->def link for the registers
858*e4b17023SJohn Marino mentioned in USE_REC. Register the valid entries in ACTIVE_DEFS_CHECK
859*e4b17023SJohn Marino too, for checking purposes. */
860*e4b17023SJohn Marino
861*e4b17023SJohn Marino static void
register_active_defs(df_ref * use_rec)862*e4b17023SJohn Marino register_active_defs (df_ref *use_rec)
863*e4b17023SJohn Marino {
864*e4b17023SJohn Marino while (*use_rec)
865*e4b17023SJohn Marino {
866*e4b17023SJohn Marino df_ref use = *use_rec++;
867*e4b17023SJohn Marino df_ref def = get_def_for_use (use);
868*e4b17023SJohn Marino int regno = DF_REF_REGNO (use);
869*e4b17023SJohn Marino
870*e4b17023SJohn Marino #ifdef ENABLE_CHECKING
871*e4b17023SJohn Marino sparseset_set_bit (active_defs_check, regno);
872*e4b17023SJohn Marino #endif
873*e4b17023SJohn Marino active_defs[regno] = def;
874*e4b17023SJohn Marino }
875*e4b17023SJohn Marino }
876*e4b17023SJohn Marino
877*e4b17023SJohn Marino
878*e4b17023SJohn Marino /* Build the use->def links that we use to update the dataflow info
879*e4b17023SJohn Marino for new uses. Note that building the links is very cheap and if
880*e4b17023SJohn Marino it were done earlier, they could be used to rule out invalid
881*e4b17023SJohn Marino propagations (in addition to what is done in all_uses_available_at).
882*e4b17023SJohn Marino I'm not doing this yet, though. */
883*e4b17023SJohn Marino
884*e4b17023SJohn Marino static void
update_df_init(rtx def_insn,rtx insn)885*e4b17023SJohn Marino update_df_init (rtx def_insn, rtx insn)
886*e4b17023SJohn Marino {
887*e4b17023SJohn Marino #ifdef ENABLE_CHECKING
888*e4b17023SJohn Marino sparseset_clear (active_defs_check);
889*e4b17023SJohn Marino #endif
890*e4b17023SJohn Marino register_active_defs (DF_INSN_USES (def_insn));
891*e4b17023SJohn Marino register_active_defs (DF_INSN_USES (insn));
892*e4b17023SJohn Marino register_active_defs (DF_INSN_EQ_USES (insn));
893*e4b17023SJohn Marino }
894*e4b17023SJohn Marino
895*e4b17023SJohn Marino
896*e4b17023SJohn Marino /* Update the USE_DEF_REF array for the given use, using the active definitions
897*e4b17023SJohn Marino in the ACTIVE_DEFS array to match pseudos to their def. */
898*e4b17023SJohn Marino
899*e4b17023SJohn Marino static inline void
update_uses(df_ref * use_rec)900*e4b17023SJohn Marino update_uses (df_ref *use_rec)
901*e4b17023SJohn Marino {
902*e4b17023SJohn Marino while (*use_rec)
903*e4b17023SJohn Marino {
904*e4b17023SJohn Marino df_ref use = *use_rec++;
905*e4b17023SJohn Marino int regno = DF_REF_REGNO (use);
906*e4b17023SJohn Marino
907*e4b17023SJohn Marino /* Set up the use-def chain. */
908*e4b17023SJohn Marino if (DF_REF_ID (use) >= (int) VEC_length (df_ref, use_def_ref))
909*e4b17023SJohn Marino VEC_safe_grow_cleared (df_ref, heap, use_def_ref,
910*e4b17023SJohn Marino DF_REF_ID (use) + 1);
911*e4b17023SJohn Marino
912*e4b17023SJohn Marino #ifdef ENABLE_CHECKING
913*e4b17023SJohn Marino gcc_assert (sparseset_bit_p (active_defs_check, regno));
914*e4b17023SJohn Marino #endif
915*e4b17023SJohn Marino VEC_replace (df_ref, use_def_ref, DF_REF_ID (use), active_defs[regno]);
916*e4b17023SJohn Marino }
917*e4b17023SJohn Marino }
918*e4b17023SJohn Marino
919*e4b17023SJohn Marino
920*e4b17023SJohn Marino /* Update the USE_DEF_REF array for the uses in INSN. Only update note
921*e4b17023SJohn Marino uses if NOTES_ONLY is true. */
922*e4b17023SJohn Marino
923*e4b17023SJohn Marino static void
update_df(rtx insn,rtx note)924*e4b17023SJohn Marino update_df (rtx insn, rtx note)
925*e4b17023SJohn Marino {
926*e4b17023SJohn Marino struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
927*e4b17023SJohn Marino
928*e4b17023SJohn Marino if (note)
929*e4b17023SJohn Marino {
930*e4b17023SJohn Marino df_uses_create (&XEXP (note, 0), insn, DF_REF_IN_NOTE);
931*e4b17023SJohn Marino df_notes_rescan (insn);
932*e4b17023SJohn Marino }
933*e4b17023SJohn Marino else
934*e4b17023SJohn Marino {
935*e4b17023SJohn Marino df_uses_create (&PATTERN (insn), insn, 0);
936*e4b17023SJohn Marino df_insn_rescan (insn);
937*e4b17023SJohn Marino update_uses (DF_INSN_INFO_USES (insn_info));
938*e4b17023SJohn Marino }
939*e4b17023SJohn Marino
940*e4b17023SJohn Marino update_uses (DF_INSN_INFO_EQ_USES (insn_info));
941*e4b17023SJohn Marino }
942*e4b17023SJohn Marino
943*e4b17023SJohn Marino
944*e4b17023SJohn Marino /* Try substituting NEW into LOC, which originated from forward propagation
945*e4b17023SJohn Marino of USE's value from DEF_INSN. SET_REG_EQUAL says whether we are
946*e4b17023SJohn Marino substituting the whole SET_SRC, so we can set a REG_EQUAL note if the
947*e4b17023SJohn Marino new insn is not recognized. Return whether the substitution was
948*e4b17023SJohn Marino performed. */
949*e4b17023SJohn Marino
950*e4b17023SJohn Marino static bool
try_fwprop_subst(df_ref use,rtx * loc,rtx new_rtx,rtx def_insn,bool set_reg_equal)951*e4b17023SJohn Marino try_fwprop_subst (df_ref use, rtx *loc, rtx new_rtx, rtx def_insn, bool set_reg_equal)
952*e4b17023SJohn Marino {
953*e4b17023SJohn Marino rtx insn = DF_REF_INSN (use);
954*e4b17023SJohn Marino rtx set = single_set (insn);
955*e4b17023SJohn Marino rtx note = NULL_RTX;
956*e4b17023SJohn Marino bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
957*e4b17023SJohn Marino int old_cost = 0;
958*e4b17023SJohn Marino bool ok;
959*e4b17023SJohn Marino
960*e4b17023SJohn Marino update_df_init (def_insn, insn);
961*e4b17023SJohn Marino
962*e4b17023SJohn Marino /* forward_propagate_subreg may be operating on an instruction with
963*e4b17023SJohn Marino multiple sets. If so, assume the cost of the new instruction is
964*e4b17023SJohn Marino not greater than the old one. */
965*e4b17023SJohn Marino if (set)
966*e4b17023SJohn Marino old_cost = set_src_cost (SET_SRC (set), speed);
967*e4b17023SJohn Marino if (dump_file)
968*e4b17023SJohn Marino {
969*e4b17023SJohn Marino fprintf (dump_file, "\nIn insn %d, replacing\n ", INSN_UID (insn));
970*e4b17023SJohn Marino print_inline_rtx (dump_file, *loc, 2);
971*e4b17023SJohn Marino fprintf (dump_file, "\n with ");
972*e4b17023SJohn Marino print_inline_rtx (dump_file, new_rtx, 2);
973*e4b17023SJohn Marino fprintf (dump_file, "\n");
974*e4b17023SJohn Marino }
975*e4b17023SJohn Marino
976*e4b17023SJohn Marino validate_unshare_change (insn, loc, new_rtx, true);
977*e4b17023SJohn Marino if (!verify_changes (0))
978*e4b17023SJohn Marino {
979*e4b17023SJohn Marino if (dump_file)
980*e4b17023SJohn Marino fprintf (dump_file, "Changes to insn %d not recognized\n",
981*e4b17023SJohn Marino INSN_UID (insn));
982*e4b17023SJohn Marino ok = false;
983*e4b17023SJohn Marino }
984*e4b17023SJohn Marino
985*e4b17023SJohn Marino else if (DF_REF_TYPE (use) == DF_REF_REG_USE
986*e4b17023SJohn Marino && set
987*e4b17023SJohn Marino && set_src_cost (SET_SRC (set), speed) > old_cost)
988*e4b17023SJohn Marino {
989*e4b17023SJohn Marino if (dump_file)
990*e4b17023SJohn Marino fprintf (dump_file, "Changes to insn %d not profitable\n",
991*e4b17023SJohn Marino INSN_UID (insn));
992*e4b17023SJohn Marino ok = false;
993*e4b17023SJohn Marino }
994*e4b17023SJohn Marino
995*e4b17023SJohn Marino else
996*e4b17023SJohn Marino {
997*e4b17023SJohn Marino if (dump_file)
998*e4b17023SJohn Marino fprintf (dump_file, "Changed insn %d\n", INSN_UID (insn));
999*e4b17023SJohn Marino ok = true;
1000*e4b17023SJohn Marino }
1001*e4b17023SJohn Marino
1002*e4b17023SJohn Marino if (ok)
1003*e4b17023SJohn Marino {
1004*e4b17023SJohn Marino confirm_change_group ();
1005*e4b17023SJohn Marino num_changes++;
1006*e4b17023SJohn Marino }
1007*e4b17023SJohn Marino else
1008*e4b17023SJohn Marino {
1009*e4b17023SJohn Marino cancel_changes (0);
1010*e4b17023SJohn Marino
1011*e4b17023SJohn Marino /* Can also record a simplified value in a REG_EQUAL note,
1012*e4b17023SJohn Marino making a new one if one does not already exist. */
1013*e4b17023SJohn Marino if (set_reg_equal)
1014*e4b17023SJohn Marino {
1015*e4b17023SJohn Marino if (dump_file)
1016*e4b17023SJohn Marino fprintf (dump_file, " Setting REG_EQUAL note\n");
1017*e4b17023SJohn Marino
1018*e4b17023SJohn Marino note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (new_rtx));
1019*e4b17023SJohn Marino }
1020*e4b17023SJohn Marino }
1021*e4b17023SJohn Marino
1022*e4b17023SJohn Marino if ((ok || note) && !CONSTANT_P (new_rtx))
1023*e4b17023SJohn Marino update_df (insn, note);
1024*e4b17023SJohn Marino
1025*e4b17023SJohn Marino return ok;
1026*e4b17023SJohn Marino }
1027*e4b17023SJohn Marino
1028*e4b17023SJohn Marino /* For the given single_set INSN, containing SRC known to be a
1029*e4b17023SJohn Marino ZERO_EXTEND or SIGN_EXTEND of a register, return true if INSN
1030*e4b17023SJohn Marino is redundant due to the register being set by a LOAD_EXTEND_OP
1031*e4b17023SJohn Marino load from memory. */
1032*e4b17023SJohn Marino
1033*e4b17023SJohn Marino static bool
free_load_extend(rtx src,rtx insn)1034*e4b17023SJohn Marino free_load_extend (rtx src, rtx insn)
1035*e4b17023SJohn Marino {
1036*e4b17023SJohn Marino rtx reg;
1037*e4b17023SJohn Marino df_ref *use_vec;
1038*e4b17023SJohn Marino df_ref use = 0, def;
1039*e4b17023SJohn Marino
1040*e4b17023SJohn Marino reg = XEXP (src, 0);
1041*e4b17023SJohn Marino #ifdef LOAD_EXTEND_OP
1042*e4b17023SJohn Marino if (LOAD_EXTEND_OP (GET_MODE (reg)) != GET_CODE (src))
1043*e4b17023SJohn Marino #endif
1044*e4b17023SJohn Marino return false;
1045*e4b17023SJohn Marino
1046*e4b17023SJohn Marino for (use_vec = DF_INSN_USES (insn); *use_vec; use_vec++)
1047*e4b17023SJohn Marino {
1048*e4b17023SJohn Marino use = *use_vec;
1049*e4b17023SJohn Marino
1050*e4b17023SJohn Marino if (!DF_REF_IS_ARTIFICIAL (use)
1051*e4b17023SJohn Marino && DF_REF_TYPE (use) == DF_REF_REG_USE
1052*e4b17023SJohn Marino && DF_REF_REG (use) == reg)
1053*e4b17023SJohn Marino break;
1054*e4b17023SJohn Marino }
1055*e4b17023SJohn Marino if (!use)
1056*e4b17023SJohn Marino return false;
1057*e4b17023SJohn Marino
1058*e4b17023SJohn Marino def = get_def_for_use (use);
1059*e4b17023SJohn Marino if (!def)
1060*e4b17023SJohn Marino return false;
1061*e4b17023SJohn Marino
1062*e4b17023SJohn Marino if (DF_REF_IS_ARTIFICIAL (def))
1063*e4b17023SJohn Marino return false;
1064*e4b17023SJohn Marino
1065*e4b17023SJohn Marino if (NONJUMP_INSN_P (DF_REF_INSN (def)))
1066*e4b17023SJohn Marino {
1067*e4b17023SJohn Marino rtx patt = PATTERN (DF_REF_INSN (def));
1068*e4b17023SJohn Marino
1069*e4b17023SJohn Marino if (GET_CODE (patt) == SET
1070*e4b17023SJohn Marino && GET_CODE (SET_SRC (patt)) == MEM
1071*e4b17023SJohn Marino && rtx_equal_p (SET_DEST (patt), reg))
1072*e4b17023SJohn Marino return true;
1073*e4b17023SJohn Marino }
1074*e4b17023SJohn Marino return false;
1075*e4b17023SJohn Marino }
1076*e4b17023SJohn Marino
1077*e4b17023SJohn Marino /* If USE is a subreg, see if it can be replaced by a pseudo. */
1078*e4b17023SJohn Marino
1079*e4b17023SJohn Marino static bool
forward_propagate_subreg(df_ref use,rtx def_insn,rtx def_set)1080*e4b17023SJohn Marino forward_propagate_subreg (df_ref use, rtx def_insn, rtx def_set)
1081*e4b17023SJohn Marino {
1082*e4b17023SJohn Marino rtx use_reg = DF_REF_REG (use);
1083*e4b17023SJohn Marino rtx use_insn, src;
1084*e4b17023SJohn Marino
1085*e4b17023SJohn Marino /* Only consider subregs... */
1086*e4b17023SJohn Marino enum machine_mode use_mode = GET_MODE (use_reg);
1087*e4b17023SJohn Marino if (GET_CODE (use_reg) != SUBREG
1088*e4b17023SJohn Marino || !REG_P (SET_DEST (def_set)))
1089*e4b17023SJohn Marino return false;
1090*e4b17023SJohn Marino
1091*e4b17023SJohn Marino /* If this is a paradoxical SUBREG... */
1092*e4b17023SJohn Marino if (GET_MODE_SIZE (use_mode)
1093*e4b17023SJohn Marino > GET_MODE_SIZE (GET_MODE (SUBREG_REG (use_reg))))
1094*e4b17023SJohn Marino {
1095*e4b17023SJohn Marino /* If this is a paradoxical SUBREG, we have no idea what value the
1096*e4b17023SJohn Marino extra bits would have. However, if the operand is equivalent to
1097*e4b17023SJohn Marino a SUBREG whose operand is the same as our mode, and all the modes
1098*e4b17023SJohn Marino are within a word, we can just use the inner operand because
1099*e4b17023SJohn Marino these SUBREGs just say how to treat the register. */
1100*e4b17023SJohn Marino use_insn = DF_REF_INSN (use);
1101*e4b17023SJohn Marino src = SET_SRC (def_set);
1102*e4b17023SJohn Marino if (GET_CODE (src) == SUBREG
1103*e4b17023SJohn Marino && REG_P (SUBREG_REG (src))
1104*e4b17023SJohn Marino && REGNO (SUBREG_REG (src)) >= FIRST_PSEUDO_REGISTER
1105*e4b17023SJohn Marino && GET_MODE (SUBREG_REG (src)) == use_mode
1106*e4b17023SJohn Marino && subreg_lowpart_p (src)
1107*e4b17023SJohn Marino && all_uses_available_at (def_insn, use_insn))
1108*e4b17023SJohn Marino return try_fwprop_subst (use, DF_REF_LOC (use), SUBREG_REG (src),
1109*e4b17023SJohn Marino def_insn, false);
1110*e4b17023SJohn Marino }
1111*e4b17023SJohn Marino
1112*e4b17023SJohn Marino /* If this is a SUBREG of a ZERO_EXTEND or SIGN_EXTEND, and the SUBREG
1113*e4b17023SJohn Marino is the low part of the reg being extended then just use the inner
1114*e4b17023SJohn Marino operand. Don't do this if the ZERO_EXTEND or SIGN_EXTEND insn will
1115*e4b17023SJohn Marino be removed due to it matching a LOAD_EXTEND_OP load from memory,
1116*e4b17023SJohn Marino or due to the operation being a no-op when applied to registers.
1117*e4b17023SJohn Marino For example, if we have:
1118*e4b17023SJohn Marino
1119*e4b17023SJohn Marino A: (set (reg:DI X) (sign_extend:DI (reg:SI Y)))
1120*e4b17023SJohn Marino B: (... (subreg:SI (reg:DI X)) ...)
1121*e4b17023SJohn Marino
1122*e4b17023SJohn Marino and mode_rep_extended says that Y is already sign-extended,
1123*e4b17023SJohn Marino the backend will typically allow A to be combined with the
1124*e4b17023SJohn Marino definition of Y or, failing that, allow A to be deleted after
1125*e4b17023SJohn Marino reload through register tying. Introducing more uses of Y
1126*e4b17023SJohn Marino prevents both optimisations. */
1127*e4b17023SJohn Marino else if (subreg_lowpart_p (use_reg))
1128*e4b17023SJohn Marino {
1129*e4b17023SJohn Marino use_insn = DF_REF_INSN (use);
1130*e4b17023SJohn Marino src = SET_SRC (def_set);
1131*e4b17023SJohn Marino if ((GET_CODE (src) == ZERO_EXTEND
1132*e4b17023SJohn Marino || GET_CODE (src) == SIGN_EXTEND)
1133*e4b17023SJohn Marino && REG_P (XEXP (src, 0))
1134*e4b17023SJohn Marino && REGNO (XEXP (src, 0)) >= FIRST_PSEUDO_REGISTER
1135*e4b17023SJohn Marino && GET_MODE (XEXP (src, 0)) == use_mode
1136*e4b17023SJohn Marino && !free_load_extend (src, def_insn)
1137*e4b17023SJohn Marino && (targetm.mode_rep_extended (use_mode, GET_MODE (src))
1138*e4b17023SJohn Marino != (int) GET_CODE (src))
1139*e4b17023SJohn Marino && all_uses_available_at (def_insn, use_insn))
1140*e4b17023SJohn Marino return try_fwprop_subst (use, DF_REF_LOC (use), XEXP (src, 0),
1141*e4b17023SJohn Marino def_insn, false);
1142*e4b17023SJohn Marino }
1143*e4b17023SJohn Marino
1144*e4b17023SJohn Marino return false;
1145*e4b17023SJohn Marino }
1146*e4b17023SJohn Marino
1147*e4b17023SJohn Marino /* Try to replace USE with SRC (defined in DEF_INSN) in __asm. */
1148*e4b17023SJohn Marino
1149*e4b17023SJohn Marino static bool
forward_propagate_asm(df_ref use,rtx def_insn,rtx def_set,rtx reg)1150*e4b17023SJohn Marino forward_propagate_asm (df_ref use, rtx def_insn, rtx def_set, rtx reg)
1151*e4b17023SJohn Marino {
1152*e4b17023SJohn Marino rtx use_insn = DF_REF_INSN (use), src, use_pat, asm_operands, new_rtx, *loc;
1153*e4b17023SJohn Marino int speed_p, i;
1154*e4b17023SJohn Marino df_ref *use_vec;
1155*e4b17023SJohn Marino
1156*e4b17023SJohn Marino gcc_assert ((DF_REF_FLAGS (use) & DF_REF_IN_NOTE) == 0);
1157*e4b17023SJohn Marino
1158*e4b17023SJohn Marino src = SET_SRC (def_set);
1159*e4b17023SJohn Marino use_pat = PATTERN (use_insn);
1160*e4b17023SJohn Marino
1161*e4b17023SJohn Marino /* In __asm don't replace if src might need more registers than
1162*e4b17023SJohn Marino reg, as that could increase register pressure on the __asm. */
1163*e4b17023SJohn Marino use_vec = DF_INSN_USES (def_insn);
1164*e4b17023SJohn Marino if (use_vec[0] && use_vec[1])
1165*e4b17023SJohn Marino return false;
1166*e4b17023SJohn Marino
1167*e4b17023SJohn Marino update_df_init (def_insn, use_insn);
1168*e4b17023SJohn Marino speed_p = optimize_bb_for_speed_p (BLOCK_FOR_INSN (use_insn));
1169*e4b17023SJohn Marino asm_operands = NULL_RTX;
1170*e4b17023SJohn Marino switch (GET_CODE (use_pat))
1171*e4b17023SJohn Marino {
1172*e4b17023SJohn Marino case ASM_OPERANDS:
1173*e4b17023SJohn Marino asm_operands = use_pat;
1174*e4b17023SJohn Marino break;
1175*e4b17023SJohn Marino case SET:
1176*e4b17023SJohn Marino if (MEM_P (SET_DEST (use_pat)))
1177*e4b17023SJohn Marino {
1178*e4b17023SJohn Marino loc = &SET_DEST (use_pat);
1179*e4b17023SJohn Marino new_rtx = propagate_rtx (*loc, GET_MODE (*loc), reg, src, speed_p);
1180*e4b17023SJohn Marino if (new_rtx)
1181*e4b17023SJohn Marino validate_unshare_change (use_insn, loc, new_rtx, true);
1182*e4b17023SJohn Marino }
1183*e4b17023SJohn Marino asm_operands = SET_SRC (use_pat);
1184*e4b17023SJohn Marino break;
1185*e4b17023SJohn Marino case PARALLEL:
1186*e4b17023SJohn Marino for (i = 0; i < XVECLEN (use_pat, 0); i++)
1187*e4b17023SJohn Marino if (GET_CODE (XVECEXP (use_pat, 0, i)) == SET)
1188*e4b17023SJohn Marino {
1189*e4b17023SJohn Marino if (MEM_P (SET_DEST (XVECEXP (use_pat, 0, i))))
1190*e4b17023SJohn Marino {
1191*e4b17023SJohn Marino loc = &SET_DEST (XVECEXP (use_pat, 0, i));
1192*e4b17023SJohn Marino new_rtx = propagate_rtx (*loc, GET_MODE (*loc), reg,
1193*e4b17023SJohn Marino src, speed_p);
1194*e4b17023SJohn Marino if (new_rtx)
1195*e4b17023SJohn Marino validate_unshare_change (use_insn, loc, new_rtx, true);
1196*e4b17023SJohn Marino }
1197*e4b17023SJohn Marino asm_operands = SET_SRC (XVECEXP (use_pat, 0, i));
1198*e4b17023SJohn Marino }
1199*e4b17023SJohn Marino else if (GET_CODE (XVECEXP (use_pat, 0, i)) == ASM_OPERANDS)
1200*e4b17023SJohn Marino asm_operands = XVECEXP (use_pat, 0, i);
1201*e4b17023SJohn Marino break;
1202*e4b17023SJohn Marino default:
1203*e4b17023SJohn Marino gcc_unreachable ();
1204*e4b17023SJohn Marino }
1205*e4b17023SJohn Marino
1206*e4b17023SJohn Marino gcc_assert (asm_operands && GET_CODE (asm_operands) == ASM_OPERANDS);
1207*e4b17023SJohn Marino for (i = 0; i < ASM_OPERANDS_INPUT_LENGTH (asm_operands); i++)
1208*e4b17023SJohn Marino {
1209*e4b17023SJohn Marino loc = &ASM_OPERANDS_INPUT (asm_operands, i);
1210*e4b17023SJohn Marino new_rtx = propagate_rtx (*loc, GET_MODE (*loc), reg, src, speed_p);
1211*e4b17023SJohn Marino if (new_rtx)
1212*e4b17023SJohn Marino validate_unshare_change (use_insn, loc, new_rtx, true);
1213*e4b17023SJohn Marino }
1214*e4b17023SJohn Marino
1215*e4b17023SJohn Marino if (num_changes_pending () == 0 || !apply_change_group ())
1216*e4b17023SJohn Marino return false;
1217*e4b17023SJohn Marino
1218*e4b17023SJohn Marino update_df (use_insn, NULL);
1219*e4b17023SJohn Marino num_changes++;
1220*e4b17023SJohn Marino return true;
1221*e4b17023SJohn Marino }
1222*e4b17023SJohn Marino
1223*e4b17023SJohn Marino /* Try to replace USE with SRC (defined in DEF_INSN) and simplify the
1224*e4b17023SJohn Marino result. */
1225*e4b17023SJohn Marino
1226*e4b17023SJohn Marino static bool
forward_propagate_and_simplify(df_ref use,rtx def_insn,rtx def_set)1227*e4b17023SJohn Marino forward_propagate_and_simplify (df_ref use, rtx def_insn, rtx def_set)
1228*e4b17023SJohn Marino {
1229*e4b17023SJohn Marino rtx use_insn = DF_REF_INSN (use);
1230*e4b17023SJohn Marino rtx use_set = single_set (use_insn);
1231*e4b17023SJohn Marino rtx src, reg, new_rtx, *loc;
1232*e4b17023SJohn Marino bool set_reg_equal;
1233*e4b17023SJohn Marino enum machine_mode mode;
1234*e4b17023SJohn Marino int asm_use = -1;
1235*e4b17023SJohn Marino
1236*e4b17023SJohn Marino if (INSN_CODE (use_insn) < 0)
1237*e4b17023SJohn Marino asm_use = asm_noperands (PATTERN (use_insn));
1238*e4b17023SJohn Marino
1239*e4b17023SJohn Marino if (!use_set && asm_use < 0 && !DEBUG_INSN_P (use_insn))
1240*e4b17023SJohn Marino return false;
1241*e4b17023SJohn Marino
1242*e4b17023SJohn Marino /* Do not propagate into PC, CC0, etc. */
1243*e4b17023SJohn Marino if (use_set && GET_MODE (SET_DEST (use_set)) == VOIDmode)
1244*e4b17023SJohn Marino return false;
1245*e4b17023SJohn Marino
1246*e4b17023SJohn Marino /* If def and use are subreg, check if they match. */
1247*e4b17023SJohn Marino reg = DF_REF_REG (use);
1248*e4b17023SJohn Marino if (GET_CODE (reg) == SUBREG && GET_CODE (SET_DEST (def_set)) == SUBREG)
1249*e4b17023SJohn Marino {
1250*e4b17023SJohn Marino if (SUBREG_BYTE (SET_DEST (def_set)) != SUBREG_BYTE (reg))
1251*e4b17023SJohn Marino return false;
1252*e4b17023SJohn Marino }
1253*e4b17023SJohn Marino /* Check if the def had a subreg, but the use has the whole reg. */
1254*e4b17023SJohn Marino else if (REG_P (reg) && GET_CODE (SET_DEST (def_set)) == SUBREG)
1255*e4b17023SJohn Marino return false;
1256*e4b17023SJohn Marino /* Check if the use has a subreg, but the def had the whole reg. Unlike the
1257*e4b17023SJohn Marino previous case, the optimization is possible and often useful indeed. */
1258*e4b17023SJohn Marino else if (GET_CODE (reg) == SUBREG && REG_P (SET_DEST (def_set)))
1259*e4b17023SJohn Marino reg = SUBREG_REG (reg);
1260*e4b17023SJohn Marino
1261*e4b17023SJohn Marino /* Make sure that we can treat REG as having the same mode as the
1262*e4b17023SJohn Marino source of DEF_SET. */
1263*e4b17023SJohn Marino if (GET_MODE (SET_DEST (def_set)) != GET_MODE (reg))
1264*e4b17023SJohn Marino return false;
1265*e4b17023SJohn Marino
1266*e4b17023SJohn Marino /* Check if the substitution is valid (last, because it's the most
1267*e4b17023SJohn Marino expensive check!). */
1268*e4b17023SJohn Marino src = SET_SRC (def_set);
1269*e4b17023SJohn Marino if (!CONSTANT_P (src) && !all_uses_available_at (def_insn, use_insn))
1270*e4b17023SJohn Marino return false;
1271*e4b17023SJohn Marino
1272*e4b17023SJohn Marino /* Check if the def is loading something from the constant pool; in this
1273*e4b17023SJohn Marino case we would undo optimization such as compress_float_constant.
1274*e4b17023SJohn Marino Still, we can set a REG_EQUAL note. */
1275*e4b17023SJohn Marino if (MEM_P (src) && MEM_READONLY_P (src))
1276*e4b17023SJohn Marino {
1277*e4b17023SJohn Marino rtx x = avoid_constant_pool_reference (src);
1278*e4b17023SJohn Marino if (x != src && use_set)
1279*e4b17023SJohn Marino {
1280*e4b17023SJohn Marino rtx note = find_reg_note (use_insn, REG_EQUAL, NULL_RTX);
1281*e4b17023SJohn Marino rtx old_rtx = note ? XEXP (note, 0) : SET_SRC (use_set);
1282*e4b17023SJohn Marino rtx new_rtx = simplify_replace_rtx (old_rtx, src, x);
1283*e4b17023SJohn Marino if (old_rtx != new_rtx)
1284*e4b17023SJohn Marino set_unique_reg_note (use_insn, REG_EQUAL, copy_rtx (new_rtx));
1285*e4b17023SJohn Marino }
1286*e4b17023SJohn Marino return false;
1287*e4b17023SJohn Marino }
1288*e4b17023SJohn Marino
1289*e4b17023SJohn Marino if (asm_use >= 0)
1290*e4b17023SJohn Marino return forward_propagate_asm (use, def_insn, def_set, reg);
1291*e4b17023SJohn Marino
1292*e4b17023SJohn Marino /* Else try simplifying. */
1293*e4b17023SJohn Marino
1294*e4b17023SJohn Marino if (DF_REF_TYPE (use) == DF_REF_REG_MEM_STORE)
1295*e4b17023SJohn Marino {
1296*e4b17023SJohn Marino loc = &SET_DEST (use_set);
1297*e4b17023SJohn Marino set_reg_equal = false;
1298*e4b17023SJohn Marino }
1299*e4b17023SJohn Marino else if (!use_set)
1300*e4b17023SJohn Marino {
1301*e4b17023SJohn Marino loc = &INSN_VAR_LOCATION_LOC (use_insn);
1302*e4b17023SJohn Marino set_reg_equal = false;
1303*e4b17023SJohn Marino }
1304*e4b17023SJohn Marino else
1305*e4b17023SJohn Marino {
1306*e4b17023SJohn Marino rtx note = find_reg_note (use_insn, REG_EQUAL, NULL_RTX);
1307*e4b17023SJohn Marino if (DF_REF_FLAGS (use) & DF_REF_IN_NOTE)
1308*e4b17023SJohn Marino loc = &XEXP (note, 0);
1309*e4b17023SJohn Marino else
1310*e4b17023SJohn Marino loc = &SET_SRC (use_set);
1311*e4b17023SJohn Marino
1312*e4b17023SJohn Marino /* Do not replace an existing REG_EQUAL note if the insn is not
1313*e4b17023SJohn Marino recognized. Either we're already replacing in the note, or we'll
1314*e4b17023SJohn Marino separately try plugging the definition in the note and simplifying.
1315*e4b17023SJohn Marino And only install a REQ_EQUAL note when the destination is a REG,
1316*e4b17023SJohn Marino as the note would be invalid otherwise. */
1317*e4b17023SJohn Marino set_reg_equal = (note == NULL_RTX && REG_P (SET_DEST (use_set)));
1318*e4b17023SJohn Marino }
1319*e4b17023SJohn Marino
1320*e4b17023SJohn Marino if (GET_MODE (*loc) == VOIDmode)
1321*e4b17023SJohn Marino mode = GET_MODE (SET_DEST (use_set));
1322*e4b17023SJohn Marino else
1323*e4b17023SJohn Marino mode = GET_MODE (*loc);
1324*e4b17023SJohn Marino
1325*e4b17023SJohn Marino new_rtx = propagate_rtx (*loc, mode, reg, src,
1326*e4b17023SJohn Marino optimize_bb_for_speed_p (BLOCK_FOR_INSN (use_insn)));
1327*e4b17023SJohn Marino
1328*e4b17023SJohn Marino if (!new_rtx)
1329*e4b17023SJohn Marino return false;
1330*e4b17023SJohn Marino
1331*e4b17023SJohn Marino return try_fwprop_subst (use, loc, new_rtx, def_insn, set_reg_equal);
1332*e4b17023SJohn Marino }
1333*e4b17023SJohn Marino
1334*e4b17023SJohn Marino
1335*e4b17023SJohn Marino /* Given a use USE of an insn, if it has a single reaching
1336*e4b17023SJohn Marino definition, try to forward propagate it into that insn.
1337*e4b17023SJohn Marino Return true if cfg cleanup will be needed. */
1338*e4b17023SJohn Marino
1339*e4b17023SJohn Marino static bool
forward_propagate_into(df_ref use)1340*e4b17023SJohn Marino forward_propagate_into (df_ref use)
1341*e4b17023SJohn Marino {
1342*e4b17023SJohn Marino df_ref def;
1343*e4b17023SJohn Marino rtx def_insn, def_set, use_insn;
1344*e4b17023SJohn Marino rtx parent;
1345*e4b17023SJohn Marino
1346*e4b17023SJohn Marino if (DF_REF_FLAGS (use) & DF_REF_READ_WRITE)
1347*e4b17023SJohn Marino return false;
1348*e4b17023SJohn Marino if (DF_REF_IS_ARTIFICIAL (use))
1349*e4b17023SJohn Marino return false;
1350*e4b17023SJohn Marino
1351*e4b17023SJohn Marino /* Only consider uses that have a single definition. */
1352*e4b17023SJohn Marino def = get_def_for_use (use);
1353*e4b17023SJohn Marino if (!def)
1354*e4b17023SJohn Marino return false;
1355*e4b17023SJohn Marino if (DF_REF_FLAGS (def) & DF_REF_READ_WRITE)
1356*e4b17023SJohn Marino return false;
1357*e4b17023SJohn Marino if (DF_REF_IS_ARTIFICIAL (def))
1358*e4b17023SJohn Marino return false;
1359*e4b17023SJohn Marino
1360*e4b17023SJohn Marino /* Do not propagate loop invariant definitions inside the loop. */
1361*e4b17023SJohn Marino if (DF_REF_BB (def)->loop_father != DF_REF_BB (use)->loop_father)
1362*e4b17023SJohn Marino return false;
1363*e4b17023SJohn Marino
1364*e4b17023SJohn Marino /* Check if the use is still present in the insn! */
1365*e4b17023SJohn Marino use_insn = DF_REF_INSN (use);
1366*e4b17023SJohn Marino if (DF_REF_FLAGS (use) & DF_REF_IN_NOTE)
1367*e4b17023SJohn Marino parent = find_reg_note (use_insn, REG_EQUAL, NULL_RTX);
1368*e4b17023SJohn Marino else
1369*e4b17023SJohn Marino parent = PATTERN (use_insn);
1370*e4b17023SJohn Marino
1371*e4b17023SJohn Marino if (!reg_mentioned_p (DF_REF_REG (use), parent))
1372*e4b17023SJohn Marino return false;
1373*e4b17023SJohn Marino
1374*e4b17023SJohn Marino def_insn = DF_REF_INSN (def);
1375*e4b17023SJohn Marino if (multiple_sets (def_insn))
1376*e4b17023SJohn Marino return false;
1377*e4b17023SJohn Marino def_set = single_set (def_insn);
1378*e4b17023SJohn Marino if (!def_set)
1379*e4b17023SJohn Marino return false;
1380*e4b17023SJohn Marino
1381*e4b17023SJohn Marino /* Only try one kind of propagation. If two are possible, we'll
1382*e4b17023SJohn Marino do it on the following iterations. */
1383*e4b17023SJohn Marino if (forward_propagate_and_simplify (use, def_insn, def_set)
1384*e4b17023SJohn Marino || forward_propagate_subreg (use, def_insn, def_set))
1385*e4b17023SJohn Marino {
1386*e4b17023SJohn Marino if (cfun->can_throw_non_call_exceptions
1387*e4b17023SJohn Marino && find_reg_note (use_insn, REG_EH_REGION, NULL_RTX)
1388*e4b17023SJohn Marino && purge_dead_edges (DF_REF_BB (use)))
1389*e4b17023SJohn Marino return true;
1390*e4b17023SJohn Marino }
1391*e4b17023SJohn Marino return false;
1392*e4b17023SJohn Marino }
1393*e4b17023SJohn Marino
1394*e4b17023SJohn Marino
1395*e4b17023SJohn Marino static void
fwprop_init(void)1396*e4b17023SJohn Marino fwprop_init (void)
1397*e4b17023SJohn Marino {
1398*e4b17023SJohn Marino num_changes = 0;
1399*e4b17023SJohn Marino calculate_dominance_info (CDI_DOMINATORS);
1400*e4b17023SJohn Marino
1401*e4b17023SJohn Marino /* We do not always want to propagate into loops, so we have to find
1402*e4b17023SJohn Marino loops and be careful about them. But we have to call flow_loops_find
1403*e4b17023SJohn Marino before df_analyze, because flow_loops_find may introduce new jump
1404*e4b17023SJohn Marino insns (sadly) if we are not working in cfglayout mode. */
1405*e4b17023SJohn Marino loop_optimizer_init (0);
1406*e4b17023SJohn Marino
1407*e4b17023SJohn Marino build_single_def_use_links ();
1408*e4b17023SJohn Marino df_set_flags (DF_DEFER_INSN_RESCAN);
1409*e4b17023SJohn Marino
1410*e4b17023SJohn Marino active_defs = XNEWVEC (df_ref, max_reg_num ());
1411*e4b17023SJohn Marino #ifdef ENABLE_CHECKING
1412*e4b17023SJohn Marino active_defs_check = sparseset_alloc (max_reg_num ());
1413*e4b17023SJohn Marino #endif
1414*e4b17023SJohn Marino }
1415*e4b17023SJohn Marino
1416*e4b17023SJohn Marino static void
fwprop_done(void)1417*e4b17023SJohn Marino fwprop_done (void)
1418*e4b17023SJohn Marino {
1419*e4b17023SJohn Marino loop_optimizer_finalize ();
1420*e4b17023SJohn Marino
1421*e4b17023SJohn Marino VEC_free (df_ref, heap, use_def_ref);
1422*e4b17023SJohn Marino free (active_defs);
1423*e4b17023SJohn Marino #ifdef ENABLE_CHECKING
1424*e4b17023SJohn Marino sparseset_free (active_defs_check);
1425*e4b17023SJohn Marino #endif
1426*e4b17023SJohn Marino
1427*e4b17023SJohn Marino free_dominance_info (CDI_DOMINATORS);
1428*e4b17023SJohn Marino cleanup_cfg (0);
1429*e4b17023SJohn Marino delete_trivially_dead_insns (get_insns (), max_reg_num ());
1430*e4b17023SJohn Marino
1431*e4b17023SJohn Marino if (dump_file)
1432*e4b17023SJohn Marino fprintf (dump_file,
1433*e4b17023SJohn Marino "\nNumber of successful forward propagations: %d\n\n",
1434*e4b17023SJohn Marino num_changes);
1435*e4b17023SJohn Marino }
1436*e4b17023SJohn Marino
1437*e4b17023SJohn Marino
1438*e4b17023SJohn Marino /* Main entry point. */
1439*e4b17023SJohn Marino
1440*e4b17023SJohn Marino static bool
gate_fwprop(void)1441*e4b17023SJohn Marino gate_fwprop (void)
1442*e4b17023SJohn Marino {
1443*e4b17023SJohn Marino return optimize > 0 && flag_forward_propagate;
1444*e4b17023SJohn Marino }
1445*e4b17023SJohn Marino
1446*e4b17023SJohn Marino static unsigned int
fwprop(void)1447*e4b17023SJohn Marino fwprop (void)
1448*e4b17023SJohn Marino {
1449*e4b17023SJohn Marino unsigned i;
1450*e4b17023SJohn Marino bool need_cleanup = false;
1451*e4b17023SJohn Marino
1452*e4b17023SJohn Marino fwprop_init ();
1453*e4b17023SJohn Marino
1454*e4b17023SJohn Marino /* Go through all the uses. df_uses_create will create new ones at the
1455*e4b17023SJohn Marino end, and we'll go through them as well.
1456*e4b17023SJohn Marino
1457*e4b17023SJohn Marino Do not forward propagate addresses into loops until after unrolling.
1458*e4b17023SJohn Marino CSE did so because it was able to fix its own mess, but we are not. */
1459*e4b17023SJohn Marino
1460*e4b17023SJohn Marino for (i = 0; i < DF_USES_TABLE_SIZE (); i++)
1461*e4b17023SJohn Marino {
1462*e4b17023SJohn Marino df_ref use = DF_USES_GET (i);
1463*e4b17023SJohn Marino if (use)
1464*e4b17023SJohn Marino if (DF_REF_TYPE (use) == DF_REF_REG_USE
1465*e4b17023SJohn Marino || DF_REF_BB (use)->loop_father == NULL
1466*e4b17023SJohn Marino /* The outer most loop is not really a loop. */
1467*e4b17023SJohn Marino || loop_outer (DF_REF_BB (use)->loop_father) == NULL)
1468*e4b17023SJohn Marino need_cleanup |= forward_propagate_into (use);
1469*e4b17023SJohn Marino }
1470*e4b17023SJohn Marino
1471*e4b17023SJohn Marino fwprop_done ();
1472*e4b17023SJohn Marino if (need_cleanup)
1473*e4b17023SJohn Marino cleanup_cfg (0);
1474*e4b17023SJohn Marino return 0;
1475*e4b17023SJohn Marino }
1476*e4b17023SJohn Marino
1477*e4b17023SJohn Marino struct rtl_opt_pass pass_rtl_fwprop =
1478*e4b17023SJohn Marino {
1479*e4b17023SJohn Marino {
1480*e4b17023SJohn Marino RTL_PASS,
1481*e4b17023SJohn Marino "fwprop1", /* name */
1482*e4b17023SJohn Marino gate_fwprop, /* gate */
1483*e4b17023SJohn Marino fwprop, /* execute */
1484*e4b17023SJohn Marino NULL, /* sub */
1485*e4b17023SJohn Marino NULL, /* next */
1486*e4b17023SJohn Marino 0, /* static_pass_number */
1487*e4b17023SJohn Marino TV_FWPROP, /* tv_id */
1488*e4b17023SJohn Marino 0, /* properties_required */
1489*e4b17023SJohn Marino 0, /* properties_provided */
1490*e4b17023SJohn Marino 0, /* properties_destroyed */
1491*e4b17023SJohn Marino 0, /* todo_flags_start */
1492*e4b17023SJohn Marino TODO_df_finish
1493*e4b17023SJohn Marino | TODO_verify_flow
1494*e4b17023SJohn Marino | TODO_verify_rtl_sharing /* todo_flags_finish */
1495*e4b17023SJohn Marino }
1496*e4b17023SJohn Marino };
1497*e4b17023SJohn Marino
1498*e4b17023SJohn Marino static unsigned int
fwprop_addr(void)1499*e4b17023SJohn Marino fwprop_addr (void)
1500*e4b17023SJohn Marino {
1501*e4b17023SJohn Marino unsigned i;
1502*e4b17023SJohn Marino bool need_cleanup = false;
1503*e4b17023SJohn Marino
1504*e4b17023SJohn Marino fwprop_init ();
1505*e4b17023SJohn Marino
1506*e4b17023SJohn Marino /* Go through all the uses. df_uses_create will create new ones at the
1507*e4b17023SJohn Marino end, and we'll go through them as well. */
1508*e4b17023SJohn Marino for (i = 0; i < DF_USES_TABLE_SIZE (); i++)
1509*e4b17023SJohn Marino {
1510*e4b17023SJohn Marino df_ref use = DF_USES_GET (i);
1511*e4b17023SJohn Marino if (use)
1512*e4b17023SJohn Marino if (DF_REF_TYPE (use) != DF_REF_REG_USE
1513*e4b17023SJohn Marino && DF_REF_BB (use)->loop_father != NULL
1514*e4b17023SJohn Marino /* The outer most loop is not really a loop. */
1515*e4b17023SJohn Marino && loop_outer (DF_REF_BB (use)->loop_father) != NULL)
1516*e4b17023SJohn Marino need_cleanup |= forward_propagate_into (use);
1517*e4b17023SJohn Marino }
1518*e4b17023SJohn Marino
1519*e4b17023SJohn Marino fwprop_done ();
1520*e4b17023SJohn Marino
1521*e4b17023SJohn Marino if (need_cleanup)
1522*e4b17023SJohn Marino cleanup_cfg (0);
1523*e4b17023SJohn Marino return 0;
1524*e4b17023SJohn Marino }
1525*e4b17023SJohn Marino
1526*e4b17023SJohn Marino struct rtl_opt_pass pass_rtl_fwprop_addr =
1527*e4b17023SJohn Marino {
1528*e4b17023SJohn Marino {
1529*e4b17023SJohn Marino RTL_PASS,
1530*e4b17023SJohn Marino "fwprop2", /* name */
1531*e4b17023SJohn Marino gate_fwprop, /* gate */
1532*e4b17023SJohn Marino fwprop_addr, /* execute */
1533*e4b17023SJohn Marino NULL, /* sub */
1534*e4b17023SJohn Marino NULL, /* next */
1535*e4b17023SJohn Marino 0, /* static_pass_number */
1536*e4b17023SJohn Marino TV_FWPROP, /* tv_id */
1537*e4b17023SJohn Marino 0, /* properties_required */
1538*e4b17023SJohn Marino 0, /* properties_provided */
1539*e4b17023SJohn Marino 0, /* properties_destroyed */
1540*e4b17023SJohn Marino 0, /* todo_flags_start */
1541*e4b17023SJohn Marino TODO_df_finish | TODO_verify_rtl_sharing /* todo_flags_finish */
1542*e4b17023SJohn Marino }
1543*e4b17023SJohn Marino };
1544