1 /* Web construction code for GNU compiler.
2 Contributed by Jan Hubicka.
3 Copyright (C) 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* Simple optimization pass that splits independent uses of each pseudo,
22 increasing effectiveness of other optimizations. The optimization can
23 serve as an example of use for the dataflow module.
25 We don't split registers with REG_USERVAR set unless -fmessy-debugging
26 is specified, because debugging information about such split variables
30 - Add code to keep debugging up-to-date after splitting user variable
31 pseudos. This can be done by keeping track of all the pseudos used
32 for the variable and using life analysis information before reload
33 to determine which one is live and, in case more than one are live,
34 choose the one with the latest definition.
36 Other optimization passes can benefit from the infrastructure too.
38 - We may use profile information and ignore infrequent use for the
39 purpose of web unifying, inserting the compensation code later to
40 implement full induction variable expansion for loops (currently
41 we expand only if the induction variable is dead afterward, which
42 is often the case). */
46 #include "coretypes.h"
51 #include "hard-reg-set.h"
54 #include "basic-block.h"
59 #include "tree-pass.h"
62 static rtx
entry_register (struct web_entry
*, struct df_ref
*, char *);
63 static void replace_ref (struct df_ref
*, rtx
);
65 /* Find the root of unionfind tree (the representative of set). */
68 unionfind_root (struct web_entry
*element
)
70 struct web_entry
*element1
= element
, *element2
;
73 element
= element
->pred
;
74 while (element1
->pred
)
76 element2
= element1
->pred
;
77 element1
->pred
= element
;
84 Return true if FIRST and SECOND points to the same web entry structure and
85 nothing is done. Otherwise, return false. */
88 unionfind_union (struct web_entry
*first
, struct web_entry
*second
)
90 first
= unionfind_root (first
);
91 second
= unionfind_root (second
);
98 /* For each use, all possible defs reaching it must come in the same
100 FUN is the function that does the union. */
103 union_defs (struct df
*df
, struct df_ref
*use
, struct web_entry
*def_entry
,
104 struct web_entry
*use_entry
,
105 bool (*fun
) (struct web_entry
*, struct web_entry
*))
107 rtx insn
= DF_REF_INSN (use
);
108 struct df_link
*link
= DF_REF_CHAIN (use
);
109 struct df_ref
*use_link
;
110 struct df_ref
*def_link
;
115 use_link
= DF_INSN_USES (df
, insn
);
116 def_link
= DF_INSN_DEFS (df
, insn
);
117 set
= single_set (insn
);
126 /* Some instructions may use match_dup for their operands. In case the
127 operands are dead, we will assign them different pseudos, creating
128 invalid instructions, so union all uses of the same operand for each
134 && DF_REF_REAL_REG (use
) == DF_REF_REAL_REG (use_link
))
135 (*fun
) (use_entry
+ DF_REF_ID (use
),
136 use_entry
+ DF_REF_ID (use_link
));
137 use_link
= use_link
->next_ref
;
140 /* Recognize trivial noop moves and attempt to keep them as noop.
141 While most of noop moves should be removed, we still keep some
142 of them at libcall boundaries and such. */
145 && SET_SRC (set
) == DF_REF_REG (use
)
146 && SET_SRC (set
) == SET_DEST (set
))
150 if (DF_REF_REAL_REG (use
) == DF_REF_REAL_REG (def_link
))
151 (*fun
) (use_entry
+ DF_REF_ID (use
),
152 def_entry
+ DF_REF_ID (def_link
));
153 def_link
= def_link
->next_ref
;
158 (*fun
) (use_entry
+ DF_REF_ID (use
),
159 def_entry
+ DF_REF_ID (link
->ref
));
163 /* A READ_WRITE use requires the corresponding def to be in the same
164 register. Find it and union. */
165 if (use
->flags
& DF_REF_READ_WRITE
)
169 if (DF_REF_INSN (use
))
170 link
= DF_INSN_DEFS (df
, DF_REF_INSN (use
));
176 if (DF_REF_REAL_REG (link
) == DF_REF_REAL_REG (use
))
177 (*fun
) (use_entry
+ DF_REF_ID (use
),
178 def_entry
+ DF_REF_ID (link
));
179 link
= link
->next_ref
;
184 /* Find the corresponding register for the given entry. */
187 entry_register (struct web_entry
*entry
, struct df_ref
*ref
, char *used
)
189 struct web_entry
*root
;
192 /* Find the corresponding web and see if it has been visited. */
193 root
= unionfind_root (entry
);
197 /* We are seeing this web for the first time, do the assignment. */
198 reg
= DF_REF_REAL_REG (ref
);
200 /* In case the original register is already assigned, generate new one. */
201 if (!used
[REGNO (reg
)])
202 newreg
= reg
, used
[REGNO (reg
)] = 1;
203 else if (REG_USERVAR_P (reg
) && 0/*&& !flag_messy_debugging*/)
208 "New web forced to keep reg=%i (user variable)\n",
213 newreg
= gen_reg_rtx (GET_MODE (reg
));
214 REG_USERVAR_P (newreg
) = REG_USERVAR_P (reg
);
215 REG_POINTER (newreg
) = REG_POINTER (reg
);
216 REG_ATTRS (newreg
) = REG_ATTRS (reg
);
218 fprintf (dump_file
, "Web oldreg=%i newreg=%i\n", REGNO (reg
),
226 /* Replace the reference by REG. */
229 replace_ref (struct df_ref
*ref
, rtx reg
)
231 rtx oldreg
= DF_REF_REAL_REG (ref
);
232 rtx
*loc
= DF_REF_REAL_LOC (ref
);
237 fprintf (dump_file
, "Updating insn %i (%i->%i)\n",
238 INSN_UID (DF_REF_INSN (ref
)), REGNO (oldreg
), REGNO (reg
));
242 /* Main entry point. */
248 struct web_entry
*def_entry
;
249 struct web_entry
*use_entry
;
251 int max
= max_reg_num ();
254 df
= df_init (DF_EQUIV_NOTES
);
255 df_chain_add_problem (df
, DF_UD_CHAIN
);
257 df_reorganize_refs (&df
->def_info
);
258 df_reorganize_refs (&df
->use_info
);
260 def_entry
= XCNEWVEC (struct web_entry
, DF_DEFS_SIZE (df
));
261 use_entry
= XCNEWVEC (struct web_entry
, DF_USES_SIZE (df
));
262 used
= XCNEWVEC (char, max
);
265 df_dump (df
, dump_file
);
267 /* Produce the web. */
268 for (i
= 0; i
< DF_USES_SIZE (df
); i
++)
269 union_defs (df
, DF_USES_GET (df
, i
), def_entry
, use_entry
, unionfind_union
);
271 /* Update the instruction stream, allocating new registers for split pseudos
273 for (i
= 0; i
< DF_USES_SIZE (df
); i
++)
274 replace_ref (DF_USES_GET (df
, i
),
275 entry_register (use_entry
+ i
, DF_USES_GET (df
, i
), used
));
276 for (i
= 0; i
< DF_DEFS_SIZE (df
); i
++)
277 replace_ref (DF_DEFS_GET (df
, i
),
278 entry_register (def_entry
+ i
, DF_DEFS_GET (df
, i
), used
));
280 /* Dataflow information is corrupt here, but it can be easily updated
281 by creating new entries for new registers and updates or calling
291 gate_handle_web (void)
293 return (optimize
> 0 && flag_web
);
297 rest_of_handle_web (void)
300 delete_trivially_dead_insns (get_insns (), max_reg_num ());
301 cleanup_cfg (CLEANUP_EXPENSIVE
);
302 reg_scan (get_insns (), max_reg_num ());
306 struct tree_opt_pass pass_web
=
309 gate_handle_web
, /* gate */
310 rest_of_handle_web
, /* execute */
313 0, /* static_pass_number */
315 0, /* properties_required */
316 0, /* properties_provided */
317 0, /* properties_destroyed */
318 0, /* todo_flags_start */
319 TODO_dump_func
, /* todo_flags_finish */