OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ree.c
1 /* Redundant Extension Elimination pass for the GNU compiler.
2    Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
3    Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
4
5    Based on the Redundant Zero-extension elimination pass contributed by
6    Sriraman Tallam (tmsriram@google.com) and Silvius Rus (rus@google.com).
7
8 This file is part of GCC.
9
10 GCC is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 3, or (at your option) any later
13 version.
14
15 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GCC; see the file COPYING3.  If not see
22 <http://www.gnu.org/licenses/>.  */
23
24
25 /* Problem Description :
26    --------------------
27    This pass is intended to remove redundant extension instructions.
28    Such instructions appear for different reasons.  We expect some of
29    them due to implicit zero-extension in 64-bit registers after writing
30    to their lower 32-bit half (e.g. for the x86-64 architecture).
31    Another possible reason is a type cast which follows a load (for
32    instance a register restore) and which can be combined into a single
33    instruction, and for which earlier local passes, e.g. the combiner,
34    weren't able to optimize.
35
36    How does this pass work  ?
37    --------------------------
38
39    This pass is run after register allocation.  Hence, all registers that
40    this pass deals with are hard registers.  This pass first looks for an
41    extension instruction that could possibly be redundant.  Such extension
42    instructions show up in RTL with the pattern  :
43    (set (reg:<SWI248> x) (any_extend:<SWI248> (reg:<SWI124> x))),
44    where x can be any hard register.
45    Now, this pass tries to eliminate this instruction by merging the
46    extension with the definitions of register x.  For instance, if
47    one of the definitions of register x was  :
48    (set (reg:SI x) (plus:SI (reg:SI z1) (reg:SI z2))),
49    followed by extension  :
50    (set (reg:DI x) (zero_extend:DI (reg:SI x)))
51    then the combination converts this into :
52    (set (reg:DI x) (zero_extend:DI (plus:SI (reg:SI z1) (reg:SI z2)))).
53    If all the merged definitions are recognizable assembly instructions,
54    the extension is effectively eliminated.
55
56    For example, for the x86-64 architecture, implicit zero-extensions
57    are captured with appropriate patterns in the i386.md file.  Hence,
58    these merged definition can be matched to a single assembly instruction.
59    The original extension instruction is then deleted if all the
60    definitions can be merged.
61
62    However, there are cases where the definition instruction cannot be
63    merged with an extension.  Examples are CALL instructions.  In such
64    cases, the original extension is not redundant and this pass does
65    not delete it.
66
67    Handling conditional moves :
68    ----------------------------
69
70    Architectures like x86-64 support conditional moves whose semantics for
71    extension differ from the other instructions.  For instance, the
72    instruction *cmov ebx, eax*
73    zero-extends eax onto rax only when the move from ebx to eax happens.
74    Otherwise, eax may not be zero-extended.  Consider conditional moves as
75    RTL instructions of the form
76    (set (reg:SI x) (if_then_else (cond) (reg:SI y) (reg:SI z))).
77    This pass tries to merge an extension with a conditional move by
78    actually merging the definitions of y and z with an extension and then
79    converting the conditional move into :
80    (set (reg:DI x) (if_then_else (cond) (reg:DI y) (reg:DI z))).
81    Since registers y and z are extended, register x will also be extended
82    after the conditional move.  Note that this step has to be done
83    transitively since the definition of a conditional copy can be
84    another conditional copy.
85
86    Motivating Example I :
87    ---------------------
88    For this program :
89    **********************************************
90    bad_code.c
91
92    int mask[1000];
93
94    int foo(unsigned x)
95    {
96      if (x < 10)
97        x = x * 45;
98      else
99        x = x * 78;
100      return mask[x];
101    }
102    **********************************************
103
104    $ gcc -O2 bad_code.c
105      ........
106      400315:       b8 4e 00 00 00          mov    $0x4e,%eax
107      40031a:       0f af f8                imul   %eax,%edi
108      40031d:       89 ff                   mov    %edi,%edi - useless extension
109      40031f:       8b 04 bd 60 19 40 00    mov    0x401960(,%rdi,4),%eax
110      400326:       c3                      retq
111      ......
112      400330:       ba 2d 00 00 00          mov    $0x2d,%edx
113      400335:       0f af fa                imul   %edx,%edi
114      400338:       89 ff                   mov    %edi,%edi - useless extension
115      40033a:       8b 04 bd 60 19 40 00    mov    0x401960(,%rdi,4),%eax
116      400341:       c3                      retq
117
118    $ gcc -O2 -free bad_code.c
119      ......
120      400315:       6b ff 4e                imul   $0x4e,%edi,%edi
121      400318:       8b 04 bd 40 19 40 00    mov    0x401940(,%rdi,4),%eax
122      40031f:       c3                      retq
123      400320:       6b ff 2d                imul   $0x2d,%edi,%edi
124      400323:       8b 04 bd 40 19 40 00    mov    0x401940(,%rdi,4),%eax
125      40032a:       c3                      retq
126
127    Motivating Example II :
128    ---------------------
129
130    Here is an example with a conditional move.
131
132    For this program :
133    **********************************************
134
135    unsigned long long foo(unsigned x , unsigned y)
136    {
137      unsigned z;
138      if (x > 100)
139        z = x + y;
140      else
141        z = x - y;
142      return (unsigned long long)(z);
143    }
144
145    $ gcc -O2 bad_code.c
146      ............
147      400360:       8d 14 3e                lea    (%rsi,%rdi,1),%edx
148      400363:       89 f8                   mov    %edi,%eax
149      400365:       29 f0                   sub    %esi,%eax
150      400367:       83 ff 65                cmp    $0x65,%edi
151      40036a:       0f 43 c2                cmovae %edx,%eax
152      40036d:       89 c0                   mov    %eax,%eax - useless extension
153      40036f:       c3                      retq
154
155    $ gcc -O2 -free bad_code.c
156      .............
157      400360:       89 fa                   mov    %edi,%edx
158      400362:       8d 04 3e                lea    (%rsi,%rdi,1),%eax
159      400365:       29 f2                   sub    %esi,%edx
160      400367:       83 ff 65                cmp    $0x65,%edi
161      40036a:       89 d6                   mov    %edx,%esi
162      40036c:       48 0f 42 c6             cmovb  %rsi,%rax
163      400370:       c3                      retq
164
165   Motivating Example III :
166   ---------------------
167
168   Here is an example with a type cast.
169
170   For this program :
171   **********************************************
172
173   void test(int size, unsigned char *in, unsigned char *out)
174   {
175     int i;
176     unsigned char xr, xg, xy=0;
177
178     for (i = 0; i < size; i++) {
179       xr = *in++;
180       xg = *in++;
181       xy = (unsigned char) ((19595*xr + 38470*xg) >> 16);
182       *out++ = xy;
183     }
184   }
185
186   $ gcc -O2 bad_code.c
187     ............
188     10:   0f b6 0e                movzbl (%rsi),%ecx
189     13:   0f b6 46 01             movzbl 0x1(%rsi),%eax
190     17:   48 83 c6 02             add    $0x2,%rsi
191     1b:   0f b6 c9                movzbl %cl,%ecx - useless extension
192     1e:   0f b6 c0                movzbl %al,%eax - useless extension
193     21:   69 c9 8b 4c 00 00       imul   $0x4c8b,%ecx,%ecx
194     27:   69 c0 46 96 00 00       imul   $0x9646,%eax,%eax
195
196    $ gcc -O2 -free bad_code.c
197      .............
198     10:   0f b6 0e                movzbl (%rsi),%ecx
199     13:   0f b6 46 01             movzbl 0x1(%rsi),%eax
200     17:   48 83 c6 02             add    $0x2,%rsi
201     1b:   69 c9 8b 4c 00 00       imul   $0x4c8b,%ecx,%ecx
202     21:   69 c0 46 96 00 00       imul   $0x9646,%eax,%eax
203
204    Usefulness :
205    ----------
206
207    The original redundant zero-extension elimination pass reported reduction
208    of the dynamic instruction count of a compression benchmark by 2.8% and
209    improvement of its run time by about 1%.
210
211    The additional performance gain with the enhanced pass is mostly expected
212    on in-order architectures where redundancy cannot be compensated by out of
213    order execution.  Measurements showed up to 10% performance gain (reduced
214    run time) on EEMBC 2.0 benchmarks on Atom processor with geomean performance
215    gain 1%.  */
216
217
218 #include "config.h"
219 #include "system.h"
220 #include "coretypes.h"
221 #include "tm.h"
222 #include "rtl.h"
223 #include "tree.h"
224 #include "tm_p.h"
225 #include "flags.h"
226 #include "regs.h"
227 #include "hard-reg-set.h"
228 #include "basic-block.h"
229 #include "insn-config.h"
230 #include "function.h"
231 #include "expr.h"
232 #include "insn-attr.h"
233 #include "recog.h"
234 #include "diagnostic-core.h"
235 #include "target.h"
236 #include "timevar.h"
237 #include "optabs.h"
238 #include "insn-codes.h"
239 #include "rtlhooks-def.h"
240 /* Include output.h for dump_file.  */
241 #include "output.h"
242 #include "params.h"
243 #include "timevar.h"
244 #include "tree-pass.h"
245 #include "df.h"
246 #include "cgraph.h"
247
248 /* This structure represents a candidate for elimination.  */
249
250 typedef struct GTY(()) ext_cand
251 {
252   /* The expression.  */
253   const_rtx expr;
254
255   /* The kind of extension.  */
256   enum rtx_code code;
257
258   /* The destination mode.  */
259   enum machine_mode mode;
260
261   /* The instruction where it lives.  */
262   rtx insn;
263 } ext_cand;
264
265 DEF_VEC_O(ext_cand);
266 DEF_VEC_ALLOC_O(ext_cand, heap);
267
268 static int max_insn_uid;
269
270 /* Given a insn (CURR_INSN), an extension candidate for removal (CAND)
271    and a pointer to the SET rtx (ORIG_SET) that needs to be modified,
272    this code modifies the SET rtx to a new SET rtx that extends the
273    right hand expression into a register on the left hand side.  Note
274    that multiple assumptions are made about the nature of the set that
275    needs to be true for this to work and is called from merge_def_and_ext.
276
277    Original :
278    (set (reg a) (expression))
279
280    Transform :
281    (set (reg a) (any_extend (expression)))
282
283    Special Cases :
284    If the expression is a constant or another extension, then directly
285    assign it to the register.  */
286
287 static bool
288 combine_set_extension (ext_cand *cand, rtx curr_insn, rtx *orig_set)
289 {
290   rtx orig_src = SET_SRC (*orig_set);
291   rtx new_reg = gen_rtx_REG (cand->mode, REGNO (SET_DEST (*orig_set)));
292   rtx new_set;
293
294   /* Merge constants by directly moving the constant into the register under
295      some conditions.  Recall that RTL constants are sign-extended.  */
296   if (GET_CODE (orig_src) == CONST_INT
297       && HOST_BITS_PER_WIDE_INT >= GET_MODE_BITSIZE (cand->mode))
298     {
299       if (INTVAL (orig_src) >= 0 || cand->code == SIGN_EXTEND)
300         new_set = gen_rtx_SET (VOIDmode, new_reg, orig_src);
301       else
302         {
303           /* Zero-extend the negative constant by masking out the bits outside
304              the source mode.  */
305           enum machine_mode src_mode = GET_MODE (SET_DEST (*orig_set));
306           rtx new_const_int
307             = GEN_INT (INTVAL (orig_src) & GET_MODE_MASK (src_mode));
308           new_set = gen_rtx_SET (VOIDmode, new_reg, new_const_int);
309         }
310     }
311   else if (GET_MODE (orig_src) == VOIDmode)
312     {
313       /* This is mostly due to a call insn that should not be optimized.  */
314       return false;
315     }
316   else if (GET_CODE (orig_src) == cand->code)
317     {
318       /* Here is a sequence of two extensions.  Try to merge them.  */
319       rtx temp_extension
320         = gen_rtx_fmt_e (cand->code, cand->mode, XEXP (orig_src, 0));
321       rtx simplified_temp_extension = simplify_rtx (temp_extension);
322       if (simplified_temp_extension)
323         temp_extension = simplified_temp_extension;
324       new_set = gen_rtx_SET (VOIDmode, new_reg, temp_extension);
325     }
326   else if (GET_CODE (orig_src) == IF_THEN_ELSE)
327     {
328       /* Only IF_THEN_ELSE of phi-type copies are combined.  Otherwise,
329          in general, IF_THEN_ELSE should not be combined.  */
330       return false;
331     }
332   else
333     {
334       /* This is the normal case.  */
335       rtx temp_extension
336         = gen_rtx_fmt_e (cand->code, cand->mode, orig_src);
337       rtx simplified_temp_extension = simplify_rtx (temp_extension);
338       if (simplified_temp_extension)
339         temp_extension = simplified_temp_extension;
340       new_set = gen_rtx_SET (VOIDmode, new_reg, temp_extension);
341     }
342
343   /* This change is a part of a group of changes.  Hence,
344      validate_change will not try to commit the change.  */
345   if (validate_change (curr_insn, orig_set, new_set, true))
346     {
347       if (dump_file)
348         {
349           fprintf (dump_file,
350                    "Tentatively merged extension with definition:\n");
351           print_rtl_single (dump_file, curr_insn);
352         }
353       return true;
354     }
355
356   return false;
357 }
358
359 /* Treat if_then_else insns, where the operands of both branches
360    are registers, as copies.  For instance,
361    Original :
362    (set (reg:SI a) (if_then_else (cond) (reg:SI b) (reg:SI c)))
363    Transformed :
364    (set (reg:DI a) (if_then_else (cond) (reg:DI b) (reg:DI c)))
365    DEF_INSN is the if_then_else insn.  */
366
367 static bool
368 transform_ifelse (ext_cand *cand, rtx def_insn)
369 {
370   rtx set_insn = PATTERN (def_insn);
371   rtx srcreg, dstreg, srcreg2;
372   rtx map_srcreg, map_dstreg, map_srcreg2;
373   rtx ifexpr;
374   rtx cond;
375   rtx new_set;
376
377   gcc_assert (GET_CODE (set_insn) == SET);
378
379   cond = XEXP (SET_SRC (set_insn), 0);
380   dstreg = SET_DEST (set_insn);
381   srcreg = XEXP (SET_SRC (set_insn), 1);
382   srcreg2 = XEXP (SET_SRC (set_insn), 2);
383   /* If the conditional move already has the right or wider mode,
384      there is nothing to do.  */
385   if (GET_MODE_SIZE (GET_MODE (dstreg)) >= GET_MODE_SIZE (cand->mode))
386     return true;
387
388   map_srcreg = gen_rtx_REG (cand->mode, REGNO (srcreg));
389   map_srcreg2 = gen_rtx_REG (cand->mode, REGNO (srcreg2));
390   map_dstreg = gen_rtx_REG (cand->mode, REGNO (dstreg));
391   ifexpr = gen_rtx_IF_THEN_ELSE (cand->mode, cond, map_srcreg, map_srcreg2);
392   new_set = gen_rtx_SET (VOIDmode, map_dstreg, ifexpr);
393
394   if (validate_change (def_insn, &PATTERN (def_insn), new_set, true))
395     {
396       if (dump_file)
397         {
398           fprintf (dump_file,
399                    "Mode of conditional move instruction extended:\n");
400           print_rtl_single (dump_file, def_insn);
401         }
402       return true;
403     }
404
405   return false;
406 }
407
408 /* Get all the reaching definitions of an instruction.  The definitions are
409    desired for REG used in INSN.  Return the definition list or NULL if a
410    definition is missing.  If DEST is non-NULL, additionally push the INSN
411    of the definitions onto DEST.  */
412
413 static struct df_link *
414 get_defs (rtx insn, rtx reg, VEC (rtx,heap) **dest)
415 {
416   df_ref reg_info, *uses;
417   struct df_link *ref_chain, *ref_link;
418
419   reg_info = NULL;
420
421   for (uses = DF_INSN_USES (insn); *uses; uses++)
422     {
423       reg_info = *uses;
424       if (GET_CODE (DF_REF_REG (reg_info)) == SUBREG)
425         return NULL;
426       if (REGNO (DF_REF_REG (reg_info)) == REGNO (reg))
427         break;
428     }
429
430   gcc_assert (reg_info != NULL && uses != NULL);
431
432   ref_chain = DF_REF_CHAIN (reg_info);
433
434   for (ref_link = ref_chain; ref_link; ref_link = ref_link->next)
435     {
436       /* Problem getting some definition for this instruction.  */
437       if (ref_link->ref == NULL)
438         return NULL;
439       if (DF_REF_INSN_INFO (ref_link->ref) == NULL)
440         return NULL;
441     }
442
443   if (dest)
444     for (ref_link = ref_chain; ref_link; ref_link = ref_link->next)
445       VEC_safe_push (rtx, heap, *dest, DF_REF_INSN (ref_link->ref));
446
447   return ref_chain;
448 }
449
450 /* Return true if INSN is
451      (SET (reg REGNO (def_reg)) (if_then_else (cond) (REG x1) (REG x2)))
452    and store x1 and x2 in REG_1 and REG_2.  */
453
454 static bool
455 is_cond_copy_insn (rtx insn, rtx *reg1, rtx *reg2)
456 {
457   rtx expr = single_set (insn);
458
459   if (expr != NULL_RTX
460       && GET_CODE (expr) == SET
461       && GET_CODE (SET_DEST (expr)) == REG
462       && GET_CODE (SET_SRC (expr))  == IF_THEN_ELSE
463       && GET_CODE (XEXP (SET_SRC (expr), 1)) == REG
464       && GET_CODE (XEXP (SET_SRC (expr), 2)) == REG)
465     {
466       *reg1 = XEXP (SET_SRC (expr), 1);
467       *reg2 = XEXP (SET_SRC (expr), 2);
468       return true;
469     }
470
471   return false;
472 }
473
474 enum ext_modified_kind
475 {
476   /* The insn hasn't been modified by ree pass yet.  */
477   EXT_MODIFIED_NONE,
478   /* Changed into zero extension.  */
479   EXT_MODIFIED_ZEXT,
480   /* Changed into sign extension.  */
481   EXT_MODIFIED_SEXT
482 };
483
484 struct ext_modified
485 {
486   /* Mode from which ree has zero or sign extended the destination.  */
487   ENUM_BITFIELD(machine_mode) mode : 8;
488
489   /* Kind of modification of the insn.  */
490   ENUM_BITFIELD(ext_modified_kind) kind : 2;
491
492   /* True if the insn is scheduled to be deleted.  */
493   unsigned int deleted : 1;
494 };
495
496 /* Vectors used by combine_reaching_defs and its helpers.  */
497 typedef struct ext_state
498 {
499   /* In order to avoid constant VEC_alloc/VEC_free, we keep these
500      4 vectors live through the entire find_and_remove_re and just
501      VEC_truncate them each time.  */
502   VEC (rtx, heap) *defs_list;
503   VEC (rtx, heap) *copies_list;
504   VEC (rtx, heap) *modified_list;
505   VEC (rtx, heap) *work_list;
506
507   /* For instructions that have been successfully modified, this is
508      the original mode from which the insn is extending and
509      kind of extension.  */
510   struct ext_modified *modified;
511 } ext_state;
512
513 /* Reaching Definitions of the extended register could be conditional copies
514    or regular definitions.  This function separates the two types into two
515    lists, STATE->DEFS_LIST and STATE->COPIES_LIST.  This is necessary because,
516    if a reaching definition is a conditional copy, merging the extension with
517    this definition is wrong.  Conditional copies are merged by transitively
518    merging their definitions.  The defs_list is populated with all the reaching
519    definitions of the extension instruction (EXTEND_INSN) which must be merged
520    with an extension.  The copies_list contains all the conditional moves that
521    will later be extended into a wider mode conditional move if all the merges
522    are successful.  The function returns false upon failure, true upon
523    success.  */
524
525 static bool
526 make_defs_and_copies_lists (rtx extend_insn, const_rtx set_pat,
527                             ext_state *state)
528 {
529   rtx src_reg = XEXP (SET_SRC (set_pat), 0);
530   bool *is_insn_visited;
531   bool ret = true;
532
533   VEC_truncate (rtx, state->work_list, 0);
534
535   /* Initialize the work list.  */
536   if (!get_defs (extend_insn, src_reg, &state->work_list))
537     gcc_unreachable ();
538
539   is_insn_visited = XCNEWVEC (bool, max_insn_uid);
540
541   /* Perform transitive closure for conditional copies.  */
542   while (!VEC_empty (rtx, state->work_list))
543     {
544       rtx def_insn = VEC_pop (rtx, state->work_list);
545       rtx reg1, reg2;
546
547       gcc_assert (INSN_UID (def_insn) < max_insn_uid);
548
549       if (is_insn_visited[INSN_UID (def_insn)])
550         continue;
551       is_insn_visited[INSN_UID (def_insn)] = true;
552
553       if (is_cond_copy_insn (def_insn, &reg1, &reg2))
554         {
555           /* Push it onto the copy list first.  */
556           VEC_safe_push (rtx, heap, state->copies_list, def_insn);
557
558           /* Now perform the transitive closure.  */
559           if (!get_defs (def_insn, reg1, &state->work_list)
560               || !get_defs (def_insn, reg2, &state->work_list))
561             {
562               ret = false;
563               break;
564             }
565         }
566       else
567         VEC_safe_push (rtx, heap, state->defs_list, def_insn);
568     }
569
570   XDELETEVEC (is_insn_visited);
571
572   return ret;
573 }
574
575 /* Merge the DEF_INSN with an extension.  Calls combine_set_extension
576    on the SET pattern.  */
577
578 static bool
579 merge_def_and_ext (ext_cand *cand, rtx def_insn, ext_state *state)
580 {
581   enum machine_mode ext_src_mode;
582   enum rtx_code code;
583   rtx *sub_rtx;
584   rtx s_expr;
585   int i;
586
587   ext_src_mode = GET_MODE (XEXP (SET_SRC (cand->expr), 0));
588   code = GET_CODE (PATTERN (def_insn));
589   sub_rtx = NULL;
590
591   if (code == PARALLEL)
592     {
593       for (i = 0; i < XVECLEN (PATTERN (def_insn), 0); i++)
594         {
595           s_expr = XVECEXP (PATTERN (def_insn), 0, i);
596           if (GET_CODE (s_expr) != SET)
597             continue;
598
599           if (sub_rtx == NULL)
600             sub_rtx = &XVECEXP (PATTERN (def_insn), 0, i);
601           else
602             {
603               /* PARALLEL with multiple SETs.  */
604               return false;
605             }
606         }
607     }
608   else if (code == SET)
609     sub_rtx = &PATTERN (def_insn);
610   else
611     {
612       /* It is not a PARALLEL or a SET, what could it be ? */
613       return false;
614     }
615
616   gcc_assert (sub_rtx != NULL);
617
618   if (REG_P (SET_DEST (*sub_rtx))
619       && (GET_MODE (SET_DEST (*sub_rtx)) == ext_src_mode
620           || ((state->modified[INSN_UID (def_insn)].kind
621                == (cand->code == ZERO_EXTEND
622                    ? EXT_MODIFIED_ZEXT : EXT_MODIFIED_SEXT))
623               && state->modified[INSN_UID (def_insn)].mode
624                  == ext_src_mode)))
625     {
626       if (GET_MODE_SIZE (GET_MODE (SET_DEST (*sub_rtx)))
627           >= GET_MODE_SIZE (cand->mode))
628         return true;
629       /* If def_insn is already scheduled to be deleted, don't attempt
630          to modify it.  */
631       if (state->modified[INSN_UID (def_insn)].deleted)
632         return false;
633       if (combine_set_extension (cand, def_insn, sub_rtx))
634         {
635           if (state->modified[INSN_UID (def_insn)].kind == EXT_MODIFIED_NONE)
636             state->modified[INSN_UID (def_insn)].mode = ext_src_mode;
637           return true;
638         }
639     }
640
641   return false;
642 }
643
644 /* This function goes through all reaching defs of the source
645    of the candidate for elimination (CAND) and tries to combine
646    the extension with the definition instruction.  The changes
647    are made as a group so that even if one definition cannot be
648    merged, all reaching definitions end up not being merged.
649    When a conditional copy is encountered, merging is attempted
650    transitively on its definitions.  It returns true upon success
651    and false upon failure.  */
652
653 static bool
654 combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
655 {
656   rtx def_insn;
657   bool merge_successful = true;
658   int i;
659   int defs_ix;
660   bool outcome;
661
662   VEC_truncate (rtx, state->defs_list, 0);
663   VEC_truncate (rtx, state->copies_list, 0);
664
665   outcome = make_defs_and_copies_lists (cand->insn, set_pat, state);
666
667   if (!outcome)
668     return false;
669
670   merge_successful = true;
671
672   /* Go through the defs vector and try to merge all the definitions
673      in this vector.  */
674   VEC_truncate (rtx, state->modified_list, 0);
675   FOR_EACH_VEC_ELT (rtx, state->defs_list, defs_ix, def_insn)
676     {
677       if (merge_def_and_ext (cand, def_insn, state))
678         VEC_safe_push (rtx, heap, state->modified_list, def_insn);
679       else
680         {
681           merge_successful = false;
682           break;
683         }
684     }
685
686   /* Now go through the conditional copies vector and try to merge all
687      the copies in this vector.  */
688   if (merge_successful)
689     {
690       FOR_EACH_VEC_ELT (rtx, state->copies_list, i, def_insn)
691         {
692           if (transform_ifelse (cand, def_insn))
693             VEC_safe_push (rtx, heap, state->modified_list, def_insn);
694           else
695             {
696               merge_successful = false;
697               break;
698             }
699         }
700     }
701
702   if (merge_successful)
703     {
704       /* Commit the changes here if possible
705          FIXME: It's an all-or-nothing scenario.  Even if only one definition
706          cannot be merged, we entirely give up.  In the future, we should allow
707          extensions to be partially eliminated along those paths where the
708          definitions could be merged.  */
709       if (apply_change_group ())
710         {
711           if (dump_file)
712             fprintf (dump_file, "All merges were successful.\n");
713
714           FOR_EACH_VEC_ELT (rtx, state->modified_list, i, def_insn)
715             if (state->modified[INSN_UID (def_insn)].kind == EXT_MODIFIED_NONE)
716               state->modified[INSN_UID (def_insn)].kind
717                 = (cand->code == ZERO_EXTEND
718                    ? EXT_MODIFIED_ZEXT : EXT_MODIFIED_SEXT);
719
720           return true;
721         }
722       else
723         {
724           /* Changes need not be cancelled explicitly as apply_change_group
725              does it.  Print list of definitions in the dump_file for debug
726              purposes.  This extension cannot be deleted.  */
727           if (dump_file)
728             {
729               fprintf (dump_file,
730                        "Merge cancelled, non-mergeable definitions:\n");
731               FOR_EACH_VEC_ELT (rtx, state->modified_list, i, def_insn)
732                 print_rtl_single (dump_file, def_insn);
733             }
734         }
735     }
736   else
737     {
738       /* Cancel any changes that have been made so far.  */
739       cancel_changes (0);
740     }
741
742   return false;
743 }
744
745 /* Add an extension pattern that could be eliminated.  */
746
747 static void
748 add_removable_extension (const_rtx expr, rtx insn,
749                          VEC (ext_cand, heap) **insn_list,
750                          unsigned *def_map)
751 {
752   enum rtx_code code;
753   enum machine_mode mode;
754   unsigned int idx;
755   rtx src, dest;
756
757   /* We are looking for SET (REG N) (ANY_EXTEND (REG N)).  */
758   if (GET_CODE (expr) != SET)
759     return;
760
761   src = SET_SRC (expr);
762   code = GET_CODE (src);
763   dest = SET_DEST (expr);
764   mode = GET_MODE (dest);
765
766   if (REG_P (dest)
767       && (code == SIGN_EXTEND || code == ZERO_EXTEND)
768       && REG_P (XEXP (src, 0))
769       && REGNO (dest) == REGNO (XEXP (src, 0)))
770     {
771       struct df_link *defs, *def;
772       ext_cand *cand;
773
774       /* First, make sure we can get all the reaching definitions.  */
775       defs = get_defs (insn, XEXP (src, 0), NULL);
776       if (!defs)
777         {
778           if (dump_file)
779             {
780               fprintf (dump_file, "Cannot eliminate extension:\n");
781               print_rtl_single (dump_file, insn);
782               fprintf (dump_file, " because of missing definition(s)\n");
783             }
784           return;
785         }
786
787       /* Second, make sure the reaching definitions don't feed another and
788          different extension.  FIXME: this obviously can be improved.  */
789       for (def = defs; def; def = def->next)
790         if ((idx = def_map[INSN_UID(DF_REF_INSN (def->ref))])
791             && (cand = VEC_index (ext_cand, *insn_list, idx - 1))
792             && (cand->code != code || cand->mode != mode))
793           {
794             if (dump_file)
795               {
796                 fprintf (dump_file, "Cannot eliminate extension:\n");
797                 print_rtl_single (dump_file, insn);
798                 fprintf (dump_file, " because of other extension\n");
799               }
800             return;
801           }
802
803       /* Then add the candidate to the list and insert the reaching definitions
804          into the definition map.  */
805       cand = VEC_safe_push (ext_cand, heap, *insn_list, NULL);
806       cand->expr = expr;
807       cand->code = code;
808       cand->mode = mode;
809       cand->insn = insn;
810       idx = VEC_length (ext_cand, *insn_list);
811
812       for (def = defs; def; def = def->next)
813         def_map[INSN_UID(DF_REF_INSN (def->ref))] = idx;
814     }
815 }
816
817 /* Traverse the instruction stream looking for extensions and return the
818    list of candidates.  */
819
820 static VEC (ext_cand, heap)*
821 find_removable_extensions (void)
822 {
823   VEC (ext_cand, heap) *insn_list = NULL;
824   basic_block bb;
825   rtx insn, set;
826   unsigned *def_map = XCNEWVEC (unsigned, max_insn_uid);
827
828   FOR_EACH_BB (bb)
829     FOR_BB_INSNS (bb, insn)
830       {
831         if (!NONDEBUG_INSN_P (insn))
832           continue;
833
834         set = single_set (insn);
835         if (set == NULL_RTX)
836           continue;
837         add_removable_extension (set, insn, &insn_list, def_map);
838       }
839
840   XDELETEVEC (def_map);
841
842   return insn_list;
843 }
844
845 /* This is the main function that checks the insn stream for redundant
846    extensions and tries to remove them if possible.  */
847
848 static void
849 find_and_remove_re (void)
850 {
851   ext_cand *curr_cand;
852   rtx curr_insn = NULL_RTX;
853   int num_re_opportunities = 0, num_realized = 0, i;
854   VEC (ext_cand, heap) *reinsn_list;
855   VEC (rtx, heap) *reinsn_del_list;
856   ext_state state;
857
858   /* Construct DU chain to get all reaching definitions of each
859      extension instruction.  */
860   df_chain_add_problem (DF_UD_CHAIN + DF_DU_CHAIN);
861   df_analyze ();
862   df_set_flags (DF_DEFER_INSN_RESCAN);
863
864   max_insn_uid = get_max_uid ();
865   reinsn_del_list = NULL;
866   reinsn_list = find_removable_extensions ();
867   state.defs_list = NULL;
868   state.copies_list = NULL;
869   state.modified_list = NULL;
870   state.work_list = NULL;
871   if (VEC_empty (ext_cand, reinsn_list))
872     state.modified = NULL;
873   else
874     state.modified = XCNEWVEC (struct ext_modified, max_insn_uid);
875
876   FOR_EACH_VEC_ELT (ext_cand, reinsn_list, i, curr_cand)
877     {
878       num_re_opportunities++;
879
880       /* Try to combine the extension with the definition.  */
881       if (dump_file)
882         {
883           fprintf (dump_file, "Trying to eliminate extension:\n");
884           print_rtl_single (dump_file, curr_cand->insn);
885         }
886
887       if (combine_reaching_defs (curr_cand, curr_cand->expr, &state))
888         {
889           if (dump_file)
890             fprintf (dump_file, "Eliminated the extension.\n");
891           num_realized++;
892           VEC_safe_push (rtx, heap, reinsn_del_list, curr_cand->insn);
893           state.modified[INSN_UID (curr_cand->insn)].deleted = 1;
894         }
895     }
896
897   /* Delete all useless extensions here in one sweep.  */
898   FOR_EACH_VEC_ELT (rtx, reinsn_del_list, i, curr_insn)
899     delete_insn (curr_insn);
900
901   VEC_free (ext_cand, heap, reinsn_list);
902   VEC_free (rtx, heap, reinsn_del_list);
903   VEC_free (rtx, heap, state.defs_list);
904   VEC_free (rtx, heap, state.copies_list);
905   VEC_free (rtx, heap, state.modified_list);
906   VEC_free (rtx, heap, state.work_list);
907   XDELETEVEC (state.modified);
908
909   if (dump_file && num_re_opportunities > 0)
910     fprintf (dump_file, "Elimination opportunities = %d realized = %d\n",
911              num_re_opportunities, num_realized);
912
913   df_finish_pass (false);
914 }
915
916 /* Find and remove redundant extensions.  */
917
918 static unsigned int
919 rest_of_handle_ree (void)
920 {
921   timevar_push (TV_REE);
922   find_and_remove_re ();
923   timevar_pop (TV_REE);
924   return 0;
925 }
926
927 /* Run REE pass when flag_ree is set at optimization level > 0.  */
928
929 static bool
930 gate_handle_ree (void)
931 {
932   return (optimize > 0 && flag_ree);
933 }
934
935 struct rtl_opt_pass pass_ree =
936 {
937  {
938   RTL_PASS,
939   "ree",                                /* name */
940   gate_handle_ree,                      /* gate */
941   rest_of_handle_ree,                   /* execute */
942   NULL,                                 /* sub */
943   NULL,                                 /* next */
944   0,                                    /* static_pass_number */
945   TV_REE,                               /* tv_id */
946   0,                                    /* properties_required */
947   0,                                    /* properties_provided */
948   0,                                    /* properties_destroyed */
949   0,                                    /* todo_flags_start */
950   TODO_ggc_collect |
951   TODO_verify_rtl_sharing,              /* todo_flags_finish */
952  }
953 };