angr.analyses.decompiler.peephole_optimizations.cmp_masked_shift

class angr.analyses.decompiler.peephole_optimizations.cmp_masked_shift.CmpMaskedShift

Bases: PeepholeOptimizationExprBase

Rewrite an equality comparison against a right-shifted value back into a masked comparison, which reads better for flag/discriminant checks.

(x >> n) == c ==> (x & mask) == (c << n) Convert(N->M, x >> n) == c ==> (x & mask) == (c << n)

where mask selects the compared bits [n, n+width-1] of x and width is the truncated width M (or N - n when there is no Convert). This is the inverse of a simplification that can turn (x & high_mask) == c (a mask that clears the low bits) into the shift/extract form: the masked compare is the clearer form in decompiled output, so restore it.

As a special case, when the compared bits are all bits above n and the constant is 0, the comparison is an unsigned bound check (libVEX 3.27+ spechelpers fold x <=u 2**n-1 into this form), so emit the bound check instead:

(x >> n) == 0 ==> x <=u 2**n - 1 (x >> n) != 0 ==> x >u 2**n - 1

Only logical right shifts and unsigned truncations are handled, and only n > 0 (a low-mask compare, n == 0, already reads as a cast).

NAME = '(x >> n) == c => (x & mask) == (c << n)'
expr_classes = (<class 'angr.ailment.expression.BinaryOp'>,)
optimize(expr, **kwargs)
Parameters:

expr (BinaryOp)