llvm-project
llvm-project copied to clipboard
miscompilation with coroutine since 15.0.0: function has no ret call
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
@llvm/issue-subscribers-coroutines
Reproduced in O2 but failed in O1. I'll take a look. Thanks!
Weird, I can't reproduce this locally. @adrianimboden could you show the result of clang++ -v
. Just like:
clang version 15.0.0 ([email protected]: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.
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
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
}
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++
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
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
}
Oh, I reproduce it successfully with libcxx. Thanks.
I will do a bisect in the meantime and report back soon.
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 <[email protected]>
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(-)
Can you please provide the -S -emit-llvm -Xclang -disable-llvm-optzns -o -
output, so this is reproducible independent of environment?
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
Oh, if @nikic will take a look, I'll resign the assignment.
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...
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
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
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.
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.
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.
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.
@ChuanqiXu9 The bad pattern is a missing i32
store writing the variant tag.
@ChuanqiXu9 The bad pattern is a missing
i32
store writing the variant tag.
Thanks I'll take a look.
Unassigned due to I may not be able to look into this in time due to personal reasons.
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:
- using
-mllvm -enable-newgvn
- using
-mllvm -enable-pre=false
- using
-mllvm -enable-gvn-memdep=false
- using
-mllvm -gvn-max-num-deps=1
- remove GVNPass entirely (code change)
I managed to make the sample quite a bit smaller.
It now only has a dependency on the coroutine header.
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}
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.
I did a little more digging on this.
1f88d804083a8a1b68df1e6677920e38ab2a6b40 and 10c531cd5bf0166ce5bf42736506733b2285fdf8 introduced either:
- a bug in the optimizer
- or optimize something that triggers a bug in the coroutine implementation
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?
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