Hi there,
When compile below case for ARM Thumb-2 target:
long long int
test (unsigned long long int a, unsigned int b)
{
return (a & 0xFFFFFFFF) * b;
}
I find the GCC function simplify_subreg fails to simplify rtx (subreg:SI
(and:DI (reg/v:DI 115 [ a ]) (const_int 4294967295 [0xffffffff])) 4) to zero
during the fwprop1 pass, considering the fact that the high 32-bit part of
(a & 0xFFFFFFFF) is zero. This leads to some unnecessary multiplications for
high 32-bit part of the result of AND operation. The attached patch is
trying to improve simplify_rtx to handle such case. Other target like x86
seems hasn't such issue because it generates different RTX to handle 64bit
multiplication on a 32bit machine.
Bootstrapped gcc on x86 machine, no problem. Tested with gcc regression test
for x86 and Thumb2, no regression.
Is it OK to stage-1?
BR,
Terry
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 04af01e..0ed88fb 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -6099,6 +6099,19 @@ simplify_subreg (enum machine_mode outermode, rtx op,
return CONST0_RTX (outermode);
}
+ /* The AND operation may clear the target bits of SUBREG to zero.
+ Then we just need to return a zero. Here is an example:
+ (subreg:SI (and:DI (reg:DI X) (const_int 0xFFFFFFFF)) 4). */
+ if (GET_CODE (op) == AND && SCALAR_INT_MODE_P (innermode))
+ {
+ unsigned int bitpos = subreg_lsb_1 (outermode, innermode, byte);
+ unsigned HOST_WIDE_INT nzmask = nonzero_bits (op, innermode);
+ unsigned HOST_WIDE_INT smask = GET_MODE_MASK (outermode);
+
+ if (((smask << bitpos) & nzmask) == 0)
+ return CONST0_RTX (outermode);
+ }
+
if (SCALAR_INT_MODE_P (outermode)
&& SCALAR_INT_MODE_P (innermode)
&& GET_MODE_PRECISION (outermode) < GET_MODE_PRECISION (innermode)
diff --git a/gcc/testsuite/gcc.target/arm/umull.c
b/gcc/testsuite/gcc.target/arm/umull.c
new file mode 100644
index 0000000..2e39baa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/umull.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { arm_thumb1 } } */
+/* { dg-options "-O2" } */
+
+long long int
+test (unsigned long long int a, unsigned int b)
+{
+ return (a & 0xFFFFFFFF) * b;
+}
+
+/* { dg-final { scan-assembler-not "mla" } } */