https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115201

            Bug ID: 115201
           Summary: Recursive binary search is incorrectly inlined
           Product: gcc
           Version: 14.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: llvm at rifkin dot dev
  Target Milestone: ---

I was sent the following code 

template<typename T, typename I, typename C>
constexpr I binarySearch(const T& item, const I start, const I end, C&& cmp) {
    if (std::next(start) == end) {
        return start;
    }

    const auto mid = std::next(start, std::distance(start, end) / 2);
    if (cmp(item, *mid)) {
        return binarySearch(item, start, mid, std::forward<C>(cmp));
    }
    return binarySearch(item, mid, end, std::forward<C>(cmp));
}

auto foo(const std::vector<int>& items) {
    return *binarySearch(5, items.begin(), items.end(), std::less{});
}

This causes gcc to aggressively inline the recursive function into itself
eventually emitting 1600 instructions whereas clang emits about 30. Textual
assembly length of course means little as far as performance goes however in
this case it is indicative of something going wrong, even if a TCO'd loop were
somehow unrolled.

It seems that the tail recursion is not transformed during the tailr1 pass and
instead binarySearch is inlined into itself during inline, and additional
inlining happens with foo. https://godbolt.org/z/45r7dvbxr

Imho this sort of inlining makes little sense and either it should be properly
TCO'd or not inlined at all.

This happen going back to at least gcc 7.

Reply via email to