]> gcc.gnu.org Git - gcc.git/blame - gcc/web.c
re PR objc++/60398 (FAIL: obj-c++.dg/invalid-method-2.mm -fgnu-runtime (test for...
[gcc.git] / gcc / web.c
CommitLineData
62551c66 1/* Web construction code for GNU compiler.
2426d8dd 2 Contributed by Jan Hubicka.
23a5b65a 3 Copyright (C) 2001-2014 Free Software Foundation, Inc.
62551c66
JH
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9dcd6f09 9Software Foundation; either version 3, or (at your option) any later
62551c66
JH
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
9dcd6f09
NC
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
62551c66 20
2426d8dd 21/* Simple optimization pass that splits independent uses of each pseudo,
d91edf86 22 increasing effectiveness of other optimizations. The optimization can
2426d8dd 23 serve as an example of use for the dataflow module.
62551c66 24
2426d8dd
EB
25 We don't split registers with REG_USERVAR set unless -fmessy-debugging
26 is specified, because debugging information about such split variables
27 is almost unusable.
62551c66
JH
28
29 TODO
2426d8dd
EB
30 - We may use profile information and ignore infrequent use for the
31 purpose of web unifying, inserting the compensation code later to
32 implement full induction variable expansion for loops (currently
33 we expand only if the induction variable is dead afterward, which
34 is often the case). */
62551c66
JH
35
36#include "config.h"
37#include "system.h"
38#include "coretypes.h"
39#include "tm.h"
718f9c0f 40#include "diagnostic-core.h"
62551c66
JH
41
42#include "rtl.h"
43#include "hard-reg-set.h"
44#include "flags.h"
7932a3db 45#include "obstack.h"
62551c66 46#include "basic-block.h"
62551c66
JH
47#include "df.h"
48#include "function.h"
4143fd36
BS
49#include "insn-config.h"
50#include "recog.h"
ef330312 51#include "tree-pass.h"
62551c66
JH
52
53
2426d8dd 54/* Find the root of unionfind tree (the representative of set). */
62551c66 55
8cd37d0b 56struct web_entry *
9373164a 57unionfind_root (struct web_entry *element)
62551c66
JH
58{
59 struct web_entry *element1 = element, *element2;
60
61 while (element->pred)
62 element = element->pred;
63 while (element1->pred)
64 {
65 element2 = element1->pred;
66 element1->pred = element;
67 element1 = element2;
68 }
69 return element;
70}
71
b8698a0f 72/* Union sets.
8cd37d0b
RL
73 Return true if FIRST and SECOND points to the same web entry structure and
74 nothing is done. Otherwise, return false. */
62551c66 75
8cd37d0b 76bool
9373164a 77unionfind_union (struct web_entry *first, struct web_entry *second)
62551c66
JH
78{
79 first = unionfind_root (first);
80 second = unionfind_root (second);
81 if (first == second)
8cd37d0b 82 return true;
62551c66 83 second->pred = first;
8cd37d0b 84 return false;
62551c66
JH
85}
86
4143fd36
BS
87/* For INSN, union all defs and uses that are linked by match_dup.
88 FUN is the function that does the union. */
89
90static void
91union_match_dups (rtx insn, struct web_entry *def_entry,
92 struct web_entry *use_entry,
93 bool (*fun) (struct web_entry *, struct web_entry *))
94{
95 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
96 df_ref *use_link = DF_INSN_INFO_USES (insn_info);
97 df_ref *def_link = DF_INSN_INFO_DEFS (insn_info);
7bd8fc3b 98 struct web_entry *dup_entry;
4143fd36
BS
99 int i;
100
101 extract_insn (insn);
102
103 for (i = 0; i < recog_data.n_dups; i++)
104 {
105 int op = recog_data.dup_num[i];
106 enum op_type type = recog_data.operand_type[op];
107 df_ref *ref, *dupref;
108 struct web_entry *entry;
109
7bd8fc3b 110 for (dup_entry = use_entry, dupref = use_link; *dupref; dupref++)
4143fd36
BS
111 if (DF_REF_LOC (*dupref) == recog_data.dup_loc[i])
112 break;
113
7bd8fc3b
JR
114 if (*dupref == NULL && type == OP_INOUT)
115 {
116
117 for (dup_entry = def_entry, dupref = def_link; *dupref; dupref++)
118 if (DF_REF_LOC (*dupref) == recog_data.dup_loc[i])
119 break;
120 }
121 /* ??? *DUPREF can still be zero, because when an operand matches
122 a memory, DF_REF_LOC (use_link[n]) points to the register part
123 of the address, whereas recog_data.dup_loc[m] points to the
124 entire memory ref, thus we fail to find the duplicate entry,
125 even though it is there.
126 Example: i686-pc-linux-gnu gcc.c-torture/compile/950607-1.c
127 -O3 -fomit-frame-pointer -funroll-loops */
4143fd36
BS
128 if (*dupref == NULL
129 || DF_REF_REGNO (*dupref) < FIRST_PSEUDO_REGISTER)
130 continue;
131
132 ref = type == OP_IN ? use_link : def_link;
133 entry = type == OP_IN ? use_entry : def_entry;
134 for (; *ref; ref++)
e7180acb 135 {
d6545f29
MS
136 rtx *l = DF_REF_LOC (*ref);
137 if (l == recog_data.operand_loc[op])
e7180acb 138 break;
d6545f29 139 if (l && DF_REF_REAL_LOC (*ref) == recog_data.operand_loc[op])
e7180acb
MS
140 break;
141 }
4143fd36 142
7bd8fc3b
JR
143 if (!*ref && type == OP_INOUT)
144 {
145 for (ref = use_link, entry = use_entry; *ref; ref++)
e7180acb 146 {
d6545f29
MS
147 rtx *l = DF_REF_LOC (*ref);
148 if (l == recog_data.operand_loc[op])
e7180acb 149 break;
d6545f29 150 if (l && DF_REF_REAL_LOC (*ref) == recog_data.operand_loc[op])
e7180acb
MS
151 break;
152 }
7bd8fc3b
JR
153 }
154
155 gcc_assert (*ref);
156 (*fun) (dup_entry + DF_REF_ID (*dupref), entry + DF_REF_ID (*ref));
4143fd36
BS
157 }
158}
159
2426d8dd 160/* For each use, all possible defs reaching it must come in the same
8cd37d0b 161 register, union them.
994ae26c
AO
162 FUN is the function that does the union.
163
164 In USED, we keep the DF_REF_ID of the first uninitialized uses of a
165 register, so that all uninitialized uses of the register can be
166 combined into a single web. We actually offset it by 2, because
167 the values 0 and 1 are reserved for use by entry_register. */
62551c66 168
8cd37d0b 169void
57512f53 170union_defs (df_ref use, struct web_entry *def_entry,
994ae26c 171 unsigned int *used, struct web_entry *use_entry,
8cd37d0b 172 bool (*fun) (struct web_entry *, struct web_entry *))
62551c66 173{
50e94c7e 174 struct df_insn_info *insn_info = DF_REF_INSN_INFO (use);
62551c66 175 struct df_link *link = DF_REF_CHAIN (use);
57512f53
KZ
176 df_ref *eq_use_link;
177 df_ref *def_link;
8cd37d0b
RL
178 rtx set;
179
50e94c7e 180 if (insn_info)
8cd37d0b 181 {
50e94c7e 182 rtx insn = insn_info->insn;
50e94c7e
SB
183 eq_use_link = DF_INSN_INFO_EQ_USES (insn_info);
184 def_link = DF_INSN_INFO_DEFS (insn_info);
8cd37d0b
RL
185 set = single_set (insn);
186 }
187 else
188 {
50e94c7e 189 /* An artificial use. It links up with nothing. */
6fb5fa3c 190 eq_use_link = NULL;
8cd37d0b
RL
191 def_link = NULL;
192 set = NULL;
193 }
62551c66 194
4143fd36 195 /* Union all occurrences of the same register in reg notes. */
6fb5fa3c
DB
196
197 if (eq_use_link)
198 while (*eq_use_link)
199 {
200 if (use != *eq_use_link
201 && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (*eq_use_link))
202 (*fun) (use_entry + DF_REF_ID (use),
203 use_entry + DF_REF_ID (*eq_use_link));
204 eq_use_link++;
62551c66
JH
205 }
206
4a8cae83 207 /* Recognize trivial noop moves and attempt to keep them as noop. */
62551c66
JH
208
209 if (set
210 && SET_SRC (set) == DF_REF_REG (use)
211 && SET_SRC (set) == SET_DEST (set))
212 {
6fb5fa3c
DB
213 if (def_link)
214 while (*def_link)
215 {
216 if (DF_REF_REAL_REG (use) == DF_REF_REAL_REG (*def_link))
217 (*fun) (use_entry + DF_REF_ID (use),
218 def_entry + DF_REF_ID (*def_link));
219 def_link++;
220 }
62551c66 221 }
994ae26c
AO
222
223 /* UD chains of uninitialized REGs are empty. Keeping all uses of
224 the same uninitialized REG in a single web is not necessary for
225 correctness, since the uses are undefined, but it's wasteful to
226 allocate one register or slot for each reference. Furthermore,
227 creating new pseudos for uninitialized references in debug insns
228 (see PR 42631) causes -fcompare-debug failures. We record the
229 number of the first uninitialized reference we found, and merge
230 with it any other uninitialized references to the same
231 register. */
232 if (!link)
233 {
234 int regno = REGNO (DF_REF_REAL_REG (use));
235 if (used[regno])
236 (*fun) (use_entry + DF_REF_ID (use), use_entry + used[regno] - 2);
237 else
238 used[regno] = DF_REF_ID (use) + 2;
239 }
240
62551c66
JH
241 while (link)
242 {
8cd37d0b
RL
243 (*fun) (use_entry + DF_REF_ID (use),
244 def_entry + DF_REF_ID (link->ref));
62551c66
JH
245 link = link->next;
246 }
247
2426d8dd 248 /* A READ_WRITE use requires the corresponding def to be in the same
62551c66 249 register. Find it and union. */
57512f53 250 if (DF_REF_FLAGS (use) & DF_REF_READ_WRITE)
62551c66 251 {
57512f53 252 df_ref *link;
8cd37d0b 253
50e94c7e
SB
254 if (insn_info)
255 link = DF_INSN_INFO_DEFS (insn_info);
8cd37d0b
RL
256 else
257 link = NULL;
62551c66 258
6fb5fa3c
DB
259 if (link)
260 while (*link)
261 {
262 if (DF_REF_REAL_REG (*link) == DF_REF_REAL_REG (use))
263 (*fun) (use_entry + DF_REF_ID (use),
264 def_entry + DF_REF_ID (*link));
265 link++;
266 }
62551c66
JH
267 }
268}
269
2426d8dd 270/* Find the corresponding register for the given entry. */
62551c66
JH
271
272static rtx
994ae26c 273entry_register (struct web_entry *entry, df_ref ref, unsigned int *used)
62551c66
JH
274{
275 struct web_entry *root;
276 rtx reg, newreg;
277
2426d8dd 278 /* Find the corresponding web and see if it has been visited. */
62551c66
JH
279 root = unionfind_root (entry);
280 if (root->reg)
281 return root->reg;
282
2426d8dd 283 /* We are seeing this web for the first time, do the assignment. */
62551c66
JH
284 reg = DF_REF_REAL_REG (ref);
285
994ae26c
AO
286 /* In case the original register is already assigned, generate new
287 one. Since we use USED to merge uninitialized refs into a single
288 web, we might found an element to be nonzero without our having
289 used it. Test for 1, because union_defs saves it for our use,
290 and there won't be any use for the other values when we get to
291 this point. */
292 if (used[REGNO (reg)] != 1)
06c969bd 293 newreg = reg, used[REGNO (reg)] = 1;
62551c66
JH
294 else
295 {
296 newreg = gen_reg_rtx (GET_MODE (reg));
297 REG_USERVAR_P (newreg) = REG_USERVAR_P (reg);
298 REG_POINTER (newreg) = REG_POINTER (reg);
62551c66 299 REG_ATTRS (newreg) = REG_ATTRS (reg);
c263766c
RH
300 if (dump_file)
301 fprintf (dump_file, "Web oldreg=%i newreg=%i\n", REGNO (reg),
62551c66
JH
302 REGNO (newreg));
303 }
304
305 root->reg = newreg;
306 return newreg;
307}
308
309/* Replace the reference by REG. */
310
311static void
57512f53 312replace_ref (df_ref ref, rtx reg)
62551c66
JH
313{
314 rtx oldreg = DF_REF_REAL_REG (ref);
315 rtx *loc = DF_REF_REAL_LOC (ref);
57512f53 316 unsigned int uid = DF_REF_INSN_UID (ref);
62551c66
JH
317
318 if (oldreg == reg)
319 return;
c263766c
RH
320 if (dump_file)
321 fprintf (dump_file, "Updating insn %i (%i->%i)\n",
b8698a0f 322 uid, REGNO (oldreg), REGNO (reg));
62551c66 323 *loc = reg;
6fb5fa3c
DB
324 df_insn_rescan (DF_REF_INSN (ref));
325}
326
327\f
328static bool
329gate_handle_web (void)
330{
331 return (optimize > 0 && flag_web);
62551c66
JH
332}
333
62551c66
JH
334/* Main entry point. */
335
6fb5fa3c 336static unsigned int
9373164a 337web_main (void)
62551c66 338{
62551c66
JH
339 struct web_entry *def_entry;
340 struct web_entry *use_entry;
6fb5fa3c 341 unsigned int max = max_reg_num ();
994ae26c 342 unsigned int *used;
6fb5fa3c
DB
343 basic_block bb;
344 unsigned int uses_num = 0;
345 rtx insn;
346
347 df_set_flags (DF_NO_HARD_REGS + DF_EQ_NOTES);
8c266ffa 348 df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
6fb5fa3c
DB
349 df_chain_add_problem (DF_UD_CHAIN);
350 df_analyze ();
351 df_set_flags (DF_DEFER_INSN_RESCAN);
352
353 /* Assign ids to the uses. */
04a90bec 354 FOR_ALL_BB_FN (bb, cfun)
6fb5fa3c
DB
355 FOR_BB_INSNS (bb, insn)
356 {
357 unsigned int uid = INSN_UID (insn);
0d9b0371 358 if (NONDEBUG_INSN_P (insn))
6fb5fa3c 359 {
57512f53 360 df_ref *use_rec;
6fb5fa3c
DB
361 for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
362 {
57512f53 363 df_ref use = *use_rec;
6fb5fa3c
DB
364 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
365 DF_REF_ID (use) = uses_num++;
366 }
367 for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
368 {
57512f53 369 df_ref use = *use_rec;
6fb5fa3c
DB
370 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
371 DF_REF_ID (use) = uses_num++;
372 }
373 }
374 }
62551c66 375
6fb5fa3c 376 /* Record the number of uses and defs at the beginning of the optimization. */
c3284718 377 def_entry = XCNEWVEC (struct web_entry, DF_DEFS_TABLE_SIZE ());
994ae26c 378 used = XCNEWVEC (unsigned, max);
6fb5fa3c 379 use_entry = XCNEWVEC (struct web_entry, uses_num);
62551c66
JH
380
381 /* Produce the web. */
04a90bec 382 FOR_ALL_BB_FN (bb, cfun)
6fb5fa3c
DB
383 FOR_BB_INSNS (bb, insn)
384 {
385 unsigned int uid = INSN_UID (insn);
0d9b0371 386 if (NONDEBUG_INSN_P (insn))
6fb5fa3c 387 {
57512f53 388 df_ref *use_rec;
4143fd36 389 union_match_dups (insn, def_entry, use_entry, unionfind_union);
6fb5fa3c
DB
390 for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
391 {
57512f53 392 df_ref use = *use_rec;
6fb5fa3c 393 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
994ae26c 394 union_defs (use, def_entry, used, use_entry, unionfind_union);
6fb5fa3c
DB
395 }
396 for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
397 {
57512f53 398 df_ref use = *use_rec;
6fb5fa3c 399 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
994ae26c 400 union_defs (use, def_entry, used, use_entry, unionfind_union);
6fb5fa3c
DB
401 }
402 }
403 }
62551c66 404
62551c66
JH
405 /* Update the instruction stream, allocating new registers for split pseudos
406 in progress. */
04a90bec 407 FOR_ALL_BB_FN (bb, cfun)
6fb5fa3c
DB
408 FOR_BB_INSNS (bb, insn)
409 {
410 unsigned int uid = INSN_UID (insn);
b152a615
JZ
411
412 if (NONDEBUG_INSN_P (insn)
413 /* Ignore naked clobber. For example, reg 134 in the second insn
414 of the following sequence will not be replaced.
415
416 (insn (clobber (reg:SI 134)))
417
418 (insn (set (reg:SI 0 r0) (reg:SI 134)))
419
420 Thus the later passes can optimize them away. */
421 && GET_CODE (PATTERN (insn)) != CLOBBER)
6fb5fa3c 422 {
57512f53
KZ
423 df_ref *use_rec;
424 df_ref *def_rec;
6fb5fa3c
DB
425 for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
426 {
57512f53 427 df_ref use = *use_rec;
6fb5fa3c
DB
428 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
429 replace_ref (use, entry_register (use_entry + DF_REF_ID (use), use, used));
430 }
431 for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
432 {
57512f53 433 df_ref use = *use_rec;
6fb5fa3c
DB
434 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
435 replace_ref (use, entry_register (use_entry + DF_REF_ID (use), use, used));
436 }
437 for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
438 {
57512f53 439 df_ref def = *def_rec;
6fb5fa3c
DB
440 if (DF_REF_REGNO (def) >= FIRST_PSEUDO_REGISTER)
441 replace_ref (def, entry_register (def_entry + DF_REF_ID (def), def, used));
442 }
443 }
444 }
445
62551c66
JH
446 free (def_entry);
447 free (use_entry);
448 free (used);
c2924966 449 return 0;
ef330312 450}
6fb5fa3c 451\f
27a4cd48
DM
452namespace {
453
454const pass_data pass_data_web =
ef330312 455{
27a4cd48
DM
456 RTL_PASS, /* type */
457 "web", /* name */
458 OPTGROUP_NONE, /* optinfo_flags */
459 true, /* has_gate */
460 true, /* has_execute */
461 TV_WEB, /* tv_id */
462 0, /* properties_required */
463 0, /* properties_provided */
464 0, /* properties_destroyed */
465 0, /* todo_flags_start */
466 ( TODO_df_finish | TODO_verify_rtl_sharing ), /* todo_flags_finish */
ef330312 467};
27a4cd48
DM
468
469class pass_web : public rtl_opt_pass
470{
471public:
c3284718
RS
472 pass_web (gcc::context *ctxt)
473 : rtl_opt_pass (pass_data_web, ctxt)
27a4cd48
DM
474 {}
475
476 /* opt_pass methods: */
477 bool gate () { return gate_handle_web (); }
478 unsigned int execute () { return web_main (); }
479
480}; // class pass_web
481
482} // anon namespace
483
484rtl_opt_pass *
485make_pass_web (gcc::context *ctxt)
486{
487 return new pass_web (ctxt);
488}
This page took 5.6687 seconds and 5 git commands to generate.