This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Fix PR rtl-optimization/28636
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 10 Sep 2006 23:34:17 +0200
- Subject: Fix PR rtl-optimization/28636
It's a regression present at -O2 on the 4.0 and 4.1 branches (latent on
the mainline) for LP64 IA-64 platforms. The interesting bits are:
struct input_ty
{
unsigned char *buffer_position;
unsigned char *buffer_end;
};
int check_header (struct input_ty *deeper)
{
[...]
if (((deeper)->buffer_position < (deeper)->buffer_end
? *((deeper)->buffer_position)++
: input_getc_complicated((deeper))) < 0)
It turns out that, even at -O2, the RTL combiner is the first pass to deduce
that
*((deeper)->buffer_position)++ < 0
is always false. So it will simplify the condition; but on IA-64 the load
contains a POST_INC
(insn 22 21 24 2 (set (reg:DI 352)
(zero_extend:DI (mem:QI (post_inc:DI (reg:DI 343 [ D.1386 ])) [0 S1
A8]))) 35 {zero_extendqidi2} (nil)
(expr_list:REG_INC (reg:DI 343 [ D.1386 ])
(nil)))
and this will get lost in the process. The simplification to zero can happen
in (at least) 3 places in the combiner which all need to test for side-effects
in order to get correct code on the 4.1 branch.
The problem does not show up on the mainline because fold_binary is able to
simplify
(int) <unsigned char expr> < 0
to false during parsing, thanks to
2006-02-24 Roger Sayle <roger@eyesopen.com>
* fold-const.c (fold_comparison): New subroutine of fold_binary
containing transformations common to both the equality and
ordering relational operators, factored out of fold_binary.
(fold_binary): Separate out the equality operators (EQ_EXPR
and NE_EXPR) from the ordering operators (LT_EXPR, GT_EXPR,
LE_EXPR and GE_EXPR), calling fold_comparison to perform the
transformations common to both.
(fold_div_compare): Fix latent bugs in the previously unreachable
LT_EXPR and GE_EXPR cases.
The code in fold_binary that triggers on the mainline is present on the 4.1
branch but the function is so convoluted in the latter case as to prevent
this code from simply being reached...
Bootstrapped/regtested on IA-64/HP-UX, applied to all active branches. It has
no effects on the gcc.c-torture/compile testcases at -O2 on this platform.
2006-09-10 Eric Botcazou <ebotcazou@libertysurf.fr>
PR rtl-optimization/28636
* combine.c (force_to_mode): Test for side-effects before
substituting by zero.
(simplify_shift_const): Likewise for zero or other constants.
2006-09-10 Eric Botcazou <ebotcazou@libertysurf.fr>
* gcc.c-torture/execute/20060910-1.c: New test.
--
Eric Botcazou
Index: combine.c
===================================================================
--- combine.c (revision 116795)
+++ combine.c (working copy)
@@ -7022,7 +7022,7 @@ force_to_mode (rtx x, enum machine_mode
nonzero = nonzero_bits (x, mode);
/* If none of the bits in X are needed, return a zero. */
- if (! just_select && (nonzero & mask) == 0)
+ if (!just_select && (nonzero & mask) == 0 && !side_effects_p (x))
x = const0_rtx;
/* If X is a CONST_INT, return a new one. Do this here since the
@@ -8802,14 +8802,14 @@ simplify_shift_const (rtx x, enum rtx_co
== 0))
code = LSHIFTRT;
- if (code == LSHIFTRT
- && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
- && !(nonzero_bits (varop, shift_mode) >> count))
- varop = const0_rtx;
- if (code == ASHIFT
- && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
- && !((nonzero_bits (varop, shift_mode) << count)
- & GET_MODE_MASK (shift_mode)))
+ if (((code == LSHIFTRT
+ && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
+ && !(nonzero_bits (varop, shift_mode) >> count))
+ || (code == ASHIFT
+ && GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
+ && !((nonzero_bits (varop, shift_mode) << count)
+ & GET_MODE_MASK (shift_mode))))
+ && !side_effects_p (varop))
varop = const0_rtx;
switch (GET_CODE (varop))
@@ -9443,9 +9443,12 @@ simplify_shift_const (rtx x, enum rtx_co
if (outer_op == AND)
x = simplify_and_const_int (NULL_RTX, result_mode, x, outer_const);
else if (outer_op == SET)
- /* This means that we have determined that the result is
- equivalent to a constant. This should be rare. */
- x = GEN_INT (outer_const);
+ {
+ /* This means that we have determined that the result is
+ equivalent to a constant. This should be rare. */
+ if (!side_effects_p (x))
+ x = GEN_INT (outer_const);
+ }
else if (GET_RTX_CLASS (outer_op) == RTX_UNARY)
x = simplify_gen_unary (outer_op, result_mode, x, result_mode);
else
/* PR rtl-optimization/28636 */
/* Origin: Andreas Schwab <schwab@suse.de> */
extern void abort(void);
struct input_ty
{
unsigned char *buffer_position;
unsigned char *buffer_end;
};
int input_getc_complicated (struct input_ty *x) { return 0; }
int check_header (struct input_ty *deeper)
{
unsigned len;
for (len = 0; len < 6; len++)
if (((deeper)->buffer_position < (deeper)->buffer_end
? *((deeper)->buffer_position)++
: input_getc_complicated((deeper))) < 0)
return 0;
return 1;
}
struct input_ty s;
unsigned char b[6];
int main (void)
{
s.buffer_position = b;
s.buffer_end = b + sizeof b;
if (!check_header(&s))
abort();
if (s.buffer_position != s.buffer_end)
abort();
return 0;
}