Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missed optimization leading to inability to remove bounds check #49229

Closed
alex mannequin opened this issue Apr 7, 2021 · 2 comments
Closed

Missed optimization leading to inability to remove bounds check #49229

alex mannequin opened this issue Apr 7, 2021 · 2 comments
Labels

Comments

@alex
Copy link
Mannequin

alex mannequin commented Apr 7, 2021

Bugzilla Link 49885
Version unspecified
OS All
CC @comex,@fhahn,@jrmuizel,@rotateright

Extended Description

(All content available as godbolt: https://godbolt.org/z/s6deqs71h)

Given the following code, llvm should be able to prove that the bounds checks within the loop are never necessary:

#include <cassert>
#include <cstdint>
#include <cstddef>
#include <vector>

uint64_t f(std::vector<uint64_t>& data, size_t start, size_t end){
    assert(start < end && start < data.size() && end <= data.size());

    uint64_t total = 0;
    for (size_t i = start; i < end; i++) {
        total += data.at(i);
    }
    return total;
}

However the following code is generated:

f(std::vector<unsigned long, std::allocator<unsigned long> >&, unsigned long, unsigned long):               # @&#8203;f(std::vector<unsigned long, std::allocator<unsigned long> >&, unsigned long, unsigned long)
        push    rax
        cmp     rsi, rdx
        jae     .LBB0_6
        mov     r9, qword ptr [rdi]
        mov     r10, qword ptr [rdi + 8]
        mov     rax, r10
        sub     rax, r9
        mov     r8, rax
        sar     r8, 3
        cmp     r8, rsi
        jbe     .LBB0_6
        cmp     r8, rdx
        jb      .LBB0_6
        test    rax, rax
        mov     rcx, -1
        cmovns  rcx, rax
        test    rcx, rcx
        mov     edi, 1
        cmovle  rdi, rcx
        mov     rcx, r9
        sub     rcx, r10
        cmp     rcx, rax
        cmovle  rcx, rax
        shr     rcx, 3
        imul    rcx, rdi
        cmp     rsi, rcx
        cmova   rcx, rsi
        xor     eax, eax
.LBB0_4:                                # =>This Inner Loop Header: Depth=1
        cmp     rcx, rsi
        je      .LBB0_5
        add     rax, qword ptr [r9 + 8*rsi]
        add     rsi, 1
        cmp     rdx, rsi
        jne     .LBB0_4
        pop     rcx
        ret
.LBB0_5:
        mov     edi, offset .L.str.2
        mov     rsi, rcx
        mov     rdx, r8
        xor     eax, eax
        call    std::__throw_out_of_range_fmt(char const*, ...)
.LBB0_6:
        mov     edi, offset .L.str
        mov     esi, offset .L.str.1
        mov     ecx, offset .L__PRETTY_FUNCTION__.f(std::vector<unsigned long, std::allocator<unsigned long> >&, unsigned long, unsigned long)
        mov     edx, 7
        call    __assert_fail
.L.str:
        .asciz  "start < end && start < data.size() && end <= data.size()"

.L.str.1:
        .asciz  "/app/example.cpp"

.L__PRETTY_FUNCTION__.f(std::vector<unsigned long, std::allocator<unsigned long> >&, unsigned long, unsigned long):
        .asciz  "uint64_t f(std::vector<uint64_t> &, size_t, size_t)"

.L.str.2:
        .asciz  "vector::_M_range_check: __n (which is %zu) >= this->size() (which is %zu)"

The throw_out_of_range exception code should be able to be optimized out.

@jrmuizel
Copy link

jrmuizel commented Apr 8, 2021

Add -mllvm -enable-constraint-elimination seems to eliminate the bounds check:
https://godbolt.org/z/EM7ra6TnW

However, adding:

if (end > data.size())
        end = data.size();

adds the bounds check back.

Interestingly enough, adding:

if (end >= data.size())
        end = data.size();

is fine.

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 11, 2021
@fhahn
Copy link
Contributor

fhahn commented Oct 21, 2022

https://godbolt.org/z/136sWEcj3

Add -mllvm -enable-constraint-elimination seems to eliminate the bounds check: https://godbolt.org/z/EM7ra6TnW

However, adding:

if (end > data.size())
        end = data.size();

adds the bounds check back.

@jrmuizel could you check this again? I think the latest version should work fine with the check: https://godbolt.org/z/rno6K1eTs

@fhahn fhahn closed this as completed in fb13dcf Jan 4, 2023
fhahn added a commit that referenced this issue Feb 6, 2023
This reverts commit 695ce48.

The compile-time regression causing the revert has been fixed. Recommit
the original patch.

Original commit message:

   The pass should help to close a functional gap when it comes to
    reasoning about related conditions in a relatively general way.

    It addresses multiple existing issues (linked below) and the need for a
    more powerful reasoning system was also discussed recently in
    https://discourse.llvm.org/t/rfc-alternative-approach-of-dealing-with-implications-from-comparisons-through-pos-analysis/65601/7

    On AArch64, the new pass performs ~2000 simplifications on
    MultiSource,SPEC2006,SPEC2017 with -O3.

    Compile-time impact:

    NewPM-O3: +0.20%
    NewPM-ReleaseThinLTO: +0.32%
    NewPM-ReleaseLTO-g: +0.28%

    https://llvm-compile-time-tracker.com/compare.php?from=f01a3a893c147c1594b9a3fbd817456b209dabbf&to=577688758ef64fb044215ec3e497ea901bb2db28&stat=instructions:u

    Fixes #49344.
    Fixes #47888.
    Fixes #48253.
    Fixes #49229.
    Fixes #58074.

    Reviewed By: asbirlea

    Differential Revision: https://reviews.llvm.org/D135915
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants