web.c 13.5 KB
Newer Older
Jan Hubicka committed
1
/* Web construction code for GNU compiler.
2
   Contributed by Jan Hubicka.
3
   Copyright (C) 2001-2013 Free Software Foundation, Inc.
Jan Hubicka committed
4 5 6 7 8

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
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
Jan Hubicka committed
10 11 12 13 14 15 16 17
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
18 19
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
Jan Hubicka committed
20

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.
Jan Hubicka committed
24

25 26 27
   We don't split registers with REG_USERVAR set unless -fmessy-debugging
   is specified, because debugging information about such split variables
   is almost unusable.
Jan Hubicka committed
28 29

   TODO
30 31 32 33 34
    - We may use profile information and ignore infrequent use for the
      purpose of web unifying, inserting the compensation code later to
      implement full induction variable expansion for loops (currently
      we expand only if the induction variable is dead afterward, which
      is often the case).  */
Jan Hubicka committed
35 36 37 38 39

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
40
#include "diagnostic-core.h"
Jan Hubicka committed
41 42 43 44

#include "rtl.h"
#include "hard-reg-set.h"
#include "flags.h"
45
#include "obstack.h"
Jan Hubicka committed
46 47 48
#include "basic-block.h"
#include "df.h"
#include "function.h"
49 50
#include "insn-config.h"
#include "recog.h"
51
#include "tree-pass.h"
Jan Hubicka committed
52 53


54
/* Find the root of unionfind tree (the representative of set).  */
Jan Hubicka committed
55

Razya Ladelsky committed
56
struct web_entry *
R. Kelley Cook committed
57
unionfind_root (struct web_entry *element)
Jan Hubicka committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71
{
  struct web_entry *element1 = element, *element2;

  while (element->pred)
    element = element->pred;
  while (element1->pred)
    {
      element2 = element1->pred;
      element1->pred = element;
      element1 = element2;
    }
  return element;
}

H.J. Lu committed
72
/* Union sets.
Razya Ladelsky committed
73 74
   Return true if FIRST and SECOND points to the same web entry structure and
   nothing is done.  Otherwise, return false.  */
Jan Hubicka committed
75

Razya Ladelsky committed
76
bool
R. Kelley Cook committed
77
unionfind_union (struct web_entry *first, struct web_entry *second)
Jan Hubicka committed
78 79 80 81
{
  first = unionfind_root (first);
  second = unionfind_root (second);
  if (first == second)
Razya Ladelsky committed
82
    return true;
Jan Hubicka committed
83
  second->pred = first;
Razya Ladelsky committed
84
  return false;
Jan Hubicka committed
85 86
}

87 88 89 90 91 92 93 94 95 96 97
/* For INSN, union all defs and uses that are linked by match_dup.
   FUN is the function that does the union.  */

static void
union_match_dups (rtx insn, struct web_entry *def_entry,
		  struct web_entry *use_entry,
		  bool (*fun) (struct web_entry *, struct web_entry *))
{
  struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
  df_ref *use_link = DF_INSN_INFO_USES (insn_info);
  df_ref *def_link = DF_INSN_INFO_DEFS (insn_info);
98
  struct web_entry *dup_entry;
99 100 101 102 103 104 105 106 107 108 109
  int i;

  extract_insn (insn);

  for (i = 0; i < recog_data.n_dups; i++)
    {
      int op = recog_data.dup_num[i];
      enum op_type type = recog_data.operand_type[op];
      df_ref *ref, *dupref;
      struct web_entry *entry;

110
      for (dup_entry = use_entry, dupref = use_link; *dupref; dupref++)
111 112 113
	if (DF_REF_LOC (*dupref) == recog_data.dup_loc[i])
	  break;

114 115 116 117 118 119 120 121 122 123 124 125 126 127
      if (*dupref == NULL && type == OP_INOUT)
	{

	  for (dup_entry = def_entry, dupref = def_link; *dupref; dupref++)
	    if (DF_REF_LOC (*dupref) == recog_data.dup_loc[i])
	      break;
	}
      /* ??? *DUPREF can still be zero, because when an operand matches
	 a memory, DF_REF_LOC (use_link[n]) points to the register part
	 of the address, whereas recog_data.dup_loc[m] points to the
	 entire memory ref, thus we fail to find the duplicate entry,
         even though it is there.
         Example: i686-pc-linux-gnu gcc.c-torture/compile/950607-1.c
		  -O3 -fomit-frame-pointer -funroll-loops  */
128 129 130 131 132 133 134
      if (*dupref == NULL
	  || DF_REF_REGNO (*dupref) < FIRST_PSEUDO_REGISTER)
	continue;

      ref = type == OP_IN ? use_link : def_link;
      entry = type == OP_IN ? use_entry : def_entry;
      for (; *ref; ref++)
135
	{
136 137
	  rtx *l = DF_REF_LOC (*ref);
	  if (l == recog_data.operand_loc[op])
138
	    break;
139
	  if (l && DF_REF_REAL_LOC (*ref) == recog_data.operand_loc[op])
140 141
	    break;
	}
142

143 144 145
      if (!*ref && type == OP_INOUT)
	{
	  for (ref = use_link, entry = use_entry; *ref; ref++)
146
	    {
147 148
	      rtx *l = DF_REF_LOC (*ref);
	      if (l == recog_data.operand_loc[op])
149
		break;
150
	      if (l && DF_REF_REAL_LOC (*ref) == recog_data.operand_loc[op])
151 152
		break;
	    }
153 154 155 156
	}

      gcc_assert (*ref);
      (*fun) (dup_entry + DF_REF_ID (*dupref), entry + DF_REF_ID (*ref));
157 158 159
    }
}

160
/* For each use, all possible defs reaching it must come in the same
Razya Ladelsky committed
161
   register, union them.
162 163 164 165 166 167
   FUN is the function that does the union.

   In USED, we keep the DF_REF_ID of the first uninitialized uses of a
   register, so that all uninitialized uses of the register can be
   combined into a single web.  We actually offset it by 2, because
   the values 0 and 1 are reserved for use by entry_register.  */
Jan Hubicka committed
168

Razya Ladelsky committed
169
void
170
union_defs (df_ref use, struct web_entry *def_entry,
171
	    unsigned int *used, struct web_entry *use_entry,
Razya Ladelsky committed
172
 	    bool (*fun) (struct web_entry *, struct web_entry *))
Jan Hubicka committed
173
{
174
  struct df_insn_info *insn_info = DF_REF_INSN_INFO (use);
Jan Hubicka committed
175
  struct df_link *link = DF_REF_CHAIN (use);
176 177
  df_ref *eq_use_link;
  df_ref *def_link;
Razya Ladelsky committed
178 179
  rtx set;

180
  if (insn_info)
Razya Ladelsky committed
181
    {
182 183 184
      rtx insn = insn_info->insn;
      eq_use_link = DF_INSN_INFO_EQ_USES (insn_info);
      def_link = DF_INSN_INFO_DEFS (insn_info);
Razya Ladelsky committed
185 186 187 188
      set = single_set (insn);
    }
  else
    {
189
      /* An artificial use.  It links up with nothing.  */
190
      eq_use_link = NULL;
Razya Ladelsky committed
191 192 193
      def_link = NULL;
      set = NULL;
    }
Jan Hubicka committed
194

195
  /* Union all occurrences of the same register in reg notes.  */
196 197 198 199 200 201 202 203 204

  if (eq_use_link)
    while (*eq_use_link)
      {
	if (use != *eq_use_link
	    && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (*eq_use_link))
	  (*fun) (use_entry + DF_REF_ID (use),
		  use_entry + DF_REF_ID (*eq_use_link));
	eq_use_link++;
Jan Hubicka committed
205 206
    }

Steven Bosscher committed
207
  /* Recognize trivial noop moves and attempt to keep them as noop.  */
Jan Hubicka committed
208 209 210 211 212

  if (set
      && SET_SRC (set) == DF_REF_REG (use)
      && SET_SRC (set) == SET_DEST (set))
    {
213 214 215 216 217 218 219 220
      if (def_link)
	while (*def_link)
	  {
	    if (DF_REF_REAL_REG (use) == DF_REF_REAL_REG (*def_link))
	      (*fun) (use_entry + DF_REF_ID (use),
		      def_entry + DF_REF_ID (*def_link));
	    def_link++;
	  }
Jan Hubicka committed
221
    }
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240

  /* UD chains of uninitialized REGs are empty.  Keeping all uses of
     the same uninitialized REG in a single web is not necessary for
     correctness, since the uses are undefined, but it's wasteful to
     allocate one register or slot for each reference.  Furthermore,
     creating new pseudos for uninitialized references in debug insns
     (see PR 42631) causes -fcompare-debug failures.  We record the
     number of the first uninitialized reference we found, and merge
     with it any other uninitialized references to the same
     register.  */
  if (!link)
    {
      int regno = REGNO (DF_REF_REAL_REG (use));
      if (used[regno])
	(*fun) (use_entry + DF_REF_ID (use), use_entry + used[regno] - 2);
      else
	used[regno] = DF_REF_ID (use) + 2;
    }

Jan Hubicka committed
241 242
  while (link)
    {
Razya Ladelsky committed
243 244
      (*fun) (use_entry + DF_REF_ID (use),
	      def_entry + DF_REF_ID (link->ref));
Jan Hubicka committed
245 246 247
      link = link->next;
    }

248
  /* A READ_WRITE use requires the corresponding def to be in the same
Jan Hubicka committed
249
     register.  Find it and union.  */
250
  if (DF_REF_FLAGS (use) & DF_REF_READ_WRITE)
Jan Hubicka committed
251
    {
252
      df_ref *link;
Razya Ladelsky committed
253

254 255
      if (insn_info)
	link = DF_INSN_INFO_DEFS (insn_info);
Razya Ladelsky committed
256 257
      else
	link = NULL;
Jan Hubicka committed
258

259 260 261 262 263 264 265 266
      if (link)
	while (*link)
	  {
	    if (DF_REF_REAL_REG (*link) == DF_REF_REAL_REG (use))
	      (*fun) (use_entry + DF_REF_ID (use),
		      def_entry + DF_REF_ID (*link));
	    link++;
	  }
Jan Hubicka committed
267 268 269
    }
}

270
/* Find the corresponding register for the given entry.  */
Jan Hubicka committed
271 272

static rtx
273
entry_register (struct web_entry *entry, df_ref ref, unsigned int *used)
Jan Hubicka committed
274 275 276 277
{
  struct web_entry *root;
  rtx reg, newreg;

278
  /* Find the corresponding web and see if it has been visited.  */
Jan Hubicka committed
279 280 281 282
  root = unionfind_root (entry);
  if (root->reg)
    return root->reg;

283
  /* We are seeing this web for the first time, do the assignment.  */
Jan Hubicka committed
284 285
  reg = DF_REF_REAL_REG (ref);

286 287 288 289 290 291 292
  /* In case the original register is already assigned, generate new
     one.  Since we use USED to merge uninitialized refs into a single
     web, we might found an element to be nonzero without our having
     used it.  Test for 1, because union_defs saves it for our use,
     and there won't be any use for the other values when we get to
     this point.  */
  if (used[REGNO (reg)] != 1)
293
    newreg = reg, used[REGNO (reg)] = 1;
Jan Hubicka committed
294 295 296 297 298 299
  else
    {
      newreg = gen_reg_rtx (GET_MODE (reg));
      REG_USERVAR_P (newreg) = REG_USERVAR_P (reg);
      REG_POINTER (newreg) = REG_POINTER (reg);
      REG_ATTRS (newreg) = REG_ATTRS (reg);
300 301
      if (dump_file)
	fprintf (dump_file, "Web oldreg=%i newreg=%i\n", REGNO (reg),
Jan Hubicka committed
302 303 304 305 306 307 308 309 310 311
		 REGNO (newreg));
    }

  root->reg = newreg;
  return newreg;
}

/* Replace the reference by REG.  */

static void
312
replace_ref (df_ref ref, rtx reg)
Jan Hubicka committed
313 314 315
{
  rtx oldreg = DF_REF_REAL_REG (ref);
  rtx *loc = DF_REF_REAL_LOC (ref);
316
  unsigned int uid = DF_REF_INSN_UID (ref);
Jan Hubicka committed
317 318 319

  if (oldreg == reg)
    return;
320 321
  if (dump_file)
    fprintf (dump_file, "Updating insn %i (%i->%i)\n",
H.J. Lu committed
322
	     uid, REGNO (oldreg), REGNO (reg));
Jan Hubicka committed
323
  *loc = reg;
324 325 326 327 328 329 330 331
  df_insn_rescan (DF_REF_INSN (ref));
}


static bool
gate_handle_web (void)
{
  return (optimize > 0 && flag_web);
Jan Hubicka committed
332 333 334 335
}

/* Main entry point.  */

336
static unsigned int
R. Kelley Cook committed
337
web_main (void)
Jan Hubicka committed
338 339 340
{
  struct web_entry *def_entry;
  struct web_entry *use_entry;
341
  unsigned int max = max_reg_num ();
342
  unsigned int *used;
343 344 345 346 347
  basic_block bb;
  unsigned int uses_num = 0;
  rtx insn;

  df_set_flags (DF_NO_HARD_REGS + DF_EQ_NOTES);
348
  df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
349 350 351 352 353 354 355 356 357
  df_chain_add_problem (DF_UD_CHAIN);
  df_analyze ();
  df_set_flags (DF_DEFER_INSN_RESCAN);

  /* Assign ids to the uses.  */
  FOR_ALL_BB (bb)
    FOR_BB_INSNS (bb, insn)
    {
      unsigned int uid = INSN_UID (insn);
358
      if (NONDEBUG_INSN_P (insn))
359
	{
360
	  df_ref *use_rec;
361 362
	  for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
	    {
363
	      df_ref use = *use_rec;
364 365 366 367 368
	      if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
		DF_REF_ID (use) = uses_num++;
	    }
	  for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
	    {
369
	      df_ref use = *use_rec;
370 371 372 373 374
	      if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
		DF_REF_ID (use) = uses_num++;
	    }
	}
    }
Jan Hubicka committed
375

376
  /* Record the number of uses and defs at the beginning of the optimization.  */
377
  def_entry = XCNEWVEC (struct web_entry, DF_DEFS_TABLE_SIZE ());
378
  used = XCNEWVEC (unsigned, max);
379
  use_entry = XCNEWVEC (struct web_entry, uses_num);
Jan Hubicka committed
380 381

  /* Produce the web.  */
382 383 384 385
  FOR_ALL_BB (bb)
    FOR_BB_INSNS (bb, insn)
    {
      unsigned int uid = INSN_UID (insn);
386
      if (NONDEBUG_INSN_P (insn))
387
	{
388
	  df_ref *use_rec;
389
	  union_match_dups (insn, def_entry, use_entry, unionfind_union);
390 391
	  for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
	    {
392
	      df_ref use = *use_rec;
393
	      if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
394
		union_defs (use, def_entry, used, use_entry, unionfind_union);
395 396 397
	    }
	  for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
	    {
398
	      df_ref use = *use_rec;
399
	      if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
400
		union_defs (use, def_entry, used, use_entry, unionfind_union);
401 402 403
	    }
	}
    }
Jan Hubicka committed
404 405 406

  /* Update the instruction stream, allocating new registers for split pseudos
     in progress.  */
407 408 409 410
  FOR_ALL_BB (bb)
    FOR_BB_INSNS (bb, insn)
    {
      unsigned int uid = INSN_UID (insn);
411 412 413 414 415 416 417 418 419 420 421

      if (NONDEBUG_INSN_P (insn)
	  /* Ignore naked clobber.  For example, reg 134 in the second insn
	     of the following sequence will not be replaced.

	       (insn (clobber (reg:SI 134)))

	       (insn (set (reg:SI 0 r0) (reg:SI 134)))

	     Thus the later passes can optimize them away.  */
	  && GET_CODE (PATTERN (insn)) != CLOBBER)
422
	{
423 424
	  df_ref *use_rec;
	  df_ref *def_rec;
425 426
	  for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
	    {
427
	      df_ref use = *use_rec;
428 429 430 431 432
	      if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
		replace_ref (use, entry_register (use_entry + DF_REF_ID (use), use, used));
	    }
	  for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
	    {
433
	      df_ref use = *use_rec;
434 435 436 437 438
	      if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER)
		replace_ref (use, entry_register (use_entry + DF_REF_ID (use), use, used));
	    }
	  for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
	    {
439
	      df_ref def = *def_rec;
440 441 442 443 444 445
	      if (DF_REF_REGNO (def) >= FIRST_PSEUDO_REGISTER)
		replace_ref (def, entry_register (def_entry + DF_REF_ID (def), def, used));
	    }
	}
    }

Jan Hubicka committed
446 447 448
  free (def_entry);
  free (use_entry);
  free (used);
449
  return 0;
450
}
451

452 453 454
namespace {

const pass_data pass_data_web =
455
{
456 457 458 459 460 461 462 463 464 465 466
  RTL_PASS, /* type */
  "web", /* name */
  OPTGROUP_NONE, /* optinfo_flags */
  true, /* has_gate */
  true, /* has_execute */
  TV_WEB, /* tv_id */
  0, /* properties_required */
  0, /* properties_provided */
  0, /* properties_destroyed */
  0, /* todo_flags_start */
  ( TODO_df_finish | TODO_verify_rtl_sharing ), /* todo_flags_finish */
467
};
468 469 470 471

class pass_web : public rtl_opt_pass
{
public:
472 473
  pass_web (gcc::context *ctxt)
    : rtl_opt_pass (pass_data_web, ctxt)
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
  {}

  /* opt_pass methods: */
  bool gate () { return gate_handle_web (); }
  unsigned int execute () { return web_main (); }

}; // class pass_web

} // anon namespace

rtl_opt_pass *
make_pass_web (gcc::context *ctxt)
{
  return new pass_web (ctxt);
}