Hi, This is a simple fix for PR94026. With this fix, combine will try make an extraction if we are in a equality comparison and this is an AND with a constant which is power of two minus one. Shift here should be an constant. For example, combine will transform (compare (and (lshiftrt x 8) 6) 0) to (compare (zero_extract (x 2 9)) 0).
Added one test case for this. Bootstrap and tested on both x86_64 and aarch64 Linux platform. Any suggestion? Thanks, Felix gcc: +2020-03-04 Felix Yang <felix.y...@huawei.com> + + PR rtl-optimization/94026 + * combine.c (make_compound_operation_int): Make an extraction + if we are in a equality comparison and this is an AND with a + constant which is power of two minus one. + gcc/testsuite: +2020-03-04 Felix Yang <felix.y...@huawei.com> + + PR rtl-optimization/94026 + * gcc.dg/pr94026.c: New test. +
diff --git a/gcc/combine.c b/gcc/combine.c index 58366a6d331..c05064fc333 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -8170,14 +8170,31 @@ make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr, if (!CONST_INT_P (XEXP (x, 1))) break; + HOST_WIDE_INT pos; + unsigned HOST_WIDE_INT len; + pos = get_pos_from_mask (UINTVAL (XEXP (x, 1)), &len); + /* If the constant is a power of two minus one and the first operand - is a logical right shift, make an extraction. */ + is a logical right shift, make an extraction. + If we are in a equality comparison and this is an AND with a constant + which is power of two minus one, also make an extraction. */ if (GET_CODE (XEXP (x, 0)) == LSHIFTRT - && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0) + && (pos == 0 || (pos > 0 && equality_comparison + && CONST_INT_P (XEXP (XEXP (x, 0), 1))))) { new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code); - new_rtx = make_extraction (mode, new_rtx, 0, XEXP (XEXP (x, 0), 1), - i, 1, 0, in_code == COMPARE); + if (pos == 0) + { + new_rtx = make_extraction (mode, new_rtx, 0, + XEXP (XEXP (x, 0), 1), len, 1, 0, + in_code == COMPARE); + } + else + { + int real_pos = pos + UINTVAL (XEXP (XEXP (x, 0), 1)); + new_rtx = make_extraction (mode, new_rtx, real_pos, NULL_RTX, + len, 1, 0, in_code == COMPARE); + } } /* Same as previous, but for (subreg (lshiftrt ...)) in first op. */ @@ -8186,13 +8203,25 @@ make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr, && is_a <scalar_int_mode> (GET_MODE (SUBREG_REG (XEXP (x, 0))), &inner_mode) && GET_CODE (SUBREG_REG (XEXP (x, 0))) == LSHIFTRT - && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0) + && (pos == 0 + || (pos > 0 && equality_comparison + && CONST_INT_P (XEXP (SUBREG_REG (XEXP (x, 0)), 1))))) { rtx inner_x0 = SUBREG_REG (XEXP (x, 0)); new_rtx = make_compound_operation (XEXP (inner_x0, 0), next_code); - new_rtx = make_extraction (inner_mode, new_rtx, 0, - XEXP (inner_x0, 1), - i, 1, 0, in_code == COMPARE); + if (pos == 0) + { + new_rtx = make_extraction (inner_mode, new_rtx, 0, + XEXP (inner_x0, 1), + len, 1, 0, in_code == COMPARE); + } + else + { + int real_pos = pos + UINTVAL (XEXP (inner_x0, 1)); + new_rtx = make_extraction (inner_mode, new_rtx, real_pos, + NULL_RTX, len, 1, 0, + in_code == COMPARE); + } /* If we narrowed the mode when dropping the subreg, then we lose. */ if (GET_MODE_SIZE (inner_mode) < GET_MODE_SIZE (mode)) @@ -8200,10 +8229,10 @@ make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr, /* If that didn't give anything, see if the AND simplifies on its own. */ - if (!new_rtx && i >= 0) + if (!new_rtx) { new_rtx = make_compound_operation (XEXP (x, 0), next_code); - new_rtx = make_extraction (mode, new_rtx, 0, NULL_RTX, i, 1, + new_rtx = make_extraction (mode, new_rtx, pos, NULL_RTX, len, 1, 0, in_code == COMPARE); } } @@ -8212,7 +8241,7 @@ make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr, || GET_CODE (XEXP (x, 0)) == IOR) && GET_CODE (XEXP (XEXP (x, 0), 0)) == LSHIFTRT && GET_CODE (XEXP (XEXP (x, 0), 1)) == LSHIFTRT - && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0) + && (pos == 0 || (pos > 0 && equality_comparison))) { /* Apply the distributive law, and then try to make extractions. */ new_rtx = gen_rtx_fmt_ee (GET_CODE (XEXP (x, 0)), mode, @@ -8228,14 +8257,14 @@ make_compound_operation_int (scalar_int_mode mode, rtx *x_ptr, else if (GET_CODE (XEXP (x, 0)) == ROTATE && CONST_INT_P (XEXP (XEXP (x, 0), 1)) - && (i = exact_log2 (UINTVAL (XEXP (x, 1)) + 1)) >= 0 - && i <= INTVAL (XEXP (XEXP (x, 0), 1))) + && (pos == 0 || (pos > 0 && equality_comparison)) + && pos + len <= UINTVAL (XEXP (XEXP (x, 0), 1))) { new_rtx = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code); new_rtx = make_extraction (mode, new_rtx, (GET_MODE_PRECISION (mode) - - INTVAL (XEXP (XEXP (x, 0), 1))), - NULL_RTX, i, 1, 0, in_code == COMPARE); + - UINTVAL (XEXP (XEXP (x, 0), 1)) + pos), + NULL_RTX, len, 1, 0, in_code == COMPARE); } /* On machines without logical shifts, if the operand of the AND is diff --git a/gcc/testsuite/gcc.dg/pr94026.c b/gcc/testsuite/gcc.dg/pr94026.c new file mode 100644 index 00000000000..7b5184dfb2c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr94026.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target aarch64*-*-* i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -fdump-rtl-combine" } */ + +int +foo (int c) +{ + int a = (c >> 8) & 7; + + if (a >= 2) { + return 1; + } + + return 0; +} + +/* The combine phase should transform (compare (and (lshiftrt x 8) 6) 0) + to (compare (zero_extract (x 2 9)) 0). We look for the *attempt* + to match this RTL pattern, regardless of whether an actual insn + may be found on the platform. */ +/* { dg-final { scan-rtl-dump "\\(zero_extract" "combine" } } */