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

Reply via email to