mbox series

[RFC,0/1] aarch64: Simplify __range_ok

Message ID 20200321051352.16484-1-richard.henderson@linaro.org (mailing list archive)
Headers show
Series aarch64: Simplify __range_ok | expand

Message

Richard Henderson March 21, 2020, 5:13 a.m. UTC
Continuing the conversation from last week, in which I attempted
to improve __range_ok with gcc asm flag outputs.  Mark and Robin
suggested it might be time to move back to C.

The largest improvment that I can manage avoids 65-bit arithmetic
entirely.  I simply need to assume that limit has some minimum value.
This covers the vast majority of the uses within the kernel.


r~


Richard Henderson (1):
  arm64: Simplify __range_ok

 arch/arm64/include/asm/uaccess.h | 31 +++++++++++++------------------
 1 file changed, 13 insertions(+), 18 deletions(-)

---

In the meanime, I've also done some work on 128-bit comparisons
for gcc.  It improves the general case, but note that the constant
case is handled even by an older compiler.

https://gcc.gnu.org/pipermail/gcc-patches/2020-March/542447.html

------------------ Test

void doit(void);
void robin(unsigned long addr, unsigned long size, unsigned long limit)
{
        __uint128_t tmp = (__uint128_t)addr + size;
        if (!tmp || tmp - 1 <= limit)
                doit();
}

static inline bool
range_ok(unsigned long addr, unsigned long size, unsigned long limit)
{
        if (__builtin_constant_p(size) && size > 0 && size < 0x100000)
                return addr <= limit + 1 - size;
        return (__uint128_t)addr + size <= (__uint128_t)limit + 1;
}

void test_v(unsigned long addr, unsigned long size, unsigned long limit)
{
        if (range_ok(addr, size, limit)) doit();
}

void test_0(unsigned long addr, unsigned long limit)
{
        if (range_ok(addr, 0, limit)) doit();
}

void test_1(unsigned long addr, unsigned long limit)
{
        if (range_ok(addr, 1, limit)) doit();
}

void test_10(unsigned long addr, unsigned long limit)
{
        if (range_ok(addr, 10, limit)) doit();
}

------------------ GCC 10.0.1 patched

robin:
        adds    x1, x0, x1
        cset    x0, cs
        orr     x3, x0, x1
        cbz     x3, .L2
        subs    x1, x1, #1
        sbc     x0, x0, xzr
        cmp     x2, x1
        sbcs    xzr, xzr, x0
        bcc     .L1
.L2:	b       doit
.L1:	ret

test_v:
        adds    x0, x0, x1
        cset    x1, cs
        adds    x2, x2, #1
        cset    x3, cs
        cmp     x2, x0
        sbcs    xzr, x3, x1
        bcs     .L10
        ret
.L10:	b       doit

test_0:
        adds    x1, x1, #1
        cset    x2, cs
        cmp     x1, x0
        sbcs    xzr, x2, xzr
        bcs     .L13
        ret
.L13:	b       doit

test_1:
        cmp     x0, x1
        bls     .L16
        ret
.L16:	b       doit

test_10:
        sub     x1, x1, #9
        cmp     x0, x1
        bls     .L19
        ret
.L19:	b       doit

------------------ GCC 7.5-ubuntu~18.04

robin:
        adds    x0, x0, x1
        cset    x1, cs
        orr     x3, x0, x1
        cbz     x3, .L2
        subs    x0, x0, #1
        sbc     x1, x1, xzr
        cbnz    x1, .L1
        cmp     x0, x2
        bhi     .L1
.L2:	b       doit
.L1:	ret

test_v:
        adds    x0, x0, x1
        cset    x4, cs
        adds    x2, x2, 1
        cset    x3, cs
        cmp     x4, x3
        bls     .L14
.L10:	ret
.L14:	bne     .L13
        cmp     x0, x2
        bhi     .L10
.L13:	b       doit

test_0:
        adds    x1, x1, 1
        bcs     .L18
        cmp     x0, x1
        bls     .L18
        ret
.L18:	b       doit

test_1:
        cmp     x0, x1
        bls     .L21
        ret
.L21:	b       doit

test_10:
        sub     x1, x1, #9
        cmp     x0, x1
        bls     .L24
        ret
.L24:	b       doit