xref: /openbsd-src/gnu/gcc/gcc/web.c (revision 404b540a9034ac75a6199ad1a32d1bbc7a0d4210)
1 /* Web construction code for GNU compiler.
2    Contributed by Jan Hubicka.
3    Copyright (C) 2001, 2002, 2004, 2006
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 2, 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 COPYING.  If not, write to the Free
20 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.  */
22 
23 /* Simple optimization pass that splits independent uses of each pseudo,
24    increasing effectiveness of other optimizations.  The optimization can
25    serve as an example of use for the dataflow module.
26 
27    We don't split registers with REG_USERVAR set unless -fmessy-debugging
28    is specified, because debugging information about such split variables
29    is almost unusable.
30 
31    TODO
32     - Add code to keep debugging up-to-date after splitting user variable
33       pseudos.  This can be done by keeping track of all the pseudos used
34       for the variable and using life analysis information before reload
35       to determine which one is live and, in case more than one are live,
36       choose the one with the latest definition.
37 
38       Other optimization passes can benefit from the infrastructure too.
39 
40     - We may use profile information and ignore infrequent use for the
41       purpose of web unifying, inserting the compensation code later to
42       implement full induction variable expansion for loops (currently
43       we expand only if the induction variable is dead afterward, which
44       is often the case).  */
45 
46 #include "config.h"
47 #include "system.h"
48 #include "coretypes.h"
49 #include "tm.h"
50 #include "toplev.h"
51 
52 #include "rtl.h"
53 #include "hard-reg-set.h"
54 #include "flags.h"
55 #include "obstack.h"
56 #include "basic-block.h"
57 #include "output.h"
58 #include "df.h"
59 #include "function.h"
60 #include "timevar.h"
61 #include "tree-pass.h"
62 
63 
64 static rtx entry_register (struct web_entry *, struct df_ref *, char *);
65 static void replace_ref (struct df_ref *, rtx);
66 
67 /* Find the root of unionfind tree (the representative of set).  */
68 
69 struct web_entry *
unionfind_root(struct web_entry * element)70 unionfind_root (struct web_entry *element)
71 {
72   struct web_entry *element1 = element, *element2;
73 
74   while (element->pred)
75     element = element->pred;
76   while (element1->pred)
77     {
78       element2 = element1->pred;
79       element1->pred = element;
80       element1 = element2;
81     }
82   return element;
83 }
84 
85 /* Union sets.
86    Return true if FIRST and SECOND points to the same web entry structure and
87    nothing is done.  Otherwise, return false.  */
88 
89 bool
unionfind_union(struct web_entry * first,struct web_entry * second)90 unionfind_union (struct web_entry *first, struct web_entry *second)
91 {
92   first = unionfind_root (first);
93   second = unionfind_root (second);
94   if (first == second)
95     return true;
96   second->pred = first;
97   return false;
98 }
99 
100 /* For each use, all possible defs reaching it must come in the same
101    register, union them.
102    FUN is the function that does the union.  */
103 
104 void
union_defs(struct df * df,struct df_ref * use,struct web_entry * def_entry,struct web_entry * use_entry,bool (* fun)(struct web_entry *,struct web_entry *))105 union_defs (struct df *df, struct df_ref *use, struct web_entry *def_entry,
106  	    struct web_entry *use_entry,
107  	    bool (*fun) (struct web_entry *, struct web_entry *))
108 {
109   rtx insn = DF_REF_INSN (use);
110   struct df_link *link = DF_REF_CHAIN (use);
111   struct df_ref *use_link;
112   struct df_ref *def_link;
113   rtx set;
114 
115   if (insn)
116     {
117       use_link = DF_INSN_USES (df, insn);
118       def_link = DF_INSN_DEFS (df, insn);
119       set = single_set (insn);
120     }
121   else
122     {
123       use_link = NULL;
124       def_link = NULL;
125       set = NULL;
126     }
127 
128   /* Some instructions may use match_dup for their operands.  In case the
129      operands are dead, we will assign them different pseudos, creating
130      invalid instructions, so union all uses of the same operand for each
131      insn.  */
132 
133   while (use_link)
134     {
135       if (use != use_link
136 	  && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (use_link))
137  	(*fun) (use_entry + DF_REF_ID (use),
138  		use_entry + DF_REF_ID (use_link));
139       use_link = use_link->next_ref;
140     }
141 
142   /* Recognize trivial noop moves and attempt to keep them as noop.
143      While most of noop moves should be removed, we still keep some
144      of them at libcall boundaries and such.  */
145 
146   if (set
147       && SET_SRC (set) == DF_REF_REG (use)
148       && SET_SRC (set) == SET_DEST (set))
149     {
150       while (def_link)
151 	{
152 	  if (DF_REF_REAL_REG (use) == DF_REF_REAL_REG (def_link))
153  	    (*fun) (use_entry + DF_REF_ID (use),
154  		    def_entry + DF_REF_ID (def_link));
155 	  def_link = def_link->next_ref;
156 	}
157     }
158   while (link)
159     {
160       (*fun) (use_entry + DF_REF_ID (use),
161 	      def_entry + DF_REF_ID (link->ref));
162       link = link->next;
163     }
164 
165   /* A READ_WRITE use requires the corresponding def to be in the same
166      register.  Find it and union.  */
167   if (use->flags & DF_REF_READ_WRITE)
168     {
169       struct df_ref *link;
170 
171       if (DF_REF_INSN (use))
172 	link = DF_INSN_DEFS (df, DF_REF_INSN (use));
173       else
174 	link = NULL;
175 
176       while (link)
177 	{
178 	  if (DF_REF_REAL_REG (link) == DF_REF_REAL_REG (use))
179  	    (*fun) (use_entry + DF_REF_ID (use),
180  		    def_entry + DF_REF_ID (link));
181 	  link = link->next_ref;
182 	}
183     }
184 }
185 
186 /* Find the corresponding register for the given entry.  */
187 
188 static rtx
entry_register(struct web_entry * entry,struct df_ref * ref,char * used)189 entry_register (struct web_entry *entry, struct df_ref *ref, char *used)
190 {
191   struct web_entry *root;
192   rtx reg, newreg;
193 
194   /* Find the corresponding web and see if it has been visited.  */
195   root = unionfind_root (entry);
196   if (root->reg)
197     return root->reg;
198 
199   /* We are seeing this web for the first time, do the assignment.  */
200   reg = DF_REF_REAL_REG (ref);
201 
202   /* In case the original register is already assigned, generate new one.  */
203   if (!used[REGNO (reg)])
204     newreg = reg, used[REGNO (reg)] = 1;
205   else if (REG_USERVAR_P (reg) && 0/*&& !flag_messy_debugging*/)
206     {
207       newreg = reg;
208       if (dump_file)
209 	fprintf (dump_file,
210 		 "New web forced to keep reg=%i (user variable)\n",
211 		 REGNO (reg));
212     }
213   else
214     {
215       newreg = gen_reg_rtx (GET_MODE (reg));
216       REG_USERVAR_P (newreg) = REG_USERVAR_P (reg);
217       REG_POINTER (newreg) = REG_POINTER (reg);
218       REG_ATTRS (newreg) = REG_ATTRS (reg);
219       if (dump_file)
220 	fprintf (dump_file, "Web oldreg=%i newreg=%i\n", REGNO (reg),
221 		 REGNO (newreg));
222     }
223 
224   root->reg = newreg;
225   return newreg;
226 }
227 
228 /* Replace the reference by REG.  */
229 
230 static void
replace_ref(struct df_ref * ref,rtx reg)231 replace_ref (struct df_ref *ref, rtx reg)
232 {
233   rtx oldreg = DF_REF_REAL_REG (ref);
234   rtx *loc = DF_REF_REAL_LOC (ref);
235 
236   if (oldreg == reg)
237     return;
238   if (dump_file)
239     fprintf (dump_file, "Updating insn %i (%i->%i)\n",
240 	     INSN_UID (DF_REF_INSN (ref)), REGNO (oldreg), REGNO (reg));
241   *loc = reg;
242 }
243 
244 /* Main entry point.  */
245 
246 static void
web_main(void)247 web_main (void)
248 {
249   struct df *df;
250   struct web_entry *def_entry;
251   struct web_entry *use_entry;
252   unsigned int i;
253   int max = max_reg_num ();
254   char *used;
255 
256   df = df_init (DF_EQUIV_NOTES);
257   df_chain_add_problem (df, DF_UD_CHAIN);
258   df_analyze (df);
259   df_reorganize_refs (&df->def_info);
260   df_reorganize_refs (&df->use_info);
261 
262   def_entry = XCNEWVEC (struct web_entry, DF_DEFS_SIZE (df));
263   use_entry = XCNEWVEC (struct web_entry, DF_USES_SIZE (df));
264   used = XCNEWVEC (char, max);
265 
266   if (dump_file)
267     df_dump (df, dump_file);
268 
269   /* Produce the web.  */
270   for (i = 0; i < DF_USES_SIZE (df); i++)
271     union_defs (df, DF_USES_GET (df, i), def_entry, use_entry, unionfind_union);
272 
273   /* Update the instruction stream, allocating new registers for split pseudos
274      in progress.  */
275   for (i = 0; i < DF_USES_SIZE (df); i++)
276     replace_ref (DF_USES_GET (df, i),
277 		 entry_register (use_entry + i, DF_USES_GET (df, i), used));
278   for (i = 0; i < DF_DEFS_SIZE (df); i++)
279     replace_ref (DF_DEFS_GET (df, i),
280 		 entry_register (def_entry + i, DF_DEFS_GET (df, i), used));
281 
282   /* Dataflow information is corrupt here, but it can be easily updated
283      by creating new entries for new registers and updates or calling
284      df_insns_modify.  */
285   free (def_entry);
286   free (use_entry);
287   free (used);
288   df_finish (df);
289   df = NULL;
290 }
291 
292 static bool
gate_handle_web(void)293 gate_handle_web (void)
294 {
295   return (optimize > 0 && flag_web);
296 }
297 
298 static unsigned int
rest_of_handle_web(void)299 rest_of_handle_web (void)
300 {
301   web_main ();
302   delete_trivially_dead_insns (get_insns (), max_reg_num ());
303   cleanup_cfg (CLEANUP_EXPENSIVE);
304   reg_scan (get_insns (), max_reg_num ());
305   return 0;
306 }
307 
308 struct tree_opt_pass pass_web =
309 {
310   "web",                                /* name */
311   gate_handle_web,                      /* gate */
312   rest_of_handle_web,                   /* execute */
313   NULL,                                 /* sub */
314   NULL,                                 /* next */
315   0,                                    /* static_pass_number */
316   TV_WEB,                               /* tv_id */
317   0,                                    /* properties_required */
318   0,                                    /* properties_provided */
319   0,                                    /* properties_destroyed */
320   0,                                    /* todo_flags_start */
321   TODO_dump_func,                       /* todo_flags_finish */
322   'Z'                                   /* letter */
323 };
324 
325