Skip to content

[aarch64] [missed-opt] Irrelevant subtraction pessimizes llvm.uadd/usub.with.overflow #171884

@purplesyringa

Description

@purplesyringa

Godbolt

#include <stdint.h>

uint64_t f(uint64_t x, uint64_t y) {
    uint64_t sum;
    if (__builtin_uaddl_overflow(x, y, &sum)) {
        return sum - 100;
    } else {
        return 0;
    }
}

uint64_t g(uint64_t x, uint64_t y) {
    uint64_t sum;
    if (__builtin_uaddl_overflow(x, y, &sum)) {
        return sum - 100;
    } else {
        return sum;
    }
}
f(unsigned long, unsigned long):
        adds    x8, x0, x1
        sub     x8, x8, #100
        cmn     x0, x1
        csel    x0, x8, xzr, hs
        ret

g(unsigned long, unsigned long):
        adds    x8, x0, x1
        sub     x8, x8, #100
        adds    x9, x0, x1
        csel    x0, x8, x9, hs
        ret

In f, note adds computing the sum and having its output flag is ignored and recomputed with cmn. In g, note adds being run twice.

This problem affects __builtin_uaddl_overflow and __builtin_usubl_overflow equally.

Replacing - 100 with + 100 miraculously fixes the lowering, but obviously changes semantics.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions