This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR39715 (Thumb pessimization)
- From: Paolo Bonzini <bonzini at gnu dot org>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Richard Earnshaw <rearnsha at arm dot com>
- Date: Sat, 1 Aug 2009 23:24:18 +0200
- Subject: [PATCH] Fix PR39715 (Thumb pessimization)
This patch fixes a bug in combine that originated PR39715. While
the pessimization in the PR was introduced by the cond-optab merge,
the bug was latent.
In the PR test case, after the cond-optab merge, an unnecessary sign
extension is introduced.
As explained in the PR, the bug is in combine's attempt to widen
the operands of a comparison. Combine incorrectly does this with a
paradoxical subreg; this however introduces undefined bits, so that
introducing the sign extension is actually correct.
With this patch, instead, a zero or sign extension is used. With this
more precise information, simplify-rtx.c can be taught to strip the
extension.
Also, since in general an AND is (if it cannot be eliminated) cheaper
than a zero or sign extension, I moved the other optimization done in
this area of combine earlier.
Tested i686-pc-linux-gnu, plus on arm-elf I looked by hand at some
testcases to test the paths I modified, but building a combined
tree failed with an internal assembler error.
Paolo
2009-08-01 Paolo Bonzini <bonzini@gnu.org>
PR rtl-optimization/39715
* combine.c (simplify_comparison): Use extensions to
widen comparisons. Try an ANDing first.
* simplify-rtx.c (simplify_relational_operation_1):
Look for useless extensions of a subreg, if the extension
is from the same mode as the subreg.
2009-08-01 Paolo Bonzini <bonzini@gnu.org>
* gcc.target/arm/thumb-bitfld1.c: New.
Index: gcc/combine.c
===================================================================
--- gcc/combine.c (branch cond-optab2)
+++ gcc/combine.c (working copy)
@@ -11208,6 +11208,22 @@ simplify_comparison (enum rtx_code code,
{
int zero_extended;
+ /* If this is a test for negative, we can make an explicit
+ test of the sign bit. Test this first so we can use
+ a paradoxical subreg to extend OP0. */
+
+ if (op1 == const0_rtx && (code == LT || code == GE)
+ && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ {
+ op0 = simplify_gen_binary (AND, tmode,
+ gen_lowpart (tmode, op0),
+ GEN_INT ((HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (mode)
+ - 1)));
+ code = (code == LT) ? NE : EQ;
+ break;
+ }
+
/* If the only nonzero bits in OP0 and OP1 are those in the
narrower mode and this is an equality or unsigned comparison,
we can use the wider mode. Similarly for sign-extended
@@ -11238,27 +11254,20 @@ simplify_comparison (enum rtx_code code,
XEXP (op0, 0)),
gen_lowpart (tmode,
XEXP (op0, 1)));
-
- op0 = gen_lowpart (tmode, op0);
- if (zero_extended && CONST_INT_P (op1))
- op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (mode));
- op1 = gen_lowpart (tmode, op1);
- break;
- }
-
- /* If this is a test for negative, we can make an explicit
- test of the sign bit. */
-
- if (op1 == const0_rtx && (code == LT || code == GE)
- && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
- {
- op0 = simplify_gen_binary (AND, tmode,
- gen_lowpart (tmode, op0),
- GEN_INT ((HOST_WIDE_INT) 1
- << (GET_MODE_BITSIZE (mode)
- - 1)));
- code = (code == LT) ? NE : EQ;
- break;
+ else
+ {
+ if (zero_extended)
+ {
+ op0 = simplify_gen_unary (ZERO_EXTEND, tmode, op0, mode);
+ op1 = simplify_gen_unary (ZERO_EXTEND, tmode, op1, mode);
+ }
+ else
+ {
+ op0 = simplify_gen_unary (SIGN_EXTEND, tmode, op0, mode);
+ op1 = simplify_gen_unary (SIGN_EXTEND, tmode, op1, mode);
+ }
+ break;
+ }
}
}
Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c (branch cond-optab2)
+++ gcc/simplify-rtx.c (working copy)
@@ -3990,6 +3990,49 @@ simplify_relational_operation_1 (enum rt
simplify_gen_binary (XOR, cmp_mode,
XEXP (op0, 1), op1));
+ /* Look for useless extensions of a subreg, if the extension
+ is from the same mode as the subreg. */
+ if (op0code == SIGN_EXTEND
+ && GET_CODE (XEXP (op0, 0)) == SUBREG
+ && subreg_lowpart_p (XEXP (op0, 0))
+ && GET_MODE (op0) == GET_MODE (SUBREG_REG (XEXP (op0, 0)))
+ && num_sign_bit_copies (SUBREG_REG (XEXP (op0, 0)), GET_MODE (op0))
+ > (unsigned) (GET_MODE_BITSIZE (GET_MODE (op0))
+ - GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))))
+ return simplify_gen_relational (code, mode, cmp_mode,
+ SUBREG_REG (XEXP (op0, 0)), op1);
+
+ if (GET_CODE (op1) == SIGN_EXTEND
+ && GET_CODE (XEXP (op1, 0)) == SUBREG
+ && subreg_lowpart_p (XEXP (op0, 0))
+ && GET_MODE (op1) == GET_MODE (SUBREG_REG (XEXP (op1, 0)))
+ && num_sign_bit_copies (SUBREG_REG (XEXP (op1, 0)), GET_MODE (op1))
+ > (unsigned) (GET_MODE_BITSIZE (GET_MODE (op1))
+ - GET_MODE_BITSIZE (GET_MODE (XEXP (op1, 0)))))
+ return simplify_gen_relational (code, mode, cmp_mode,
+ op0, SUBREG_REG (XEXP (op1, 0)));
+
+ if (code != LE && code != GE && code != LT && code != GT)
+ {
+ if (op0code == ZERO_EXTEND
+ && GET_CODE (XEXP (op0, 0)) == SUBREG
+ && subreg_lowpart_p (XEXP (op0, 0))
+ && GET_MODE (op0) == GET_MODE (SUBREG_REG (XEXP (op0, 0)))
+ && (nonzero_bits (SUBREG_REG (XEXP (op0, 0)), GET_MODE (op0))
+ & ~GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))) == 0)
+ return simplify_gen_relational (code, mode, cmp_mode,
+ SUBREG_REG (XEXP (op0, 0)), op1);
+
+ if (GET_CODE (op1) == ZERO_EXTEND
+ && GET_CODE (XEXP (op1, 0)) == SUBREG
+ && subreg_lowpart_p (XEXP (op0, 0))
+ && GET_MODE (op1) == GET_MODE (SUBREG_REG (XEXP (op1, 0)))
+ && (nonzero_bits (SUBREG_REG (XEXP (op1, 0)), GET_MODE (op1))
+ & ~GET_MODE_MASK (GET_MODE (XEXP (op1, 0)))) == 0)
+ return simplify_gen_relational (code, mode, cmp_mode,
+ op0, SUBREG_REG (XEXP (op1, 0)));
+ }
+
if (op0code == POPCOUNT && op1 == const0_rtx)
switch (code)
{
/* { dg-do compile } */
/* { dg-options "-O1 -mthumb -march=armv5t" } */
struct foo
{
unsigned b31 : 1;
unsigned b30 : 1;
unsigned b29 : 1;
unsigned b28 : 1;
unsigned rest : 28;
};
foo(a)
struct foo a;
{
return a.b30;
}
/* { dg-final { scan-assembler-times "lsl" 1 } } */
/* { dg-final { scan-assembler-times "lsr" 1 } } */