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