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, ®1, ®2))
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