This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PR/13274] Fold subregs that are produced by zero_extend
- From: Paolo Bonzini <paolo dot bonzini at polimi dot it>
- To: Richard Henderson <rth at redhat dot com>, gcc-patches at gcc dot gnu dot org, roger at eyesopen dot com
- Date: Tue, 20 Jan 2004 12:28:43 +0100
- Subject: Re: [PR/13274] Fold subregs that are produced by zero_extend
- References: <400BD6FE.2030100@polimi.it> <20040119210724.GF20347@redhat.com>
- Reply-to: bonzini at gnu dot org
I think you should be using subreg_lsb here.
Did not know about this (not heavily used...) function. This version of
the patch (bootstrapped on i686-pc-linux-gnu, C/C++/Java) is smaller
than the first take, so that I think it does not require a copyright
assignment (it is just ten lines of added code, one line being moved,
and a big comment being moved and reformatted). I am going to file it
anyway as soon as possible.
I also tried to follow Roger's comment and add the simplification in
simplify_subreg. However in my case the SUBREG holds a REG, which
cannot be folded, so fold_rtx does not call simplify_subreg. I had
hoped that the combiner did something and even that -O0 would do the
optimization, but I am probably not understanding it. I got it to
optimize (and bootstrap) if I made fold_rtx try simplifying every
equivalence of the SUBREG's operand if it is a REG. Not sure if it does
actually improve performance in other cases (and what impact it has on
compile time, subregs are not terribly frequent but...), but I can
provide the patch if you want.
2004-01-20 Paolo Bonzini <bonzini@gnu.org>
PR optimization/13724
* cse.c (fold_rtx) <SUBREG>: Fold a SUBREG to zero
if it represents the zero bits produced by a ZERO_EXTEND
operation.
Paolo
--- cse.c.save 2004-01-12 12:15:32.000000000 +0100
+++ cse.c 2004-01-20 11:12:18.000000000 +0100
@@ -3353,24 +3353,8 @@
return new;
}
- /* If this is a narrowing SUBREG and our operand is a REG, see if
- we can find an equivalence for REG that is an arithmetic operation
- in a wider mode where both operands are paradoxical SUBREGs
- from objects of our result mode. In that case, we couldn't report
- an equivalent value for that operation, since we don't know what the
- extra bits will be. But we can find an equivalence for this SUBREG
- by folding that operation is the narrow mode. This allows us to
- fold arithmetic in narrow modes when the machine only supports
- word-sized arithmetic.
-
- Also look for a case where we have a SUBREG whose operand is the
- same as our result. If both modes are smaller than a word, we
- are simply interpreting a register in different modes and we
- can use the inner value. */
-
if (GET_CODE (folded_arg0) == REG
- && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0))
- && subreg_lowpart_p (x))
+ && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0)))
{
struct table_elt *elt;
@@ -3383,95 +3367,120 @@
if (elt)
elt = elt->first_same_value;
- for (; elt; elt = elt->next_same_value)
- {
- enum rtx_code eltcode = GET_CODE (elt->exp);
-
- /* Just check for unary and binary operations. */
- if (GET_RTX_CLASS (GET_CODE (elt->exp)) == '1'
- && GET_CODE (elt->exp) != SIGN_EXTEND
- && GET_CODE (elt->exp) != ZERO_EXTEND
- && GET_CODE (XEXP (elt->exp, 0)) == SUBREG
- && GET_MODE (SUBREG_REG (XEXP (elt->exp, 0))) == mode
- && (GET_MODE_CLASS (mode)
- == GET_MODE_CLASS (GET_MODE (XEXP (elt->exp, 0)))))
- {
- rtx op0 = SUBREG_REG (XEXP (elt->exp, 0));
+ if (subreg_lowpart_p (x))
+ /* If this is a narrowing SUBREG and our operand is a REG, see
+ if we can find an equivalence for REG that is an arithmetic
+ operation in a wider mode where both operands are paradoxical
+ SUBREGs from objects of our result mode. In that case, we
+ couldn-t report an equivalent value for that operation, since we
+ don't know what the extra bits will be. But we can find an
+ equivalence for this SUBREG by folding that operation in the
+ narrow mode. This allows us to fold arithmetic in narrow modes
+ when the machine only supports word-sized arithmetic.
+
+ Also look for a case where we have a SUBREG whose operand
+ is the same as our result. If both modes are smaller
+ than a word, we are simply interpreting a register in
+ different modes and we can use the inner value. */
- if (GET_CODE (op0) != REG && ! CONSTANT_P (op0))
- op0 = fold_rtx (op0, NULL_RTX);
+ for (; elt; elt = elt->next_same_value)
+ {
+ enum rtx_code eltcode = GET_CODE (elt->exp);
- op0 = equiv_constant (op0);
- if (op0)
- new = simplify_unary_operation (GET_CODE (elt->exp), mode,
- op0, mode);
- }
- else if ((GET_RTX_CLASS (GET_CODE (elt->exp)) == '2'
- || GET_RTX_CLASS (GET_CODE (elt->exp)) == 'c')
- && eltcode != DIV && eltcode != MOD
- && eltcode != UDIV && eltcode != UMOD
- && eltcode != ASHIFTRT && eltcode != LSHIFTRT
- && eltcode != ROTATE && eltcode != ROTATERT
- && ((GET_CODE (XEXP (elt->exp, 0)) == SUBREG
- && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 0)))
- == mode))
- || CONSTANT_P (XEXP (elt->exp, 0)))
- && ((GET_CODE (XEXP (elt->exp, 1)) == SUBREG
- && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 1)))
- == mode))
- || CONSTANT_P (XEXP (elt->exp, 1))))
- {
- rtx op0 = gen_lowpart_common (mode, XEXP (elt->exp, 0));
- rtx op1 = gen_lowpart_common (mode, XEXP (elt->exp, 1));
+ /* Just check for unary and binary operations. */
+ if (GET_RTX_CLASS (GET_CODE (elt->exp)) == '1'
+ && GET_CODE (elt->exp) != SIGN_EXTEND
+ && GET_CODE (elt->exp) != ZERO_EXTEND
+ && GET_CODE (XEXP (elt->exp, 0)) == SUBREG
+ && GET_MODE (SUBREG_REG (XEXP (elt->exp, 0))) == mode
+ && (GET_MODE_CLASS (mode)
+ == GET_MODE_CLASS (GET_MODE (XEXP (elt->exp, 0)))))
+ {
+ rtx op0 = SUBREG_REG (XEXP (elt->exp, 0));
- if (op0 && GET_CODE (op0) != REG && ! CONSTANT_P (op0))
- op0 = fold_rtx (op0, NULL_RTX);
+ if (GET_CODE (op0) != REG && ! CONSTANT_P (op0))
+ op0 = fold_rtx (op0, NULL_RTX);
- if (op0)
op0 = equiv_constant (op0);
+ if (op0)
+ new = simplify_unary_operation (GET_CODE (elt->exp), mode,
+ op0, mode);
+ }
+ else if ((GET_RTX_CLASS (GET_CODE (elt->exp)) == '2'
+ || GET_RTX_CLASS (GET_CODE (elt->exp)) == 'c')
+ && eltcode != DIV && eltcode != MOD
+ && eltcode != UDIV && eltcode != UMOD
+ && eltcode != ASHIFTRT && eltcode != LSHIFTRT
+ && eltcode != ROTATE && eltcode != ROTATERT
+ && ((GET_CODE (XEXP (elt->exp, 0)) == SUBREG
+ && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 0)))
+ == mode))
+ || CONSTANT_P (XEXP (elt->exp, 0)))
+ && ((GET_CODE (XEXP (elt->exp, 1)) == SUBREG
+ && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 1)))
+ == mode))
+ || CONSTANT_P (XEXP (elt->exp, 1))))
+ {
+ rtx op0 = gen_lowpart_common (mode, XEXP (elt->exp, 0));
+ rtx op1 = gen_lowpart_common (mode, XEXP (elt->exp, 1));
- if (op1 && GET_CODE (op1) != REG && ! CONSTANT_P (op1))
- op1 = fold_rtx (op1, NULL_RTX);
-
- if (op1)
- op1 = equiv_constant (op1);
+ if (op0 && GET_CODE (op0) != REG && ! CONSTANT_P (op0))
+ op0 = fold_rtx (op0, NULL_RTX);
- /* If we are looking for the low SImode part of
- (ashift:DI c (const_int 32)), it doesn't work
- to compute that in SImode, because a 32-bit shift
- in SImode is unpredictable. We know the value is 0. */
- if (op0 && op1
- && GET_CODE (elt->exp) == ASHIFT
- && GET_CODE (op1) == CONST_INT
- && INTVAL (op1) >= GET_MODE_BITSIZE (mode))
- {
- if (INTVAL (op1) < GET_MODE_BITSIZE (GET_MODE (elt->exp)))
+ if (op0)
+ op0 = equiv_constant (op0);
- /* If the count fits in the inner mode's width,
- but exceeds the outer mode's width,
- the value will get truncated to 0
- by the subreg. */
- new = const0_rtx;
- else
- /* If the count exceeds even the inner mode's width,
+ if (op1 && GET_CODE (op1) != REG && ! CONSTANT_P (op1))
+ op1 = fold_rtx (op1, NULL_RTX);
+
+ if (op1)
+ op1 = equiv_constant (op1);
+
+ /* If we are looking for the low SImode part of
+ (ashift:DI c (const_int 32)), it doesn't work
+ to compute that in SImode, because a 32-bit shift
+ in SImode is unpredictable. We know the value is 0. */
+ if (op0 && op1
+ && GET_CODE (elt->exp) == ASHIFT
+ && GET_CODE (op1) == CONST_INT
+ && INTVAL (op1) >= GET_MODE_BITSIZE (mode))
+ {
+ if (INTVAL (op1)
+ < GET_MODE_BITSIZE (GET_MODE (elt->exp)))
+ /* If the count fits in the inner mode's width,
+ but exceeds the outer mode's width,
+ the value will get truncated to 0
+ by the subreg. */
+ new = const0_rtx;
+ else
+ /* If the count exceeds even the inner mode's width,
don't fold this expression. */
- new = 0;
- }
- else if (op0 && op1)
- new = simplify_binary_operation (GET_CODE (elt->exp), mode,
- op0, op1);
- }
+ new = 0;
+ }
+ else if (op0 && op1)
+ new = simplify_binary_operation (GET_CODE (elt->exp), mode, op0, op1);
+ }
- else if (GET_CODE (elt->exp) == SUBREG
- && GET_MODE (SUBREG_REG (elt->exp)) == mode
- && (GET_MODE_SIZE (GET_MODE (folded_arg0))
- <= UNITS_PER_WORD)
- && exp_equiv_p (elt->exp, elt->exp, 1, 0))
- new = copy_rtx (SUBREG_REG (elt->exp));
+ else if (GET_CODE (elt->exp) == SUBREG
+ && GET_MODE (SUBREG_REG (elt->exp)) == mode
+ && (GET_MODE_SIZE (GET_MODE (folded_arg0))
+ <= UNITS_PER_WORD)
+ && exp_equiv_p (elt->exp, elt->exp, 1, 0))
+ new = copy_rtx (SUBREG_REG (elt->exp));
- if (new)
- return new;
- }
+ if (new)
+ return new;
+ }
+ else
+ /* A SUBREG resulting from a zero extension may fold to zero if
+ it extracts higher bits than the ZERO_EXTEND's source bits. */
+ for (; elt; elt = elt->next_same_value)
+ {
+ if (GET_CODE (elt->exp) == ZERO_EXTEND
+ && subreg_lsb (x) / BITS_PER_UNIT
+ >= GET_MODE_SIZE (GET_MODE (XEXP (elt->exp, 0))))
+ return const0_rtx;
+ }
}
return x;
--- cse.c.save 2004-01-12 12:15:32.000000000 +0100
+++ cse.c 2004-01-20 11:12:18.000000000 +0100
@@ -3353,24 +3353,8 @@
return new;
}
- /* If this is a narrowing SUBREG and our operand is a REG, see if
- we can find an equivalence for REG that is an arithmetic operation
- in a wider mode where both operands are paradoxical SUBREGs
- from objects of our result mode. In that case, we couldn't report
- an equivalent value for that operation, since we don't know what the
- extra bits will be. But we can find an equivalence for this SUBREG
- by folding that operation is the narrow mode. This allows us to
- fold arithmetic in narrow modes when the machine only supports
- word-sized arithmetic.
-
- Also look for a case where we have a SUBREG whose operand is the
- same as our result. If both modes are smaller than a word, we
- are simply interpreting a register in different modes and we
- can use the inner value. */
-
if (GET_CODE (folded_arg0) == REG
- && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0))
- && subreg_lowpart_p (x))
+ && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0)))
{
struct table_elt *elt;
@@ -3383,6 +3367,22 @@
if (elt)
elt = elt->first_same_value;
+ if (subreg_lowpart_p (x))
+ /* If this is a narrowing SUBREG and our operand is a REG, see
+ if we can find an equivalence for REG that is an arithmetic
+ operation in a wider mode where both operands are paradoxical
+ SUBREGs from objects of our result mode. In that case, we
+ couldn-t report an equivalent value for that operation, since we
+ don't know what the extra bits will be. But we can find an
+ equivalence for this SUBREG by folding that operation in the
+ narrow mode. This allows us to fold arithmetic in narrow modes
+ when the machine only supports word-sized arithmetic.
+
+ Also look for a case where we have a SUBREG whose operand
+ is the same as our result. If both modes are smaller
+ than a word, we are simply interpreting a register in
+ different modes and we can use the inner value. */
+
for (; elt; elt = elt->next_same_value)
{
enum rtx_code eltcode = GET_CODE (elt->exp);
@@ -3445,8 +3445,8 @@
&& GET_CODE (op1) == CONST_INT
&& INTVAL (op1) >= GET_MODE_BITSIZE (mode))
{
- if (INTVAL (op1) < GET_MODE_BITSIZE (GET_MODE (elt->exp)))
-
+ if (INTVAL (op1)
+ < GET_MODE_BITSIZE (GET_MODE (elt->exp)))
/* If the count fits in the inner mode's width,
but exceeds the outer mode's width,
the value will get truncated to 0
@@ -3458,8 +3458,7 @@
new = 0;
}
else if (op0 && op1)
- new = simplify_binary_operation (GET_CODE (elt->exp), mode,
- op0, op1);
+ new = simplify_binary_operation (GET_CODE (elt->exp), mode, op0, op1);
}
else if (GET_CODE (elt->exp) == SUBREG
@@ -3472,6 +3471,16 @@
if (new)
return new;
}
+ else
+ /* A SUBREG resulting from a zero extension may fold to zero if
+ it extracts higher bits than the ZERO_EXTEND's source bits. */
+ for (; elt; elt = elt->next_same_value)
+ {
+ if (GET_CODE (elt->exp) == ZERO_EXTEND
+ && subreg_lsb (x) / BITS_PER_UNIT
+ >= GET_MODE_SIZE (GET_MODE (XEXP (elt->exp, 0))))
+ return const0_rtx;
+ }
}
return x;