On 3/2/2026 6:26 AM, Daniel Henrique Barboza wrote:
> From: Daniel Barboza <[email protected]>
>
> Given a comparison with the format
>
> A << CST1 EQ|NE CST2
>
> Turn it into:
>
> A & CSTmask EQ|NE CST2 >> CST1
>
> Where 'CSTmask' is a bitmask that filters A bits that would be discarded
> during the shift. The idea is that a bit_and is, on most common targets
> at least, more efficient than a lshift.
>
> Note that we're not handling the case "A << 1 != CST2" because this is a
> pattern that is optimized by tree-ssa-loop-niter.cc, turning a whole
> loop into a single CTZ().
>
> Bootstrapped and regression tested on x86. Includes aarch64 regression
> changes pointed by Linaro automatic CI bot.
>
> PR tree-optimization/124019
>
> gcc/ChangeLog:
>
> * match.pd (`A<<CST1 EQ|NE CST2 -> (A&CSTmask) EQ|NE (CST2>>CST1)`):
> New pattern.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/aarch64/cmp_shifted_reg_1.c: changed shift
> immediate to "1" to dodge this optimization and keep
> generating the shift and compare.
> * gcc.target/aarch64/negs.c: changed shift immediate to "1" in
> negs_si_test3 and negs_di_test3, and switched the comparison
> from "== 0" to "!= 0", to dodge this optimization and keep
> generating "negs". Expected value for both were updated
> accordingly.
> * gcc.dg/tree-ssa/pr124019.c: New test.
lol. My first thought was this is a canonicalization pattern rather
than a simplification pattern based on the fact that it doesn't reduce
the number of expressions evaluated. Then I reviewed the PR again,
that's exactly what we were shooting for. Duh.
> +(for cmp (eq ne)
> + (simplify
> + (cmp (lshift@3 @0 INTEGER_CST@1) INTEGER_CST@2)
> + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
> + && TREE_INT_CST_LOW (@1) <= TYPE_PRECISION (TREE_TYPE (@0))
> + /* The "A << 1 != CST1" pattern is used in trailing zero
> + count detection to determine if a loop consists of a
> + CTZ call, and that generates better code than what
> + we're doing here. See pr114760-1.c, ntz32_3 () for
> + more info. */
> + && (!(cmp == NE_EXPR && TREE_INT_CST_LOW (@1) == 1)))
Per the patch review for another shift case earlier today. It's
probably wise to verify the shift count is non-negative as well. You
also need to make sure @2 is unsigned, otherwise you're potentially
doing a left shift of a signed integer. I also think you want to test
"<" rather than "<=". If the shift count matches the precision then I
think we're in undefined or implementation defined behavior space.
Rather than TREE_INT_CST_LOW, you can use tree_to_[su]hwi to convert
into a signed or unsigned HOST_WIDE_INT.
Don't you need to verify the low @1 bits of the constant @2 are zero?
Very much looks to be on the right track, just niggling details. We
probably should do some kind of test to ensure cris-elf doesn't
obviously regress its code generation. Probably take the main testcase
you've got compile it before/after and compare the results. Even better
would be to turn that into a test in the testsuite. You can #include
the main test from the cris specific directory, but provide your own dg
directives. ie
/* dg-whatever */
#include <../../whatever.c>
/* dg-final-whatever */
Not sure the best scan to do. We could use the objdump scan to check
the size of the text sections (m68k has examples of this), or
check-function-bodies, though it'll require a fair amount of regexp work
to ensure it's not dependent on specific registers and such.
jeff