diff options
Diffstat (limited to 'meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch')
-rw-r--r-- | meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch | 873 |
1 files changed, 873 insertions, 0 deletions
diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch b/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch new file mode 100644 index 000000000..802c3816f --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99443.patch | |||
@@ -0,0 +1,873 @@ | |||
1 | 2010-11-26 Tom de Vries <tom@codesourcery.com> | ||
2 | |||
3 | gcc/ | ||
4 | * gcc/ee.c: New file. | ||
5 | * gcc/tree-pass.h (pass_ee): Declare. | ||
6 | * gcc/opts.c (decode_options): Set flag_ee at -O2. | ||
7 | * gcc/timevar.def (TV_EE): New timevar. | ||
8 | * gcc/common.opt (fextension-elimination): New option. | ||
9 | * gcc/Makefile.in (ee.o): New rule. | ||
10 | * gcc/passes.c (pass_ee): Add it. | ||
11 | * gcc/testsuite/gcc.dg/extend-4.c: New test. | ||
12 | * gcc/testsuite/gcc.dg/extend-1.c: New test. | ||
13 | * gcc/testsuite/gcc.dg/extend-2.c: New test. | ||
14 | * gcc/testsuite/gcc.dg/extend-2-64.c: New test. | ||
15 | * gcc/testsuite/gcc.dg/extend-3.c: New test. | ||
16 | |||
17 | === modified file 'gcc/Makefile.in' | ||
18 | --- old/gcc/Makefile.in 2010-11-16 18:05:53 +0000 | ||
19 | +++ new/gcc/Makefile.in 2010-12-10 15:33:37 +0000 | ||
20 | @@ -1194,6 +1194,7 @@ | ||
21 | dse.o \ | ||
22 | dwarf2asm.o \ | ||
23 | dwarf2out.o \ | ||
24 | + ee.o \ | ||
25 | ebitmap.o \ | ||
26 | emit-rtl.o \ | ||
27 | et-forest.o \ | ||
28 | @@ -2965,6 +2966,11 @@ | ||
29 | web.o : web.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ | ||
30 | hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h $(TOPLEV_H) \ | ||
31 | $(DF_H) $(OBSTACK_H) $(TIMEVAR_H) $(TREE_PASS_H) | ||
32 | +ee.o : ee.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ | ||
33 | + hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h \ | ||
34 | + $(DF_H) $(TIMEVAR_H) tree-pass.h $(RECOG_H) $(EXPR_H) \ | ||
35 | + $(REGS_H) $(TREE_H) $(TM_P_H) insn-config.h $(INSN_ATTR_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) \ | ||
36 | + $(TARGET_H) $(OPTABS_H) insn-codes.h rtlhooks-def.h $(PARAMS_H) $(CGRAPH_H) | ||
37 | gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ | ||
38 | $(REGS_H) hard-reg-set.h $(FLAGS_H) $(REAL_H) insn-config.h $(GGC_H) \ | ||
39 | $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h $(TOPLEV_H) \ | ||
40 | |||
41 | === modified file 'gcc/common.opt' | ||
42 | --- old/gcc/common.opt 2010-11-04 12:43:52 +0000 | ||
43 | +++ new/gcc/common.opt 2010-12-10 15:33:37 +0000 | ||
44 | @@ -496,6 +496,10 @@ | ||
45 | Common Report Var(flag_early_inlining) Init(1) Optimization | ||
46 | Perform early inlining | ||
47 | |||
48 | +fextension-elimination | ||
49 | +Common Report Var(flag_ee) Init(0) Optimization | ||
50 | +Perform extension elimination | ||
51 | + | ||
52 | feliminate-dwarf2-dups | ||
53 | Common Report Var(flag_eliminate_dwarf2_dups) | ||
54 | Perform DWARF2 duplicate elimination | ||
55 | |||
56 | === added file 'gcc/ee.c' | ||
57 | --- old/gcc/ee.c 1970-01-01 00:00:00 +0000 | ||
58 | +++ new/gcc/ee.c 2010-12-10 15:33:37 +0000 | ||
59 | @@ -0,0 +1,662 @@ | ||
60 | +/* Redundant extension elimination | ||
61 | + Copyright (C) 2010 Free Software Foundation, Inc. | ||
62 | + Contributed by Tom de Vries (tom@codesourcery.com) | ||
63 | + | ||
64 | +This file is part of GCC. | ||
65 | + | ||
66 | +GCC is free software; you can redistribute it and/or modify it under | ||
67 | +the terms of the GNU General Public License as published by the Free | ||
68 | +Software Foundation; either version 3, or (at your option) any later | ||
69 | +version. | ||
70 | + | ||
71 | +GCC is distributed in the hope that it will be useful, but WITHOUT ANY | ||
72 | +WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
73 | +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
74 | +for more details. | ||
75 | + | ||
76 | +You should have received a copy of the GNU General Public License | ||
77 | +along with GCC; see the file COPYING3. If not see | ||
78 | +<http://www.gnu.org/licenses/>. */ | ||
79 | + | ||
80 | +/* | ||
81 | + | ||
82 | + MOTIVATING EXAMPLE | ||
83 | + | ||
84 | + The motivating example for this pass is: | ||
85 | + | ||
86 | + void f(unsigned char *p, short s, int c, int *z) | ||
87 | + { | ||
88 | + if (c) | ||
89 | + *z = 0; | ||
90 | + *p ^= (unsigned char)s; | ||
91 | + } | ||
92 | + | ||
93 | + For MIPS, compilation results in the following insns. | ||
94 | + | ||
95 | + (set (reg/v:SI 199) | ||
96 | + (sign_extend:SI (subreg:HI (reg:SI 200) 2))) | ||
97 | + | ||
98 | + ... | ||
99 | + | ||
100 | + (set (reg:QI 203) | ||
101 | + (subreg:QI (reg/v:SI 199) 3)) | ||
102 | + | ||
103 | + These insns are the only def and the only use of reg 199, each located in a | ||
104 | + different bb. | ||
105 | + | ||
106 | + The sign-extension preserves the lower half of reg 200 and copies them to | ||
107 | + reg 199, and the subreg use of reg 199 only reads the least significant byte. | ||
108 | + The sign extension is therefore redundant (the extension part, not the copy | ||
109 | + part), and can safely be replaced with a regcopy from reg 200 to reg 199. | ||
110 | + | ||
111 | + | ||
112 | + OTHER SIGN/ZERO EXTENSION ELIMINATION PASSES | ||
113 | + | ||
114 | + There are other passes which eliminate sign/zero-extension: combine and | ||
115 | + implicit_zee. Both attempt to eliminate extensions by combining them with | ||
116 | + other instructions. The combine pass does this at bb level, | ||
117 | + implicit_zee works at inter-bb level. | ||
118 | + | ||
119 | + The combine pass combine an extension with either: | ||
120 | + - all uses of the extension, or | ||
121 | + - all defs of the operand of the extension. | ||
122 | + The implicit_zee pass only implements the latter. | ||
123 | + | ||
124 | + For our motivating example, combine doesn't work since the def and the use of | ||
125 | + reg 199 are in a different bb. | ||
126 | + | ||
127 | + Implicit_zee does not work since it only combines an extension with the defs | ||
128 | + of its operand. | ||
129 | + | ||
130 | + | ||
131 | + INTENDED EFFECT | ||
132 | + | ||
133 | + This pass works by removing sign/zero-extensions, or replacing them with | ||
134 | + regcopies. The idea there is that the regcopy might be eliminated by a later | ||
135 | + pass. In case the regcopy cannot be eliminated, it might at least be cheaper | ||
136 | + than the extension. | ||
137 | + | ||
138 | + | ||
139 | + IMPLEMENTATION | ||
140 | + | ||
141 | + The pass scans twice over all instructions. | ||
142 | + | ||
143 | + The first scan registers all uses of a reg in the biggest_use array. After | ||
144 | + that first scan, the biggest_use array contains the size in bits of the | ||
145 | + biggest use of each reg. | ||
146 | + | ||
147 | + The second scan finds extensions, determines whether they are redundant based | ||
148 | + on the biggest use, and deletes or replaces them. | ||
149 | + | ||
150 | + In case that the src and dest reg of the replacement are not of the same size, | ||
151 | + we do not replace with a normal regcopy, but with a truncate or with the copy | ||
152 | + of a paradoxical subreg instead. | ||
153 | + | ||
154 | + | ||
155 | + LIMITATIONS | ||
156 | + | ||
157 | + The scope of the analysis is limited to an extension and its uses. The other | ||
158 | + type of analysis (related to the defs of the operand of an extension) is not | ||
159 | + done. | ||
160 | + | ||
161 | + Furthermore, we do the analysis of biggest use per reg. So when determining | ||
162 | + whether an extension is redundant, we take all uses of a the dest reg into | ||
163 | + account, also the ones that are not uses of the extension. This could be | ||
164 | + overcome by calculating the def-use chains and using those for analysis | ||
165 | + instead. | ||
166 | + | ||
167 | + Finally, during the analysis each insn is looked at in isolation. There is no | ||
168 | + propagation of information during the analysis. To overcome this limitation, | ||
169 | + a backward iterative bit-level liveness analysis is needed. */ | ||
170 | + | ||
171 | + | ||
172 | +#include "config.h" | ||
173 | +#include "system.h" | ||
174 | +#include "coretypes.h" | ||
175 | +#include "tm.h" | ||
176 | +#include "rtl.h" | ||
177 | +#include "tree.h" | ||
178 | +#include "tm_p.h" | ||
179 | +#include "flags.h" | ||
180 | +#include "regs.h" | ||
181 | +#include "hard-reg-set.h" | ||
182 | +#include "basic-block.h" | ||
183 | +#include "insn-config.h" | ||
184 | +#include "function.h" | ||
185 | +#include "expr.h" | ||
186 | +#include "insn-attr.h" | ||
187 | +#include "recog.h" | ||
188 | +#include "toplev.h" | ||
189 | +#include "target.h" | ||
190 | +#include "timevar.h" | ||
191 | +#include "optabs.h" | ||
192 | +#include "insn-codes.h" | ||
193 | +#include "rtlhooks-def.h" | ||
194 | +#include "output.h" | ||
195 | +#include "params.h" | ||
196 | +#include "timevar.h" | ||
197 | +#include "tree-pass.h" | ||
198 | +#include "cgraph.h" | ||
199 | + | ||
200 | +#define SKIP_REG (-1) | ||
201 | + | ||
202 | +/* Array to register the biggest use of a reg, in bits. */ | ||
203 | + | ||
204 | +static int *biggest_use; | ||
205 | + | ||
206 | +/* Forward declaration. */ | ||
207 | + | ||
208 | +static void note_use (rtx *x, void *data); | ||
209 | + | ||
210 | +/* The following two functions are borrowed from trunk/gcc/toplev.c. They can be | ||
211 | + removed for a check-in into gcc trunk. */ | ||
212 | + | ||
213 | +/* Given X, an unsigned number, return the number of least significant bits | ||
214 | + that are zero. When X == 0, the result is the word size. */ | ||
215 | + | ||
216 | +static int | ||
217 | +ctz_hwi (unsigned HOST_WIDE_INT x) | ||
218 | +{ | ||
219 | + return x ? floor_log2 (x & -x) : HOST_BITS_PER_WIDE_INT; | ||
220 | +} | ||
221 | + | ||
222 | +/* Similarly for most significant bits. */ | ||
223 | + | ||
224 | +static int | ||
225 | +clz_hwi (unsigned HOST_WIDE_INT x) | ||
226 | +{ | ||
227 | + return HOST_BITS_PER_WIDE_INT - 1 - floor_log2(x); | ||
228 | +} | ||
229 | + | ||
230 | +/* Check whether this is a paradoxical subreg. */ | ||
231 | + | ||
232 | +static bool | ||
233 | +paradoxical_subreg_p (rtx subreg) | ||
234 | +{ | ||
235 | + enum machine_mode subreg_mode, reg_mode; | ||
236 | + | ||
237 | + if (GET_CODE (subreg) != SUBREG) | ||
238 | + return false; | ||
239 | + | ||
240 | + subreg_mode = GET_MODE (subreg); | ||
241 | + reg_mode = GET_MODE (SUBREG_REG (subreg)); | ||
242 | + | ||
243 | + if (GET_MODE_SIZE (subreg_mode) > GET_MODE_SIZE (reg_mode)) | ||
244 | + return true; | ||
245 | + | ||
246 | + return false; | ||
247 | +} | ||
248 | + | ||
249 | +/* Get the size and reg number of a REG or SUBREG use. */ | ||
250 | + | ||
251 | +static bool | ||
252 | +reg_use_p (rtx use, int *size, unsigned int *regno) | ||
253 | +{ | ||
254 | + rtx reg; | ||
255 | + | ||
256 | + if (REG_P (use)) | ||
257 | + { | ||
258 | + *regno = REGNO (use); | ||
259 | + *size = GET_MODE_BITSIZE (GET_MODE (use)); | ||
260 | + return true; | ||
261 | + } | ||
262 | + else if (GET_CODE (use) == SUBREG) | ||
263 | + { | ||
264 | + reg = SUBREG_REG (use); | ||
265 | + | ||
266 | + if (!REG_P (reg)) | ||
267 | + return false; | ||
268 | + | ||
269 | + *regno = REGNO (reg); | ||
270 | + | ||
271 | + if (paradoxical_subreg_p (use)) | ||
272 | + *size = GET_MODE_BITSIZE (GET_MODE (reg)); | ||
273 | + else | ||
274 | + *size = subreg_lsb (use) + GET_MODE_BITSIZE (GET_MODE (use)); | ||
275 | + | ||
276 | + return true; | ||
277 | + } | ||
278 | + | ||
279 | + return false; | ||
280 | +} | ||
281 | + | ||
282 | +/* Register the use of a reg. */ | ||
283 | + | ||
284 | +static void | ||
285 | +register_use (int size, unsigned int regno) | ||
286 | +{ | ||
287 | + int *current = &biggest_use[regno]; | ||
288 | + | ||
289 | + if (*current == SKIP_REG) | ||
290 | + return; | ||
291 | + | ||
292 | + *current = MAX (*current, size); | ||
293 | +} | ||
294 | + | ||
295 | +/* Handle embedded uses. */ | ||
296 | + | ||
297 | +static void | ||
298 | +note_embedded_uses (rtx use, rtx pattern) | ||
299 | +{ | ||
300 | + const char *format_ptr; | ||
301 | + int i, j; | ||
302 | + | ||
303 | + format_ptr = GET_RTX_FORMAT (GET_CODE (use)); | ||
304 | + for (i = 0; i < GET_RTX_LENGTH (GET_CODE (use)); i++) | ||
305 | + if (format_ptr[i] == 'e') | ||
306 | + note_use (&XEXP (use, i), pattern); | ||
307 | + else if (format_ptr[i] == 'E') | ||
308 | + for (j = 0; j < XVECLEN (use, i); j++) | ||
309 | + note_use (&XVECEXP (use, i, j), pattern); | ||
310 | +} | ||
311 | + | ||
312 | +/* Get the set that has use as its SRC operand. */ | ||
313 | + | ||
314 | +static rtx | ||
315 | +get_set (rtx use, rtx pattern) | ||
316 | +{ | ||
317 | + rtx sub; | ||
318 | + int i; | ||
319 | + | ||
320 | + if (GET_CODE (pattern) == SET && SET_SRC (pattern) == use) | ||
321 | + return pattern; | ||
322 | + | ||
323 | + if (GET_CODE (pattern) == PARALLEL) | ||
324 | + for (i = 0; i < XVECLEN (pattern, 0); ++i) | ||
325 | + { | ||
326 | + sub = XVECEXP (pattern, 0, i); | ||
327 | + if (GET_CODE (sub) == SET && SET_SRC (sub) == use) | ||
328 | + return sub; | ||
329 | + } | ||
330 | + | ||
331 | + return NULL_RTX; | ||
332 | +} | ||
333 | + | ||
334 | +/* Handle a restricted op use. In this context restricted means that a bit in an | ||
335 | + operand influences only the same bit or more significant bits in the result. | ||
336 | + The bitwise ops are a subclass, but PLUS is one as well. */ | ||
337 | + | ||
338 | +static void | ||
339 | +note_restricted_op_use (rtx use, unsigned int nr_operands, rtx pattern) | ||
340 | +{ | ||
341 | + unsigned int i, smallest; | ||
342 | + int operand_size[2]; | ||
343 | + int used_size; | ||
344 | + unsigned int operand_regno[2]; | ||
345 | + bool operand_reg[2]; | ||
346 | + bool operand_ignore[2]; | ||
347 | + rtx set; | ||
348 | + | ||
349 | + /* Init operand_reg, operand_size, operand_regno and operand_ignore. */ | ||
350 | + for (i = 0; i < nr_operands; ++i) | ||
351 | + { | ||
352 | + operand_reg[i] = reg_use_p (XEXP (use, i), &operand_size[i], | ||
353 | + &operand_regno[i]); | ||
354 | + operand_ignore[i] = false; | ||
355 | + } | ||
356 | + | ||
357 | + /* Handle case of reg and-masked with const. */ | ||
358 | + if (GET_CODE (use) == AND && CONST_INT_P (XEXP (use, 1)) && operand_reg[0]) | ||
359 | + { | ||
360 | + used_size = | ||
361 | + HOST_BITS_PER_WIDE_INT - clz_hwi (UINTVAL (XEXP (use, 1))); | ||
362 | + operand_size[0] = MIN (operand_size[0], used_size); | ||
363 | + } | ||
364 | + | ||
365 | + /* Handle case of reg or-masked with const. */ | ||
366 | + if (GET_CODE (use) == IOR && CONST_INT_P (XEXP (use, 1)) && operand_reg[0]) | ||
367 | + { | ||
368 | + used_size = | ||
369 | + HOST_BITS_PER_WIDE_INT - clz_hwi (~UINTVAL (XEXP (use, 1))); | ||
370 | + operand_size[0] = MIN (operand_size[0], used_size); | ||
371 | + } | ||
372 | + | ||
373 | + /* Ignore the use of a in 'a = a + b'. */ | ||
374 | + set = get_set (use, pattern); | ||
375 | + if (set != NULL_RTX && REG_P (SET_DEST (set))) | ||
376 | + for (i = 0; i < nr_operands; ++i) | ||
377 | + operand_ignore[i] = (operand_reg[i] | ||
378 | + && (REGNO (SET_DEST (set)) == operand_regno[i])); | ||
379 | + | ||
380 | + /* Handle the case a reg is combined with don't care bits. */ | ||
381 | + if (nr_operands == 2 && operand_reg[0] && operand_reg[1] | ||
382 | + && operand_size[0] != operand_size[1]) | ||
383 | + { | ||
384 | + smallest = operand_size[0] > operand_size[1]; | ||
385 | + | ||
386 | + if (paradoxical_subreg_p (XEXP (use, smallest)) | ||
387 | + && !SUBREG_PROMOTED_VAR_P (XEXP (use, smallest))) | ||
388 | + operand_size[1 - smallest] = operand_size[smallest]; | ||
389 | + } | ||
390 | + | ||
391 | + /* Register the operand use, if necessary. */ | ||
392 | + for (i = 0; i < nr_operands; ++i) | ||
393 | + if (!operand_reg[i]) | ||
394 | + note_use (&XEXP (use, i), pattern); | ||
395 | + else if (!operand_ignore[i]) | ||
396 | + register_use (operand_size[i], operand_regno[i]); | ||
397 | +} | ||
398 | + | ||
399 | +/* Handle all uses noted by note_uses. */ | ||
400 | + | ||
401 | +static void | ||
402 | +note_use (rtx *x, void *data) | ||
403 | +{ | ||
404 | + rtx use = *x; | ||
405 | + rtx pattern = (rtx)data; | ||
406 | + int use_size; | ||
407 | + unsigned int use_regno; | ||
408 | + | ||
409 | + switch (GET_CODE (use)) | ||
410 | + { | ||
411 | + case REG: | ||
412 | + case SUBREG: | ||
413 | + if (!reg_use_p (use, &use_size, &use_regno)) | ||
414 | + { | ||
415 | + note_embedded_uses (use, pattern); | ||
416 | + return; | ||
417 | + } | ||
418 | + register_use (use_size, use_regno); | ||
419 | + return; | ||
420 | + case IOR: | ||
421 | + case AND: | ||
422 | + case XOR: | ||
423 | + case PLUS: | ||
424 | + case MINUS: | ||
425 | + note_restricted_op_use (use, 2, pattern); | ||
426 | + return; | ||
427 | + case NOT: | ||
428 | + case NEG: | ||
429 | + note_restricted_op_use (use, 1, pattern); | ||
430 | + return; | ||
431 | + case ASHIFT: | ||
432 | + if (!reg_use_p (XEXP (use, 0), &use_size, &use_regno) | ||
433 | + || !CONST_INT_P (XEXP (use, 1)) | ||
434 | + || INTVAL (XEXP (use, 1)) <= 0 | ||
435 | + || paradoxical_subreg_p (XEXP (use, 0))) | ||
436 | + { | ||
437 | + note_embedded_uses (use, pattern); | ||
438 | + return; | ||
439 | + } | ||
440 | + register_use (use_size - INTVAL (XEXP (use, 1)), use_regno); | ||
441 | + return; | ||
442 | + default: | ||
443 | + note_embedded_uses (use, pattern); | ||
444 | + return; | ||
445 | + } | ||
446 | +} | ||
447 | + | ||
448 | +/* Check whether reg is implicitly used. */ | ||
449 | + | ||
450 | +static bool | ||
451 | +implicit_use_p (int regno) | ||
452 | +{ | ||
453 | +#ifdef EPILOGUE_USES | ||
454 | + if (EPILOGUE_USES (regno)) | ||
455 | + return true; | ||
456 | +#endif | ||
457 | + | ||
458 | +#ifdef EH_USES | ||
459 | + if (EH_USES (regno)) | ||
460 | + return true; | ||
461 | +#endif | ||
462 | + | ||
463 | + return false; | ||
464 | +} | ||
465 | + | ||
466 | +/* Note the uses of argument registers in a call. */ | ||
467 | + | ||
468 | +static void | ||
469 | +note_call_uses (rtx insn) | ||
470 | +{ | ||
471 | + rtx link, link_expr; | ||
472 | + | ||
473 | + if (!CALL_P (insn)) | ||
474 | + return; | ||
475 | + | ||
476 | + for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1)) | ||
477 | + { | ||
478 | + link_expr = XEXP (link, 0); | ||
479 | + | ||
480 | + if (GET_CODE (link_expr) == USE) | ||
481 | + note_use (&XEXP (link_expr, 0), link); | ||
482 | + } | ||
483 | +} | ||
484 | + | ||
485 | +/* Calculate the biggest use mode for all regs. */ | ||
486 | + | ||
487 | +static void | ||
488 | +calculate_biggest_use (void) | ||
489 | +{ | ||
490 | + int i; | ||
491 | + basic_block bb; | ||
492 | + rtx insn; | ||
493 | + | ||
494 | + /* Initialize biggest_use for all regs to 0. If a reg is used implicitly, we | ||
495 | + handle that reg conservatively and set it to SKIP_REG instead. */ | ||
496 | + for (i = 0; i < max_reg_num (); i++) | ||
497 | + biggest_use[i] = ((implicit_use_p (i) || HARD_REGISTER_NUM_P (i)) | ||
498 | + ? SKIP_REG : 0); | ||
499 | + | ||
500 | + /* For all insns, call note_use for each use in insn. */ | ||
501 | + FOR_EACH_BB (bb) | ||
502 | + FOR_BB_INSNS (bb, insn) | ||
503 | + { | ||
504 | + if (!NONDEBUG_INSN_P (insn)) | ||
505 | + continue; | ||
506 | + | ||
507 | + note_uses (&PATTERN (insn), note_use, PATTERN (insn)); | ||
508 | + | ||
509 | + if (CALL_P (insn)) | ||
510 | + note_call_uses (insn); | ||
511 | + } | ||
512 | + | ||
513 | + /* Dump the biggest uses found. */ | ||
514 | + if (dump_file) | ||
515 | + for (i = 0; i < max_reg_num (); i++) | ||
516 | + if (biggest_use[i] > 0) | ||
517 | + fprintf (dump_file, "reg %d: size %d\n", i, biggest_use[i]); | ||
518 | +} | ||
519 | + | ||
520 | +/* Check whether this is a sign/zero extension. */ | ||
521 | + | ||
522 | +static bool | ||
523 | +extension_p (rtx insn, rtx *dest, rtx *inner, int *preserved_size) | ||
524 | +{ | ||
525 | + rtx src, op0; | ||
526 | + | ||
527 | + /* Detect set of reg. */ | ||
528 | + if (GET_CODE (PATTERN (insn)) != SET) | ||
529 | + return false; | ||
530 | + | ||
531 | + src = SET_SRC (PATTERN (insn)); | ||
532 | + *dest = SET_DEST (PATTERN (insn)); | ||
533 | + | ||
534 | + if (!REG_P (*dest)) | ||
535 | + return false; | ||
536 | + | ||
537 | + /* Detect sign or zero extension. */ | ||
538 | + if (GET_CODE (src) == ZERO_EXTEND || GET_CODE (src) == SIGN_EXTEND | ||
539 | + || (GET_CODE (src) == AND && CONST_INT_P (XEXP (src, 1)))) | ||
540 | + { | ||
541 | + op0 = XEXP (src, 0); | ||
542 | + | ||
543 | + /* Determine amount of least significant bits preserved by operation. */ | ||
544 | + if (GET_CODE (src) == AND) | ||
545 | + *preserved_size = ctz_hwi (~UINTVAL (XEXP (src, 1))); | ||
546 | + else | ||
547 | + *preserved_size = GET_MODE_BITSIZE (GET_MODE (op0)); | ||
548 | + | ||
549 | + if (GET_CODE (op0) == SUBREG) | ||
550 | + { | ||
551 | + if (subreg_lsb (op0) != 0) | ||
552 | + return false; | ||
553 | + | ||
554 | + *inner = SUBREG_REG (op0); | ||
555 | + return true; | ||
556 | + } | ||
557 | + else if (REG_P (op0)) | ||
558 | + { | ||
559 | + *inner = op0; | ||
560 | + return true; | ||
561 | + } | ||
562 | + } | ||
563 | + | ||
564 | + return false; | ||
565 | +} | ||
566 | + | ||
567 | +/* Check whether this is a redundant sign/zero extension. */ | ||
568 | + | ||
569 | +static bool | ||
570 | +redundant_extension_p (rtx insn, rtx *dest, rtx *inner) | ||
571 | +{ | ||
572 | + int biggest_dest_use; | ||
573 | + int preserved_size; | ||
574 | + | ||
575 | + if (!extension_p (insn, dest, inner, &preserved_size)) | ||
576 | + return false; | ||
577 | + | ||
578 | + if (dump_file) | ||
579 | + fprintf (dump_file, "considering extension %u with preserved size %d\n", | ||
580 | + INSN_UID (insn), preserved_size); | ||
581 | + | ||
582 | + biggest_dest_use = biggest_use[REGNO (*dest)]; | ||
583 | + | ||
584 | + if (biggest_dest_use == SKIP_REG) | ||
585 | + return false; | ||
586 | + | ||
587 | + if (preserved_size < biggest_dest_use) | ||
588 | + return false; | ||
589 | + | ||
590 | + if (dump_file) | ||
591 | + fprintf (dump_file, "found superfluous extension %u\n", INSN_UID (insn)); | ||
592 | + | ||
593 | + return true; | ||
594 | +} | ||
595 | + | ||
596 | +/* Try to remove or replace the redundant extension. */ | ||
597 | + | ||
598 | +static void | ||
599 | +try_remove_or_replace_extension (rtx insn, rtx dest, rtx inner) | ||
600 | +{ | ||
601 | + rtx cp_src, cp_dest, seq, one; | ||
602 | + | ||
603 | + if (GET_MODE_CLASS (GET_MODE (dest)) != GET_MODE_CLASS (GET_MODE (inner))) | ||
604 | + return; | ||
605 | + | ||
606 | + /* Check whether replacement is needed. */ | ||
607 | + if (dest != inner) | ||
608 | + { | ||
609 | + start_sequence (); | ||
610 | + | ||
611 | + /* Determine the proper replacement operation. */ | ||
612 | + if (GET_MODE (dest) == GET_MODE (inner)) | ||
613 | + { | ||
614 | + cp_src = inner; | ||
615 | + cp_dest = dest; | ||
616 | + } | ||
617 | + else if (GET_MODE_SIZE (GET_MODE (dest)) | ||
618 | + > GET_MODE_SIZE (GET_MODE (inner))) | ||
619 | + { | ||
620 | + emit_clobber (dest); | ||
621 | + cp_src = inner; | ||
622 | + cp_dest = gen_lowpart_SUBREG (GET_MODE (inner), dest); | ||
623 | + } | ||
624 | + else | ||
625 | + { | ||
626 | + cp_src = gen_rtx_TRUNCATE (GET_MODE (dest), inner); | ||
627 | + cp_dest = dest; | ||
628 | + } | ||
629 | + | ||
630 | + emit_move_insn (cp_dest, cp_src); | ||
631 | + | ||
632 | + seq = get_insns (); | ||
633 | + end_sequence (); | ||
634 | + | ||
635 | + /* If the replacement is not supported, bail out. */ | ||
636 | + for (one = seq; one != NULL_RTX; one = NEXT_INSN (one)) | ||
637 | + if (recog_memoized (one) < 0 && GET_CODE (PATTERN (one)) != CLOBBER) | ||
638 | + return; | ||
639 | + | ||
640 | + /* Insert the replacement. */ | ||
641 | + emit_insn_before (seq, insn); | ||
642 | + } | ||
643 | + | ||
644 | + /* Note replacement/removal in the dump. */ | ||
645 | + if (dump_file) | ||
646 | + { | ||
647 | + fprintf (dump_file, "superfluous extension %u ", INSN_UID (insn)); | ||
648 | + if (dest != inner) | ||
649 | + fprintf (dump_file, "replaced by %u\n", INSN_UID (seq)); | ||
650 | + else | ||
651 | + fprintf (dump_file, "removed\n"); | ||
652 | + } | ||
653 | + | ||
654 | + /* Remove the extension. */ | ||
655 | + delete_insn (insn); | ||
656 | +} | ||
657 | + | ||
658 | +/* Find redundant extensions and remove or replace them if possible. */ | ||
659 | + | ||
660 | +static void | ||
661 | +remove_redundant_extensions (void) | ||
662 | +{ | ||
663 | + basic_block bb; | ||
664 | + rtx insn, next, dest, inner; | ||
665 | + | ||
666 | + biggest_use = XNEWVEC (int, max_reg_num ()); | ||
667 | + calculate_biggest_use (); | ||
668 | + | ||
669 | + /* Remove redundant extensions. */ | ||
670 | + FOR_EACH_BB (bb) | ||
671 | + FOR_BB_INSNS_SAFE (bb, insn, next) | ||
672 | + { | ||
673 | + if (!NONDEBUG_INSN_P (insn)) | ||
674 | + continue; | ||
675 | + | ||
676 | + if (!redundant_extension_p (insn, &dest, &inner)) | ||
677 | + continue; | ||
678 | + | ||
679 | + try_remove_or_replace_extension (insn, dest, inner); | ||
680 | + } | ||
681 | + | ||
682 | + free (biggest_use); | ||
683 | +} | ||
684 | + | ||
685 | +/* Remove redundant extensions. */ | ||
686 | + | ||
687 | +static unsigned int | ||
688 | +rest_of_handle_ee (void) | ||
689 | +{ | ||
690 | + remove_redundant_extensions (); | ||
691 | + return 0; | ||
692 | +} | ||
693 | + | ||
694 | +/* Run ee pass when flag_ee is set at optimization level > 0. */ | ||
695 | + | ||
696 | +static bool | ||
697 | +gate_handle_ee (void) | ||
698 | +{ | ||
699 | + return (optimize > 0 && flag_ee); | ||
700 | +} | ||
701 | + | ||
702 | +struct rtl_opt_pass pass_ee = | ||
703 | +{ | ||
704 | + { | ||
705 | + RTL_PASS, | ||
706 | + "ee", /* name */ | ||
707 | + gate_handle_ee, /* gate */ | ||
708 | + rest_of_handle_ee, /* execute */ | ||
709 | + NULL, /* sub */ | ||
710 | + NULL, /* next */ | ||
711 | + 0, /* static_pass_number */ | ||
712 | + TV_EE, /* tv_id */ | ||
713 | + 0, /* properties_required */ | ||
714 | + 0, /* properties_provided */ | ||
715 | + 0, /* properties_destroyed */ | ||
716 | + 0, /* todo_flags_start */ | ||
717 | + TODO_ggc_collect | | ||
718 | + TODO_dump_func | | ||
719 | + TODO_verify_rtl_sharing, /* todo_flags_finish */ | ||
720 | + } | ||
721 | +}; | ||
722 | |||
723 | === modified file 'gcc/opts.c' | ||
724 | --- old/gcc/opts.c 2010-05-17 09:13:28 +0000 | ||
725 | +++ new/gcc/opts.c 2010-12-10 15:33:37 +0000 | ||
726 | @@ -907,6 +907,7 @@ | ||
727 | flag_tree_switch_conversion = opt2; | ||
728 | flag_ipa_cp = opt2; | ||
729 | flag_ipa_sra = opt2; | ||
730 | + flag_ee = opt2; | ||
731 | |||
732 | /* Track fields in field-sensitive alias analysis. */ | ||
733 | set_param_value ("max-fields-for-field-sensitive", | ||
734 | |||
735 | === modified file 'gcc/passes.c' | ||
736 | --- old/gcc/passes.c 2010-09-01 13:29:58 +0000 | ||
737 | +++ new/gcc/passes.c 2010-12-10 15:33:37 +0000 | ||
738 | @@ -974,6 +974,7 @@ | ||
739 | NEXT_PASS (pass_lower_subreg); | ||
740 | NEXT_PASS (pass_df_initialize_opt); | ||
741 | NEXT_PASS (pass_cse); | ||
742 | + NEXT_PASS (pass_ee); | ||
743 | NEXT_PASS (pass_rtl_fwprop); | ||
744 | NEXT_PASS (pass_rtl_cprop); | ||
745 | NEXT_PASS (pass_rtl_pre); | ||
746 | |||
747 | === added file 'gcc/testsuite/gcc.dg/extend-1.c' | ||
748 | --- old/gcc/testsuite/gcc.dg/extend-1.c 1970-01-01 00:00:00 +0000 | ||
749 | +++ new/gcc/testsuite/gcc.dg/extend-1.c 2010-12-10 15:33:37 +0000 | ||
750 | @@ -0,0 +1,13 @@ | ||
751 | +/* { dg-do compile } */ | ||
752 | +/* { dg-options "-O2 -fdump-rtl-ee" } */ | ||
753 | + | ||
754 | +void f(unsigned char * p, short s, int c, int *z) | ||
755 | +{ | ||
756 | + if (c) | ||
757 | + *z = 0; | ||
758 | + *p ^= (unsigned char)s; | ||
759 | +} | ||
760 | + | ||
761 | +/* { dg-final { scan-rtl-dump-times "sign_extend:" 0 "ee" { target mips*-*-* } } } */ | ||
762 | +/* { dg-final { scan-rtl-dump-times "superfluous extension \[0-9\]+ replaced" 1 "ee" { target mips*-*-* } } } */ | ||
763 | +/* { dg-final { cleanup-rtl-dump "ee" } } */ | ||
764 | |||
765 | === added file 'gcc/testsuite/gcc.dg/extend-2-64.c' | ||
766 | --- old/gcc/testsuite/gcc.dg/extend-2-64.c 1970-01-01 00:00:00 +0000 | ||
767 | +++ new/gcc/testsuite/gcc.dg/extend-2-64.c 2010-12-10 15:33:37 +0000 | ||
768 | @@ -0,0 +1,20 @@ | ||
769 | +/* { dg-do compile } */ | ||
770 | +/* { dg-options "-O2 -fdump-rtl-ee" } */ | ||
771 | +/* { dg-require-effective-target mips64 } */ | ||
772 | + | ||
773 | +void f(unsigned char * p, short *s, int c) | ||
774 | +{ | ||
775 | + short or = 0; | ||
776 | + while (c) | ||
777 | + { | ||
778 | + or = or | s[c]; | ||
779 | + c --; | ||
780 | + } | ||
781 | + *p = (unsigned char)or; | ||
782 | +} | ||
783 | + | ||
784 | +/* { dg-final { scan-rtl-dump-times "zero_extend:" 1 "ee" { target mips*-*-* } } } */ | ||
785 | +/* { dg-final { scan-rtl-dump-times "sign_extend:" 0 "ee" { target mips*-*-* } } } */ | ||
786 | +/* { dg-final { scan-rtl-dump-times "superfluous extension \[0-9\]+ replaced" 3 "ee" { target mips*-*-* } } } */ | ||
787 | +/* { dg-final { cleanup-rtl-dump "ee" } } */ | ||
788 | + | ||
789 | |||
790 | === added file 'gcc/testsuite/gcc.dg/extend-2.c' | ||
791 | --- old/gcc/testsuite/gcc.dg/extend-2.c 1970-01-01 00:00:00 +0000 | ||
792 | +++ new/gcc/testsuite/gcc.dg/extend-2.c 2010-12-10 15:33:37 +0000 | ||
793 | @@ -0,0 +1,20 @@ | ||
794 | +/* { dg-do compile } */ | ||
795 | +/* { dg-options "-O2 -fdump-rtl-ee" } */ | ||
796 | +/* { dg-require-effective-target ilp32 } */ | ||
797 | + | ||
798 | +void f(unsigned char * p, short *s, int c) | ||
799 | +{ | ||
800 | + short or = 0; | ||
801 | + while (c) | ||
802 | + { | ||
803 | + or = or | s[c]; | ||
804 | + c --; | ||
805 | + } | ||
806 | + *p = (unsigned char)or; | ||
807 | +} | ||
808 | + | ||
809 | +/* { dg-final { scan-rtl-dump-times "zero_extend" 0 "ee" { target mips*-*-* } } } */ | ||
810 | +/* { dg-final { scan-rtl-dump-times "sign_extend" 0 "ee" { target mips*-*-* } } } */ | ||
811 | +/* { dg-final { scan-rtl-dump-times "superfluous extension \[0-9\]+ replaced" 2 "ee" { target mips*-*-* } } } */ | ||
812 | +/* { dg-final { cleanup-rtl-dump "ee" } } */ | ||
813 | + | ||
814 | |||
815 | === added file 'gcc/testsuite/gcc.dg/extend-3.c' | ||
816 | --- old/gcc/testsuite/gcc.dg/extend-3.c 1970-01-01 00:00:00 +0000 | ||
817 | +++ new/gcc/testsuite/gcc.dg/extend-3.c 2010-12-10 15:33:37 +0000 | ||
818 | @@ -0,0 +1,12 @@ | ||
819 | +/* { dg-do compile } */ | ||
820 | +/* { dg-options "-O2 -fdump-rtl-ee" } */ | ||
821 | + | ||
822 | +unsigned int f(unsigned char byte) | ||
823 | +{ | ||
824 | + return byte << 25; | ||
825 | +} | ||
826 | + | ||
827 | +/* { dg-final { scan-rtl-dump-times "zero_extend:" 0 "ee" { target mips*-*-* } } } */ | ||
828 | +/* { dg-final { scan-rtl-dump "superfluous extension \[0-9\]+ replaced" "ee" { target mips*-*-* } } } */ | ||
829 | +/* { dg-final { cleanup-rtl-dump "ee" } } */ | ||
830 | + | ||
831 | |||
832 | === added file 'gcc/testsuite/gcc.dg/extend-4.c' | ||
833 | --- old/gcc/testsuite/gcc.dg/extend-4.c 1970-01-01 00:00:00 +0000 | ||
834 | +++ new/gcc/testsuite/gcc.dg/extend-4.c 2010-12-10 15:33:37 +0000 | ||
835 | @@ -0,0 +1,13 @@ | ||
836 | +/* { dg-do compile } */ | ||
837 | +/* { dg-options "-O2 -fdump-rtl-ee" } */ | ||
838 | + | ||
839 | +unsigned char f(unsigned int a) | ||
840 | +{ | ||
841 | + unsigned int b = a & 0x10ff; | ||
842 | + return b; | ||
843 | +} | ||
844 | + | ||
845 | +/* { dg-final { scan-rtl-dump-times "and:" 0 "ee" { target mips*-*-* } } } */ | ||
846 | +/* { dg-final { scan-rtl-dump-times "superfluous extension \[0-9\]+ replaced" 1 "ee" { target mips*-*-* } } } */ | ||
847 | +/* { dg-final { cleanup-rtl-dump "ee" } } */ | ||
848 | + | ||
849 | |||
850 | === modified file 'gcc/timevar.def' | ||
851 | --- old/gcc/timevar.def 2009-11-27 12:43:08 +0000 | ||
852 | +++ new/gcc/timevar.def 2010-12-10 15:33:37 +0000 | ||
853 | @@ -162,6 +162,7 @@ | ||
854 | DEFTIMEVAR (TV_VARCONST , "varconst") | ||
855 | DEFTIMEVAR (TV_LOWER_SUBREG , "lower subreg") | ||
856 | DEFTIMEVAR (TV_JUMP , "jump") | ||
857 | +DEFTIMEVAR (TV_EE , "extension elimination") | ||
858 | DEFTIMEVAR (TV_FWPROP , "forward prop") | ||
859 | DEFTIMEVAR (TV_CSE , "CSE") | ||
860 | DEFTIMEVAR (TV_DCE , "dead code elimination") | ||
861 | |||
862 | === modified file 'gcc/tree-pass.h' | ||
863 | --- old/gcc/tree-pass.h 2010-09-01 13:29:58 +0000 | ||
864 | +++ new/gcc/tree-pass.h 2010-12-10 15:33:37 +0000 | ||
865 | @@ -468,6 +468,7 @@ | ||
866 | extern struct rtl_opt_pass pass_initial_value_sets; | ||
867 | extern struct rtl_opt_pass pass_unshare_all_rtl; | ||
868 | extern struct rtl_opt_pass pass_instantiate_virtual_regs; | ||
869 | +extern struct rtl_opt_pass pass_ee; | ||
870 | extern struct rtl_opt_pass pass_rtl_fwprop; | ||
871 | extern struct rtl_opt_pass pass_rtl_fwprop_addr; | ||
872 | extern struct rtl_opt_pass pass_jump2; | ||
873 | |||