Skip to content

Clang does not optimize some redundant checks in std::find with a bounds-checked iterator  #78882

Open
@davidben

Description

@davidben

For some context, see #78876. This bug is about:

There's also something funny going on with std::ranges::find which I have not yet figured out yet, but I suspect there are some further missed optimization opportunities.

I've now figured that out. 😄 Here is a minimal version of the checks that Clang cannot delete.

void minimized(const uint64_t *data, size_t size) {
    const uint64_t *begin = data;
    const uint64_t *end = data + size;
    const uint64_t *iter = begin;
    while (iter != end) {
        if (*iter == 42) {
            break;
        }
        ++iter;
    }

    // I would naively think this would be easy to delete.
    // `++iter` cannot overflow, so the compiler should know
    // that `begin <= iter`.
    assert(begin <= iter);

    // This is trickier. I believe the compiler first needs to
    // learn that `begin <= end`. See
    // https://github.com/llvm/llvm-project/issues/78784 for how
    // it could learn this. From there, I think the loop structure
    // should be sufficient. That said, if I stick
    // `assert(begin <= end)` at the top of the function, it
    // could not delete this check, so there may be more going on.
    assert(iter <= end);
}

These asserts show up as a consequence of __rewrap_iter, as part of how std::find determines whether to specialize with memchr and friends. In the process of doing that specialization, libc++ needs compute begin + (iter - begin). In principle, that could be replaced with iter, but a bounds-checked iterator will emit the above asserts to do it.

See also this godbolt, which contains more extensive examples and some of the intermediate steps to get to that minimal version:
https://godbolt.org/z/T3E9hxbTT

I think #78784 may be needed to delete the second assert. I'm a little surprised it's not deleting the first though.

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