]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/web.c
Update copyright years.
[thirdparty/gcc.git] / gcc / web.c
CommitLineData
eeb4a70e 1/* Web construction code for GNU compiler.
8b5b1013 2 Contributed by Jan Hubicka.
fbd26352 3 Copyright (C) 2001-2019 Free Software Foundation, Inc.
eeb4a70e 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
8c4c00c1 9Software Foundation; either version 3, or (at your option) any later
eeb4a70e 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
8c4c00c1 18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
eeb4a70e 20
8b5b1013 21/* Simple optimization pass that splits independent uses of each pseudo,
40e55fbb 22 increasing effectiveness of other optimizations. The optimization can
8b5b1013 23 serve as an example of use for the dataflow module.
eeb4a70e 24
eeb4a70e 25 TODO
8b5b1013 26 - We may use profile information and ignore infrequent use for the
27 purpose of web unifying, inserting the compensation code later to
28 implement full induction variable expansion for loops (currently
29 we expand only if the induction variable is dead afterward, which
30 is often the case). */
eeb4a70e 31
32#include "config.h"
33#include "system.h"
34#include "coretypes.h"
9ef16211 35#include "backend.h"
36#include "rtl.h"
37#include "df.h"
7c29e30e 38#include "insn-config.h"
39#include "recog.h"
eeb4a70e 40
77fce4cd 41#include "tree-pass.h"
eeb4a70e 42
43
8b5b1013 44/* Find the root of unionfind tree (the representative of set). */
eeb4a70e 45
370ad268 46web_entry_base *
47web_entry_base::unionfind_root ()
eeb4a70e 48{
370ad268 49 web_entry_base *element = this, *element1 = this, *element2;
eeb4a70e 50
370ad268 51 while (element->pred ())
52 element = element->pred ();
53 while (element1->pred ())
eeb4a70e 54 {
370ad268 55 element2 = element1->pred ();
56 element1->set_pred (element);
eeb4a70e 57 element1 = element2;
58 }
59 return element;
60}
61
48e1416a 62/* Union sets.
2b74c150 63 Return true if FIRST and SECOND points to the same web entry structure and
64 nothing is done. Otherwise, return false. */
eeb4a70e 65
2b74c150 66bool
370ad268 67unionfind_union (web_entry_base *first, web_entry_base *second)
eeb4a70e 68{
370ad268 69 first = first->unionfind_root ();
70 second = second->unionfind_root ();
eeb4a70e 71 if (first == second)
2b74c150 72 return true;
370ad268 73 second->set_pred (first);
2b74c150 74 return false;
eeb4a70e 75}
76
370ad268 77class web_entry : public web_entry_base
78{
79 private:
80 rtx reg_pvt;
81
82 public:
83 rtx reg () { return reg_pvt; }
84 void set_reg (rtx r) { reg_pvt = r; }
85};
86
9a3f5556 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
45630655 91union_match_dups (rtx_insn *insn, web_entry *def_entry, web_entry *use_entry,
370ad268 92 bool (*fun) (web_entry_base *, web_entry_base *))
9a3f5556 93{
94 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
ddc2d0e3 95 df_ref use_link = DF_INSN_INFO_USES (insn_info);
96 df_ref def_link = DF_INSN_INFO_DEFS (insn_info);
4241a7eb 97 struct web_entry *dup_entry;
9a3f5556 98 int i;
99
100 extract_insn (insn);
101
102 for (i = 0; i < recog_data.n_dups; i++)
103 {
104 int op = recog_data.dup_num[i];
105 enum op_type type = recog_data.operand_type[op];
ddc2d0e3 106 df_ref ref, dupref;
9a3f5556 107 struct web_entry *entry;
108
ddc2d0e3 109 dup_entry = use_entry;
110 for (dupref = use_link; dupref; dupref = DF_REF_NEXT_LOC (dupref))
111 if (DF_REF_LOC (dupref) == recog_data.dup_loc[i])
9a3f5556 112 break;
113
ddc2d0e3 114 if (dupref == NULL && type == OP_INOUT)
4241a7eb 115 {
ddc2d0e3 116 dup_entry = def_entry;
117 for (dupref = def_link; dupref; dupref = DF_REF_NEXT_LOC (dupref))
118 if (DF_REF_LOC (dupref) == recog_data.dup_loc[i])
4241a7eb 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 */
ddc2d0e3 128 if (dupref == NULL
129 || DF_REF_REGNO (dupref) < FIRST_PSEUDO_REGISTER)
9a3f5556 130 continue;
131
132 ref = type == OP_IN ? use_link : def_link;
133 entry = type == OP_IN ? use_entry : def_entry;
ddc2d0e3 134 for (; ref; ref = DF_REF_NEXT_LOC (ref))
14d27f18 135 {
ddc2d0e3 136 rtx *l = DF_REF_LOC (ref);
639d27bb 137 if (l == recog_data.operand_loc[op])
14d27f18 138 break;
ddc2d0e3 139 if (l && DF_REF_REAL_LOC (ref) == recog_data.operand_loc[op])
14d27f18 140 break;
141 }
9a3f5556 142
ddc2d0e3 143 if (!ref && type == OP_INOUT)
4241a7eb 144 {
ddc2d0e3 145 entry = use_entry;
146 for (ref = use_link; ref; ref = DF_REF_NEXT_LOC (ref))
14d27f18 147 {
ddc2d0e3 148 rtx *l = DF_REF_LOC (ref);
639d27bb 149 if (l == recog_data.operand_loc[op])
14d27f18 150 break;
ddc2d0e3 151 if (l && DF_REF_REAL_LOC (ref) == recog_data.operand_loc[op])
14d27f18 152 break;
153 }
4241a7eb 154 }
155
ddc2d0e3 156 gcc_assert (ref);
157 (*fun) (dup_entry + DF_REF_ID (dupref), entry + DF_REF_ID (ref));
9a3f5556 158 }
159}
160
8b5b1013 161/* For each use, all possible defs reaching it must come in the same
2b74c150 162 register, union them.
388bf4a2 163 FUN is the function that does the union.
164
165 In USED, we keep the DF_REF_ID of the first uninitialized uses of a
166 register, so that all uninitialized uses of the register can be
167 combined into a single web. We actually offset it by 2, because
168 the values 0 and 1 are reserved for use by entry_register. */
eeb4a70e 169
2b74c150 170void
370ad268 171union_defs (df_ref use, web_entry *def_entry,
172 unsigned int *used, web_entry *use_entry,
173 bool (*fun) (web_entry_base *, web_entry_base *))
eeb4a70e 174{
158b6cc9 175 struct df_insn_info *insn_info = DF_REF_INSN_INFO (use);
eeb4a70e 176 struct df_link *link = DF_REF_CHAIN (use);
2b74c150 177 rtx set;
178
158b6cc9 179 if (insn_info)
2b74c150 180 {
be10bb5a 181 df_ref eq_use;
182
183 set = single_set (insn_info->insn);
184 FOR_EACH_INSN_INFO_EQ_USE (eq_use, insn_info)
185 if (use != eq_use
186 && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (eq_use))
187 (*fun) (use_entry + DF_REF_ID (use), use_entry + DF_REF_ID (eq_use));
2b74c150 188 }
189 else
be10bb5a 190 set = NULL;
eeb4a70e 191
9a3f5556 192 /* Union all occurrences of the same register in reg notes. */
3072d30e 193
1e5b92fa 194 /* Recognize trivial noop moves and attempt to keep them as noop. */
eeb4a70e 195
196 if (set
197 && SET_SRC (set) == DF_REF_REG (use)
198 && SET_SRC (set) == SET_DEST (set))
199 {
be10bb5a 200 df_ref def;
201
202 FOR_EACH_INSN_INFO_DEF (def, insn_info)
203 if (DF_REF_REAL_REG (use) == DF_REF_REAL_REG (def))
204 (*fun) (use_entry + DF_REF_ID (use), def_entry + DF_REF_ID (def));
eeb4a70e 205 }
388bf4a2 206
207 /* UD chains of uninitialized REGs are empty. Keeping all uses of
208 the same uninitialized REG in a single web is not necessary for
209 correctness, since the uses are undefined, but it's wasteful to
210 allocate one register or slot for each reference. Furthermore,
211 creating new pseudos for uninitialized references in debug insns
212 (see PR 42631) causes -fcompare-debug failures. We record the
213 number of the first uninitialized reference we found, and merge
214 with it any other uninitialized references to the same
215 register. */
216 if (!link)
217 {
218 int regno = REGNO (DF_REF_REAL_REG (use));
219 if (used[regno])
220 (*fun) (use_entry + DF_REF_ID (use), use_entry + used[regno] - 2);
221 else
222 used[regno] = DF_REF_ID (use) + 2;
223 }
224
eeb4a70e 225 while (link)
226 {
2b74c150 227 (*fun) (use_entry + DF_REF_ID (use),
228 def_entry + DF_REF_ID (link->ref));
eeb4a70e 229 link = link->next;
230 }
231
8b5b1013 232 /* A READ_WRITE use requires the corresponding def to be in the same
eeb4a70e 233 register. Find it and union. */
ed6e85ae 234 if (DF_REF_FLAGS (use) & DF_REF_READ_WRITE)
be10bb5a 235 if (insn_info)
236 {
237 df_ref def;
2b74c150 238
be10bb5a 239 FOR_EACH_INSN_INFO_DEF (def, insn_info)
240 if (DF_REF_REAL_REG (use) == DF_REF_REAL_REG (def))
241 (*fun) (use_entry + DF_REF_ID (use), def_entry + DF_REF_ID (def));
242 }
eeb4a70e 243}
244
8b5b1013 245/* Find the corresponding register for the given entry. */
eeb4a70e 246
247static rtx
370ad268 248entry_register (web_entry *entry, df_ref ref, unsigned int *used)
eeb4a70e 249{
370ad268 250 web_entry *root;
eeb4a70e 251 rtx reg, newreg;
252
8b5b1013 253 /* Find the corresponding web and see if it has been visited. */
370ad268 254 root = (web_entry *)entry->unionfind_root ();
255 if (root->reg ())
256 return root->reg ();
eeb4a70e 257
8b5b1013 258 /* We are seeing this web for the first time, do the assignment. */
eeb4a70e 259 reg = DF_REF_REAL_REG (ref);
260
388bf4a2 261 /* In case the original register is already assigned, generate new
262 one. Since we use USED to merge uninitialized refs into a single
263 web, we might found an element to be nonzero without our having
264 used it. Test for 1, because union_defs saves it for our use,
265 and there won't be any use for the other values when we get to
266 this point. */
267 if (used[REGNO (reg)] != 1)
de963f40 268 newreg = reg, used[REGNO (reg)] = 1;
eeb4a70e 269 else
270 {
271 newreg = gen_reg_rtx (GET_MODE (reg));
272 REG_USERVAR_P (newreg) = REG_USERVAR_P (reg);
273 REG_POINTER (newreg) = REG_POINTER (reg);
eeb4a70e 274 REG_ATTRS (newreg) = REG_ATTRS (reg);
450d042a 275 if (dump_file)
276 fprintf (dump_file, "Web oldreg=%i newreg=%i\n", REGNO (reg),
eeb4a70e 277 REGNO (newreg));
278 }
279
370ad268 280 root->set_reg (newreg);
eeb4a70e 281 return newreg;
282}
283
284/* Replace the reference by REG. */
285
286static void
ed6e85ae 287replace_ref (df_ref ref, rtx reg)
eeb4a70e 288{
289 rtx oldreg = DF_REF_REAL_REG (ref);
290 rtx *loc = DF_REF_REAL_LOC (ref);
ed6e85ae 291 unsigned int uid = DF_REF_INSN_UID (ref);
eeb4a70e 292
293 if (oldreg == reg)
294 return;
450d042a 295 if (dump_file)
296 fprintf (dump_file, "Updating insn %i (%i->%i)\n",
48e1416a 297 uid, REGNO (oldreg), REGNO (reg));
eeb4a70e 298 *loc = reg;
3072d30e 299 df_insn_rescan (DF_REF_INSN (ref));
300}
301
302\f
7620bc82 303namespace {
304
305const pass_data pass_data_web =
65b0537f 306{
307 RTL_PASS, /* type */
308 "web", /* name */
309 OPTGROUP_NONE, /* optinfo_flags */
65b0537f 310 TV_WEB, /* tv_id */
311 0, /* properties_required */
312 0, /* properties_provided */
313 0, /* properties_destroyed */
314 0, /* todo_flags_start */
8b88439e 315 TODO_df_finish, /* todo_flags_finish */
65b0537f 316};
317
7620bc82 318class pass_web : public rtl_opt_pass
65b0537f 319{
320public:
321 pass_web (gcc::context *ctxt)
322 : rtl_opt_pass (pass_data_web, ctxt)
323 {}
324
325 /* opt_pass methods: */
326 virtual bool gate (function *) { return (optimize > 0 && flag_web); }
327 virtual unsigned int execute (function *);
eeb4a70e 328
65b0537f 329}; // class pass_web
330
331unsigned int
332pass_web::execute (function *fun)
eeb4a70e 333{
370ad268 334 web_entry *def_entry;
335 web_entry *use_entry;
3072d30e 336 unsigned int max = max_reg_num ();
388bf4a2 337 unsigned int *used;
3072d30e 338 basic_block bb;
339 unsigned int uses_num = 0;
45630655 340 rtx_insn *insn;
3072d30e 341
342 df_set_flags (DF_NO_HARD_REGS + DF_EQ_NOTES);
b250e9bb 343 df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
3072d30e 344 df_chain_add_problem (DF_UD_CHAIN);
345 df_analyze ();
346 df_set_flags (DF_DEFER_INSN_RESCAN);
347
348 /* Assign ids to the uses. */
65b0537f 349 FOR_ALL_BB_FN (bb, fun)
3072d30e 350 FOR_BB_INSNS (bb, insn)
351 {
41ceca3d 352 if (NONDEBUG_INSN_P (insn))
3072d30e 353 {
be10bb5a 354 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
355 df_ref use;
356 FOR_EACH_INSN_INFO_USE (use, insn_info)
357 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
358 DF_REF_ID (use) = uses_num++;
359 FOR_EACH_INSN_INFO_EQ_USE (use, insn_info)
360 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
361 DF_REF_ID (use) = uses_num++;
3072d30e 362 }
363 }
eeb4a70e 364
3072d30e 365 /* Record the number of uses and defs at the beginning of the optimization. */
370ad268 366 def_entry = XCNEWVEC (web_entry, DF_DEFS_TABLE_SIZE ());
388bf4a2 367 used = XCNEWVEC (unsigned, max);
370ad268 368 use_entry = XCNEWVEC (web_entry, uses_num);
eeb4a70e 369
370 /* Produce the web. */
65b0537f 371 FOR_ALL_BB_FN (bb, fun)
3072d30e 372 FOR_BB_INSNS (bb, insn)
41ceca3d 373 if (NONDEBUG_INSN_P (insn))
3072d30e 374 {
be10bb5a 375 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
376 df_ref use;
9a3f5556 377 union_match_dups (insn, def_entry, use_entry, unionfind_union);
be10bb5a 378 FOR_EACH_INSN_INFO_USE (use, insn_info)
379 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
380 union_defs (use, def_entry, used, use_entry, unionfind_union);
381 FOR_EACH_INSN_INFO_EQ_USE (use, insn_info)
382 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
383 union_defs (use, def_entry, used, use_entry, unionfind_union);
3072d30e 384 }
eeb4a70e 385
eeb4a70e 386 /* Update the instruction stream, allocating new registers for split pseudos
387 in progress. */
65b0537f 388 FOR_ALL_BB_FN (bb, fun)
3072d30e 389 FOR_BB_INSNS (bb, insn)
90db8e34 390 if (NONDEBUG_INSN_P (insn)
391 /* Ignore naked clobber. For example, reg 134 in the second insn
392 of the following sequence will not be replaced.
393
394 (insn (clobber (reg:SI 134)))
395
396 (insn (set (reg:SI 0 r0) (reg:SI 134)))
397
398 Thus the later passes can optimize them away. */
399 && GET_CODE (PATTERN (insn)) != CLOBBER)
3072d30e 400 {
be10bb5a 401 struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
402 df_ref def, use;
403 FOR_EACH_INSN_INFO_USE (use, insn_info)
404 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
405 replace_ref (use, entry_register (use_entry + DF_REF_ID (use),
406 use, used));
407 FOR_EACH_INSN_INFO_EQ_USE (use, insn_info)
408 if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
409 replace_ref (use, entry_register (use_entry + DF_REF_ID (use),
410 use, used));
411 FOR_EACH_INSN_INFO_DEF (def, insn_info)
412 if (DF_REF_REGNO (def) >= FIRST_PSEUDO_REGISTER)
413 replace_ref (def, entry_register (def_entry + DF_REF_ID (def),
414 def, used));
3072d30e 415 }
3072d30e 416
eeb4a70e 417 free (def_entry);
418 free (use_entry);
419 free (used);
2a1990e9 420 return 0;
77fce4cd 421}
3072d30e 422\f
7620bc82 423} // anon namespace
424
cbe8bda8 425rtl_opt_pass *
426make_pass_web (gcc::context *ctxt)
427{
428 return new pass_web (ctxt);
429}