OSDN Git Service

84987df5e1ffa443aae31b206e62d0b7a0f9b836
[pf3gnuchains/gcc-fork.git] / gcc / web.c
1 /* Web construction code for GNU compiler.
2    Contributed by Jan Hubicka.
3    Copyright (C) 2001, 2002, 2004, 2006, 2007
4    Free Software Foundation, Inc.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3.  If not see
20 <http://www.gnu.org/licenses/>.  */
21
22 /* Simple optimization pass that splits independent uses of each pseudo,
23    increasing effectiveness of other optimizations.  The optimization can
24    serve as an example of use for the dataflow module.
25
26    We don't split registers with REG_USERVAR set unless -fmessy-debugging
27    is specified, because debugging information about such split variables
28    is almost unusable.
29
30    TODO
31     - Add code to keep debugging up-to-date after splitting user variable
32       pseudos.  This can be done by keeping track of all the pseudos used
33       for the variable and using life analysis information before reload
34       to determine which one is live and, in case more than one are live,
35       choose the one with the latest definition.
36
37       Other optimization passes can benefit from the infrastructure too.
38
39     - We may use profile information and ignore infrequent use for the
40       purpose of web unifying, inserting the compensation code later to
41       implement full induction variable expansion for loops (currently
42       we expand only if the induction variable is dead afterward, which
43       is often the case).  */
44
45 #include "config.h"
46 #include "system.h"
47 #include "coretypes.h"
48 #include "tm.h"
49 #include "toplev.h"
50
51 #include "rtl.h"
52 #include "hard-reg-set.h"
53 #include "flags.h"
54 #include "obstack.h"
55 #include "basic-block.h"
56 #include "output.h"
57 #include "df.h"
58 #include "function.h"
59 #include "timevar.h"
60 #include "tree-pass.h"
61
62
63 static rtx entry_register (struct web_entry *, struct df_ref *, char *);
64 static void replace_ref (struct df_ref *, rtx);
65
66 /* Find the root of unionfind tree (the representative of set).  */
67
68 struct web_entry *
69 unionfind_root (struct web_entry *element)
70 {
71   struct web_entry *element1 = element, *element2;
72
73   while (element->pred)
74     element = element->pred;
75   while (element1->pred)
76     {
77       element2 = element1->pred;
78       element1->pred = element;
79       element1 = element2;
80     }
81   return element;
82 }
83
84 /* Union sets.  
85    Return true if FIRST and SECOND points to the same web entry structure and
86    nothing is done.  Otherwise, return false.  */
87
88 bool
89 unionfind_union (struct web_entry *first, struct web_entry *second)
90 {
91   first = unionfind_root (first);
92   second = unionfind_root (second);
93   if (first == second)
94     return true;
95   second->pred = first;
96   return false;
97 }
98
99 /* For each use, all possible defs reaching it must come in the same
100    register, union them.
101    FUN is the function that does the union.  */
102
103 void
104 union_defs (struct df_ref *use, struct web_entry *def_entry,
105             struct web_entry *use_entry,
106             bool (*fun) (struct web_entry *, struct web_entry *))
107 {
108   rtx insn = DF_REF_INSN (use);
109   struct df_link *link = DF_REF_CHAIN (use);
110   struct df_ref **use_link;
111   struct df_ref **eq_use_link;
112   struct df_ref **def_link;
113   rtx set;
114
115   if (insn)
116     {
117       use_link = DF_INSN_USES (insn);
118       eq_use_link = DF_INSN_EQ_USES (insn);
119       def_link = DF_INSN_DEFS (insn);
120       set = single_set (insn);
121     }
122   else
123     {
124       use_link = NULL;
125       eq_use_link = NULL;
126       def_link = NULL;
127       set = NULL;
128     }
129
130   /* Some instructions may use match_dup for their operands.  In case the
131      operands are dead, we will assign them different pseudos, creating
132      invalid instructions, so union all uses of the same operand for each
133      insn.  */
134
135   if (use_link)
136     while (*use_link)
137       {
138         if (use != *use_link
139             && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (*use_link))
140           (*fun) (use_entry + DF_REF_ID (use),
141                   use_entry + DF_REF_ID (*use_link));
142         use_link++;
143       }
144
145   if (eq_use_link)
146     while (*eq_use_link)
147       {
148         if (use != *eq_use_link
149             && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (*eq_use_link))
150           (*fun) (use_entry + DF_REF_ID (use),
151                   use_entry + DF_REF_ID (*eq_use_link));
152         eq_use_link++;
153     }
154
155   /* Recognize trivial noop moves and attempt to keep them as noop.  */
156
157   if (set
158       && SET_SRC (set) == DF_REF_REG (use)
159       && SET_SRC (set) == SET_DEST (set))
160     {
161       if (def_link)
162         while (*def_link)
163           {
164             if (DF_REF_REAL_REG (use) == DF_REF_REAL_REG (*def_link))
165               (*fun) (use_entry + DF_REF_ID (use),
166                       def_entry + DF_REF_ID (*def_link));
167             def_link++;
168           }
169     }
170   while (link)
171     {
172       (*fun) (use_entry + DF_REF_ID (use),
173               def_entry + DF_REF_ID (link->ref));
174       link = link->next;
175     }
176
177   /* A READ_WRITE use requires the corresponding def to be in the same
178      register.  Find it and union.  */
179   if (use->flags & DF_REF_READ_WRITE)
180     {
181       struct df_ref **link;
182
183       if (DF_REF_INSN (use))
184         link = DF_INSN_DEFS (DF_REF_INSN (use));
185       else
186         link = NULL;
187
188       if (link)
189         while (*link)
190           {
191             if (DF_REF_REAL_REG (*link) == DF_REF_REAL_REG (use))
192               (*fun) (use_entry + DF_REF_ID (use),
193                       def_entry + DF_REF_ID (*link));
194             link++;
195           }
196     }
197 }
198
199 /* Find the corresponding register for the given entry.  */
200
201 static rtx
202 entry_register (struct web_entry *entry, struct df_ref *ref, char *used)
203 {
204   struct web_entry *root;
205   rtx reg, newreg;
206
207   /* Find the corresponding web and see if it has been visited.  */
208   root = unionfind_root (entry);
209   if (root->reg)
210     return root->reg;
211
212   /* We are seeing this web for the first time, do the assignment.  */
213   reg = DF_REF_REAL_REG (ref);
214
215   /* In case the original register is already assigned, generate new one.  */
216   if (!used[REGNO (reg)])
217     newreg = reg, used[REGNO (reg)] = 1;
218   else if (REG_USERVAR_P (reg) && 0/*&& !flag_messy_debugging*/)
219     {
220       newreg = reg;
221       if (dump_file)
222         fprintf (dump_file,
223                  "New web forced to keep reg=%i (user variable)\n",
224                  REGNO (reg));
225     }
226   else
227     {
228       newreg = gen_reg_rtx (GET_MODE (reg));
229       REG_USERVAR_P (newreg) = REG_USERVAR_P (reg);
230       REG_POINTER (newreg) = REG_POINTER (reg);
231       REG_ATTRS (newreg) = REG_ATTRS (reg);
232       if (dump_file)
233         fprintf (dump_file, "Web oldreg=%i newreg=%i\n", REGNO (reg),
234                  REGNO (newreg));
235     }
236
237   root->reg = newreg;
238   return newreg;
239 }
240
241 /* Replace the reference by REG.  */
242
243 static void
244 replace_ref (struct df_ref *ref, rtx reg)
245 {
246   rtx oldreg = DF_REF_REAL_REG (ref);
247   rtx *loc = DF_REF_REAL_LOC (ref);
248   unsigned int uid = INSN_UID (DF_REF_INSN (ref));
249
250   if (oldreg == reg)
251     return;
252   if (dump_file)
253     fprintf (dump_file, "Updating insn %i (%i->%i)\n",
254              uid, REGNO (oldreg), REGNO (reg)); 
255   *loc = reg;
256   df_insn_rescan (DF_REF_INSN (ref));
257 }
258
259 \f
260 static bool
261 gate_handle_web (void)
262 {
263   return (optimize > 0 && flag_web);
264 }
265
266 /* Main entry point.  */
267
268 static unsigned int
269 web_main (void)
270 {
271   struct web_entry *def_entry;
272   struct web_entry *use_entry;
273   unsigned int max = max_reg_num ();
274   char *used;
275   basic_block bb;
276   unsigned int uses_num = 0;
277   rtx insn;
278
279   df_set_flags (DF_NO_HARD_REGS + DF_EQ_NOTES);
280   df_chain_add_problem (DF_UD_CHAIN);
281   df_analyze ();
282   df_set_flags (DF_DEFER_INSN_RESCAN);
283
284   /* Assign ids to the uses.  */
285   FOR_ALL_BB (bb)
286     FOR_BB_INSNS (bb, insn)
287     {
288       unsigned int uid = INSN_UID (insn);
289       if (INSN_P (insn))
290         {
291           struct df_ref **use_rec;
292           for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
293             {
294               struct df_ref *use = *use_rec;
295               if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
296                 DF_REF_ID (use) = uses_num++;
297             }
298           for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
299             {
300               struct df_ref *use = *use_rec;
301               if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
302                 DF_REF_ID (use) = uses_num++;
303             }
304         }
305     }
306
307   /* Record the number of uses and defs at the beginning of the optimization.  */
308   def_entry = XCNEWVEC (struct web_entry, DF_DEFS_TABLE_SIZE());
309   used = XCNEWVEC (char, max);
310   use_entry = XCNEWVEC (struct web_entry, uses_num);
311
312   /* Produce the web.  */
313   FOR_ALL_BB (bb)
314     FOR_BB_INSNS (bb, insn)
315     {
316       unsigned int uid = INSN_UID (insn);
317       if (INSN_P (insn))
318         {
319           struct df_ref **use_rec;
320           for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
321             {
322               struct df_ref *use = *use_rec;
323               if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
324                 union_defs (use, def_entry, use_entry, unionfind_union);
325             }
326           for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
327             {
328               struct df_ref *use = *use_rec;
329               if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
330                 union_defs (use, def_entry, use_entry, unionfind_union);
331             }
332         }
333     }
334
335   /* Update the instruction stream, allocating new registers for split pseudos
336      in progress.  */
337   FOR_ALL_BB (bb)
338     FOR_BB_INSNS (bb, insn)
339     {
340       unsigned int uid = INSN_UID (insn);
341       if (INSN_P (insn))
342         {
343           struct df_ref **use_rec;
344           struct df_ref **def_rec;
345           for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
346             {
347               struct df_ref *use = *use_rec;
348               if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
349                 replace_ref (use, entry_register (use_entry + DF_REF_ID (use), use, used));
350             }
351           for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
352             {
353               struct df_ref *use = *use_rec;
354               if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
355                 replace_ref (use, entry_register (use_entry + DF_REF_ID (use), use, used));
356             }
357           for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
358             {
359               struct df_ref *def = *def_rec;
360               if (DF_REF_REGNO (def) >= FIRST_PSEUDO_REGISTER)
361                 replace_ref (def, entry_register (def_entry + DF_REF_ID (def), def, used));
362             }
363         }
364     }
365
366   free (def_entry);
367   free (use_entry);
368   free (used);
369   return 0;
370 }
371 \f
372 struct rtl_opt_pass pass_web =
373 {
374  {
375   RTL_PASS,
376   "web",                                /* name */
377   gate_handle_web,                      /* gate */
378   web_main,                             /* execute */
379   NULL,                                 /* sub */
380   NULL,                                 /* next */
381   0,                                    /* static_pass_number */
382   TV_WEB,                               /* tv_id */
383   0,                                    /* properties_required */
384   0,                                    /* properties_provided */
385   0,                                    /* properties_destroyed */
386   0,                                    /* todo_flags_start */
387   TODO_df_finish | TODO_verify_rtl_sharing | 
388   TODO_dump_func                        /* todo_flags_finish */
389  }
390 };
391