[llvm-bugs] [Bug 51253] New: awful code generated for std::any_of / std::find_if looking for a zero byte

via llvm-bugs llvm-bugs at lists.llvm.org
Wed Jul 28 12:51:27 PDT 2021


https://bugs.llvm.org/show_bug.cgi?id=51253

            Bug ID: 51253
           Summary: awful code generated for std::any_of / std::find_if
                    looking for a zero byte
           Product: libraries
           Version: trunk
          Hardware: PC
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: Scalar Optimizations
          Assignee: unassignedbugs at nondot.org
          Reporter: richard-llvm at metafoo.co.uk
                CC: llvm-bugs at lists.llvm.org

Live demo: https://godbolt.org/z/xsn9hY1W1

Testcase:

#include <algorithm>
#include <array>
void do_this();
void do_that();
void f5(std::array<unsigned char, 8> arr) {
  if (std::any_of(arr.begin(), arr.end(),
                  [](unsigned char c) { return c != 0x00; }))
    do_this();
  else
    do_that();
}

This should compile into a single 8-byte comparison of arr against zero and a
branch. But (when using libstdc++ as the standard library) LLVM produces awful
code:

define dso_local void @_Z2f5St5arrayIhLm8EE(i64 %0) local_unnamed_addr #0 {
  %2 = alloca i64, align 8
  %3 = bitcast i64* %2 to i8*
  store i64 %0, i64* %2, align 8
  %4 = getelementptr inbounds i64, i64* %2, i64 1
  %5 = bitcast i64* %4 to i8*
  %6 = getelementptr inbounds i8, i8* %3, i64 4
  %7 = trunc i64 %0 to i8
  %8 = icmp eq i8 %7, 0
  br i1 %8, label %9, label %33

9:                                                ; preds = %1
  %10 = and i64 %0, 65280
  %11 = icmp eq i64 %10, 0
  br i1 %11, label %12, label %21

12:                                               ; preds = %9
  %13 = and i64 %0, 16711680
  %14 = icmp eq i64 %13, 0
  br i1 %14, label %15, label %24

15:                                               ; preds = %12
  %16 = and i64 %0, 4278190080
  %17 = icmp eq i64 %16, 0
  br i1 %17, label %18, label %27

18:                                               ; preds = %15
  %19 = and i64 %0, 1095216660480
  %20 = icmp eq i64 %19, 0
  br i1 %20, label %36, label %33

...


(It's masking out a byte at a time, and comparing that, then eventually it
branches on whether any was non-zero.)

The code generated with -stdlib=libc++ is different but still bad: there we
spill the argument to the stack and do a series of 1-byte loads and compares.

If we remove all the abstraction manually:

void f5(std::array<unsigned char, 8> arr) {
  if (arr[0] || arr[1] || arr[2] || arr[3] || arr[4] || arr[5] || arr[6] ||
arr[7])
    do_this();
  else
    do_that();
}

... then LLVM generates good code:

  %2 = icmp eq i64 %0, 0
  br i1 %2, label %4, label %3

3:                                                ; preds = %1
  tail call void @_Z7do_thisv()
  br label %5

4:                                                ; preds = %1
  tail call void @_Z7do_thatv()
  br label %5

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20210728/aa7ab1d8/attachment.html>


More information about the llvm-bugs mailing list