https://llvm.org/bugs/show_bug.cgi?id=28672

            Bug ID: 28672
           Summary: Integer divide by constant close to UINT*_MAX can be
                    compare rather than divide
           Product: new-bugs
           Version: trunk
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: new bugs
          Assignee: unassignedb...@nondot.org
          Reporter: simon.ho...@arm.com
                CC: llvm-bugs@lists.llvm.org
    Classification: Unclassified

When doing unsigned division by an integer which is greater than `UINT_MAX / 2`
(or another range limit in place of UINT_MAX, as appropriate), the result can
be only 0 or 1, and this can be evaluated with a compare rather than a
reciprocal-multiply (or divide).

For example:

    uint32_t f(uint32_t x) { return (x + 1) % 4000569407; }

is equivalent to:

    uint32_t f(uint32_t x) { x++; return x < 4000569407 ? x : x - 4000569407; }

Clang gives me:

        clang --target=arm-linux-gnueabihf -O3 -S -o- p1modk.c

        ldr     r1, .LCPI0_0        // 316062335
        add     r0, r0, #1
        umull   r1, r2, r0, r1
        sub     r1, r0, r2
        add     r1, r2, r1, lsr #1
        ldr     r2, .LCPI0_1        // 4000569407
        lsr     r1, r1, #31
        mul     r1, r1, r2
        sub     r0, r0, r1

I expect something more like:

        ldr     r1, =4000569407
        add     r0, r0, #1
        cmp     r0, r1
        subhs   r0, r0, r1


Note that this applicable in loops containing the `x = (x + 1) % k;` idiom if x
can be shown to be never greater than k (even if k is variable, I think).

-- 
You are receiving this mail because:
You are on the CC list for the bug.
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to