llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.03k stars 11.58k forks source link

miscompilation with coroutine since 15.0.0: function has no ret call #57861

Closed adrianimboden closed 1 year ago

adrianimboden commented 1 year ago

godbolt: https://godbolt.org/z/b6odeohqa

#include <coroutine>

struct monostate { };

struct Nontrivial {
    ~Nontrivial() {
    }
};

struct variant {
    void never_called() {
        __index = 0;
    }

    ~variant() {
        if (__index != 99) {
            variant& __vs = *this;
            using Fn      = void (*)(variant&);
            Fn __buf_[2]  = {
                 [](auto&) {},
                 [](auto&) {},
            };

            __buf_[__vs.__index](__vs);
        }
    }

    Nontrivial   nontrivial_suboject;
    unsigned int __index = 0;
};

struct Generator {
    std::coroutine_handle<> coro_;

    struct promise_type {
        variant                 never_used_;
        std::coroutine_handle<> next_coro_ = nullptr;

        auto initial_suspend() {
            return std::suspend_never{};
        }

        auto get_return_object() {
            return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
        }

        auto yield_value(int) noexcept {
            return std::suspend_always{};
        }

        void unhandled_exception() {
        }

        auto final_suspend() noexcept {
            // never called in this example
            struct Suspension {
                promise_type* this_;

                auto await_ready() noexcept {
                    return false;
                }

                auto await_suspend(std::coroutine_handle<>) noexcept {
                    if (this_->next_coro_) {
                        this_->next_coro_.resume();
                    }

                    this_->never_used_.never_called();
                }

                auto await_resume() noexcept {
                }
            };
            return Suspension{this};
        }
    };

    ~Generator() noexcept {
        coro_.destroy();
    }
};

static Generator bar() {
    co_yield 0;
}

int main() {
    asm("nop"); // not strictly necessary, but bug is better visible that way
    bar();
}

clang++-14 -O3 -std=c++20

main():                                # @foo()
        nop
        ret

clang++-15 -O3 -std=c++20

main():                                # @foo()
        nop

output of -S -emit-llvm -Xclang -disable-llvm-optzns -o -: llvm.txt

llvmbot commented 1 year ago

@llvm/issue-subscribers-coroutines

ChuanqiXu9 commented 1 year ago

Reproduced in O2 but failed in O1. I'll take a look. Thanks!

ChuanqiXu9 commented 1 year ago

Weird, I can't reproduce this locally. @adrianimboden could you show the result of clang++ -v. Just like:

clang version 15.0.0 (git@github.com:llvm/llvm-project.git 4ba6a9c9f65bbc8bd06e3652cb20fd4dfc846137)
Target: x86_64-unknown-linux-gnu
Thread model: posix

I want to test the compiler with the same commit id.

adrianimboden commented 1 year ago

Did you see the godbolt? It says:

clang version 15.0.0 (https://github.com/llvm/llvm-project.git 4ba6a9c9f65bbc8bd06e3652cb20fd4dfc846137)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /opt/compiler-explorer/clang-15.0.0/bin

For my personal tests, I used this one (self-built master from yesterday):

clang version 15.0.1 (https://github.com/llvm/llvm-project.git b73d2c8c720a8c8e6e73b11be4e27afa6cb75bdf)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
ChuanqiXu9 commented 1 year ago

Did you see the godbolt? It says:

clang version 15.0.0 (https://github.com/llvm/llvm-project.git 4ba6a9c9f65bbc8bd06e3652cb20fd4dfc846137) Target: x86_64-unknown-linux-gnu Thread model: posix InstalledDir: /opt/compiler-explorer/clang-15.0.0/bin 

For my personal tests, I used this one (self-built master from yesterday):

clang version 15.0.1 (https://github.com/llvm/llvm-project.git b73d2c8c720a8c8e6e73b11be4e27afa6cb75bdf)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

Yeah, I can reproduce it within godbolt but failed to reproduce it locally. Could you paste the result of clang++ -std=c++20 -O3 PR57861.cpp -S -emit-llvm -o -? In the godbolt, the result is:

define dso_local void @_Z3foov() local_unnamed_addr #0 personality ptr @__gxx_personality_v0 !dbg !2856 {
  tail call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() #1, !dbg !2857, !srcloc !2858
  unreachable
}

but the result I got locally is:

define dso_local void @_Z3foov() local_unnamed_addr #1 personality ptr @__gxx_personality_v0 {
_ZN15async_generatorD2Ev.exit:
  tail call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() #2, !srcloc !3
  ret void
}
adrianimboden commented 1 year ago

sure:

; ModuleID = 'PR57861.cpp'
source_filename = "PR57861.cpp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: uwtable
define dso_local void @_Z3foov() local_unnamed_addr #0 personality ptr @__gxx_personality_v0 {
  tail call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() #1, !srcloc !5
  unreachable
}

declare i32 @__gxx_personality_v0(...)

attributes #0 = { uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { nounwind }

!llvm.linker.options = !{}
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{!"clang version 15.0.1 (https://github.com/llvm/llvm-project.git b73d2c8c720a8c8e6e73b11be4e27afa6cb75bdf)"}
!5 = !{i64 1517}

I set clang up in a way to automatically use libstd++. Do you use the stdlib++ from the system? On godbolt the error does only reproduce with libc++

ChuanqiXu9 commented 1 year ago

sure:

; ModuleID = 'main.cpp'
source_filename = "main.cpp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: norecurse uwtable
define dso_local noundef i32 @main() local_unnamed_addr #0 personality ptr @__gxx_personality_v0 {
  tail call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() #1, !srcloc !5
  unreachable
}

declare i32 @__gxx_personality_v0(...)

attributes #0 = { norecurse uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { nounwind }

!llvm.linker.options = !{}
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{!"clang version 15.0.1 (https://github.com/llvm/llvm-project.git b73d2c8c720a8c8e6e73b11be4e27afa6cb75bdf)"}
!5 = !{i64 1704}

I set clang up in a way to automatically use libstd++. Do you use the stdlib++ from the system? On godbolt the error does only reproduce with libc++

Yeah, I'll try to use libc++. But godbolt reproduce the error with libstdc++ too: https://godbolt.org/z/Gf47Y3a5e

adrianimboden commented 1 year ago

Ah yes, you're right. On my system (ubuntu 20.04), it does not even compile with libstd++ (no coroutine support yet).

I just tried it out with this: repro.tar.gz

FROM ubuntu:22.04

RUN \
  apt-get update && \
  apt-get -y install sudo lsb-release wget software-properties-common gnupg && \
  sudo rm -rf /var/lib/apt/lists/*

RUN \
  echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-15 main" | sudo tee /etc/apt/sources.list.d/llvm.list && \
  (wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -) && \
  sudo apt-get -y update && \
  sudo apt-get -y install clang-15 lld-15 clang-tools-15 libc++-15-dev && \
  sudo rm -rf /var/lib/apt/lists/*

WORKDIR /root

COPY PR57861.cpp /root/PR57861.cpp

RUN clang++-15 -stdlib=libc++ -std=c++20 -O3 PR57861.cpp -S -emit-llvm -o -

with -stdlib=libc++:

define dso_local void @_Z3foov() local_unnamed_addr #0 personality ptr @__gxx_personality_v0 {
  tail call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() #1, !srcloc !5
  unreachable
}

with -stdlib=libstdc++:

define dso_local void @_Z3foov() local_unnamed_addr #0 personality ptr @__gxx_personality_v0 {
  tail call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() #1, !srcloc !5
  ret void
}
ChuanqiXu9 commented 1 year ago

Oh, I reproduce it successfully with libcxx. Thanks.

adrianimboden commented 1 year ago

I will do a bisect in the meantime and report back soon.

adrianimboden commented 1 year ago

I did the bisect, this is the result: https://github.com/llvm/llvm-project/commit/10c531cd5bf0166ce5bf42736506733b2285fdf8

@nikic maybe you have an idea how the change might be causing that?

10c531cd5bf0166ce5bf42736506733b2285fdf8 is the first bad commit
commit 10c531cd5bf0166ce5bf42736506733b2285fdf8
Author: Nikita Popov <npopov@redhat.com>
Date:   Mon Jun 27 17:14:41 2022 +0200

    [SCCP] Simplify CFG in SCCP as well

    Currently, we only remove dead blocks and non-feasible edges in
    IPSCCP, but not in SCCP. I'm not aware of any strong reason for
    that difference, so this patch updates SCCP to perform the CFG
    cleanup as well.

    Compile-time impact seems to be pretty minimal, in the 0.05%
    geomean range on CTMark.

    For the test case from https://reviews.llvm.org/D126962#3611579
    the result after -sccp now looks like this:

        define void @test(i1 %c) {
        entry:
          br i1 %c, label %unreachable, label %next
        next:
          unreachable
        unreachable:
          call void @bar()
          unreachable
        }

    -jump-threading does nothing on this, but -simplifycfg will produce
    the optimal result.

    Differential Revision: https://reviews.llvm.org/D128796

 llvm/lib/Transforms/Scalar/SCCP.cpp                | 37 +++++++++++++++++-----
 .../test/Transforms/GVN/gvn-loop-load-pre-order.ll |  4 +--
 .../Transforms/SCCP/2004-12-10-UndefBranchBug.ll   |  4 +--
 .../Transforms/SCCP/2008-01-27-UndefCorrelate.ll   | 12 -------
 llvm/test/Transforms/SCCP/preserve-analysis.ll     |  4 +--
 llvm/test/Transforms/SCCP/sccptest.ll              |  9 ++----
 llvm/test/Transforms/SCCP/strictfp-phis-fcmp.ll    |  6 ----
 llvm/test/Transforms/SCCP/strictfp-phis-fcmps.ll   |  6 ----
 llvm/test/Transforms/SCCP/widening.ll              | 14 ++++----
 9 files changed, 43 insertions(+), 53 deletions(-)
nikic commented 1 year ago

Can you please provide the -S -emit-llvm -Xclang -disable-llvm-optzns -o - output, so this is reproducible independent of environment?

adrianimboden commented 1 year ago

Sorry for the inconvenience. I did not work with llvm on that level so far.

here you go: out.txt revision: 1e55ec6666fa command: /usr/local/bin/clang++ -stdlib=libc++ -std=c++20 -O2 /root/PR57861.cpp -S -emit-llvm -Xclang -disable-llvm-optzns -o - > out.txt

ChuanqiXu9 commented 1 year ago

Oh, if @nikic will take a look, I'll resign the assignment.

adrianimboden commented 1 year ago

I just want to support you as good as I can. I surely can't fix the bug, I don't know anything about how the optimizer and the associated llvm internals work.

I just hope to get this fixed soon. These kinds of bugs make me uneasy around the compiler...

ChuanqiXu9 commented 1 year ago

I just want to support you as good as I can. I surely can't fix the bug, I don't know anything about how the optimizer and the associated llvm internals work.

I just hope to get this fixed soon. These kinds of bugs make me uneasy around the compiler...

Thanks for your reporting, but we can't be sure if we can fix the problem soon enough. A not-so-good workaround for you may use union instead of std::variant. https://godbolt.org/z/aGW17en55

adrianimboden commented 1 year ago

I tested our whole codebase with 10c531cd5bf0166ce5bf42736506733b2285fdf8 being reverted.

I think we should revert this simplification in favor of correctness as soon as possible.

https://reviews.llvm.org/D134421

nikic commented 1 year ago

I just took a quick look, and SCCP only seems relevant in that it folds a br i1 undef produced by a previous GVN pass into unreachable (correctly). GVN produces this from a load and comparison of the variant tag (I think), which is uninitialized at that point (also correctly). The issue must be introduced at some earlier point.

adrianimboden commented 1 year ago

If I can help in any way, please tell me.

Just replacing some variant and hoping for the error to go away seems quite risky to me. I would really like to find the underlying problem, but I have absolutely no knowledge of the LLVM IR, passes and such.

nikic commented 1 year ago

I spent some time looking into this, but wasn't able to identify where the miscompile occurs. Possibly it's in coroutine-specific parts that I'm not familiar with.

ChuanqiXu9 commented 1 year ago

I spent some time looking into this, but wasn't able to identify where the miscompile occurs. Possibly it's in coroutine-specific parts that I'm not familiar with.

What's the bad pattern? Is the br i1 undef the bad pattern? So that I can try to locate.

nikic commented 1 year ago

@ChuanqiXu9 The bad pattern is a missing i32 store writing the variant tag.

ChuanqiXu9 commented 1 year ago

@ChuanqiXu9 The bad pattern is a missing i32 store writing the variant tag.

Thanks I'll take a look.

ChuanqiXu9 commented 1 year ago

Unassigned due to I may not be able to look into this in time due to personal reasons.

adrianimboden commented 1 year ago

I'm don't really know how the optimizations work. With the help of https://llvm.org/docs/OptBisect.html i did a bisect on the opt-passes (bugpoint does not work when coroutines are involved: https://github.com/llvm/llvm-project/issues/57856).

First try

the pass that makes the example fail is: EarlyCSEPass on _ZL3barv

root@1102436d5071:~# /usr/local/bin/clang++ -stdlib=libc++ -std=c++20 -O2 -mllvm -opt-bisect-limit=7032 /root/PR57861.cpp -o app 2>/dev/null && valgrind ./app
==11502== Memcheck, a memory error detector
...
==11502== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

root@1102436d5071:~# /usr/local/bin/clang++ -stdlib=libc++ -std=c++20 -O2 -mllvm -opt-bisect-limit=7033 /root/PR57861.cpp -o app 2>/dev/null && valgrind ./app
==11506== Memcheck, a memory error detector
...
==11506== Conditional jump or move depends on uninitialised value(s)
==11506==    at 0x1095E9: bar() [clone .destroy] (in /root/app)
==11506==    by 0x1098E6: std::__1::coroutine_handle<async_generator::promise_type>::destroy[abi:v160000]() const (in /root/app)
==11506==    by 0x109764: async_generator::~async_generator() (in /root/app)
==11506==    by 0x109201: main (in /root/app)
==11506== 
==11506== Use of uninitialised value of size 8
==11506==    at 0x1095F4: bar() [clone .destroy] (in /root/app)
==11506==    by 0x1098E6: std::__1::coroutine_handle<async_generator::promise_type>::destroy[abi:v160000]() const (in /root/app)
==11506==    by 0x109764: async_generator::~async_generator() (in /root/app)
==11506==    by 0x109201: main (in /root/app)
...
==11506== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

root@1102436d5071:~# /usr/local/bin/clang++ -stdlib=libc++ -std=c++20 -O2 -mllvm -opt-bisect-limit=7032 /root/PR57861.cpp -S -emit-llvm -o /llvm-project/7032.llvm 2> /llvm-project/7032.out
root@1102436d5071:~# /usr/local/bin/clang++ -stdlib=libc++ -std=c++20 -O2 -mllvm -opt-bisect-limit=7033 /root/PR57861.cpp -S -emit-llvm -o /llvm-project/7033.llvm 2> /llvm-project/7033.out

outputs from the commands: files.tar.gz

the problem: if i remove EarlyCSEPass completely from the codebase, it has no effect. This pass seems to be only bringing the problem to the surface.

Next try

I found out that the GVNPass somehow has an effect. The following changes or command line arguments make the miscompilation go away:

adrianimboden commented 1 year ago

I managed to make the sample quite a bit smaller.

It now only has a dependency on the coroutine header.

adrianimboden commented 1 year ago

new -S -emit-llvm -Xclang -disable-llvm-optzns -o -:

; ModuleID = '/repro_minimal/PR57861.cpp'
source_filename = "/repro_minimal/PR57861.cpp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

%struct.Generator = type { %"struct.std::__1::coroutine_handle" }
%"struct.std::__1::coroutine_handle" = type { ptr }
%"struct.Generator::promise_type" = type { %struct.variant, %"struct.std::__1::coroutine_handle" }
%struct.variant = type { %struct.Nontrivial, i32 }
%struct.Nontrivial = type { i8 }
%"struct.std::__1::suspend_never" = type { i8 }
%"struct.std::__1::coroutine_handle.0" = type { ptr }
%"struct.std::__1::suspend_always" = type { i8 }
%struct.Suspension = type { ptr }
%class.anon = type { i8 }
%class.anon.1 = type { i8 }

$_ZN9GeneratorD2Ev = comdat any

$_ZN9Generator12promise_typeC2Ev = comdat any

$_ZN9Generator12promise_type17get_return_objectEv = comdat any

$_ZN9Generator12promise_type15initial_suspendEv = comdat any

$_ZNKSt3__113suspend_never11await_readyB7v160000Ev = comdat any

$_ZNKSt3__113suspend_never13await_suspendB7v160000ENS_16coroutine_handleIvEE = comdat any

$_ZNSt3__116coroutine_handleIN9Generator12promise_typeEE12from_addressB7v160000EPv = comdat any

$_ZNKSt3__116coroutine_handleIN9Generator12promise_typeEEcvNS0_IvEEB7v160000Ev = comdat any

$_ZNKSt3__113suspend_never12await_resumeB7v160000Ev = comdat any

$_ZN9Generator12promise_type11yield_valueEi = comdat any

$_ZNKSt3__114suspend_always11await_readyB7v160000Ev = comdat any

$_ZNKSt3__114suspend_always13await_suspendB7v160000ENS_16coroutine_handleIvEE = comdat any

$_ZNKSt3__114suspend_always12await_resumeB7v160000Ev = comdat any

$_ZN9Generator12promise_type13final_suspendEv = comdat any

$_ZZN9Generator12promise_type13final_suspendEvEN10Suspension11await_readyEv = comdat any

$_ZZN9Generator12promise_type13final_suspendEvEN10Suspension13await_suspendENSt3__116coroutine_handleIvEE = comdat any

$_ZZN9Generator12promise_type13final_suspendEvEN10Suspension12await_resumeEv = comdat any

$_ZN9Generator12promise_typeD2Ev = comdat any

$_ZN7variantC2Ev = comdat any

$_ZNSt3__116coroutine_handleIvEC2B7v160000EDn = comdat any

$_ZNSt3__116coroutine_handleIN9Generator12promise_typeEE12from_promiseB7v160000ERS2_ = comdat any

$_ZNSt3__116coroutine_handleIN9Generator12promise_typeEEC2B7v160000Ev = comdat any

$_ZNSt3__116coroutine_handleIvE12from_addressB7v160000EPv = comdat any

$_ZNKSt3__116coroutine_handleIN9Generator12promise_typeEE7addressB7v160000Ev = comdat any

$_ZNSt3__116coroutine_handleIvEC2B7v160000Ev = comdat any

$_ZNKSt3__116coroutine_handleIvEcvbB7v160000Ev = comdat any

$_ZNKSt3__116coroutine_handleIvE6resumeB7v160000Ev = comdat any

$__clang_call_terminate = comdat any

$_ZN7variant12never_calledEv = comdat any

$_ZN7variantD2Ev = comdat any

$_ZZN7variantD1EvENUlRT_E_8__invokeIS_EEDaS1_ = comdat any

$_ZZN7variantD1EvENUlRT_E0_8__invokeIS_EEDaS1_ = comdat any

$_ZN10NontrivialD2Ev = comdat any

$_ZZN7variantD1EvENKUlRT_E_clIS_EEDaS1_ = comdat any

$_ZZN7variantD1EvENKUlRT_E0_clIS_EEDaS1_ = comdat any

$_ZNKSt3__116coroutine_handleIvE7destroyB7v160000Ev = comdat any

@"__const.~variant.__buf_" = private unnamed_addr constant [2 x ptr] [ptr @_ZZN7variantD1EvENUlRT_E_8__invokeIS_EEDaS1_, ptr @_ZZN7variantD1EvENUlRT_E0_8__invokeIS_EEDaS1_], align 16

; Function Attrs: mustprogress norecurse uwtable
define dso_local noundef i32 @main() #0 {
  %1 = alloca %struct.Generator, align 8
  call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() #4, !srcloc !5
  call void @_ZL3barv(ptr sret(%struct.Generator) align 8 %1)
  call void @_ZN9GeneratorD2Ev(ptr noundef nonnull align 8 dereferenceable(8) %1) #4
  ret i32 0
}

; Function Attrs: mustprogress presplitcoroutine uwtable
define internal void @_ZL3barv(ptr noalias sret(%struct.Generator) align 8 %0) #1 personality ptr @__gxx_personality_v0 {
  %2 = alloca ptr, align 8
  %3 = alloca %"struct.Generator::promise_type", align 8
  %4 = alloca ptr, align 8
  %5 = alloca i32, align 4
  %6 = alloca %"struct.std::__1::suspend_never", align 1
  %7 = alloca %"struct.std::__1::suspend_never", align 1
  %8 = alloca %"struct.std::__1::coroutine_handle", align 8
  %9 = alloca %"struct.std::__1::coroutine_handle.0", align 8
  %10 = alloca %"struct.std::__1::suspend_always", align 1
  %11 = alloca %"struct.std::__1::suspend_always", align 1
  %12 = alloca %"struct.std::__1::coroutine_handle", align 8
  %13 = alloca %"struct.std::__1::coroutine_handle.0", align 8
  %14 = alloca %struct.Suspension, align 8
  %15 = alloca %"struct.std::__1::coroutine_handle", align 8
  %16 = alloca %"struct.std::__1::coroutine_handle.0", align 8
  store ptr %0, ptr %2, align 8
  %17 = bitcast ptr %3 to ptr
  %18 = call token @llvm.coro.id(i32 16, ptr %17, ptr null, ptr null)
  %19 = call i1 @llvm.coro.alloc(token %18)
  br i1 %19, label %20, label %23

20:                                               ; preds = %1
  %21 = call i64 @llvm.coro.size.i64()
  %22 = call noalias noundef nonnull ptr @_Znwm(i64 noundef %21) #17
  br label %23

23:                                               ; preds = %20, %1
  %24 = phi ptr [ null, %1 ], [ %22, %20 ]
  %25 = call ptr @llvm.coro.begin(token %18, ptr %24)
  call void @llvm.lifetime.start.p0(i64 16, ptr %3) #4
  call void @_ZN9Generator12promise_typeC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %3) #4
  invoke void @_ZN9Generator12promise_type17get_return_objectEv(ptr sret(%struct.Generator) align 8 %0, ptr noundef nonnull align 8 dereferenceable(16) %3)
          to label %26 unwind label %39

26:                                               ; preds = %23
  call void @llvm.lifetime.start.p0(i64 1, ptr %6) #4
  invoke void @_ZN9Generator12promise_type15initial_suspendEv(ptr noundef nonnull align 8 dereferenceable(16) %3)
          to label %27 unwind label %43

27:                                               ; preds = %26
  %28 = call noundef zeroext i1 @_ZNKSt3__113suspend_never11await_readyB7v160000Ev(ptr noundef nonnull align 1 dereferenceable(1) %6) #4
  br i1 %28, label %48, label %29

29:                                               ; preds = %27
  %30 = call token @llvm.coro.save(ptr null)
  call void @llvm.lifetime.start.p0(i64 8, ptr %9) #4
  %31 = call ptr @_ZNSt3__116coroutine_handleIN9Generator12promise_typeEE12from_addressB7v160000EPv(ptr noundef %25) #4
  %32 = getelementptr inbounds %"struct.std::__1::coroutine_handle.0", ptr %9, i32 0, i32 0
  store ptr %31, ptr %32, align 8
  %33 = call ptr @_ZNKSt3__116coroutine_handleIN9Generator12promise_typeEEcvNS0_IvEEB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %9) #4
  %34 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %8, i32 0, i32 0
  store ptr %33, ptr %34, align 8
  %35 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %8, i32 0, i32 0
  %36 = load ptr, ptr %35, align 8
  call void @_ZNKSt3__113suspend_never13await_suspendB7v160000ENS_16coroutine_handleIvEE(ptr noundef nonnull align 1 dereferenceable(1) %6, ptr %36) #4
  call void @llvm.lifetime.end.p0(i64 8, ptr %9) #4
  %37 = call i8 @llvm.coro.suspend(token %30, i1 false)
  switch i8 %37, label %92 [
    i8 0, label %48
    i8 1, label %38
  ]

38:                                               ; preds = %29
  br label %49

39:                                               ; preds = %23
  %40 = landingpad { ptr, i32 }
          cleanup
  %41 = extractvalue { ptr, i32 } %40, 0
  store ptr %41, ptr %4, align 8
  %42 = extractvalue { ptr, i32 } %40, 1
  store i32 %42, ptr %5, align 4
  br label %95

43:                                               ; preds = %26
  %44 = landingpad { ptr, i32 }
          cleanup
  %45 = extractvalue { ptr, i32 } %44, 0
  store ptr %45, ptr %4, align 8
  %46 = extractvalue { ptr, i32 } %44, 1
  store i32 %46, ptr %5, align 4
  call void @llvm.lifetime.end.p0(i64 1, ptr %6) #4
  %47 = call i1 @llvm.coro.end(ptr null, i1 true)
  br i1 %47, label %100, label %94

48:                                               ; preds = %29, %27
  call void @_ZNKSt3__113suspend_never12await_resumeB7v160000Ev(ptr noundef nonnull align 1 dereferenceable(1) %6) #4
  br label %49

49:                                               ; preds = %48, %38
  %50 = phi i32 [ 0, %48 ], [ 2, %38 ]
  call void @llvm.lifetime.end.p0(i64 1, ptr %6) #4
  switch i32 %50, label %85 [
    i32 0, label %51
  ]

51:                                               ; preds = %49
  call void @llvm.lifetime.start.p0(i64 1, ptr %10) #4
  call void @_ZN9Generator12promise_type11yield_valueEi(ptr noundef nonnull align 8 dereferenceable(16) %3, i32 noundef 0) #4
  %52 = call noundef zeroext i1 @_ZNKSt3__114suspend_always11await_readyB7v160000Ev(ptr noundef nonnull align 1 dereferenceable(1) %10) #4
  br i1 %52, label %63, label %53

53:                                               ; preds = %51
  %54 = call token @llvm.coro.save(ptr null)
  call void @llvm.lifetime.start.p0(i64 8, ptr %13) #4
  %55 = call ptr @_ZNSt3__116coroutine_handleIN9Generator12promise_typeEE12from_addressB7v160000EPv(ptr noundef %25) #4
  %56 = getelementptr inbounds %"struct.std::__1::coroutine_handle.0", ptr %13, i32 0, i32 0
  store ptr %55, ptr %56, align 8
  %57 = call ptr @_ZNKSt3__116coroutine_handleIN9Generator12promise_typeEEcvNS0_IvEEB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %13) #4
  %58 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %12, i32 0, i32 0
  store ptr %57, ptr %58, align 8
  %59 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %12, i32 0, i32 0
  %60 = load ptr, ptr %59, align 8
  call void @_ZNKSt3__114suspend_always13await_suspendB7v160000ENS_16coroutine_handleIvEE(ptr noundef nonnull align 1 dereferenceable(1) %10, ptr %60) #4
  call void @llvm.lifetime.end.p0(i64 8, ptr %13) #4
  %61 = call i8 @llvm.coro.suspend(token %54, i1 false)
  switch i8 %61, label %92 [
    i8 0, label %63
    i8 1, label %62
  ]

62:                                               ; preds = %53
  br label %64

63:                                               ; preds = %53, %51
  call void @_ZNKSt3__114suspend_always12await_resumeB7v160000Ev(ptr noundef nonnull align 1 dereferenceable(1) %10) #4
  br label %64

64:                                               ; preds = %63, %62
  %65 = phi i32 [ 0, %63 ], [ 2, %62 ]
  call void @llvm.lifetime.end.p0(i64 1, ptr %10) #4
  switch i32 %65, label %85 [
    i32 0, label %66
  ]

66:                                               ; preds = %64
  br label %67

67:                                               ; preds = %66
  call void @llvm.lifetime.start.p0(i64 8, ptr %14) #4
  %68 = call ptr @_ZN9Generator12promise_type13final_suspendEv(ptr noundef nonnull align 8 dereferenceable(16) %3) #4
  %69 = getelementptr inbounds %struct.Suspension, ptr %14, i32 0, i32 0
  store ptr %68, ptr %69, align 8
  %70 = call noundef zeroext i1 @_ZZN9Generator12promise_type13final_suspendEvEN10Suspension11await_readyEv(ptr noundef nonnull align 8 dereferenceable(8) %14) #4
  br i1 %70, label %81, label %71

71:                                               ; preds = %67
  %72 = call token @llvm.coro.save(ptr null)
  call void @llvm.lifetime.start.p0(i64 8, ptr %16) #4
  %73 = call ptr @_ZNSt3__116coroutine_handleIN9Generator12promise_typeEE12from_addressB7v160000EPv(ptr noundef %25) #4
  %74 = getelementptr inbounds %"struct.std::__1::coroutine_handle.0", ptr %16, i32 0, i32 0
  store ptr %73, ptr %74, align 8
  %75 = call ptr @_ZNKSt3__116coroutine_handleIN9Generator12promise_typeEEcvNS0_IvEEB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %16) #4
  %76 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %15, i32 0, i32 0
  store ptr %75, ptr %76, align 8
  %77 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %15, i32 0, i32 0
  %78 = load ptr, ptr %77, align 8
  call void @_ZZN9Generator12promise_type13final_suspendEvEN10Suspension13await_suspendENSt3__116coroutine_handleIvEE(ptr noundef nonnull align 8 dereferenceable(8) %14, ptr %78) #4
  call void @llvm.lifetime.end.p0(i64 8, ptr %16) #4
  %79 = call i8 @llvm.coro.suspend(token %72, i1 true)
  switch i8 %79, label %92 [
    i8 0, label %81
    i8 1, label %80
  ]

80:                                               ; preds = %71
  br label %82

81:                                               ; preds = %71, %67
  call void @_ZZN9Generator12promise_type13final_suspendEvEN10Suspension12await_resumeEv(ptr noundef nonnull align 8 dereferenceable(8) %14) #4
  br label %82

82:                                               ; preds = %81, %80
  %83 = phi i32 [ 0, %81 ], [ 2, %80 ]
  call void @llvm.lifetime.end.p0(i64 8, ptr %14) #4
  switch i32 %83, label %85 [
    i32 0, label %84
  ]

84:                                               ; preds = %82
  br label %85

85:                                               ; preds = %84, %82, %64, %49
  %86 = phi i32 [ %50, %49 ], [ %65, %64 ], [ %83, %82 ], [ 0, %84 ]
  call void @_ZN9Generator12promise_typeD2Ev(ptr noundef nonnull align 8 dereferenceable(16) %3) #4
  call void @llvm.lifetime.end.p0(i64 16, ptr %3) #4
  %87 = call ptr @llvm.coro.free(token %18, ptr %25)
  %88 = icmp ne ptr %87, null
  br i1 %88, label %89, label %90

89:                                               ; preds = %85
  call void @_ZdlPv(ptr noundef %87) #4
  br label %90

90:                                               ; preds = %85, %89
  switch i32 %86, label %105 [
    i32 0, label %91
    i32 2, label %92
  ]

91:                                               ; preds = %90
  br label %92

92:                                               ; preds = %91, %90, %71, %53, %29
  %93 = call i1 @llvm.coro.end(ptr null, i1 false)
  ret void

94:                                               ; preds = %43
  br label %95

95:                                               ; preds = %94, %39
  call void @_ZN9Generator12promise_typeD2Ev(ptr noundef nonnull align 8 dereferenceable(16) %3) #4
  call void @llvm.lifetime.end.p0(i64 16, ptr %3) #4
  %96 = call ptr @llvm.coro.free(token %18, ptr %25)
  %97 = icmp ne ptr %96, null
  br i1 %97, label %98, label %99

98:                                               ; preds = %95
  call void @_ZdlPv(ptr noundef %96) #4
  br label %99

99:                                               ; preds = %95, %98
  br label %100

100:                                              ; preds = %99, %43
  %101 = load ptr, ptr %4, align 8
  %102 = load i32, ptr %5, align 4
  %103 = insertvalue { ptr, i32 } undef, ptr %101, 0
  %104 = insertvalue { ptr, i32 } %103, i32 %102, 1
  resume { ptr, i32 } %104

105:                                              ; preds = %90
  unreachable
}

; Function Attrs: nounwind uwtable
define linkonce_odr dso_local void @_ZN9GeneratorD2Ev(ptr noundef nonnull align 8 dereferenceable(8) %0) unnamed_addr #2 comdat align 2 personality ptr @__gxx_personality_v0 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %struct.Generator, ptr %3, i32 0, i32 0
  invoke void @_ZNKSt3__116coroutine_handleIvE7destroyB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %4)
          to label %5 unwind label %6

5:                                                ; preds = %1
  ret void

6:                                                ; preds = %1
  %7 = landingpad { ptr, i32 }
          catch ptr null
  %8 = extractvalue { ptr, i32 } %7, 0
  call void @__clang_call_terminate(ptr %8) #18
  unreachable
}

; Function Attrs: argmemonly nounwind readonly
declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) #3

; Function Attrs: nounwind
declare i1 @llvm.coro.alloc(token) #4

; Function Attrs: nobuiltin allocsize(0)
declare noundef nonnull ptr @_Znwm(i64 noundef) #5

; Function Attrs: nounwind readnone
declare i64 @llvm.coro.size.i64() #6

; Function Attrs: nounwind
declare ptr @llvm.coro.begin(token, ptr writeonly) #4

; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #7

; Function Attrs: inlinehint nounwind uwtable
define linkonce_odr dso_local void @_ZN9Generator12promise_typeC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %0) unnamed_addr #8 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %"struct.Generator::promise_type", ptr %3, i32 0, i32 0
  call void @_ZN7variantC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %4) #4
  %5 = getelementptr inbounds %"struct.Generator::promise_type", ptr %3, i32 0, i32 1
  call void @_ZNSt3__116coroutine_handleIvEC2B7v160000EDn(ptr noundef nonnull align 8 dereferenceable(8) %5, ptr null) #4
  ret void
}

; Function Attrs: mustprogress uwtable
define linkonce_odr dso_local void @_ZN9Generator12promise_type17get_return_objectEv(ptr noalias sret(%struct.Generator) align 8 %0, ptr noundef nonnull align 8 dereferenceable(16) %1) #9 comdat align 2 {
  %3 = alloca ptr, align 8
  %4 = alloca ptr, align 8
  %5 = alloca %"struct.std::__1::coroutine_handle.0", align 8
  store ptr %0, ptr %3, align 8
  store ptr %1, ptr %4, align 8, !tbaa !6
  %6 = load ptr, ptr %4, align 8
  %7 = getelementptr inbounds %struct.Generator, ptr %0, i32 0, i32 0
  call void @llvm.lifetime.start.p0(i64 8, ptr %5) #4
  %8 = call ptr @_ZNSt3__116coroutine_handleIN9Generator12promise_typeEE12from_promiseB7v160000ERS2_(ptr noundef nonnull align 8 dereferenceable(16) %6)
  %9 = getelementptr inbounds %"struct.std::__1::coroutine_handle.0", ptr %5, i32 0, i32 0
  store ptr %8, ptr %9, align 8
  %10 = call ptr @_ZNKSt3__116coroutine_handleIN9Generator12promise_typeEEcvNS0_IvEEB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %5) #4
  %11 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %7, i32 0, i32 0
  store ptr %10, ptr %11, align 8
  call void @llvm.lifetime.end.p0(i64 8, ptr %5) #4
  ret void
}

declare i32 @__gxx_personality_v0(...)

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr dso_local void @_ZN9Generator12promise_type15initial_suspendEv(ptr noundef nonnull align 8 dereferenceable(16) %0) #10 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  ret void
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden noundef zeroext i1 @_ZNKSt3__113suspend_never11await_readyB7v160000Ev(ptr noundef nonnull align 1 dereferenceable(1) %0) #10 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  ret i1 true
}

; Function Attrs: nomerge nounwind
declare token @llvm.coro.save(ptr) #11

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden void @_ZNKSt3__113suspend_never13await_suspendB7v160000ENS_16coroutine_handleIvEE(ptr noundef nonnull align 1 dereferenceable(1) %0, ptr %1) #10 comdat align 2 {
  %3 = alloca %"struct.std::__1::coroutine_handle", align 8
  %4 = alloca ptr, align 8
  %5 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %3, i32 0, i32 0
  store ptr %1, ptr %5, align 8
  store ptr %0, ptr %4, align 8, !tbaa !6
  %6 = load ptr, ptr %4, align 8
  ret void
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden ptr @_ZNSt3__116coroutine_handleIN9Generator12promise_typeEE12from_addressB7v160000EPv(ptr noundef %0) #10 comdat align 2 {
  %2 = alloca %"struct.std::__1::coroutine_handle.0", align 8
  %3 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8, !tbaa !6
  call void @_ZNSt3__116coroutine_handleIN9Generator12promise_typeEEC2B7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %2) #4
  %4 = load ptr, ptr %3, align 8, !tbaa !6
  %5 = getelementptr inbounds %"struct.std::__1::coroutine_handle.0", ptr %2, i32 0, i32 0
  store ptr %4, ptr %5, align 8, !tbaa !10
  %6 = getelementptr inbounds %"struct.std::__1::coroutine_handle.0", ptr %2, i32 0, i32 0
  %7 = load ptr, ptr %6, align 8
  ret ptr %7
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden ptr @_ZNKSt3__116coroutine_handleIN9Generator12promise_typeEEcvNS0_IvEEB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %0) #10 comdat align 2 {
  %2 = alloca %"struct.std::__1::coroutine_handle", align 8
  %3 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8, !tbaa !6
  %4 = load ptr, ptr %3, align 8
  %5 = call noundef ptr @_ZNKSt3__116coroutine_handleIN9Generator12promise_typeEE7addressB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %4) #4
  %6 = call ptr @_ZNSt3__116coroutine_handleIvE12from_addressB7v160000EPv(ptr noundef %5) #4
  %7 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %2, i32 0, i32 0
  store ptr %6, ptr %7, align 8
  %8 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %2, i32 0, i32 0
  %9 = load ptr, ptr %8, align 8
  ret ptr %9
}

; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #7

; Function Attrs: nounwind
declare i8 @llvm.coro.suspend(token, i1) #4

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden void @_ZNKSt3__113suspend_never12await_resumeB7v160000Ev(ptr noundef nonnull align 1 dereferenceable(1) %0) #10 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  ret void
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr dso_local void @_ZN9Generator12promise_type11yield_valueEi(ptr noundef nonnull align 8 dereferenceable(16) %0, i32 noundef %1) #10 comdat align 2 {
  %3 = alloca ptr, align 8
  %4 = alloca i32, align 4
  store ptr %0, ptr %3, align 8, !tbaa !6
  store i32 %1, ptr %4, align 4, !tbaa !12
  %5 = load ptr, ptr %3, align 8
  ret void
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden noundef zeroext i1 @_ZNKSt3__114suspend_always11await_readyB7v160000Ev(ptr noundef nonnull align 1 dereferenceable(1) %0) #10 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  ret i1 false
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden void @_ZNKSt3__114suspend_always13await_suspendB7v160000ENS_16coroutine_handleIvEE(ptr noundef nonnull align 1 dereferenceable(1) %0, ptr %1) #10 comdat align 2 {
  %3 = alloca %"struct.std::__1::coroutine_handle", align 8
  %4 = alloca ptr, align 8
  %5 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %3, i32 0, i32 0
  store ptr %1, ptr %5, align 8
  store ptr %0, ptr %4, align 8, !tbaa !6
  %6 = load ptr, ptr %4, align 8
  ret void
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden void @_ZNKSt3__114suspend_always12await_resumeB7v160000Ev(ptr noundef nonnull align 1 dereferenceable(1) %0) #10 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  ret void
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr dso_local ptr @_ZN9Generator12promise_type13final_suspendEv(ptr noundef nonnull align 8 dereferenceable(16) %0) #10 comdat align 2 {
  %2 = alloca %struct.Suspension, align 8
  %3 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8, !tbaa !6
  %4 = load ptr, ptr %3, align 8
  %5 = getelementptr inbounds %struct.Suspension, ptr %2, i32 0, i32 0
  store ptr %4, ptr %5, align 8, !tbaa !14
  %6 = getelementptr inbounds %struct.Suspension, ptr %2, i32 0, i32 0
  %7 = load ptr, ptr %6, align 8
  ret ptr %7
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr dso_local noundef zeroext i1 @_ZZN9Generator12promise_type13final_suspendEvEN10Suspension11await_readyEv(ptr noundef nonnull align 8 dereferenceable(8) %0) #10 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  ret i1 false
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr dso_local void @_ZZN9Generator12promise_type13final_suspendEvEN10Suspension13await_suspendENSt3__116coroutine_handleIvEE(ptr noundef nonnull align 8 dereferenceable(8) %0, ptr %1) #10 comdat align 2 personality ptr @__gxx_personality_v0 {
  %3 = alloca %"struct.std::__1::coroutine_handle", align 8
  %4 = alloca ptr, align 8
  %5 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %3, i32 0, i32 0
  store ptr %1, ptr %5, align 8
  store ptr %0, ptr %4, align 8, !tbaa !6
  %6 = load ptr, ptr %4, align 8
  %7 = getelementptr inbounds %struct.Suspension, ptr %6, i32 0, i32 0
  %8 = load ptr, ptr %7, align 8, !tbaa !14
  %9 = getelementptr inbounds %"struct.Generator::promise_type", ptr %8, i32 0, i32 1
  %10 = call noundef zeroext i1 @_ZNKSt3__116coroutine_handleIvEcvbB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %9) #4
  br i1 %10, label %11, label %16

11:                                               ; preds = %2
  %12 = getelementptr inbounds %struct.Suspension, ptr %6, i32 0, i32 0
  %13 = load ptr, ptr %12, align 8, !tbaa !14
  %14 = getelementptr inbounds %"struct.Generator::promise_type", ptr %13, i32 0, i32 1
  invoke void @_ZNKSt3__116coroutine_handleIvE6resumeB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %14)
          to label %15 unwind label %21

15:                                               ; preds = %11
  br label %16

16:                                               ; preds = %15, %2
  %17 = getelementptr inbounds %struct.Suspension, ptr %6, i32 0, i32 0
  %18 = load ptr, ptr %17, align 8, !tbaa !14
  %19 = getelementptr inbounds %"struct.Generator::promise_type", ptr %18, i32 0, i32 0
  invoke void @_ZN7variant12never_calledEv(ptr noundef nonnull align 4 dereferenceable(8) %19)
          to label %20 unwind label %21

20:                                               ; preds = %16
  ret void

21:                                               ; preds = %16, %11
  %22 = landingpad { ptr, i32 }
          catch ptr null
  %23 = extractvalue { ptr, i32 } %22, 0
  call void @__clang_call_terminate(ptr %23) #18
  unreachable
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr dso_local void @_ZZN9Generator12promise_type13final_suspendEvEN10Suspension12await_resumeEv(ptr noundef nonnull align 8 dereferenceable(8) %0) #10 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  ret void
}

; Function Attrs: nounwind
declare i1 @llvm.coro.end(ptr, i1) #4

; Function Attrs: inlinehint nounwind uwtable
define linkonce_odr dso_local void @_ZN9Generator12promise_typeD2Ev(ptr noundef nonnull align 8 dereferenceable(16) %0) unnamed_addr #8 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %"struct.Generator::promise_type", ptr %3, i32 0, i32 0
  call void @_ZN7variantD2Ev(ptr noundef nonnull align 4 dereferenceable(8) %4) #4
  ret void
}

; Function Attrs: nobuiltin nounwind
declare void @_ZdlPv(ptr noundef) #12

; Function Attrs: argmemonly nounwind readonly
declare ptr @llvm.coro.free(token, ptr nocapture readonly) #3

; Function Attrs: inlinehint nounwind uwtable
define linkonce_odr dso_local void @_ZN7variantC2Ev(ptr noundef nonnull align 4 dereferenceable(8) %0) unnamed_addr #8 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %struct.variant, ptr %3, i32 0, i32 0
  %5 = getelementptr inbounds %struct.variant, ptr %3, i32 0, i32 1
  store i32 0, ptr %5, align 4, !tbaa !16
  ret void
}

; Function Attrs: nounwind uwtable
define linkonce_odr hidden void @_ZNSt3__116coroutine_handleIvEC2B7v160000EDn(ptr noundef nonnull align 8 dereferenceable(8) %0, ptr %1) unnamed_addr #2 comdat align 2 {
  %3 = alloca ptr, align 8
  %4 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8, !tbaa !6
  store ptr %1, ptr %4, align 8, !tbaa !19
  %5 = load ptr, ptr %3, align 8
  %6 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %5, i32 0, i32 0
  store ptr null, ptr %6, align 8, !tbaa !21
  ret void
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden ptr @_ZNSt3__116coroutine_handleIN9Generator12promise_typeEE12from_promiseB7v160000ERS2_(ptr noundef nonnull align 8 dereferenceable(16) %0) #10 comdat align 2 {
  %2 = alloca %"struct.std::__1::coroutine_handle.0", align 8
  %3 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8, !tbaa !6
  call void @_ZNSt3__116coroutine_handleIN9Generator12promise_typeEEC2B7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %2) #4
  %4 = load ptr, ptr %3, align 8, !tbaa !6
  %5 = call ptr @llvm.coro.promise(ptr %4, i32 8, i1 true)
  %6 = getelementptr inbounds %"struct.std::__1::coroutine_handle.0", ptr %2, i32 0, i32 0
  store ptr %5, ptr %6, align 8, !tbaa !10
  %7 = getelementptr inbounds %"struct.std::__1::coroutine_handle.0", ptr %2, i32 0, i32 0
  %8 = load ptr, ptr %7, align 8
  ret ptr %8
}

; Function Attrs: nounwind uwtable
define linkonce_odr hidden void @_ZNSt3__116coroutine_handleIN9Generator12promise_typeEEC2B7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %0) unnamed_addr #2 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %"struct.std::__1::coroutine_handle.0", ptr %3, i32 0, i32 0
  store ptr null, ptr %4, align 8, !tbaa !10
  ret void
}

; Function Attrs: nounwind readnone
declare ptr @llvm.coro.promise(ptr nocapture, i32, i1) #6

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden ptr @_ZNSt3__116coroutine_handleIvE12from_addressB7v160000EPv(ptr noundef %0) #10 comdat align 2 {
  %2 = alloca %"struct.std::__1::coroutine_handle", align 8
  %3 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8, !tbaa !6
  call void @_ZNSt3__116coroutine_handleIvEC2B7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %2) #4
  %4 = load ptr, ptr %3, align 8, !tbaa !6
  %5 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %2, i32 0, i32 0
  store ptr %4, ptr %5, align 8, !tbaa !21
  %6 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %2, i32 0, i32 0
  %7 = load ptr, ptr %6, align 8
  ret ptr %7
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden noundef ptr @_ZNKSt3__116coroutine_handleIN9Generator12promise_typeEE7addressB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %0) #10 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %"struct.std::__1::coroutine_handle.0", ptr %3, i32 0, i32 0
  %5 = load ptr, ptr %4, align 8, !tbaa !10
  ret ptr %5
}

; Function Attrs: nounwind uwtable
define linkonce_odr hidden void @_ZNSt3__116coroutine_handleIvEC2B7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %0) unnamed_addr #2 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %3, i32 0, i32 0
  store ptr null, ptr %4, align 8, !tbaa !21
  ret void
}

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr hidden noundef zeroext i1 @_ZNKSt3__116coroutine_handleIvEcvbB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %0) #10 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %3, i32 0, i32 0
  %5 = load ptr, ptr %4, align 8, !tbaa !21
  %6 = icmp ne ptr %5, null
  ret i1 %6
}

; Function Attrs: mustprogress uwtable
define linkonce_odr hidden void @_ZNKSt3__116coroutine_handleIvE6resumeB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %0) #9 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %3, i32 0, i32 0
  %5 = load ptr, ptr %4, align 8, !tbaa !21
  call void @llvm.coro.resume(ptr %5)
  ret void
}

; Function Attrs: noinline noreturn nounwind
define linkonce_odr hidden void @__clang_call_terminate(ptr %0) #13 comdat {
  %2 = call ptr @__cxa_begin_catch(ptr %0) #4
  call void @_ZSt9terminatev() #18
  unreachable
}

declare ptr @__cxa_begin_catch(ptr)

declare void @_ZSt9terminatev()

; Function Attrs: mustprogress nounwind uwtable
define linkonce_odr dso_local void @_ZN7variant12never_calledEv(ptr noundef nonnull align 4 dereferenceable(8) %0) #10 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %struct.variant, ptr %3, i32 0, i32 1
  store i32 0, ptr %4, align 4, !tbaa !16
  ret void
}

declare void @llvm.coro.resume(ptr)

; Function Attrs: nounwind uwtable
define linkonce_odr dso_local void @_ZN7variantD2Ev(ptr noundef nonnull align 4 dereferenceable(8) %0) unnamed_addr #2 comdat align 2 personality ptr @__gxx_personality_v0 {
  %2 = alloca ptr, align 8
  %3 = alloca ptr, align 8
  %4 = alloca [2 x ptr], align 16
  store ptr %0, ptr %2, align 8, !tbaa !6
  %5 = load ptr, ptr %2, align 8
  %6 = getelementptr inbounds %struct.variant, ptr %5, i32 0, i32 1
  %7 = load i32, ptr %6, align 4, !tbaa !16
  %8 = icmp ne i32 %7, 99
  br i1 %8, label %9, label %18

9:                                                ; preds = %1
  call void @llvm.lifetime.start.p0(i64 8, ptr %3) #4
  store ptr %5, ptr %3, align 8, !tbaa !6
  call void @llvm.lifetime.start.p0(i64 16, ptr %4) #4
  call void @llvm.memcpy.p0.p0.i64(ptr align 16 %4, ptr align 16 @"__const.~variant.__buf_", i64 16, i1 false)
  %10 = load ptr, ptr %3, align 8, !tbaa !6
  %11 = getelementptr inbounds %struct.variant, ptr %10, i32 0, i32 1
  %12 = load i32, ptr %11, align 4, !tbaa !16
  %13 = zext i32 %12 to i64
  %14 = getelementptr inbounds [2 x ptr], ptr %4, i64 0, i64 %13
  %15 = load ptr, ptr %14, align 8, !tbaa !6
  %16 = load ptr, ptr %3, align 8, !tbaa !6
  invoke void %15(ptr noundef nonnull align 4 dereferenceable(8) %16)
          to label %17 unwind label %20

17:                                               ; preds = %9
  call void @llvm.lifetime.end.p0(i64 16, ptr %4) #4
  call void @llvm.lifetime.end.p0(i64 8, ptr %3) #4
  br label %18

18:                                               ; preds = %17, %1
  %19 = getelementptr inbounds %struct.variant, ptr %5, i32 0, i32 0
  call void @_ZN10NontrivialD2Ev(ptr noundef nonnull align 1 dereferenceable(1) %19) #4
  ret void

20:                                               ; preds = %9
  %21 = landingpad { ptr, i32 }
          catch ptr null
  %22 = extractvalue { ptr, i32 } %21, 0
  call void @__clang_call_terminate(ptr %22) #18
  unreachable
}

; Function Attrs: inlinehint uwtable
define linkonce_odr dso_local void @_ZZN7variantD1EvENUlRT_E_8__invokeIS_EEDaS1_(ptr noundef nonnull align 4 dereferenceable(8) %0) #14 comdat align 2 {
  %2 = alloca ptr, align 8
  %3 = alloca %class.anon, align 1
  store ptr %0, ptr %2, align 8, !tbaa !6
  %4 = load ptr, ptr %2, align 8
  call void @_ZZN7variantD1EvENKUlRT_E_clIS_EEDaS1_(ptr noundef nonnull align 1 dereferenceable(1) %3, ptr noundef nonnull align 4 dereferenceable(8) %4)
  ret void
}

; Function Attrs: inlinehint uwtable
define linkonce_odr dso_local void @_ZZN7variantD1EvENUlRT_E0_8__invokeIS_EEDaS1_(ptr noundef nonnull align 4 dereferenceable(8) %0) #14 comdat align 2 {
  %2 = alloca ptr, align 8
  %3 = alloca %class.anon.1, align 1
  store ptr %0, ptr %2, align 8, !tbaa !6
  %4 = load ptr, ptr %2, align 8
  call void @_ZZN7variantD1EvENKUlRT_E0_clIS_EEDaS1_(ptr noundef nonnull align 1 dereferenceable(1) %3, ptr noundef nonnull align 4 dereferenceable(8) %4)
  ret void
}

; Function Attrs: argmemonly nocallback nofree nounwind willreturn
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #15

; Function Attrs: nounwind uwtable
define linkonce_odr dso_local void @_ZN10NontrivialD2Ev(ptr noundef nonnull align 1 dereferenceable(1) %0) unnamed_addr #2 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  ret void
}

; Function Attrs: inlinehint mustprogress nounwind uwtable
define linkonce_odr dso_local void @_ZZN7variantD1EvENKUlRT_E_clIS_EEDaS1_(ptr noundef nonnull align 1 dereferenceable(1) %0, ptr noundef nonnull align 4 dereferenceable(8) %1) #16 comdat align 2 {
  %3 = alloca ptr, align 8
  %4 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8, !tbaa !6
  store ptr %1, ptr %4, align 8, !tbaa !6
  %5 = load ptr, ptr %3, align 8
  ret void
}

; Function Attrs: inlinehint mustprogress nounwind uwtable
define linkonce_odr dso_local void @_ZZN7variantD1EvENKUlRT_E0_clIS_EEDaS1_(ptr noundef nonnull align 1 dereferenceable(1) %0, ptr noundef nonnull align 4 dereferenceable(8) %1) #16 comdat align 2 {
  %3 = alloca ptr, align 8
  %4 = alloca ptr, align 8
  store ptr %0, ptr %3, align 8, !tbaa !6
  store ptr %1, ptr %4, align 8, !tbaa !6
  %5 = load ptr, ptr %3, align 8
  ret void
}

; Function Attrs: mustprogress uwtable
define linkonce_odr hidden void @_ZNKSt3__116coroutine_handleIvE7destroyB7v160000Ev(ptr noundef nonnull align 8 dereferenceable(8) %0) #9 comdat align 2 {
  %2 = alloca ptr, align 8
  store ptr %0, ptr %2, align 8, !tbaa !6
  %3 = load ptr, ptr %2, align 8
  %4 = getelementptr inbounds %"struct.std::__1::coroutine_handle", ptr %3, i32 0, i32 0
  %5 = load ptr, ptr %4, align 8, !tbaa !21
  call void @llvm.coro.destroy(ptr %5)
  ret void
}

declare void @llvm.coro.destroy(ptr)

attributes #0 = { mustprogress norecurse uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { mustprogress presplitcoroutine uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #2 = { nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #3 = { argmemonly nounwind readonly }
attributes #4 = { nounwind }
attributes #5 = { nobuiltin allocsize(0) "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #6 = { nounwind readnone }
attributes #7 = { argmemonly nocallback nofree nosync nounwind willreturn }
attributes #8 = { inlinehint nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #9 = { mustprogress uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #10 = { mustprogress nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #11 = { nomerge nounwind }
attributes #12 = { nobuiltin nounwind "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #13 = { noinline noreturn nounwind }
attributes #14 = { inlinehint uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #15 = { argmemonly nocallback nofree nounwind willreturn }
attributes #16 = { inlinehint mustprogress nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #17 = { allocsize(0) }
attributes #18 = { noreturn nounwind }

!llvm.linker.options = !{}
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{!"clang version 16.0.0"}
!5 = !{i64 1857}
!6 = !{!7, !7, i64 0}
!7 = !{!"any pointer", !8, i64 0}
!8 = !{!"omnipotent char", !9, i64 0}
!9 = !{!"Simple C++ TBAA"}
!10 = !{!11, !7, i64 0}
!11 = !{!"_ZTSNSt3__116coroutine_handleIN9Generator12promise_typeEEE", !7, i64 0}
!12 = !{!13, !13, i64 0}
!13 = !{!"int", !8, i64 0}
!14 = !{!15, !7, i64 0}
!15 = !{!"_ZTSZN9Generator12promise_type13final_suspendEvE10Suspension", !7, i64 0}
!16 = !{!17, !13, i64 4}
!17 = !{!"_ZTS7variant", !18, i64 0, !13, i64 4}
!18 = !{!"_ZTS10Nontrivial"}
!19 = !{!20, !20, i64 0}
!20 = !{!"std::nullptr_t", !8, i64 0}
!21 = !{!22, !7, i64 0}
!22 = !{!"_ZTSNSt3__116coroutine_handleIvEE", !7, i64 0}
adrianimboden commented 1 year ago

I did a optimizer bisect on this small example.

/usr/local/bin/clang++ -stdlib=libc++ -std=c++20 -O2 /repro_minimal/PR57861.cpp -mllvm -opt-bisect-limit=1589 -S -emit-llvm -o - > bad.txt crashes like this:

# /usr/local/bin/clang++ -stdlib=libc++ -std=c++20 -O2 /repro_minimal/PR57861.cpp -mllvm -opt-bisect-limit=1589
# valgrind ./a.out 
==42258== Memcheck, a memory error detector
==42258== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==42258== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==42258== Command: ./a.out
==42258== 
==42258== Conditional jump or move depends on uninitialised value(s)
==42258==    at 0x1093E7: bar() [clone .destroy] (in /root/a.out)
==42258==    by 0x109536: std::__1::coroutine_handle<void>::destroy[abi:v160000]() const (in /root/a.out)
==42258==    by 0x1094E5: Generator::~Generator() (in /root/a.out)
==42258==    by 0x109181: main (in /root/a.out)
==42258== 
==42258== Use of uninitialised value of size 8
==42258==    at 0x1093F2: bar() [clone .destroy] (in /root/a.out)
==42258==    by 0x109536: std::__1::coroutine_handle<void>::destroy[abi:v160000]() const (in /root/a.out)
==42258==    by 0x1094E5: Generator::~Generator() (in /root/a.out)
==42258==    by 0x109181: main (in /root/a.out)

one step before, it passes:

# /usr/local/bin/clang++ -stdlib=libc++ -std=c++20 -O2 /repro_minimal/PR57861.cpp -mllvm -opt-bisect-limit=1588
root@9da1d93ab429:~# ./^C
root@9da1d93ab429:~# valgrind ./a.out 
==42282== Memcheck, a memory error detector
==42282== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==42282== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==42282== Command: ./a.out
==42282== 
==42282== 
==42282== HEAP SUMMARY:
==42282==     in use at exit: 0 bytes in 0 blocks
==42282==   total heap usage: 1 allocs, 1 frees, 40 bytes allocated
==42282== 
==42282== All heap blocks were freed -- no leaks are possible
==42282== 
==42282== For lists of detected and suppressed errors, rerun with: -s
==42282== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

this pass gets skipped:

BISECT: NOT running pass (1589) EarlyCSEPass on _ZL3barv

I don't know anything about optimizers and the llvm bitcode. I am willing to read into that, but this will likely take much time and this bug seems serious enough to be fixed rather sooner than later.

@nikic, would it be possible for you to see from the input EarlyCSEPass on _ZL3barv receives (good.txt), whether the miscompile is being triggered from a transform before or by the EarlyCSEPass itself?

If I know what part of the bitcode is triggering the collapse into unreachable, I will do some more bisects to see where that gets introduced.

Thank you very much.

adrianimboden commented 1 year ago

I did a little more digging on this.

1f88d804083a8a1b68df1e6677920e38ab2a6b40 and 10c531cd5bf0166ce5bf42736506733b2285fdf8 introduced either:

I invested some more time to see what would happen when we cherry-pick those changes on older clang versions. I did go to version 13.0.0 (12.0.0 was too different to easely apply the patch). When the coroutine is actually the buggy part, the change in the optimizer also triggers it on this version.

TLDR; had 1f88d804083a8a1b68df1e6677920e38ab2a6b40 and 10c531cd5bf0166ce5bf42736506733b2285fdf8 already been done on clang 13.0.0, we would have this miscompile on those versions also.

I would strongly prefer to revert https://reviews.llvm.org/D126962 as soon as possible until we have time invest the coroutine case more. This miscompile is no joke, and it may not be related to coroutines at all

@nikic, you implemented those changes. What do you think about that?

nikic commented 1 year ago

As I explained before, the miscompile here is caused by an incorrectly removed store to the variant tag. The SCCP changes only make the miscompile easy to reproduce, by not also removing the read of the variant tag.

I just took another look at this, and the problem appears to be that the variant tag write happens on an alloca, rather than the resume.addr returned by coro.begin. Possibly this happens because the GEP used to access it is hoisted above coro.begin and this breaks the spill rewrite somehow.

Edit: This might be the problematic place: https://github.com/llvm/llvm-project/blob/75b18ba14d07d38f7031f282f0d216fa6153fd81/llvm/lib/Transforms/Coroutines/CoroFrame.cpp#L1767

adrianimboden commented 1 year ago

Thank you for looking into it again.

@lxfind, you also did some work on that code. Is there something we can do about this? Coroutines are pretty much unusable in clang 15 right now.

I would really like to help, but I have absolutely no knowledge about the LLVM internals, let alone compilers or optimizers.

nikic commented 1 year ago

I think this is a reasonably minimal reproducer for -passes=coro-split:

define ptr @f() presplitcoroutine {
entry:
  %a = alloca { i32, i32 }
  %gep = getelementptr i32, ptr %a, i64 1
  %id = call token @llvm.coro.id(i32 0, ptr %a, ptr null, ptr null)
  %size = call i32 @llvm.coro.size.i32()
  %alloc = call ptr @malloc(i32 %size)
  %hdl = call ptr @llvm.coro.begin(token %id, ptr %alloc)
  store i32 0, ptr %gep
  %sp1 = call i8 @llvm.coro.suspend(token none, i1 false)
  switch i8 %sp1, label %suspend [i8 0, label %resume
                                  i8 1, label %cleanup]
resume:
  %v = load i32, ptr %gep
  call void @print(i32 %v)
  br label %cleanup

cleanup:
  %mem = call ptr @llvm.coro.free(token %id, ptr %hdl) 
  call void @free(ptr %mem)
  br label %suspend

suspend:
  call i1 @llvm.coro.end(ptr %hdl, i1 0)
  ret ptr %hdl
}

declare token @llvm.coro.id(i32, ptr, ptr, ptr)
declare i32 @llvm.coro.size.i32()
declare ptr @llvm.coro.begin(token, ptr)
declare i8  @llvm.coro.suspend(token, i1)
declare ptr @llvm.coro.free(token, ptr)
declare i1 @llvm.coro.end(ptr, i1) 

declare void @print(i32)
declare noalias ptr @malloc(i32)
declare void @free(ptr)

This will end up storing to the original %gep, not GEP based on %a.reload.addr. If the %gep is moved below llvm.coro.begin, then it is converted into %gep = getelementptr i32, ptr %a.reload.addr, i64 1.

ChuanqiXu9 commented 1 year ago

Thanks for the reducing. But the pattern looks consistency with the design... we are intended to rewrites the use after coro.begin(). Let me see how can I fix this...

meongmeongasd commented 1 year ago

looking at opt pipeline viewer visualization on https://godbolt.org/z/q11Whnn1o very interesting the avalanche effect from different on line count since 1st inliner pass to 8th (green+white) instcombine pass wipes out the main blocks

adrianimboden commented 1 year ago

Thank you both for looking into it. Do you have any news on this yet? Does it look like a fundamental-ish problem and would there maybe be an optimization step I could disable or something, so that we are sure that the problem cannot not surface?

Thank you very much :smile:

As always, If I can help with bisecting, testing or something else, I am at your service.

ChuanqiXu9 commented 1 year ago

Thank you both for looking into it. Do you have any news on this yet? Does it look like a fundamental-ish problem and would there maybe be an optimization step I could disable or something, so that we are sure that the problem cannot not surface?

Thank you very much 😄

As always, If I can help with bisecting, testing or something else, I am at your service.

The current progress is that when we initialize the variant, we didn't follow the restriction with coroutines. And I am still looking for how to fix it.

adrianimboden commented 1 year ago

@tru, is this bug considered unimportant? I don't know what to expect here to be honest. I thought coroutines are no longer experimental? This kind of bug makes the coroutines a high risk thing to use in llvm.

tru commented 1 year ago

@adrianimboden the 15.x branch is generally closed and won't have any more fixes unless we find a catastrophic bug. It would have to be up to the code owner to argue for another point release or it would end up in LLVM 16 which is due early next year.

tru commented 1 year ago

We will probably do a 15.0.4 - so if a fix can be ready for this before end of next week it should be able to get included there.

ChuanqiXu9 commented 1 year ago

I feel like it is not so hopeful to fix this in the next week unless we find a simple and trivial fix so that we can implement and review it quickly. But now I feel like the bug is not the case.

tru commented 1 year ago

Ok - if you find a fix, let me know. Otherwise, this will probably just end up in LLVM 16 instead.

nikic commented 1 year ago

@ChuanqiXu9 It works fine if the alloca is not passed to llvm.coro.id, so I'd expect that there is already code somewhere for correctly handling this (i.e. rewrite based on load/store position, not gep position)?

ChuanqiXu9 commented 1 year ago

In fact, there is existing code to sink alloca uses: https://github.com/llvm/llvm-project/blob/9cedab654d587134c0bb2ce8557891cab5d06440/llvm/lib/Transforms/Coroutines/CoroFrame.cpp#L2810-L2812. But it only works for modes other than the C++ (whose ABI is coro::ABI::Switch). I remember I tried to enable this for C++ a long time ago. But I forgot the reason to not make it. And the current principle is requiring the uses of alloca be behind of coro.id.

Maybe it can be a good fix to enable the pattern. I am not sure. But I don't want to do such a hurry fix for the deadline. I worry it may cause other problems.

adrianimboden commented 1 year ago

If you provide a patch, I will apply it on our codebase to try it out.

Our codebase uses coroutines all over the place, it would be a good starting point to see whether it is a good idea to start with.

ChuanqiXu9 commented 1 year ago

debase uses coroutines all over the place, it would be a good starting point to see whether it is a good

You can try to remove the above condition simply.

adrianimboden commented 1 year ago

using this commit: https://github.com/thingdust/llvm-project/commit/ee53fb0132e7e8815e8a0aebaa3b8ae1b8c0d9ea

$ clang++ -O3 -std=c++20 main.cpp
$ ./a.out 
Trace/breakpoint trap (core dumped)
$ valgrind ./a.out
==80292== Memcheck, a memory error detector
==80292== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==80292== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==80292== Command: ./a.out
==80292== 
==80292== 
==80292== Process terminating with default action of signal 5 (SIGTRAP): dumping core
==80292==    at 0x109772: ??? (in /home/thingdust/src/repro/a.out)
==80292==    by 0x4B05082: (below main) (libc-start.c:308)
==80292== 
==80292== HEAP SUMMARY:
==80292==     in use at exit: 0 bytes in 0 blocks
==80292==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==80292== 
==80292== All heap blocks were freed -- no leaks are possible
==80292== 
==80292== For lists of detected and suppressed errors, rerun with: -s
==80292== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Trace/breakpoint trap

clang++ -O3 -std=c++20 -S -emit-llvm -Xclang -disable-llvm-optzns -o - main.cpp > out.txt: out.txt

It optimizes away way less, but I don't see whats going wrong.

adrianimboden commented 1 year ago

@nikic I also tried to run your bitcode reproducer, but I think I am doing something wrong (the crash also happens on 15.0.1)?

$ cat bitcode.ll
define ptr @f() presplitcoroutine {
entry:
  %a = alloca { i32, i32 }
  %gep = getelementptr i32, ptr %a, i64 1
  %id = call token @llvm.coro.id(i32 0, ptr %a, ptr null, ptr null)
  %size = call i32 @llvm.coro.size.i32()
  %alloc = call ptr @malloc(i32 %size)
  %hdl = call ptr @llvm.coro.begin(token %id, ptr %alloc)
  store i32 0, ptr %gep
  %sp1 = call i8 @llvm.coro.suspend(token none, i1 false)
  switch i8 %sp1, label %suspend [i8 0, label %resume
                                  i8 1, label %cleanup]
resume:
  %v = load i32, ptr %gep
  call void @print(i32 %v)
  br label %cleanup

cleanup:
  %mem = call ptr @llvm.coro.free(token %id, ptr %hdl) 
  call void @free(ptr %mem)
  br label %suspend

suspend:
  call i1 @llvm.coro.end(ptr %hdl, i1 0)
  ret ptr %hdl
}

declare token @llvm.coro.id(i32, ptr, ptr, ptr)
declare i32 @llvm.coro.size.i32()
declare ptr @llvm.coro.begin(token, ptr)
declare i8  @llvm.coro.suspend(token, i1)
declare ptr @llvm.coro.free(token, ptr)
declare i1 @llvm.coro.end(ptr, i1) 

declare void @print(i32)
declare noalias ptr @malloc(i32)
declare void @free(ptr)
$ llc bitcode.ll
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: llc bitcode.ll
1.      Running pass 'Function Pass Manager' on module 'bitcode.ll'.
2.      Running pass 'X86 DAG->DAG Instruction Selection' on function '@f'
 #0 0x000056390564d6f4 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/bin/llc+0x25296f4)
 #1 0x000056390564b02e llvm::sys::RunSignalHandlers() (/usr/bin/llc+0x252702e)
 #2 0x000056390564de3d SignalHandler(int) Signals.cpp:0:0
 #3 0x00007f50917db420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)
 #4 0x0000563903ee8a34 llvm::MVT::getSizeInBits() const X86ISelLowering.cpp:0:0
 #5 0x00005639053fc636 llvm::SelectionDAG::getConstant(unsigned long, llvm::SDLoc const&, llvm::EVT, bool, bool) (/usr/bin/llc+0x22d8636)
 #6 0x00005639053ac3e6 llvm::SelectionDAGBuilder::getValueImpl(llvm::Value const*) (/usr/bin/llc+0x22883e6)
 #7 0x00005639053ab248 llvm::SelectionDAGBuilder::getValue(llvm::Value const*) (/usr/bin/llc+0x2287248)
 #8 0x00005639053c15ad llvm::SelectionDAGBuilder::visitTargetIntrinsic(llvm::CallInst const&, unsigned int) (/usr/bin/llc+0x229d5ad)
 #9 0x00005639053c3e5c llvm::SelectionDAGBuilder::visitIntrinsicCall(llvm::CallInst const&, unsigned int) (/usr/bin/llc+0x229fe5c)
#10 0x000056390539499d llvm::SelectionDAGBuilder::visit(llvm::Instruction const&) (/usr/bin/llc+0x227099d)
#11 0x000056390544dd74 llvm::SelectionDAGISel::SelectBasicBlock(llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction, false, false, void>, false, true>, llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction, false, false, void>, false, true>, bool&) (/usr/bin/llc+0x2329d74)
#12 0x000056390544d1b6 llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) (/usr/bin/llc+0x23291b6)
#13 0x0000563905449b63 llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) (/usr/bin/llc+0x2325b63)
#14 0x000056390418915b (anonymous namespace)::X86DAGToDAGISel::runOnMachineFunction(llvm::MachineFunction&) (.llvm.6844038841662300506) X86ISelDAGToDAG.cpp:0:0
#15 0x00005639048f09db llvm::MachineFunctionPass::runOnFunction(llvm::Function&) (/usr/bin/llc+0x17cc9db)
#16 0x0000563904d95382 llvm::FPPassManager::runOnFunction(llvm::Function&) (/usr/bin/llc+0x1c71382)
#17 0x0000563904d9ef33 llvm::FPPassManager::runOnModule(llvm::Module&) (/usr/bin/llc+0x1c7af33)
#18 0x0000563904d961f6 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/usr/bin/llc+0x1c721f6)
#19 0x0000563903e6f426 main (/usr/bin/llc+0xd4b426)
#20 0x00007f509132f083 __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:342:3
#21 0x0000563903e6ae4e _start (/usr/bin/llc+0xd46e4e)
Segmentation fault (core dumped)
ChuanqiXu9 commented 1 year ago

The example in the issue report can be fixed by https://reviews.llvm.org/D136749. But it is a draft really and I need more time to review and test it. (@adrianimboden it'll be appreciated if you can test this with your internal workloads). I don't want to land this in 15.0.4 so hurrily. It looks error prone. But if we have 15.1, I think we may be able to reach that. Otherwise we can only wish to fix this in 16.

adrianimboden commented 1 year ago

https://github.com/thingdust/llvm-project/commit/eb27f9521e5229e80adb41e9513d08b154619ac3:

error.tar.gz

$ build
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.Program arguments: /usr/bin/clang++ -x c++ -c /home/thingdust/src/backend/src/libs/http/src/http/http_server.cpp -o backend/src/libs/http/CMakeFiles/libs_http.dir/src/http/http_server.cpp.o -I/home/thingdust/src/backend/src/libs/http/src -I/home/thingdust/deps/spdlog/include -I/home/thingdust/src/backend/src/libs/util/src -I/home/thingdust/repo_deps/messages_lib/src -I/home/thingdust/src/backend/src/libs/logging/src -I/home/thingdust/src/backend/src/libs/stats/src -I/home/thingdust/src/backend/src/libs/async/src -I/home/thingdust/src/backend/src/libs/proc_client/src -Ibackend/src/libs/proc_api/safe_generated/proc/safe_generated -Iexternal-grpc-build/third_party/cares/cares -I/home/thingdust/deps/grpc/third_party/cares/cares -I/home/thingdust/deps/grpc/third_party/cares/cares/include -I/home/thingdust/deps/grpc/third_party/re2 -I/home/thingdust/src/backend/src/libs/safe_api/src -I/home/thingdust/src/backend/src/libs/time/src -I/home/thingdust/src/backend/src/libs/grpc/src -I/home/thingdust/src/backend/src/libs/proc/src -isystem /home/thingdust/deps/gsl/include -isystem /home/thingdust/deps/json/include -isystem /home/thingdust/deps/range/include -isystem /home/thingdust/deps/googlebenchmark/include -isystem /home/thingdust/deps/abseil -isystem generated/raw -isystem /home/thingdust/deps/grpc/include -isystem /home/thingdust/deps/grpc/third_party/protobuf/src -nostdinc -nostdinc++ -isystem /usr/cxxlib/release_for_perf/include/c++/v1 -isystem /usr/cxxlib/release_for_perf/include/clang -isystem /usr/cxxlib/release_for_perf/include/x86_64-linux-gnu -isystem /usr/cxxlib/release_for_perf/include -isystem /home/thingdust/deps/spdlog//include --sysroot=/usr/cxxlib/release_for_perf -DCARES_STATICLIB -fstack-protector -DHAVE_THREAD_SAFETY_ATTRIBUTES -D_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR -D_LIBCPP_ENABLE_CXX17_REMOVED_RANDOM_SHUFFLE -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -D_LIBCPP_ENABLE_NODISCARD -D_LIBCPP_ENABLE_CXX20_REMOVED_TYPE_TRAITS -D_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS -DFMT_NO_FMT_STRING_ALIAS -DDYNAMIC_ANNOTATIONS_ENABLED -fPIC -Wno-unused-command-line-argument -fno-limit-debug-info -fsized-deallocation -DTHINGDUST_FLAVOR=release -DNDEBUG -O3 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -std=c++20 -std=c++17 -ftemplate-backtrace-limit=0 -ferror-limit=0 -Wno-unused-parameter -Wno-unused-variable -Weverything -Werror -Wno-thread-safety-negative -Wno-ctad-maybe-unsupported -Wno-user-defined-warnings -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-c++20-compat -Wno-padded -Wno-weak-vtables -Wno-weak-template-vtables -Wno-global-constructors -Wno-exit-time-destructors -Wno-undefined-func-template -Wno-newline-eof -Wno-zero-as-null-pointer-constant -Wno-gnu-zero-variadic-macro-arguments -Wno-unneeded-internal-declaration -Wno-reserved-identifier -fprofile-instr-generate -fcoverage-mapping -Wno-unused-function -std=gnu++20
1.<eof> parser at end of file
2.Optimizer
3.While splitting coroutine @_ZN11http_server8shutdownEN3ptr6sharedINS_11ServerStateEEE
 #0 0x00005637a75eb294 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/bin/clang+++0x35a3294)
 #1 0x00005637a75e8bce llvm::sys::RunSignalHandlers() (/usr/bin/clang+++0x35a0bce)
 #2 0x00005637a75ea531 llvm::sys::CleanupOnSignal(unsigned long) (/usr/bin/clang+++0x35a2531)
 #3 0x00005637a7545891 (anonymous namespace)::CrashRecoveryContextImpl::HandleCrash(int, unsigned long) (.llvm.6601137296067471773) CrashRecoveryContext.cpp:0:0
 #4 0x00005637a7545b6c CrashRecoverySignalHandler(int) (.llvm.6601137296067471773) CrashRecoveryContext.cpp:0:0
 #5 0x00007f897818a420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)
 #6 0x00005637a7618f27 llvm::CloneFunctionInto(llvm::Function*, llvm::Function const*, llvm::ValueMap<llvm::Value const*, llvm::WeakTrackingVH, llvm::ValueMapConfig<llvm::Value const*, llvm::sys::SmartMutex<false>>>&, llvm::CloneFunctionChangeType, llvm::SmallVectorImpl<llvm::ReturnInst*>&, char const*, llvm::ClonedCodeInfo*, llvm::ValueMapTypeRemapper*, llvm::ValueMaterializer*) (/usr/bin/clang+++0x35d0f27)
 #7 0x00005637a90efa77 (anonymous namespace)::CoroCloner::create() CoroSplit.cpp:0:0
 #8 0x00005637a90ef631 createClone(llvm::Function&, llvm::Twine const&, llvm::coro::Shape&, (anonymous namespace)::CoroCloner::Kind) CoroSplit.cpp:0:0
 #9 0x00005637a90eb8c3 splitCoroutine(llvm::Function&, llvm::SmallVectorImpl<llvm::Function*>&, llvm::TargetTransformInfo&, bool) CoroSplit.cpp:0:0
#10 0x00005637a90e863c llvm::CoroSplitPass::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/usr/bin/clang+++0x50a063c)
#11 0x00005637a8f8b3ed llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::CoroSplitPass, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) PassBuilder.cpp:0:0
#12 0x00005637a6f09a7d llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/usr/bin/clang+++0x2ec1a7d)
#13 0x00005637a6ff18fd llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::PassManager<llvm::LazyCallGraph::SCC, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) Inliner.cpp:0:0
#14 0x00005637a6f0c190 llvm::DevirtSCCRepeatedPass::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) (/usr/bin/clang+++0x2ec4190)
#15 0x00005637a6ff20ed llvm::detail::PassModel<llvm::LazyCallGraph::SCC, llvm::DevirtSCCRepeatedPass, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&>::run(llvm::LazyCallGraph::SCC&, llvm::AnalysisManager<llvm::LazyCallGraph::SCC, llvm::LazyCallGraph&>&, llvm::LazyCallGraph&, llvm::CGSCCUpdateResult&) Inliner.cpp:0:0
#16 0x00005637a6f0b3e8 llvm::ModuleToPostOrderCGSCCPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/usr/bin/clang+++0x2ec33e8)
#17 0x00005637a6ff1e1d llvm::detail::PassModel<llvm::Module, llvm::ModuleToPostOrderCGSCCPassAdaptor, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) Inliner.cpp:0:0
#18 0x00005637a6e98919 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/usr/bin/clang+++0x2e50919)
#19 0x00005637a6fee7ac llvm::ModuleInlinerWrapperPass::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/usr/bin/clang+++0x2fa67ac)
#20 0x00005637a8c1f7cd llvm::detail::PassModel<llvm::Module, llvm::ModuleInlinerWrapperPass, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) Canonicalization.cpp:0:0
#21 0x00005637a6e98919 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/usr/bin/clang+++0x2e50919)
#22 0x00005637a7f1a063 (anonymous namespace)::EmitAssemblyHelper::RunOptimizationPipeline(clang::BackendAction, std::__2::unique_ptr<llvm::raw_pwrite_stream, std::__2::default_delete<llvm::raw_pwrite_stream>>&, std::__2::unique_ptr<llvm::ToolOutputFile, std::__2::default_delete<llvm::ToolOutputFile>>&) BackendUtil.cpp:0:0
#23 0x00005637a7f12ad2 clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::StringRef, llvm::Module*, clang::BackendAction, std::__2::unique_ptr<llvm::raw_pwrite_stream, std::__2::default_delete<llvm::raw_pwrite_stream>>) (/usr/bin/clang+++0x3ecaad2)
#24 0x00005637a84b16d2 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) CodeGenAction.cpp:0:0
#25 0x00005637a9c6e669 clang::ParseAST(clang::Sema&, bool, bool) (/usr/bin/clang+++0x5c26669)
#26 0x00005637a83bfa71 clang::FrontendAction::Execute() (/usr/bin/clang+++0x4377a71)
#27 0x00005637a8323be0 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/usr/bin/clang+++0x42dbbe0)
#28 0x00005637a84aa26a clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/usr/bin/clang+++0x446226a)
#29 0x00005637a5f82001 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/usr/bin/clang+++0x1f3a001)
#30 0x00005637a5f7ff5b ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&) driver.cpp:0:0
#31 0x00005637a814c7d2 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<llvm::Optional<llvm::StringRef>>, std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char>>*, bool*) const::$_0>(long) Job.cpp:0:0
#32 0x00005637a754572e llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/usr/bin/clang+++0x34fd72e)
#33 0x00005637a814c07f clang::driver::CC1Command::Execute(llvm::ArrayRef<llvm::Optional<llvm::StringRef>>, std::__2::basic_string<char, std::__2::char_traits<char>, std::__2::allocator<char>>*, bool*) const (/usr/bin/clang+++0x410407f)
#34 0x00005637a8105e3e clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/usr/bin/clang+++0x40bde3e)
#35 0x00005637a8129acc clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::__2::pair<int, clang::driver::Command const*>>&) (/usr/bin/clang+++0x40e1acc)
#36 0x00005637a5f7f370 clang_main(int, char**) (/usr/bin/clang+++0x1f37370)
#37 0x00007f8977cde083 __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:342:3
#38 0x00005637a5f708ae _start (/usr/bin/clang+++0x1f288ae)
clang-16: error: clang frontend command failed with exit code 139 (use -v to see invocation)
clang version 16.0.0 (https://github.com/thingdust/llvm-project.git eb27f9521e5229e80adb41e9513d08b154619ac3)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
clang-16: note: diagnostic msg: 
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang-16: note: diagnostic msg: /tmp/http_server-ebb843.cpp
clang-16: note: diagnostic msg: /tmp/http_server-ebb843.sh
clang-16: note: diagnostic msg: 

********************
ninja: build stopped: subcommand failed.
adrianimboden commented 1 year ago

Any news? I would be happy to test more or help out with the patch in other ways if possible.