annotate gcc/ree.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Redundant Extension Elimination pass for the GNU compiler.
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2 Copyright (C) 2010-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
3 Contributed by Ilya Enkovich (ilya.enkovich@intel.com)
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 Based on the Redundant Zero-extension elimination pass contributed by
kono
parents:
diff changeset
6 Sriraman Tallam (tmsriram@google.com) and Silvius Rus (rus@google.com).
kono
parents:
diff changeset
7
kono
parents:
diff changeset
8 This file is part of GCC.
kono
parents:
diff changeset
9
kono
parents:
diff changeset
10 GCC is free software; you can redistribute it and/or modify it under
kono
parents:
diff changeset
11 the terms of the GNU General Public License as published by the Free
kono
parents:
diff changeset
12 Software Foundation; either version 3, or (at your option) any later
kono
parents:
diff changeset
13 version.
kono
parents:
diff changeset
14
kono
parents:
diff changeset
15 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
kono
parents:
diff changeset
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
18 for more details.
kono
parents:
diff changeset
19
kono
parents:
diff changeset
20 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
21 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
22 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
23
kono
parents:
diff changeset
24
kono
parents:
diff changeset
25 /* Problem Description :
kono
parents:
diff changeset
26 --------------------
kono
parents:
diff changeset
27 This pass is intended to remove redundant extension instructions.
kono
parents:
diff changeset
28 Such instructions appear for different reasons. We expect some of
kono
parents:
diff changeset
29 them due to implicit zero-extension in 64-bit registers after writing
kono
parents:
diff changeset
30 to their lower 32-bit half (e.g. for the x86-64 architecture).
kono
parents:
diff changeset
31 Another possible reason is a type cast which follows a load (for
kono
parents:
diff changeset
32 instance a register restore) and which can be combined into a single
kono
parents:
diff changeset
33 instruction, and for which earlier local passes, e.g. the combiner,
kono
parents:
diff changeset
34 weren't able to optimize.
kono
parents:
diff changeset
35
kono
parents:
diff changeset
36 How does this pass work ?
kono
parents:
diff changeset
37 --------------------------
kono
parents:
diff changeset
38
kono
parents:
diff changeset
39 This pass is run after register allocation. Hence, all registers that
kono
parents:
diff changeset
40 this pass deals with are hard registers. This pass first looks for an
kono
parents:
diff changeset
41 extension instruction that could possibly be redundant. Such extension
kono
parents:
diff changeset
42 instructions show up in RTL with the pattern :
kono
parents:
diff changeset
43 (set (reg:<SWI248> x) (any_extend:<SWI248> (reg:<SWI124> x))),
kono
parents:
diff changeset
44 where x can be any hard register.
kono
parents:
diff changeset
45 Now, this pass tries to eliminate this instruction by merging the
kono
parents:
diff changeset
46 extension with the definitions of register x. For instance, if
kono
parents:
diff changeset
47 one of the definitions of register x was :
kono
parents:
diff changeset
48 (set (reg:SI x) (plus:SI (reg:SI z1) (reg:SI z2))),
kono
parents:
diff changeset
49 followed by extension :
kono
parents:
diff changeset
50 (set (reg:DI x) (zero_extend:DI (reg:SI x)))
kono
parents:
diff changeset
51 then the combination converts this into :
kono
parents:
diff changeset
52 (set (reg:DI x) (zero_extend:DI (plus:SI (reg:SI z1) (reg:SI z2)))).
kono
parents:
diff changeset
53 If all the merged definitions are recognizable assembly instructions,
kono
parents:
diff changeset
54 the extension is effectively eliminated.
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 For example, for the x86-64 architecture, implicit zero-extensions
kono
parents:
diff changeset
57 are captured with appropriate patterns in the i386.md file. Hence,
kono
parents:
diff changeset
58 these merged definition can be matched to a single assembly instruction.
kono
parents:
diff changeset
59 The original extension instruction is then deleted if all the
kono
parents:
diff changeset
60 definitions can be merged.
kono
parents:
diff changeset
61
kono
parents:
diff changeset
62 However, there are cases where the definition instruction cannot be
kono
parents:
diff changeset
63 merged with an extension. Examples are CALL instructions. In such
kono
parents:
diff changeset
64 cases, the original extension is not redundant and this pass does
kono
parents:
diff changeset
65 not delete it.
kono
parents:
diff changeset
66
kono
parents:
diff changeset
67 Handling conditional moves :
kono
parents:
diff changeset
68 ----------------------------
kono
parents:
diff changeset
69
kono
parents:
diff changeset
70 Architectures like x86-64 support conditional moves whose semantics for
kono
parents:
diff changeset
71 extension differ from the other instructions. For instance, the
kono
parents:
diff changeset
72 instruction *cmov ebx, eax*
kono
parents:
diff changeset
73 zero-extends eax onto rax only when the move from ebx to eax happens.
kono
parents:
diff changeset
74 Otherwise, eax may not be zero-extended. Consider conditional moves as
kono
parents:
diff changeset
75 RTL instructions of the form
kono
parents:
diff changeset
76 (set (reg:SI x) (if_then_else (cond) (reg:SI y) (reg:SI z))).
kono
parents:
diff changeset
77 This pass tries to merge an extension with a conditional move by
kono
parents:
diff changeset
78 actually merging the definitions of y and z with an extension and then
kono
parents:
diff changeset
79 converting the conditional move into :
kono
parents:
diff changeset
80 (set (reg:DI x) (if_then_else (cond) (reg:DI y) (reg:DI z))).
kono
parents:
diff changeset
81 Since registers y and z are extended, register x will also be extended
kono
parents:
diff changeset
82 after the conditional move. Note that this step has to be done
kono
parents:
diff changeset
83 transitively since the definition of a conditional copy can be
kono
parents:
diff changeset
84 another conditional copy.
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 Motivating Example I :
kono
parents:
diff changeset
87 ---------------------
kono
parents:
diff changeset
88 For this program :
kono
parents:
diff changeset
89 **********************************************
kono
parents:
diff changeset
90 bad_code.c
kono
parents:
diff changeset
91
kono
parents:
diff changeset
92 int mask[1000];
kono
parents:
diff changeset
93
kono
parents:
diff changeset
94 int foo(unsigned x)
kono
parents:
diff changeset
95 {
kono
parents:
diff changeset
96 if (x < 10)
kono
parents:
diff changeset
97 x = x * 45;
kono
parents:
diff changeset
98 else
kono
parents:
diff changeset
99 x = x * 78;
kono
parents:
diff changeset
100 return mask[x];
kono
parents:
diff changeset
101 }
kono
parents:
diff changeset
102 **********************************************
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 $ gcc -O2 bad_code.c
kono
parents:
diff changeset
105 ........
kono
parents:
diff changeset
106 400315: b8 4e 00 00 00 mov $0x4e,%eax
kono
parents:
diff changeset
107 40031a: 0f af f8 imul %eax,%edi
kono
parents:
diff changeset
108 40031d: 89 ff mov %edi,%edi - useless extension
kono
parents:
diff changeset
109 40031f: 8b 04 bd 60 19 40 00 mov 0x401960(,%rdi,4),%eax
kono
parents:
diff changeset
110 400326: c3 retq
kono
parents:
diff changeset
111 ......
kono
parents:
diff changeset
112 400330: ba 2d 00 00 00 mov $0x2d,%edx
kono
parents:
diff changeset
113 400335: 0f af fa imul %edx,%edi
kono
parents:
diff changeset
114 400338: 89 ff mov %edi,%edi - useless extension
kono
parents:
diff changeset
115 40033a: 8b 04 bd 60 19 40 00 mov 0x401960(,%rdi,4),%eax
kono
parents:
diff changeset
116 400341: c3 retq
kono
parents:
diff changeset
117
kono
parents:
diff changeset
118 $ gcc -O2 -free bad_code.c
kono
parents:
diff changeset
119 ......
kono
parents:
diff changeset
120 400315: 6b ff 4e imul $0x4e,%edi,%edi
kono
parents:
diff changeset
121 400318: 8b 04 bd 40 19 40 00 mov 0x401940(,%rdi,4),%eax
kono
parents:
diff changeset
122 40031f: c3 retq
kono
parents:
diff changeset
123 400320: 6b ff 2d imul $0x2d,%edi,%edi
kono
parents:
diff changeset
124 400323: 8b 04 bd 40 19 40 00 mov 0x401940(,%rdi,4),%eax
kono
parents:
diff changeset
125 40032a: c3 retq
kono
parents:
diff changeset
126
kono
parents:
diff changeset
127 Motivating Example II :
kono
parents:
diff changeset
128 ---------------------
kono
parents:
diff changeset
129
kono
parents:
diff changeset
130 Here is an example with a conditional move.
kono
parents:
diff changeset
131
kono
parents:
diff changeset
132 For this program :
kono
parents:
diff changeset
133 **********************************************
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135 unsigned long long foo(unsigned x , unsigned y)
kono
parents:
diff changeset
136 {
kono
parents:
diff changeset
137 unsigned z;
kono
parents:
diff changeset
138 if (x > 100)
kono
parents:
diff changeset
139 z = x + y;
kono
parents:
diff changeset
140 else
kono
parents:
diff changeset
141 z = x - y;
kono
parents:
diff changeset
142 return (unsigned long long)(z);
kono
parents:
diff changeset
143 }
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 $ gcc -O2 bad_code.c
kono
parents:
diff changeset
146 ............
kono
parents:
diff changeset
147 400360: 8d 14 3e lea (%rsi,%rdi,1),%edx
kono
parents:
diff changeset
148 400363: 89 f8 mov %edi,%eax
kono
parents:
diff changeset
149 400365: 29 f0 sub %esi,%eax
kono
parents:
diff changeset
150 400367: 83 ff 65 cmp $0x65,%edi
kono
parents:
diff changeset
151 40036a: 0f 43 c2 cmovae %edx,%eax
kono
parents:
diff changeset
152 40036d: 89 c0 mov %eax,%eax - useless extension
kono
parents:
diff changeset
153 40036f: c3 retq
kono
parents:
diff changeset
154
kono
parents:
diff changeset
155 $ gcc -O2 -free bad_code.c
kono
parents:
diff changeset
156 .............
kono
parents:
diff changeset
157 400360: 89 fa mov %edi,%edx
kono
parents:
diff changeset
158 400362: 8d 04 3e lea (%rsi,%rdi,1),%eax
kono
parents:
diff changeset
159 400365: 29 f2 sub %esi,%edx
kono
parents:
diff changeset
160 400367: 83 ff 65 cmp $0x65,%edi
kono
parents:
diff changeset
161 40036a: 89 d6 mov %edx,%esi
kono
parents:
diff changeset
162 40036c: 48 0f 42 c6 cmovb %rsi,%rax
kono
parents:
diff changeset
163 400370: c3 retq
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 Motivating Example III :
kono
parents:
diff changeset
166 ---------------------
kono
parents:
diff changeset
167
kono
parents:
diff changeset
168 Here is an example with a type cast.
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 For this program :
kono
parents:
diff changeset
171 **********************************************
kono
parents:
diff changeset
172
kono
parents:
diff changeset
173 void test(int size, unsigned char *in, unsigned char *out)
kono
parents:
diff changeset
174 {
kono
parents:
diff changeset
175 int i;
kono
parents:
diff changeset
176 unsigned char xr, xg, xy=0;
kono
parents:
diff changeset
177
kono
parents:
diff changeset
178 for (i = 0; i < size; i++) {
kono
parents:
diff changeset
179 xr = *in++;
kono
parents:
diff changeset
180 xg = *in++;
kono
parents:
diff changeset
181 xy = (unsigned char) ((19595*xr + 38470*xg) >> 16);
kono
parents:
diff changeset
182 *out++ = xy;
kono
parents:
diff changeset
183 }
kono
parents:
diff changeset
184 }
kono
parents:
diff changeset
185
kono
parents:
diff changeset
186 $ gcc -O2 bad_code.c
kono
parents:
diff changeset
187 ............
kono
parents:
diff changeset
188 10: 0f b6 0e movzbl (%rsi),%ecx
kono
parents:
diff changeset
189 13: 0f b6 46 01 movzbl 0x1(%rsi),%eax
kono
parents:
diff changeset
190 17: 48 83 c6 02 add $0x2,%rsi
kono
parents:
diff changeset
191 1b: 0f b6 c9 movzbl %cl,%ecx - useless extension
kono
parents:
diff changeset
192 1e: 0f b6 c0 movzbl %al,%eax - useless extension
kono
parents:
diff changeset
193 21: 69 c9 8b 4c 00 00 imul $0x4c8b,%ecx,%ecx
kono
parents:
diff changeset
194 27: 69 c0 46 96 00 00 imul $0x9646,%eax,%eax
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 $ gcc -O2 -free bad_code.c
kono
parents:
diff changeset
197 .............
kono
parents:
diff changeset
198 10: 0f b6 0e movzbl (%rsi),%ecx
kono
parents:
diff changeset
199 13: 0f b6 46 01 movzbl 0x1(%rsi),%eax
kono
parents:
diff changeset
200 17: 48 83 c6 02 add $0x2,%rsi
kono
parents:
diff changeset
201 1b: 69 c9 8b 4c 00 00 imul $0x4c8b,%ecx,%ecx
kono
parents:
diff changeset
202 21: 69 c0 46 96 00 00 imul $0x9646,%eax,%eax
kono
parents:
diff changeset
203
kono
parents:
diff changeset
204 Usefulness :
kono
parents:
diff changeset
205 ----------
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 The original redundant zero-extension elimination pass reported reduction
kono
parents:
diff changeset
208 of the dynamic instruction count of a compression benchmark by 2.8% and
kono
parents:
diff changeset
209 improvement of its run time by about 1%.
kono
parents:
diff changeset
210
kono
parents:
diff changeset
211 The additional performance gain with the enhanced pass is mostly expected
kono
parents:
diff changeset
212 on in-order architectures where redundancy cannot be compensated by out of
kono
parents:
diff changeset
213 order execution. Measurements showed up to 10% performance gain (reduced
kono
parents:
diff changeset
214 run time) on EEMBC 2.0 benchmarks on Atom processor with geomean performance
kono
parents:
diff changeset
215 gain 1%. */
kono
parents:
diff changeset
216
kono
parents:
diff changeset
217
kono
parents:
diff changeset
218 #include "config.h"
kono
parents:
diff changeset
219 #include "system.h"
kono
parents:
diff changeset
220 #include "coretypes.h"
kono
parents:
diff changeset
221 #include "backend.h"
kono
parents:
diff changeset
222 #include "target.h"
kono
parents:
diff changeset
223 #include "rtl.h"
kono
parents:
diff changeset
224 #include "tree.h"
kono
parents:
diff changeset
225 #include "df.h"
kono
parents:
diff changeset
226 #include "memmodel.h"
kono
parents:
diff changeset
227 #include "tm_p.h"
kono
parents:
diff changeset
228 #include "optabs.h"
kono
parents:
diff changeset
229 #include "regs.h"
kono
parents:
diff changeset
230 #include "emit-rtl.h"
kono
parents:
diff changeset
231 #include "recog.h"
kono
parents:
diff changeset
232 #include "cfgrtl.h"
kono
parents:
diff changeset
233 #include "expr.h"
kono
parents:
diff changeset
234 #include "tree-pass.h"
kono
parents:
diff changeset
235
kono
parents:
diff changeset
236 /* This structure represents a candidate for elimination. */
kono
parents:
diff changeset
237
kono
parents:
diff changeset
238 struct ext_cand
kono
parents:
diff changeset
239 {
kono
parents:
diff changeset
240 /* The expression. */
kono
parents:
diff changeset
241 const_rtx expr;
kono
parents:
diff changeset
242
kono
parents:
diff changeset
243 /* The kind of extension. */
kono
parents:
diff changeset
244 enum rtx_code code;
kono
parents:
diff changeset
245
kono
parents:
diff changeset
246 /* The destination mode. */
kono
parents:
diff changeset
247 machine_mode mode;
kono
parents:
diff changeset
248
kono
parents:
diff changeset
249 /* The instruction where it lives. */
kono
parents:
diff changeset
250 rtx_insn *insn;
kono
parents:
diff changeset
251 };
kono
parents:
diff changeset
252
kono
parents:
diff changeset
253
kono
parents:
diff changeset
254 static int max_insn_uid;
kono
parents:
diff changeset
255
kono
parents:
diff changeset
256 /* Update or remove REG_EQUAL or REG_EQUIV notes for INSN. */
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 static bool
kono
parents:
diff changeset
259 update_reg_equal_equiv_notes (rtx_insn *insn, machine_mode new_mode,
kono
parents:
diff changeset
260 machine_mode old_mode, enum rtx_code code)
kono
parents:
diff changeset
261 {
kono
parents:
diff changeset
262 rtx *loc = &REG_NOTES (insn);
kono
parents:
diff changeset
263 while (*loc)
kono
parents:
diff changeset
264 {
kono
parents:
diff changeset
265 enum reg_note kind = REG_NOTE_KIND (*loc);
kono
parents:
diff changeset
266 if (kind == REG_EQUAL || kind == REG_EQUIV)
kono
parents:
diff changeset
267 {
kono
parents:
diff changeset
268 rtx orig_src = XEXP (*loc, 0);
kono
parents:
diff changeset
269 /* Update equivalency constants. Recall that RTL constants are
kono
parents:
diff changeset
270 sign-extended. */
kono
parents:
diff changeset
271 if (GET_CODE (orig_src) == CONST_INT
kono
parents:
diff changeset
272 && HWI_COMPUTABLE_MODE_P (new_mode))
kono
parents:
diff changeset
273 {
kono
parents:
diff changeset
274 if (INTVAL (orig_src) >= 0 || code == SIGN_EXTEND)
kono
parents:
diff changeset
275 /* Nothing needed. */;
kono
parents:
diff changeset
276 else
kono
parents:
diff changeset
277 {
kono
parents:
diff changeset
278 /* Zero-extend the negative constant by masking out the
kono
parents:
diff changeset
279 bits outside the source mode. */
kono
parents:
diff changeset
280 rtx new_const_int
kono
parents:
diff changeset
281 = gen_int_mode (INTVAL (orig_src)
kono
parents:
diff changeset
282 & GET_MODE_MASK (old_mode),
kono
parents:
diff changeset
283 new_mode);
kono
parents:
diff changeset
284 if (!validate_change (insn, &XEXP (*loc, 0),
kono
parents:
diff changeset
285 new_const_int, true))
kono
parents:
diff changeset
286 return false;
kono
parents:
diff changeset
287 }
kono
parents:
diff changeset
288 loc = &XEXP (*loc, 1);
kono
parents:
diff changeset
289 }
kono
parents:
diff changeset
290 /* Drop all other notes, they assume a wrong mode. */
kono
parents:
diff changeset
291 else if (!validate_change (insn, loc, XEXP (*loc, 1), true))
kono
parents:
diff changeset
292 return false;
kono
parents:
diff changeset
293 }
kono
parents:
diff changeset
294 else
kono
parents:
diff changeset
295 loc = &XEXP (*loc, 1);
kono
parents:
diff changeset
296 }
kono
parents:
diff changeset
297 return true;
kono
parents:
diff changeset
298 }
kono
parents:
diff changeset
299
kono
parents:
diff changeset
300 /* Given a insn (CURR_INSN), an extension candidate for removal (CAND)
kono
parents:
diff changeset
301 and a pointer to the SET rtx (ORIG_SET) that needs to be modified,
kono
parents:
diff changeset
302 this code modifies the SET rtx to a new SET rtx that extends the
kono
parents:
diff changeset
303 right hand expression into a register on the left hand side. Note
kono
parents:
diff changeset
304 that multiple assumptions are made about the nature of the set that
kono
parents:
diff changeset
305 needs to be true for this to work and is called from merge_def_and_ext.
kono
parents:
diff changeset
306
kono
parents:
diff changeset
307 Original :
kono
parents:
diff changeset
308 (set (reg a) (expression))
kono
parents:
diff changeset
309
kono
parents:
diff changeset
310 Transform :
kono
parents:
diff changeset
311 (set (reg a) (any_extend (expression)))
kono
parents:
diff changeset
312
kono
parents:
diff changeset
313 Special Cases :
kono
parents:
diff changeset
314 If the expression is a constant or another extension, then directly
kono
parents:
diff changeset
315 assign it to the register. */
kono
parents:
diff changeset
316
kono
parents:
diff changeset
317 static bool
kono
parents:
diff changeset
318 combine_set_extension (ext_cand *cand, rtx_insn *curr_insn, rtx *orig_set)
kono
parents:
diff changeset
319 {
kono
parents:
diff changeset
320 rtx orig_src = SET_SRC (*orig_set);
kono
parents:
diff changeset
321 machine_mode orig_mode = GET_MODE (SET_DEST (*orig_set));
kono
parents:
diff changeset
322 rtx new_set;
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
323 rtx cand_pat = single_set (cand->insn);
111
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 /* If the extension's source/destination registers are not the same
kono
parents:
diff changeset
326 then we need to change the original load to reference the destination
kono
parents:
diff changeset
327 of the extension. Then we need to emit a copy from that destination
kono
parents:
diff changeset
328 to the original destination of the load. */
kono
parents:
diff changeset
329 rtx new_reg;
kono
parents:
diff changeset
330 bool copy_needed
kono
parents:
diff changeset
331 = (REGNO (SET_DEST (cand_pat)) != REGNO (XEXP (SET_SRC (cand_pat), 0)));
kono
parents:
diff changeset
332 if (copy_needed)
kono
parents:
diff changeset
333 new_reg = gen_rtx_REG (cand->mode, REGNO (SET_DEST (cand_pat)));
kono
parents:
diff changeset
334 else
kono
parents:
diff changeset
335 new_reg = gen_rtx_REG (cand->mode, REGNO (SET_DEST (*orig_set)));
kono
parents:
diff changeset
336
kono
parents:
diff changeset
337 /* Merge constants by directly moving the constant into the register under
kono
parents:
diff changeset
338 some conditions. Recall that RTL constants are sign-extended. */
kono
parents:
diff changeset
339 if (GET_CODE (orig_src) == CONST_INT
kono
parents:
diff changeset
340 && HWI_COMPUTABLE_MODE_P (cand->mode))
kono
parents:
diff changeset
341 {
kono
parents:
diff changeset
342 if (INTVAL (orig_src) >= 0 || cand->code == SIGN_EXTEND)
kono
parents:
diff changeset
343 new_set = gen_rtx_SET (new_reg, orig_src);
kono
parents:
diff changeset
344 else
kono
parents:
diff changeset
345 {
kono
parents:
diff changeset
346 /* Zero-extend the negative constant by masking out the bits outside
kono
parents:
diff changeset
347 the source mode. */
kono
parents:
diff changeset
348 rtx new_const_int
kono
parents:
diff changeset
349 = gen_int_mode (INTVAL (orig_src) & GET_MODE_MASK (orig_mode),
kono
parents:
diff changeset
350 GET_MODE (new_reg));
kono
parents:
diff changeset
351 new_set = gen_rtx_SET (new_reg, new_const_int);
kono
parents:
diff changeset
352 }
kono
parents:
diff changeset
353 }
kono
parents:
diff changeset
354 else if (GET_MODE (orig_src) == VOIDmode)
kono
parents:
diff changeset
355 {
kono
parents:
diff changeset
356 /* This is mostly due to a call insn that should not be optimized. */
kono
parents:
diff changeset
357 return false;
kono
parents:
diff changeset
358 }
kono
parents:
diff changeset
359 else if (GET_CODE (orig_src) == cand->code)
kono
parents:
diff changeset
360 {
kono
parents:
diff changeset
361 /* Here is a sequence of two extensions. Try to merge them. */
kono
parents:
diff changeset
362 rtx temp_extension
kono
parents:
diff changeset
363 = gen_rtx_fmt_e (cand->code, cand->mode, XEXP (orig_src, 0));
kono
parents:
diff changeset
364 rtx simplified_temp_extension = simplify_rtx (temp_extension);
kono
parents:
diff changeset
365 if (simplified_temp_extension)
kono
parents:
diff changeset
366 temp_extension = simplified_temp_extension;
kono
parents:
diff changeset
367 new_set = gen_rtx_SET (new_reg, temp_extension);
kono
parents:
diff changeset
368 }
kono
parents:
diff changeset
369 else if (GET_CODE (orig_src) == IF_THEN_ELSE)
kono
parents:
diff changeset
370 {
kono
parents:
diff changeset
371 /* Only IF_THEN_ELSE of phi-type copies are combined. Otherwise,
kono
parents:
diff changeset
372 in general, IF_THEN_ELSE should not be combined. */
kono
parents:
diff changeset
373 return false;
kono
parents:
diff changeset
374 }
kono
parents:
diff changeset
375 else
kono
parents:
diff changeset
376 {
kono
parents:
diff changeset
377 /* This is the normal case. */
kono
parents:
diff changeset
378 rtx temp_extension
kono
parents:
diff changeset
379 = gen_rtx_fmt_e (cand->code, cand->mode, orig_src);
kono
parents:
diff changeset
380 rtx simplified_temp_extension = simplify_rtx (temp_extension);
kono
parents:
diff changeset
381 if (simplified_temp_extension)
kono
parents:
diff changeset
382 temp_extension = simplified_temp_extension;
kono
parents:
diff changeset
383 new_set = gen_rtx_SET (new_reg, temp_extension);
kono
parents:
diff changeset
384 }
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 /* This change is a part of a group of changes. Hence,
kono
parents:
diff changeset
387 validate_change will not try to commit the change. */
kono
parents:
diff changeset
388 if (validate_change (curr_insn, orig_set, new_set, true)
kono
parents:
diff changeset
389 && update_reg_equal_equiv_notes (curr_insn, cand->mode, orig_mode,
kono
parents:
diff changeset
390 cand->code))
kono
parents:
diff changeset
391 {
kono
parents:
diff changeset
392 if (dump_file)
kono
parents:
diff changeset
393 {
kono
parents:
diff changeset
394 fprintf (dump_file,
kono
parents:
diff changeset
395 "Tentatively merged extension with definition %s:\n",
kono
parents:
diff changeset
396 (copy_needed) ? "(copy needed)" : "");
kono
parents:
diff changeset
397 print_rtl_single (dump_file, curr_insn);
kono
parents:
diff changeset
398 }
kono
parents:
diff changeset
399 return true;
kono
parents:
diff changeset
400 }
kono
parents:
diff changeset
401
kono
parents:
diff changeset
402 return false;
kono
parents:
diff changeset
403 }
kono
parents:
diff changeset
404
kono
parents:
diff changeset
405 /* Treat if_then_else insns, where the operands of both branches
kono
parents:
diff changeset
406 are registers, as copies. For instance,
kono
parents:
diff changeset
407 Original :
kono
parents:
diff changeset
408 (set (reg:SI a) (if_then_else (cond) (reg:SI b) (reg:SI c)))
kono
parents:
diff changeset
409 Transformed :
kono
parents:
diff changeset
410 (set (reg:DI a) (if_then_else (cond) (reg:DI b) (reg:DI c)))
kono
parents:
diff changeset
411 DEF_INSN is the if_then_else insn. */
kono
parents:
diff changeset
412
kono
parents:
diff changeset
413 static bool
kono
parents:
diff changeset
414 transform_ifelse (ext_cand *cand, rtx_insn *def_insn)
kono
parents:
diff changeset
415 {
kono
parents:
diff changeset
416 rtx set_insn = PATTERN (def_insn);
kono
parents:
diff changeset
417 rtx srcreg, dstreg, srcreg2;
kono
parents:
diff changeset
418 rtx map_srcreg, map_dstreg, map_srcreg2;
kono
parents:
diff changeset
419 rtx ifexpr;
kono
parents:
diff changeset
420 rtx cond;
kono
parents:
diff changeset
421 rtx new_set;
kono
parents:
diff changeset
422
kono
parents:
diff changeset
423 gcc_assert (GET_CODE (set_insn) == SET);
kono
parents:
diff changeset
424
kono
parents:
diff changeset
425 cond = XEXP (SET_SRC (set_insn), 0);
kono
parents:
diff changeset
426 dstreg = SET_DEST (set_insn);
kono
parents:
diff changeset
427 srcreg = XEXP (SET_SRC (set_insn), 1);
kono
parents:
diff changeset
428 srcreg2 = XEXP (SET_SRC (set_insn), 2);
kono
parents:
diff changeset
429 /* If the conditional move already has the right or wider mode,
kono
parents:
diff changeset
430 there is nothing to do. */
kono
parents:
diff changeset
431 if (GET_MODE_UNIT_SIZE (GET_MODE (dstreg))
kono
parents:
diff changeset
432 >= GET_MODE_UNIT_SIZE (cand->mode))
kono
parents:
diff changeset
433 return true;
kono
parents:
diff changeset
434
kono
parents:
diff changeset
435 map_srcreg = gen_rtx_REG (cand->mode, REGNO (srcreg));
kono
parents:
diff changeset
436 map_srcreg2 = gen_rtx_REG (cand->mode, REGNO (srcreg2));
kono
parents:
diff changeset
437 map_dstreg = gen_rtx_REG (cand->mode, REGNO (dstreg));
kono
parents:
diff changeset
438 ifexpr = gen_rtx_IF_THEN_ELSE (cand->mode, cond, map_srcreg, map_srcreg2);
kono
parents:
diff changeset
439 new_set = gen_rtx_SET (map_dstreg, ifexpr);
kono
parents:
diff changeset
440
kono
parents:
diff changeset
441 if (validate_change (def_insn, &PATTERN (def_insn), new_set, true)
kono
parents:
diff changeset
442 && update_reg_equal_equiv_notes (def_insn, cand->mode, GET_MODE (dstreg),
kono
parents:
diff changeset
443 cand->code))
kono
parents:
diff changeset
444 {
kono
parents:
diff changeset
445 if (dump_file)
kono
parents:
diff changeset
446 {
kono
parents:
diff changeset
447 fprintf (dump_file,
kono
parents:
diff changeset
448 "Mode of conditional move instruction extended:\n");
kono
parents:
diff changeset
449 print_rtl_single (dump_file, def_insn);
kono
parents:
diff changeset
450 }
kono
parents:
diff changeset
451 return true;
kono
parents:
diff changeset
452 }
kono
parents:
diff changeset
453
kono
parents:
diff changeset
454 return false;
kono
parents:
diff changeset
455 }
kono
parents:
diff changeset
456
kono
parents:
diff changeset
457 /* Get all the reaching definitions of an instruction. The definitions are
kono
parents:
diff changeset
458 desired for REG used in INSN. Return the definition list or NULL if a
kono
parents:
diff changeset
459 definition is missing. If DEST is non-NULL, additionally push the INSN
kono
parents:
diff changeset
460 of the definitions onto DEST. */
kono
parents:
diff changeset
461
kono
parents:
diff changeset
462 static struct df_link *
kono
parents:
diff changeset
463 get_defs (rtx_insn *insn, rtx reg, vec<rtx_insn *> *dest)
kono
parents:
diff changeset
464 {
kono
parents:
diff changeset
465 df_ref use;
kono
parents:
diff changeset
466 struct df_link *ref_chain, *ref_link;
kono
parents:
diff changeset
467
kono
parents:
diff changeset
468 FOR_EACH_INSN_USE (use, insn)
kono
parents:
diff changeset
469 {
kono
parents:
diff changeset
470 if (GET_CODE (DF_REF_REG (use)) == SUBREG)
kono
parents:
diff changeset
471 return NULL;
kono
parents:
diff changeset
472 if (REGNO (DF_REF_REG (use)) == REGNO (reg))
kono
parents:
diff changeset
473 break;
kono
parents:
diff changeset
474 }
kono
parents:
diff changeset
475
kono
parents:
diff changeset
476 gcc_assert (use != NULL);
kono
parents:
diff changeset
477
kono
parents:
diff changeset
478 ref_chain = DF_REF_CHAIN (use);
kono
parents:
diff changeset
479
kono
parents:
diff changeset
480 for (ref_link = ref_chain; ref_link; ref_link = ref_link->next)
kono
parents:
diff changeset
481 {
kono
parents:
diff changeset
482 /* Problem getting some definition for this instruction. */
kono
parents:
diff changeset
483 if (ref_link->ref == NULL)
kono
parents:
diff changeset
484 return NULL;
kono
parents:
diff changeset
485 if (DF_REF_INSN_INFO (ref_link->ref) == NULL)
kono
parents:
diff changeset
486 return NULL;
kono
parents:
diff changeset
487 /* As global regs are assumed to be defined at each function call
kono
parents:
diff changeset
488 dataflow can report a call_insn as being a definition of REG.
kono
parents:
diff changeset
489 But we can't do anything with that in this pass so proceed only
kono
parents:
diff changeset
490 if the instruction really sets REG in a way that can be deduced
kono
parents:
diff changeset
491 from the RTL structure. */
kono
parents:
diff changeset
492 if (global_regs[REGNO (reg)]
kono
parents:
diff changeset
493 && !set_of (reg, DF_REF_INSN (ref_link->ref)))
kono
parents:
diff changeset
494 return NULL;
kono
parents:
diff changeset
495 }
kono
parents:
diff changeset
496
kono
parents:
diff changeset
497 if (dest)
kono
parents:
diff changeset
498 for (ref_link = ref_chain; ref_link; ref_link = ref_link->next)
kono
parents:
diff changeset
499 dest->safe_push (DF_REF_INSN (ref_link->ref));
kono
parents:
diff changeset
500
kono
parents:
diff changeset
501 return ref_chain;
kono
parents:
diff changeset
502 }
kono
parents:
diff changeset
503
kono
parents:
diff changeset
504 /* Get all the reaching uses of an instruction. The uses are desired for REG
kono
parents:
diff changeset
505 set in INSN. Return use list or NULL if a use is missing or irregular. */
kono
parents:
diff changeset
506
kono
parents:
diff changeset
507 static struct df_link *
kono
parents:
diff changeset
508 get_uses (rtx_insn *insn, rtx reg)
kono
parents:
diff changeset
509 {
kono
parents:
diff changeset
510 df_ref def;
kono
parents:
diff changeset
511 struct df_link *ref_chain, *ref_link;
kono
parents:
diff changeset
512
kono
parents:
diff changeset
513 FOR_EACH_INSN_DEF (def, insn)
kono
parents:
diff changeset
514 if (REGNO (DF_REF_REG (def)) == REGNO (reg))
kono
parents:
diff changeset
515 break;
kono
parents:
diff changeset
516
kono
parents:
diff changeset
517 gcc_assert (def != NULL);
kono
parents:
diff changeset
518
kono
parents:
diff changeset
519 ref_chain = DF_REF_CHAIN (def);
kono
parents:
diff changeset
520
kono
parents:
diff changeset
521 for (ref_link = ref_chain; ref_link; ref_link = ref_link->next)
kono
parents:
diff changeset
522 {
kono
parents:
diff changeset
523 /* Problem getting some use for this instruction. */
kono
parents:
diff changeset
524 if (ref_link->ref == NULL)
kono
parents:
diff changeset
525 return NULL;
kono
parents:
diff changeset
526 if (DF_REF_CLASS (ref_link->ref) != DF_REF_REGULAR)
kono
parents:
diff changeset
527 return NULL;
kono
parents:
diff changeset
528 }
kono
parents:
diff changeset
529
kono
parents:
diff changeset
530 return ref_chain;
kono
parents:
diff changeset
531 }
kono
parents:
diff changeset
532
kono
parents:
diff changeset
533 /* Return true if INSN is
kono
parents:
diff changeset
534 (SET (reg REGNO (def_reg)) (if_then_else (cond) (REG x1) (REG x2)))
kono
parents:
diff changeset
535 and store x1 and x2 in REG_1 and REG_2. */
kono
parents:
diff changeset
536
kono
parents:
diff changeset
537 static bool
kono
parents:
diff changeset
538 is_cond_copy_insn (rtx_insn *insn, rtx *reg1, rtx *reg2)
kono
parents:
diff changeset
539 {
kono
parents:
diff changeset
540 rtx expr = single_set (insn);
kono
parents:
diff changeset
541
kono
parents:
diff changeset
542 if (expr != NULL_RTX
kono
parents:
diff changeset
543 && GET_CODE (expr) == SET
kono
parents:
diff changeset
544 && GET_CODE (SET_DEST (expr)) == REG
kono
parents:
diff changeset
545 && GET_CODE (SET_SRC (expr)) == IF_THEN_ELSE
kono
parents:
diff changeset
546 && GET_CODE (XEXP (SET_SRC (expr), 1)) == REG
kono
parents:
diff changeset
547 && GET_CODE (XEXP (SET_SRC (expr), 2)) == REG)
kono
parents:
diff changeset
548 {
kono
parents:
diff changeset
549 *reg1 = XEXP (SET_SRC (expr), 1);
kono
parents:
diff changeset
550 *reg2 = XEXP (SET_SRC (expr), 2);
kono
parents:
diff changeset
551 return true;
kono
parents:
diff changeset
552 }
kono
parents:
diff changeset
553
kono
parents:
diff changeset
554 return false;
kono
parents:
diff changeset
555 }
kono
parents:
diff changeset
556
kono
parents:
diff changeset
557 enum ext_modified_kind
kono
parents:
diff changeset
558 {
kono
parents:
diff changeset
559 /* The insn hasn't been modified by ree pass yet. */
kono
parents:
diff changeset
560 EXT_MODIFIED_NONE,
kono
parents:
diff changeset
561 /* Changed into zero extension. */
kono
parents:
diff changeset
562 EXT_MODIFIED_ZEXT,
kono
parents:
diff changeset
563 /* Changed into sign extension. */
kono
parents:
diff changeset
564 EXT_MODIFIED_SEXT
kono
parents:
diff changeset
565 };
kono
parents:
diff changeset
566
kono
parents:
diff changeset
567 struct ATTRIBUTE_PACKED ext_modified
kono
parents:
diff changeset
568 {
kono
parents:
diff changeset
569 /* Mode from which ree has zero or sign extended the destination. */
kono
parents:
diff changeset
570 ENUM_BITFIELD(machine_mode) mode : 8;
kono
parents:
diff changeset
571
kono
parents:
diff changeset
572 /* Kind of modification of the insn. */
kono
parents:
diff changeset
573 ENUM_BITFIELD(ext_modified_kind) kind : 2;
kono
parents:
diff changeset
574
kono
parents:
diff changeset
575 unsigned int do_not_reextend : 1;
kono
parents:
diff changeset
576
kono
parents:
diff changeset
577 /* True if the insn is scheduled to be deleted. */
kono
parents:
diff changeset
578 unsigned int deleted : 1;
kono
parents:
diff changeset
579 };
kono
parents:
diff changeset
580
kono
parents:
diff changeset
581 /* Vectors used by combine_reaching_defs and its helpers. */
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
582 class ext_state
111
kono
parents:
diff changeset
583 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
584 public:
111
kono
parents:
diff changeset
585 /* In order to avoid constant alloc/free, we keep these
kono
parents:
diff changeset
586 4 vectors live through the entire find_and_remove_re and just
kono
parents:
diff changeset
587 truncate them each time. */
kono
parents:
diff changeset
588 auto_vec<rtx_insn *> defs_list;
kono
parents:
diff changeset
589 auto_vec<rtx_insn *> copies_list;
kono
parents:
diff changeset
590 auto_vec<rtx_insn *> modified_list;
kono
parents:
diff changeset
591 auto_vec<rtx_insn *> work_list;
kono
parents:
diff changeset
592
kono
parents:
diff changeset
593 /* For instructions that have been successfully modified, this is
kono
parents:
diff changeset
594 the original mode from which the insn is extending and
kono
parents:
diff changeset
595 kind of extension. */
kono
parents:
diff changeset
596 struct ext_modified *modified;
kono
parents:
diff changeset
597 };
kono
parents:
diff changeset
598
kono
parents:
diff changeset
599 /* Reaching Definitions of the extended register could be conditional copies
kono
parents:
diff changeset
600 or regular definitions. This function separates the two types into two
kono
parents:
diff changeset
601 lists, STATE->DEFS_LIST and STATE->COPIES_LIST. This is necessary because,
kono
parents:
diff changeset
602 if a reaching definition is a conditional copy, merging the extension with
kono
parents:
diff changeset
603 this definition is wrong. Conditional copies are merged by transitively
kono
parents:
diff changeset
604 merging their definitions. The defs_list is populated with all the reaching
kono
parents:
diff changeset
605 definitions of the extension instruction (EXTEND_INSN) which must be merged
kono
parents:
diff changeset
606 with an extension. The copies_list contains all the conditional moves that
kono
parents:
diff changeset
607 will later be extended into a wider mode conditional move if all the merges
kono
parents:
diff changeset
608 are successful. The function returns false upon failure, true upon
kono
parents:
diff changeset
609 success. */
kono
parents:
diff changeset
610
kono
parents:
diff changeset
611 static bool
kono
parents:
diff changeset
612 make_defs_and_copies_lists (rtx_insn *extend_insn, const_rtx set_pat,
kono
parents:
diff changeset
613 ext_state *state)
kono
parents:
diff changeset
614 {
kono
parents:
diff changeset
615 rtx src_reg = XEXP (SET_SRC (set_pat), 0);
kono
parents:
diff changeset
616 bool *is_insn_visited;
kono
parents:
diff changeset
617 bool ret = true;
kono
parents:
diff changeset
618
kono
parents:
diff changeset
619 state->work_list.truncate (0);
kono
parents:
diff changeset
620
kono
parents:
diff changeset
621 /* Initialize the work list. */
kono
parents:
diff changeset
622 if (!get_defs (extend_insn, src_reg, &state->work_list))
kono
parents:
diff changeset
623 return false;
kono
parents:
diff changeset
624
kono
parents:
diff changeset
625 is_insn_visited = XCNEWVEC (bool, max_insn_uid);
kono
parents:
diff changeset
626
kono
parents:
diff changeset
627 /* Perform transitive closure for conditional copies. */
kono
parents:
diff changeset
628 while (!state->work_list.is_empty ())
kono
parents:
diff changeset
629 {
kono
parents:
diff changeset
630 rtx_insn *def_insn = state->work_list.pop ();
kono
parents:
diff changeset
631 rtx reg1, reg2;
kono
parents:
diff changeset
632
kono
parents:
diff changeset
633 gcc_assert (INSN_UID (def_insn) < max_insn_uid);
kono
parents:
diff changeset
634
kono
parents:
diff changeset
635 if (is_insn_visited[INSN_UID (def_insn)])
kono
parents:
diff changeset
636 continue;
kono
parents:
diff changeset
637 is_insn_visited[INSN_UID (def_insn)] = true;
kono
parents:
diff changeset
638
kono
parents:
diff changeset
639 if (is_cond_copy_insn (def_insn, &reg1, &reg2))
kono
parents:
diff changeset
640 {
kono
parents:
diff changeset
641 /* Push it onto the copy list first. */
kono
parents:
diff changeset
642 state->copies_list.safe_push (def_insn);
kono
parents:
diff changeset
643
kono
parents:
diff changeset
644 /* Now perform the transitive closure. */
kono
parents:
diff changeset
645 if (!get_defs (def_insn, reg1, &state->work_list)
kono
parents:
diff changeset
646 || !get_defs (def_insn, reg2, &state->work_list))
kono
parents:
diff changeset
647 {
kono
parents:
diff changeset
648 ret = false;
kono
parents:
diff changeset
649 break;
kono
parents:
diff changeset
650 }
kono
parents:
diff changeset
651 }
kono
parents:
diff changeset
652 else
kono
parents:
diff changeset
653 state->defs_list.safe_push (def_insn);
kono
parents:
diff changeset
654 }
kono
parents:
diff changeset
655
kono
parents:
diff changeset
656 XDELETEVEC (is_insn_visited);
kono
parents:
diff changeset
657
kono
parents:
diff changeset
658 return ret;
kono
parents:
diff changeset
659 }
kono
parents:
diff changeset
660
kono
parents:
diff changeset
661 /* If DEF_INSN has single SET expression, possibly buried inside
kono
parents:
diff changeset
662 a PARALLEL, return the address of the SET expression, else
kono
parents:
diff changeset
663 return NULL. This is similar to single_set, except that
kono
parents:
diff changeset
664 single_set allows multiple SETs when all but one is dead. */
kono
parents:
diff changeset
665 static rtx *
kono
parents:
diff changeset
666 get_sub_rtx (rtx_insn *def_insn)
kono
parents:
diff changeset
667 {
kono
parents:
diff changeset
668 enum rtx_code code = GET_CODE (PATTERN (def_insn));
kono
parents:
diff changeset
669 rtx *sub_rtx = NULL;
kono
parents:
diff changeset
670
kono
parents:
diff changeset
671 if (code == PARALLEL)
kono
parents:
diff changeset
672 {
kono
parents:
diff changeset
673 for (int i = 0; i < XVECLEN (PATTERN (def_insn), 0); i++)
kono
parents:
diff changeset
674 {
kono
parents:
diff changeset
675 rtx s_expr = XVECEXP (PATTERN (def_insn), 0, i);
kono
parents:
diff changeset
676 if (GET_CODE (s_expr) != SET)
kono
parents:
diff changeset
677 continue;
kono
parents:
diff changeset
678
kono
parents:
diff changeset
679 if (sub_rtx == NULL)
kono
parents:
diff changeset
680 sub_rtx = &XVECEXP (PATTERN (def_insn), 0, i);
kono
parents:
diff changeset
681 else
kono
parents:
diff changeset
682 {
kono
parents:
diff changeset
683 /* PARALLEL with multiple SETs. */
kono
parents:
diff changeset
684 return NULL;
kono
parents:
diff changeset
685 }
kono
parents:
diff changeset
686 }
kono
parents:
diff changeset
687 }
kono
parents:
diff changeset
688 else if (code == SET)
kono
parents:
diff changeset
689 sub_rtx = &PATTERN (def_insn);
kono
parents:
diff changeset
690 else
kono
parents:
diff changeset
691 {
kono
parents:
diff changeset
692 /* It is not a PARALLEL or a SET, what could it be ? */
kono
parents:
diff changeset
693 return NULL;
kono
parents:
diff changeset
694 }
kono
parents:
diff changeset
695
kono
parents:
diff changeset
696 gcc_assert (sub_rtx != NULL);
kono
parents:
diff changeset
697 return sub_rtx;
kono
parents:
diff changeset
698 }
kono
parents:
diff changeset
699
kono
parents:
diff changeset
700 /* Merge the DEF_INSN with an extension. Calls combine_set_extension
kono
parents:
diff changeset
701 on the SET pattern. */
kono
parents:
diff changeset
702
kono
parents:
diff changeset
703 static bool
kono
parents:
diff changeset
704 merge_def_and_ext (ext_cand *cand, rtx_insn *def_insn, ext_state *state)
kono
parents:
diff changeset
705 {
kono
parents:
diff changeset
706 machine_mode ext_src_mode;
kono
parents:
diff changeset
707 rtx *sub_rtx;
kono
parents:
diff changeset
708
kono
parents:
diff changeset
709 ext_src_mode = GET_MODE (XEXP (SET_SRC (cand->expr), 0));
kono
parents:
diff changeset
710 sub_rtx = get_sub_rtx (def_insn);
kono
parents:
diff changeset
711
kono
parents:
diff changeset
712 if (sub_rtx == NULL)
kono
parents:
diff changeset
713 return false;
kono
parents:
diff changeset
714
kono
parents:
diff changeset
715 if (REG_P (SET_DEST (*sub_rtx))
kono
parents:
diff changeset
716 && (GET_MODE (SET_DEST (*sub_rtx)) == ext_src_mode
kono
parents:
diff changeset
717 || ((state->modified[INSN_UID (def_insn)].kind
kono
parents:
diff changeset
718 == (cand->code == ZERO_EXTEND
kono
parents:
diff changeset
719 ? EXT_MODIFIED_ZEXT : EXT_MODIFIED_SEXT))
kono
parents:
diff changeset
720 && state->modified[INSN_UID (def_insn)].mode
kono
parents:
diff changeset
721 == ext_src_mode)))
kono
parents:
diff changeset
722 {
kono
parents:
diff changeset
723 if (GET_MODE_UNIT_SIZE (GET_MODE (SET_DEST (*sub_rtx)))
kono
parents:
diff changeset
724 >= GET_MODE_UNIT_SIZE (cand->mode))
kono
parents:
diff changeset
725 return true;
kono
parents:
diff changeset
726 /* If def_insn is already scheduled to be deleted, don't attempt
kono
parents:
diff changeset
727 to modify it. */
kono
parents:
diff changeset
728 if (state->modified[INSN_UID (def_insn)].deleted)
kono
parents:
diff changeset
729 return false;
kono
parents:
diff changeset
730 if (combine_set_extension (cand, def_insn, sub_rtx))
kono
parents:
diff changeset
731 {
kono
parents:
diff changeset
732 if (state->modified[INSN_UID (def_insn)].kind == EXT_MODIFIED_NONE)
kono
parents:
diff changeset
733 state->modified[INSN_UID (def_insn)].mode = ext_src_mode;
kono
parents:
diff changeset
734 return true;
kono
parents:
diff changeset
735 }
kono
parents:
diff changeset
736 }
kono
parents:
diff changeset
737
kono
parents:
diff changeset
738 return false;
kono
parents:
diff changeset
739 }
kono
parents:
diff changeset
740
kono
parents:
diff changeset
741 /* Given SRC, which should be one or more extensions of a REG, strip
kono
parents:
diff changeset
742 away the extensions and return the REG. */
kono
parents:
diff changeset
743
kono
parents:
diff changeset
744 static inline rtx
kono
parents:
diff changeset
745 get_extended_src_reg (rtx src)
kono
parents:
diff changeset
746 {
kono
parents:
diff changeset
747 while (GET_CODE (src) == SIGN_EXTEND || GET_CODE (src) == ZERO_EXTEND)
kono
parents:
diff changeset
748 src = XEXP (src, 0);
kono
parents:
diff changeset
749 gcc_assert (REG_P (src));
kono
parents:
diff changeset
750 return src;
kono
parents:
diff changeset
751 }
kono
parents:
diff changeset
752
kono
parents:
diff changeset
753 /* This function goes through all reaching defs of the source
kono
parents:
diff changeset
754 of the candidate for elimination (CAND) and tries to combine
kono
parents:
diff changeset
755 the extension with the definition instruction. The changes
kono
parents:
diff changeset
756 are made as a group so that even if one definition cannot be
kono
parents:
diff changeset
757 merged, all reaching definitions end up not being merged.
kono
parents:
diff changeset
758 When a conditional copy is encountered, merging is attempted
kono
parents:
diff changeset
759 transitively on its definitions. It returns true upon success
kono
parents:
diff changeset
760 and false upon failure. */
kono
parents:
diff changeset
761
kono
parents:
diff changeset
762 static bool
kono
parents:
diff changeset
763 combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
kono
parents:
diff changeset
764 {
kono
parents:
diff changeset
765 rtx_insn *def_insn;
kono
parents:
diff changeset
766 bool merge_successful = true;
kono
parents:
diff changeset
767 int i;
kono
parents:
diff changeset
768 int defs_ix;
kono
parents:
diff changeset
769 bool outcome;
kono
parents:
diff changeset
770
kono
parents:
diff changeset
771 state->defs_list.truncate (0);
kono
parents:
diff changeset
772 state->copies_list.truncate (0);
kono
parents:
diff changeset
773
kono
parents:
diff changeset
774 outcome = make_defs_and_copies_lists (cand->insn, set_pat, state);
kono
parents:
diff changeset
775
kono
parents:
diff changeset
776 if (!outcome)
kono
parents:
diff changeset
777 return false;
kono
parents:
diff changeset
778
kono
parents:
diff changeset
779 /* If the destination operand of the extension is a different
kono
parents:
diff changeset
780 register than the source operand, then additional restrictions
kono
parents:
diff changeset
781 are needed. Note we have to handle cases where we have nested
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
782 extensions in the source operand.
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
783
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
784 Candidate insns are known to be single_sets, via the test in
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
785 find_removable_extensions. So we continue to use single_set here
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
786 rather than get_sub_rtx. */
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
787 rtx set = single_set (cand->insn);
111
kono
parents:
diff changeset
788 bool copy_needed
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
789 = (REGNO (SET_DEST (set)) != REGNO (get_extended_src_reg (SET_SRC (set))));
111
kono
parents:
diff changeset
790 if (copy_needed)
kono
parents:
diff changeset
791 {
kono
parents:
diff changeset
792 /* Considering transformation of
kono
parents:
diff changeset
793 (set (reg1) (expression))
kono
parents:
diff changeset
794 ...
kono
parents:
diff changeset
795 (set (reg2) (any_extend (reg1)))
kono
parents:
diff changeset
796
kono
parents:
diff changeset
797 into
kono
parents:
diff changeset
798
kono
parents:
diff changeset
799 (set (reg2) (any_extend (expression)))
kono
parents:
diff changeset
800 (set (reg1) (reg2))
kono
parents:
diff changeset
801 ... */
kono
parents:
diff changeset
802
kono
parents:
diff changeset
803 /* In theory we could handle more than one reaching def, it
kono
parents:
diff changeset
804 just makes the code to update the insn stream more complex. */
kono
parents:
diff changeset
805 if (state->defs_list.length () != 1)
kono
parents:
diff changeset
806 return false;
kono
parents:
diff changeset
807
kono
parents:
diff changeset
808 /* We don't have the structure described above if there are
kono
parents:
diff changeset
809 conditional moves in between the def and the candidate,
kono
parents:
diff changeset
810 and we will not handle them correctly. See PR68194. */
kono
parents:
diff changeset
811 if (state->copies_list.length () > 0)
kono
parents:
diff changeset
812 return false;
kono
parents:
diff changeset
813
kono
parents:
diff changeset
814 /* We require the candidate not already be modified. It may,
kono
parents:
diff changeset
815 for example have been changed from a (sign_extend (reg))
kono
parents:
diff changeset
816 into (zero_extend (sign_extend (reg))).
kono
parents:
diff changeset
817
kono
parents:
diff changeset
818 Handling that case shouldn't be terribly difficult, but the code
kono
parents:
diff changeset
819 here and the code to emit copies would need auditing. Until
kono
parents:
diff changeset
820 we see a need, this is the safe thing to do. */
kono
parents:
diff changeset
821 if (state->modified[INSN_UID (cand->insn)].kind != EXT_MODIFIED_NONE)
kono
parents:
diff changeset
822 return false;
kono
parents:
diff changeset
823
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
824 machine_mode dst_mode = GET_MODE (SET_DEST (set));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
825 rtx src_reg = get_extended_src_reg (SET_SRC (set));
111
kono
parents:
diff changeset
826
kono
parents:
diff changeset
827 /* Ensure we can use the src_reg in dst_mode (needed for
kono
parents:
diff changeset
828 the (set (reg1) (reg2)) insn mentioned above). */
kono
parents:
diff changeset
829 if (!targetm.hard_regno_mode_ok (REGNO (src_reg), dst_mode))
kono
parents:
diff changeset
830 return false;
kono
parents:
diff changeset
831
kono
parents:
diff changeset
832 /* Ensure the number of hard registers of the copy match. */
kono
parents:
diff changeset
833 if (hard_regno_nregs (REGNO (src_reg), dst_mode) != REG_NREGS (src_reg))
kono
parents:
diff changeset
834 return false;
kono
parents:
diff changeset
835
kono
parents:
diff changeset
836 /* There's only one reaching def. */
kono
parents:
diff changeset
837 rtx_insn *def_insn = state->defs_list[0];
kono
parents:
diff changeset
838
kono
parents:
diff changeset
839 /* The defining statement must not have been modified either. */
kono
parents:
diff changeset
840 if (state->modified[INSN_UID (def_insn)].kind != EXT_MODIFIED_NONE)
kono
parents:
diff changeset
841 return false;
kono
parents:
diff changeset
842
kono
parents:
diff changeset
843 /* The defining statement and candidate insn must be in the same block.
kono
parents:
diff changeset
844 This is merely to keep the test for safety and updating the insn
kono
parents:
diff changeset
845 stream simple. Also ensure that within the block the candidate
kono
parents:
diff changeset
846 follows the defining insn. */
kono
parents:
diff changeset
847 basic_block bb = BLOCK_FOR_INSN (cand->insn);
kono
parents:
diff changeset
848 if (bb != BLOCK_FOR_INSN (def_insn)
kono
parents:
diff changeset
849 || DF_INSN_LUID (def_insn) > DF_INSN_LUID (cand->insn))
kono
parents:
diff changeset
850 return false;
kono
parents:
diff changeset
851
kono
parents:
diff changeset
852 /* If there is an overlap between the destination of DEF_INSN and
kono
parents:
diff changeset
853 CAND->insn, then this transformation is not safe. Note we have
kono
parents:
diff changeset
854 to test in the widened mode. */
kono
parents:
diff changeset
855 rtx *dest_sub_rtx = get_sub_rtx (def_insn);
kono
parents:
diff changeset
856 if (dest_sub_rtx == NULL
kono
parents:
diff changeset
857 || !REG_P (SET_DEST (*dest_sub_rtx)))
kono
parents:
diff changeset
858 return false;
kono
parents:
diff changeset
859
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
860 rtx tmp_reg = gen_rtx_REG (GET_MODE (SET_DEST (set)),
111
kono
parents:
diff changeset
861 REGNO (SET_DEST (*dest_sub_rtx)));
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
862 if (reg_overlap_mentioned_p (tmp_reg, SET_DEST (set)))
111
kono
parents:
diff changeset
863 return false;
kono
parents:
diff changeset
864
kono
parents:
diff changeset
865 /* On RISC machines we must make sure that changing the mode of SRC_REG
kono
parents:
diff changeset
866 as destination register will not affect its reaching uses, which may
kono
parents:
diff changeset
867 read its value in a larger mode because DEF_INSN implicitly sets it
kono
parents:
diff changeset
868 in word mode. */
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
869 poly_int64 prec
111
kono
parents:
diff changeset
870 = GET_MODE_PRECISION (GET_MODE (SET_DEST (*dest_sub_rtx)));
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
871 if (WORD_REGISTER_OPERATIONS && known_lt (prec, BITS_PER_WORD))
111
kono
parents:
diff changeset
872 {
kono
parents:
diff changeset
873 struct df_link *uses = get_uses (def_insn, src_reg);
kono
parents:
diff changeset
874 if (!uses)
kono
parents:
diff changeset
875 return false;
kono
parents:
diff changeset
876
kono
parents:
diff changeset
877 for (df_link *use = uses; use; use = use->next)
kono
parents:
diff changeset
878 if (paradoxical_subreg_p (GET_MODE (*DF_REF_LOC (use->ref)),
kono
parents:
diff changeset
879 GET_MODE (SET_DEST (*dest_sub_rtx))))
kono
parents:
diff changeset
880 return false;
kono
parents:
diff changeset
881 }
kono
parents:
diff changeset
882
kono
parents:
diff changeset
883 /* The destination register of the extension insn must not be
kono
parents:
diff changeset
884 used or set between the def_insn and cand->insn exclusive. */
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
885 if (reg_used_between_p (SET_DEST (set), def_insn, cand->insn)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
886 || reg_set_between_p (SET_DEST (set), def_insn, cand->insn))
111
kono
parents:
diff changeset
887 return false;
kono
parents:
diff changeset
888
kono
parents:
diff changeset
889 /* We must be able to copy between the two registers. Generate,
kono
parents:
diff changeset
890 recognize and verify constraints of the copy. Also fail if this
kono
parents:
diff changeset
891 generated more than one insn.
kono
parents:
diff changeset
892
kono
parents:
diff changeset
893 This generates garbage since we throw away the insn when we're
kono
parents:
diff changeset
894 done, only to recreate it later if this test was successful.
kono
parents:
diff changeset
895
kono
parents:
diff changeset
896 Make sure to get the mode from the extension (cand->insn). This
kono
parents:
diff changeset
897 is different than in the code to emit the copy as we have not
kono
parents:
diff changeset
898 modified the defining insn yet. */
kono
parents:
diff changeset
899 start_sequence ();
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
900 rtx new_dst = gen_rtx_REG (GET_MODE (SET_DEST (set)),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
901 REGNO (get_extended_src_reg (SET_SRC (set))));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
902 rtx new_src = gen_rtx_REG (GET_MODE (SET_DEST (set)),
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
903 REGNO (SET_DEST (set)));
111
kono
parents:
diff changeset
904 emit_move_insn (new_dst, new_src);
kono
parents:
diff changeset
905
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
906 rtx_insn *insn = get_insns ();
111
kono
parents:
diff changeset
907 end_sequence ();
kono
parents:
diff changeset
908 if (NEXT_INSN (insn))
kono
parents:
diff changeset
909 return false;
kono
parents:
diff changeset
910 if (recog_memoized (insn) == -1)
kono
parents:
diff changeset
911 return false;
kono
parents:
diff changeset
912 extract_insn (insn);
kono
parents:
diff changeset
913 if (!constrain_operands (1, get_preferred_alternatives (insn, bb)))
kono
parents:
diff changeset
914 return false;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
915
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
916 while (REG_P (SET_SRC (*dest_sub_rtx))
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
917 && (REGNO (SET_SRC (*dest_sub_rtx)) == REGNO (SET_DEST (set))))
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
918 {
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
919 /* Considering transformation of
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
920 (set (reg2) (expression))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
921 ...
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
922 (set (reg1) (reg2))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
923 ...
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
924 (set (reg2) (any_extend (reg1)))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
925
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
926 into
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
927
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
928 (set (reg2) (any_extend (expression)))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
929 (set (reg1) (reg2))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
930 ... */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
931 struct df_link *defs
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
932 = get_defs (def_insn, SET_SRC (*dest_sub_rtx), NULL);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
933 if (defs == NULL || defs->next)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
934 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
935
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
936 /* There is only one reaching def. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
937 rtx_insn *def_insn2 = DF_REF_INSN (defs->ref);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
938
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
939 /* The defining statement must not have been modified either. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
940 if (state->modified[INSN_UID (def_insn2)].kind != EXT_MODIFIED_NONE)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
941 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
942
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
943 /* The def_insn2 and candidate insn must be in the same
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
944 block and def_insn follows def_insn2. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
945 if (bb != BLOCK_FOR_INSN (def_insn2)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
946 || DF_INSN_LUID (def_insn2) > DF_INSN_LUID (def_insn))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
947 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
948
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
949 rtx *dest_sub_rtx2 = get_sub_rtx (def_insn2);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
950 if (dest_sub_rtx2 == NULL
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
951 || !REG_P (SET_DEST (*dest_sub_rtx2)))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
952 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
953
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
954 /* On RISC machines we must make sure that changing the mode of
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
955 SRC_REG as destination register will not affect its reaching
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
956 uses, which may read its value in a larger mode because DEF_INSN
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
957 implicitly sets it in word mode. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
958 if (WORD_REGISTER_OPERATIONS && known_lt (prec, BITS_PER_WORD))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
959 {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
960 struct df_link *uses = get_uses (def_insn2, SET_DEST (set));
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
961 if (!uses)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
962 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
963
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
964 df_link *use;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
965 rtx dest2 = SET_DEST (*dest_sub_rtx2);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
966 for (use = uses; use; use = use->next)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
967 if (paradoxical_subreg_p (GET_MODE (*DF_REF_LOC (use->ref)),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
968 GET_MODE (dest2)))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
969 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
970 if (use)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
971 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
972 }
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
973
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
974 /* The destination register of the extension insn must not be
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
975 used or set between the def_insn2 and def_insn exclusive.
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
976 Likewise for the other reg, i.e. check both reg1 and reg2
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
977 in the above comment. */
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
978 if (reg_used_between_p (SET_DEST (set), def_insn2, def_insn)
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
979 || reg_set_between_p (SET_DEST (set), def_insn2, def_insn)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
980 || reg_used_between_p (src_reg, def_insn2, def_insn)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
981 || reg_set_between_p (src_reg, def_insn2, def_insn))
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
982 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
983
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
984 state->defs_list[0] = def_insn2;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
985 break;
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
986 }
111
kono
parents:
diff changeset
987 }
kono
parents:
diff changeset
988
kono
parents:
diff changeset
989 /* If cand->insn has been already modified, update cand->mode to a wider
kono
parents:
diff changeset
990 mode if possible, or punt. */
kono
parents:
diff changeset
991 if (state->modified[INSN_UID (cand->insn)].kind != EXT_MODIFIED_NONE)
kono
parents:
diff changeset
992 {
kono
parents:
diff changeset
993 machine_mode mode;
kono
parents:
diff changeset
994
kono
parents:
diff changeset
995 if (state->modified[INSN_UID (cand->insn)].kind
kono
parents:
diff changeset
996 != (cand->code == ZERO_EXTEND
kono
parents:
diff changeset
997 ? EXT_MODIFIED_ZEXT : EXT_MODIFIED_SEXT)
kono
parents:
diff changeset
998 || state->modified[INSN_UID (cand->insn)].mode != cand->mode
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
999 || (set == NULL_RTX))
111
kono
parents:
diff changeset
1000 return false;
kono
parents:
diff changeset
1001 mode = GET_MODE (SET_DEST (set));
kono
parents:
diff changeset
1002 gcc_assert (GET_MODE_UNIT_SIZE (mode)
kono
parents:
diff changeset
1003 >= GET_MODE_UNIT_SIZE (cand->mode));
kono
parents:
diff changeset
1004 cand->mode = mode;
kono
parents:
diff changeset
1005 }
kono
parents:
diff changeset
1006
kono
parents:
diff changeset
1007 merge_successful = true;
kono
parents:
diff changeset
1008
kono
parents:
diff changeset
1009 /* Go through the defs vector and try to merge all the definitions
kono
parents:
diff changeset
1010 in this vector. */
kono
parents:
diff changeset
1011 state->modified_list.truncate (0);
kono
parents:
diff changeset
1012 FOR_EACH_VEC_ELT (state->defs_list, defs_ix, def_insn)
kono
parents:
diff changeset
1013 {
kono
parents:
diff changeset
1014 if (merge_def_and_ext (cand, def_insn, state))
kono
parents:
diff changeset
1015 state->modified_list.safe_push (def_insn);
kono
parents:
diff changeset
1016 else
kono
parents:
diff changeset
1017 {
kono
parents:
diff changeset
1018 merge_successful = false;
kono
parents:
diff changeset
1019 break;
kono
parents:
diff changeset
1020 }
kono
parents:
diff changeset
1021 }
kono
parents:
diff changeset
1022
kono
parents:
diff changeset
1023 /* Now go through the conditional copies vector and try to merge all
kono
parents:
diff changeset
1024 the copies in this vector. */
kono
parents:
diff changeset
1025 if (merge_successful)
kono
parents:
diff changeset
1026 {
kono
parents:
diff changeset
1027 FOR_EACH_VEC_ELT (state->copies_list, i, def_insn)
kono
parents:
diff changeset
1028 {
kono
parents:
diff changeset
1029 if (transform_ifelse (cand, def_insn))
kono
parents:
diff changeset
1030 state->modified_list.safe_push (def_insn);
kono
parents:
diff changeset
1031 else
kono
parents:
diff changeset
1032 {
kono
parents:
diff changeset
1033 merge_successful = false;
kono
parents:
diff changeset
1034 break;
kono
parents:
diff changeset
1035 }
kono
parents:
diff changeset
1036 }
kono
parents:
diff changeset
1037 }
kono
parents:
diff changeset
1038
kono
parents:
diff changeset
1039 if (merge_successful)
kono
parents:
diff changeset
1040 {
kono
parents:
diff changeset
1041 /* Commit the changes here if possible
kono
parents:
diff changeset
1042 FIXME: It's an all-or-nothing scenario. Even if only one definition
kono
parents:
diff changeset
1043 cannot be merged, we entirely give up. In the future, we should allow
kono
parents:
diff changeset
1044 extensions to be partially eliminated along those paths where the
kono
parents:
diff changeset
1045 definitions could be merged. */
kono
parents:
diff changeset
1046 if (apply_change_group ())
kono
parents:
diff changeset
1047 {
kono
parents:
diff changeset
1048 if (dump_file)
kono
parents:
diff changeset
1049 fprintf (dump_file, "All merges were successful.\n");
kono
parents:
diff changeset
1050
kono
parents:
diff changeset
1051 FOR_EACH_VEC_ELT (state->modified_list, i, def_insn)
kono
parents:
diff changeset
1052 {
kono
parents:
diff changeset
1053 ext_modified *modified = &state->modified[INSN_UID (def_insn)];
kono
parents:
diff changeset
1054 if (modified->kind == EXT_MODIFIED_NONE)
kono
parents:
diff changeset
1055 modified->kind = (cand->code == ZERO_EXTEND ? EXT_MODIFIED_ZEXT
kono
parents:
diff changeset
1056 : EXT_MODIFIED_SEXT);
kono
parents:
diff changeset
1057
kono
parents:
diff changeset
1058 if (copy_needed)
kono
parents:
diff changeset
1059 modified->do_not_reextend = 1;
kono
parents:
diff changeset
1060 }
kono
parents:
diff changeset
1061 return true;
kono
parents:
diff changeset
1062 }
kono
parents:
diff changeset
1063 else
kono
parents:
diff changeset
1064 {
kono
parents:
diff changeset
1065 /* Changes need not be cancelled explicitly as apply_change_group
kono
parents:
diff changeset
1066 does it. Print list of definitions in the dump_file for debug
kono
parents:
diff changeset
1067 purposes. This extension cannot be deleted. */
kono
parents:
diff changeset
1068 if (dump_file)
kono
parents:
diff changeset
1069 {
kono
parents:
diff changeset
1070 fprintf (dump_file,
kono
parents:
diff changeset
1071 "Merge cancelled, non-mergeable definitions:\n");
kono
parents:
diff changeset
1072 FOR_EACH_VEC_ELT (state->modified_list, i, def_insn)
kono
parents:
diff changeset
1073 print_rtl_single (dump_file, def_insn);
kono
parents:
diff changeset
1074 }
kono
parents:
diff changeset
1075 }
kono
parents:
diff changeset
1076 }
kono
parents:
diff changeset
1077 else
kono
parents:
diff changeset
1078 {
kono
parents:
diff changeset
1079 /* Cancel any changes that have been made so far. */
kono
parents:
diff changeset
1080 cancel_changes (0);
kono
parents:
diff changeset
1081 }
kono
parents:
diff changeset
1082
kono
parents:
diff changeset
1083 return false;
kono
parents:
diff changeset
1084 }
kono
parents:
diff changeset
1085
kono
parents:
diff changeset
1086 /* Add an extension pattern that could be eliminated. */
kono
parents:
diff changeset
1087
kono
parents:
diff changeset
1088 static void
kono
parents:
diff changeset
1089 add_removable_extension (const_rtx expr, rtx_insn *insn,
kono
parents:
diff changeset
1090 vec<ext_cand> *insn_list,
kono
parents:
diff changeset
1091 unsigned *def_map,
kono
parents:
diff changeset
1092 bitmap init_regs)
kono
parents:
diff changeset
1093 {
kono
parents:
diff changeset
1094 enum rtx_code code;
kono
parents:
diff changeset
1095 machine_mode mode;
kono
parents:
diff changeset
1096 unsigned int idx;
kono
parents:
diff changeset
1097 rtx src, dest;
kono
parents:
diff changeset
1098
kono
parents:
diff changeset
1099 /* We are looking for SET (REG N) (ANY_EXTEND (REG N)). */
kono
parents:
diff changeset
1100 if (GET_CODE (expr) != SET)
kono
parents:
diff changeset
1101 return;
kono
parents:
diff changeset
1102
kono
parents:
diff changeset
1103 src = SET_SRC (expr);
kono
parents:
diff changeset
1104 code = GET_CODE (src);
kono
parents:
diff changeset
1105 dest = SET_DEST (expr);
kono
parents:
diff changeset
1106 mode = GET_MODE (dest);
kono
parents:
diff changeset
1107
kono
parents:
diff changeset
1108 if (REG_P (dest)
kono
parents:
diff changeset
1109 && (code == SIGN_EXTEND || code == ZERO_EXTEND)
kono
parents:
diff changeset
1110 && REG_P (XEXP (src, 0)))
kono
parents:
diff changeset
1111 {
kono
parents:
diff changeset
1112 rtx reg = XEXP (src, 0);
kono
parents:
diff changeset
1113 struct df_link *defs, *def;
kono
parents:
diff changeset
1114 ext_cand *cand;
kono
parents:
diff changeset
1115
kono
parents:
diff changeset
1116 /* Zero-extension of an undefined value is partly defined (it's
kono
parents:
diff changeset
1117 completely undefined for sign-extension, though). So if there exists
kono
parents:
diff changeset
1118 a path from the entry to this zero-extension that leaves this register
kono
parents:
diff changeset
1119 uninitialized, removing the extension could change the behavior of
kono
parents:
diff changeset
1120 correct programs. So first, check it is not the case. */
kono
parents:
diff changeset
1121 if (code == ZERO_EXTEND && !bitmap_bit_p (init_regs, REGNO (reg)))
kono
parents:
diff changeset
1122 {
kono
parents:
diff changeset
1123 if (dump_file)
kono
parents:
diff changeset
1124 {
kono
parents:
diff changeset
1125 fprintf (dump_file, "Cannot eliminate extension:\n");
kono
parents:
diff changeset
1126 print_rtl_single (dump_file, insn);
kono
parents:
diff changeset
1127 fprintf (dump_file, " because it can operate on uninitialized"
kono
parents:
diff changeset
1128 " data\n");
kono
parents:
diff changeset
1129 }
kono
parents:
diff changeset
1130 return;
kono
parents:
diff changeset
1131 }
kono
parents:
diff changeset
1132
kono
parents:
diff changeset
1133 /* Second, make sure we can get all the reaching definitions. */
kono
parents:
diff changeset
1134 defs = get_defs (insn, reg, NULL);
kono
parents:
diff changeset
1135 if (!defs)
kono
parents:
diff changeset
1136 {
kono
parents:
diff changeset
1137 if (dump_file)
kono
parents:
diff changeset
1138 {
kono
parents:
diff changeset
1139 fprintf (dump_file, "Cannot eliminate extension:\n");
kono
parents:
diff changeset
1140 print_rtl_single (dump_file, insn);
kono
parents:
diff changeset
1141 fprintf (dump_file, " because of missing definition(s)\n");
kono
parents:
diff changeset
1142 }
kono
parents:
diff changeset
1143 return;
kono
parents:
diff changeset
1144 }
kono
parents:
diff changeset
1145
kono
parents:
diff changeset
1146 /* Third, make sure the reaching definitions don't feed another and
kono
parents:
diff changeset
1147 different extension. FIXME: this obviously can be improved. */
kono
parents:
diff changeset
1148 for (def = defs; def; def = def->next)
kono
parents:
diff changeset
1149 if ((idx = def_map[INSN_UID (DF_REF_INSN (def->ref))])
kono
parents:
diff changeset
1150 && idx != -1U
kono
parents:
diff changeset
1151 && (cand = &(*insn_list)[idx - 1])
kono
parents:
diff changeset
1152 && cand->code != code)
kono
parents:
diff changeset
1153 {
kono
parents:
diff changeset
1154 if (dump_file)
kono
parents:
diff changeset
1155 {
kono
parents:
diff changeset
1156 fprintf (dump_file, "Cannot eliminate extension:\n");
kono
parents:
diff changeset
1157 print_rtl_single (dump_file, insn);
kono
parents:
diff changeset
1158 fprintf (dump_file, " because of other extension\n");
kono
parents:
diff changeset
1159 }
kono
parents:
diff changeset
1160 return;
kono
parents:
diff changeset
1161 }
kono
parents:
diff changeset
1162 /* For vector mode extensions, ensure that all uses of the
kono
parents:
diff changeset
1163 XEXP (src, 0) register are in insn or debug insns, as unlike
kono
parents:
diff changeset
1164 integral extensions lowpart subreg of the sign/zero extended
kono
parents:
diff changeset
1165 register are not equal to the original register, so we have
kono
parents:
diff changeset
1166 to change all uses or none and the current code isn't able
kono
parents:
diff changeset
1167 to change them all at once in one transaction. */
kono
parents:
diff changeset
1168 else if (VECTOR_MODE_P (GET_MODE (XEXP (src, 0))))
kono
parents:
diff changeset
1169 {
kono
parents:
diff changeset
1170 if (idx == 0)
kono
parents:
diff changeset
1171 {
kono
parents:
diff changeset
1172 struct df_link *ref_chain, *ref_link;
kono
parents:
diff changeset
1173
kono
parents:
diff changeset
1174 ref_chain = DF_REF_CHAIN (def->ref);
kono
parents:
diff changeset
1175 for (ref_link = ref_chain; ref_link; ref_link = ref_link->next)
kono
parents:
diff changeset
1176 {
kono
parents:
diff changeset
1177 if (ref_link->ref == NULL
kono
parents:
diff changeset
1178 || DF_REF_INSN_INFO (ref_link->ref) == NULL)
kono
parents:
diff changeset
1179 {
kono
parents:
diff changeset
1180 idx = -1U;
kono
parents:
diff changeset
1181 break;
kono
parents:
diff changeset
1182 }
kono
parents:
diff changeset
1183 rtx_insn *use_insn = DF_REF_INSN (ref_link->ref);
kono
parents:
diff changeset
1184 if (use_insn != insn && !DEBUG_INSN_P (use_insn))
kono
parents:
diff changeset
1185 {
kono
parents:
diff changeset
1186 idx = -1U;
kono
parents:
diff changeset
1187 break;
kono
parents:
diff changeset
1188 }
kono
parents:
diff changeset
1189 }
kono
parents:
diff changeset
1190 if (idx == -1U)
kono
parents:
diff changeset
1191 def_map[INSN_UID (DF_REF_INSN (def->ref))] = idx;
kono
parents:
diff changeset
1192 }
kono
parents:
diff changeset
1193 if (idx == -1U)
kono
parents:
diff changeset
1194 {
kono
parents:
diff changeset
1195 if (dump_file)
kono
parents:
diff changeset
1196 {
kono
parents:
diff changeset
1197 fprintf (dump_file, "Cannot eliminate extension:\n");
kono
parents:
diff changeset
1198 print_rtl_single (dump_file, insn);
kono
parents:
diff changeset
1199 fprintf (dump_file,
kono
parents:
diff changeset
1200 " because some vector uses aren't extension\n");
kono
parents:
diff changeset
1201 }
kono
parents:
diff changeset
1202 return;
kono
parents:
diff changeset
1203 }
kono
parents:
diff changeset
1204 }
kono
parents:
diff changeset
1205
kono
parents:
diff changeset
1206 /* Fourth, if the extended version occupies more registers than the
kono
parents:
diff changeset
1207 original and the source of the extension is the same hard register
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1208 as the destination of the extension, then we cannot eliminate
111
kono
parents:
diff changeset
1209 the extension without deep analysis, so just punt.
kono
parents:
diff changeset
1210
kono
parents:
diff changeset
1211 We allow this when the registers are different because the
kono
parents:
diff changeset
1212 code in combine_reaching_defs will handle that case correctly. */
kono
parents:
diff changeset
1213 if (hard_regno_nregs (REGNO (dest), mode) != REG_NREGS (reg)
kono
parents:
diff changeset
1214 && reg_overlap_mentioned_p (dest, reg))
kono
parents:
diff changeset
1215 return;
kono
parents:
diff changeset
1216
kono
parents:
diff changeset
1217 /* Then add the candidate to the list and insert the reaching definitions
kono
parents:
diff changeset
1218 into the definition map. */
kono
parents:
diff changeset
1219 ext_cand e = {expr, code, mode, insn};
kono
parents:
diff changeset
1220 insn_list->safe_push (e);
kono
parents:
diff changeset
1221 idx = insn_list->length ();
kono
parents:
diff changeset
1222
kono
parents:
diff changeset
1223 for (def = defs; def; def = def->next)
kono
parents:
diff changeset
1224 def_map[INSN_UID (DF_REF_INSN (def->ref))] = idx;
kono
parents:
diff changeset
1225 }
kono
parents:
diff changeset
1226 }
kono
parents:
diff changeset
1227
kono
parents:
diff changeset
1228 /* Traverse the instruction stream looking for extensions and return the
kono
parents:
diff changeset
1229 list of candidates. */
kono
parents:
diff changeset
1230
kono
parents:
diff changeset
1231 static vec<ext_cand>
kono
parents:
diff changeset
1232 find_removable_extensions (void)
kono
parents:
diff changeset
1233 {
kono
parents:
diff changeset
1234 vec<ext_cand> insn_list = vNULL;
kono
parents:
diff changeset
1235 basic_block bb;
kono
parents:
diff changeset
1236 rtx_insn *insn;
kono
parents:
diff changeset
1237 rtx set;
kono
parents:
diff changeset
1238 unsigned *def_map = XCNEWVEC (unsigned, max_insn_uid);
kono
parents:
diff changeset
1239 bitmap_head init, kill, gen, tmp;
kono
parents:
diff changeset
1240
kono
parents:
diff changeset
1241 bitmap_initialize (&init, NULL);
kono
parents:
diff changeset
1242 bitmap_initialize (&kill, NULL);
kono
parents:
diff changeset
1243 bitmap_initialize (&gen, NULL);
kono
parents:
diff changeset
1244 bitmap_initialize (&tmp, NULL);
kono
parents:
diff changeset
1245
kono
parents:
diff changeset
1246 FOR_EACH_BB_FN (bb, cfun)
kono
parents:
diff changeset
1247 {
kono
parents:
diff changeset
1248 bitmap_copy (&init, DF_MIR_IN (bb));
kono
parents:
diff changeset
1249 bitmap_clear (&kill);
kono
parents:
diff changeset
1250 bitmap_clear (&gen);
kono
parents:
diff changeset
1251
kono
parents:
diff changeset
1252 FOR_BB_INSNS (bb, insn)
kono
parents:
diff changeset
1253 {
kono
parents:
diff changeset
1254 if (NONDEBUG_INSN_P (insn))
kono
parents:
diff changeset
1255 {
kono
parents:
diff changeset
1256 set = single_set (insn);
kono
parents:
diff changeset
1257 if (set != NULL_RTX)
kono
parents:
diff changeset
1258 add_removable_extension (set, insn, &insn_list, def_map,
kono
parents:
diff changeset
1259 &init);
kono
parents:
diff changeset
1260 df_mir_simulate_one_insn (bb, insn, &kill, &gen);
kono
parents:
diff changeset
1261 bitmap_ior_and_compl (&tmp, &gen, &init, &kill);
kono
parents:
diff changeset
1262 bitmap_copy (&init, &tmp);
kono
parents:
diff changeset
1263 }
kono
parents:
diff changeset
1264 }
kono
parents:
diff changeset
1265 }
kono
parents:
diff changeset
1266
kono
parents:
diff changeset
1267 XDELETEVEC (def_map);
kono
parents:
diff changeset
1268
kono
parents:
diff changeset
1269 return insn_list;
kono
parents:
diff changeset
1270 }
kono
parents:
diff changeset
1271
kono
parents:
diff changeset
1272 /* This is the main function that checks the insn stream for redundant
kono
parents:
diff changeset
1273 extensions and tries to remove them if possible. */
kono
parents:
diff changeset
1274
kono
parents:
diff changeset
1275 static void
kono
parents:
diff changeset
1276 find_and_remove_re (void)
kono
parents:
diff changeset
1277 {
kono
parents:
diff changeset
1278 ext_cand *curr_cand;
kono
parents:
diff changeset
1279 rtx_insn *curr_insn = NULL;
kono
parents:
diff changeset
1280 int num_re_opportunities = 0, num_realized = 0, i;
kono
parents:
diff changeset
1281 vec<ext_cand> reinsn_list;
kono
parents:
diff changeset
1282 auto_vec<rtx_insn *> reinsn_del_list;
kono
parents:
diff changeset
1283 auto_vec<rtx_insn *> reinsn_copy_list;
kono
parents:
diff changeset
1284
kono
parents:
diff changeset
1285 /* Construct DU chain to get all reaching definitions of each
kono
parents:
diff changeset
1286 extension instruction. */
kono
parents:
diff changeset
1287 df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
kono
parents:
diff changeset
1288 df_chain_add_problem (DF_UD_CHAIN + DF_DU_CHAIN);
kono
parents:
diff changeset
1289 df_mir_add_problem ();
kono
parents:
diff changeset
1290 df_analyze ();
kono
parents:
diff changeset
1291 df_set_flags (DF_DEFER_INSN_RESCAN);
kono
parents:
diff changeset
1292
kono
parents:
diff changeset
1293 max_insn_uid = get_max_uid ();
kono
parents:
diff changeset
1294 reinsn_list = find_removable_extensions ();
kono
parents:
diff changeset
1295
kono
parents:
diff changeset
1296 ext_state state;
kono
parents:
diff changeset
1297 if (reinsn_list.is_empty ())
kono
parents:
diff changeset
1298 state.modified = NULL;
kono
parents:
diff changeset
1299 else
kono
parents:
diff changeset
1300 state.modified = XCNEWVEC (struct ext_modified, max_insn_uid);
kono
parents:
diff changeset
1301
kono
parents:
diff changeset
1302 FOR_EACH_VEC_ELT (reinsn_list, i, curr_cand)
kono
parents:
diff changeset
1303 {
kono
parents:
diff changeset
1304 num_re_opportunities++;
kono
parents:
diff changeset
1305
kono
parents:
diff changeset
1306 /* Try to combine the extension with the definition. */
kono
parents:
diff changeset
1307 if (dump_file)
kono
parents:
diff changeset
1308 {
kono
parents:
diff changeset
1309 fprintf (dump_file, "Trying to eliminate extension:\n");
kono
parents:
diff changeset
1310 print_rtl_single (dump_file, curr_cand->insn);
kono
parents:
diff changeset
1311 }
kono
parents:
diff changeset
1312
kono
parents:
diff changeset
1313 if (combine_reaching_defs (curr_cand, curr_cand->expr, &state))
kono
parents:
diff changeset
1314 {
kono
parents:
diff changeset
1315 if (dump_file)
kono
parents:
diff changeset
1316 fprintf (dump_file, "Eliminated the extension.\n");
kono
parents:
diff changeset
1317 num_realized++;
kono
parents:
diff changeset
1318 /* If the RHS of the current candidate is not (extend (reg)), then
kono
parents:
diff changeset
1319 we do not allow the optimization of extensions where
kono
parents:
diff changeset
1320 the source and destination registers do not match. Thus
kono
parents:
diff changeset
1321 checking REG_P here is correct. */
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1322 rtx set = single_set (curr_cand->insn);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1323 if (REG_P (XEXP (SET_SRC (set), 0))
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1324 && (REGNO (SET_DEST (set)) != REGNO (XEXP (SET_SRC (set), 0))))
111
kono
parents:
diff changeset
1325 {
kono
parents:
diff changeset
1326 reinsn_copy_list.safe_push (curr_cand->insn);
kono
parents:
diff changeset
1327 reinsn_copy_list.safe_push (state.defs_list[0]);
kono
parents:
diff changeset
1328 }
kono
parents:
diff changeset
1329 reinsn_del_list.safe_push (curr_cand->insn);
kono
parents:
diff changeset
1330 state.modified[INSN_UID (curr_cand->insn)].deleted = 1;
kono
parents:
diff changeset
1331 }
kono
parents:
diff changeset
1332 }
kono
parents:
diff changeset
1333
kono
parents:
diff changeset
1334 /* The copy list contains pairs of insns which describe copies we
kono
parents:
diff changeset
1335 need to insert into the INSN stream.
kono
parents:
diff changeset
1336
kono
parents:
diff changeset
1337 The first insn in each pair is the extension insn, from which
kono
parents:
diff changeset
1338 we derive the source and destination of the copy.
kono
parents:
diff changeset
1339
kono
parents:
diff changeset
1340 The second insn in each pair is the memory reference where the
kono
parents:
diff changeset
1341 extension will ultimately happen. We emit the new copy
kono
parents:
diff changeset
1342 immediately after this insn.
kono
parents:
diff changeset
1343
kono
parents:
diff changeset
1344 It may first appear that the arguments for the copy are reversed.
kono
parents:
diff changeset
1345 Remember that the memory reference will be changed to refer to the
kono
parents:
diff changeset
1346 destination of the extention. So we're actually emitting a copy
kono
parents:
diff changeset
1347 from the new destination to the old destination. */
kono
parents:
diff changeset
1348 for (unsigned int i = 0; i < reinsn_copy_list.length (); i += 2)
kono
parents:
diff changeset
1349 {
kono
parents:
diff changeset
1350 rtx_insn *curr_insn = reinsn_copy_list[i];
kono
parents:
diff changeset
1351 rtx_insn *def_insn = reinsn_copy_list[i + 1];
kono
parents:
diff changeset
1352
kono
parents:
diff changeset
1353 /* Use the mode of the destination of the defining insn
kono
parents:
diff changeset
1354 for the mode of the copy. This is necessary if the
kono
parents:
diff changeset
1355 defining insn was used to eliminate a second extension
kono
parents:
diff changeset
1356 that was wider than the first. */
kono
parents:
diff changeset
1357 rtx sub_rtx = *get_sub_rtx (def_insn);
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1358 rtx set = single_set (curr_insn);
111
kono
parents:
diff changeset
1359 rtx new_dst = gen_rtx_REG (GET_MODE (SET_DEST (sub_rtx)),
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1360 REGNO (XEXP (SET_SRC (set), 0)));
111
kono
parents:
diff changeset
1361 rtx new_src = gen_rtx_REG (GET_MODE (SET_DEST (sub_rtx)),
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1362 REGNO (SET_DEST (set)));
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1363 rtx new_set = gen_rtx_SET (new_dst, new_src);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1364 emit_insn_after (new_set, def_insn);
111
kono
parents:
diff changeset
1365 }
kono
parents:
diff changeset
1366
kono
parents:
diff changeset
1367 /* Delete all useless extensions here in one sweep. */
kono
parents:
diff changeset
1368 FOR_EACH_VEC_ELT (reinsn_del_list, i, curr_insn)
kono
parents:
diff changeset
1369 delete_insn (curr_insn);
kono
parents:
diff changeset
1370
kono
parents:
diff changeset
1371 reinsn_list.release ();
kono
parents:
diff changeset
1372 XDELETEVEC (state.modified);
kono
parents:
diff changeset
1373
kono
parents:
diff changeset
1374 if (dump_file && num_re_opportunities > 0)
kono
parents:
diff changeset
1375 fprintf (dump_file, "Elimination opportunities = %d realized = %d\n",
kono
parents:
diff changeset
1376 num_re_opportunities, num_realized);
kono
parents:
diff changeset
1377 }
kono
parents:
diff changeset
1378
kono
parents:
diff changeset
1379 /* Find and remove redundant extensions. */
kono
parents:
diff changeset
1380
kono
parents:
diff changeset
1381 static unsigned int
kono
parents:
diff changeset
1382 rest_of_handle_ree (void)
kono
parents:
diff changeset
1383 {
kono
parents:
diff changeset
1384 find_and_remove_re ();
kono
parents:
diff changeset
1385 return 0;
kono
parents:
diff changeset
1386 }
kono
parents:
diff changeset
1387
kono
parents:
diff changeset
1388 namespace {
kono
parents:
diff changeset
1389
kono
parents:
diff changeset
1390 const pass_data pass_data_ree =
kono
parents:
diff changeset
1391 {
kono
parents:
diff changeset
1392 RTL_PASS, /* type */
kono
parents:
diff changeset
1393 "ree", /* name */
kono
parents:
diff changeset
1394 OPTGROUP_NONE, /* optinfo_flags */
kono
parents:
diff changeset
1395 TV_REE, /* tv_id */
kono
parents:
diff changeset
1396 0, /* properties_required */
kono
parents:
diff changeset
1397 0, /* properties_provided */
kono
parents:
diff changeset
1398 0, /* properties_destroyed */
kono
parents:
diff changeset
1399 0, /* todo_flags_start */
kono
parents:
diff changeset
1400 TODO_df_finish, /* todo_flags_finish */
kono
parents:
diff changeset
1401 };
kono
parents:
diff changeset
1402
kono
parents:
diff changeset
1403 class pass_ree : public rtl_opt_pass
kono
parents:
diff changeset
1404 {
kono
parents:
diff changeset
1405 public:
kono
parents:
diff changeset
1406 pass_ree (gcc::context *ctxt)
kono
parents:
diff changeset
1407 : rtl_opt_pass (pass_data_ree, ctxt)
kono
parents:
diff changeset
1408 {}
kono
parents:
diff changeset
1409
kono
parents:
diff changeset
1410 /* opt_pass methods: */
kono
parents:
diff changeset
1411 virtual bool gate (function *) { return (optimize > 0 && flag_ree); }
kono
parents:
diff changeset
1412 virtual unsigned int execute (function *) { return rest_of_handle_ree (); }
kono
parents:
diff changeset
1413
kono
parents:
diff changeset
1414 }; // class pass_ree
kono
parents:
diff changeset
1415
kono
parents:
diff changeset
1416 } // anon namespace
kono
parents:
diff changeset
1417
kono
parents:
diff changeset
1418 rtl_opt_pass *
kono
parents:
diff changeset
1419 make_pass_ree (gcc::context *ctxt)
kono
parents:
diff changeset
1420 {
kono
parents:
diff changeset
1421 return new pass_ree (ctxt);
kono
parents:
diff changeset
1422 }