Closed adrianimboden closed 1 year ago
@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 (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.
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 <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(-)
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.
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).
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.
I found out that the GVNPass
somehow has an effect.
The following changes or command line arguments make the miscompilation go away:
-mllvm -enable-newgvn
-mllvm -enable-pre=false
-mllvm -enable-gvn-memdep=false
-mllvm -gvn-max-num-deps=1
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:
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
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.
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
.
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...
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
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.
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.
@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.
@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.
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.
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.
Ok - if you find a fix, let me know. Otherwise, this will probably just end up in LLVM 16 instead.
@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)?
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.
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.
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.
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.
@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)
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.
https://github.com/thingdust/llvm-project/commit/eb27f9521e5229e80adb41e9513d08b154619ac3:
$ 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.
Any news? I would be happy to test more or help out with the patch in other ways if possible.
godbolt: https://godbolt.org/z/b6odeohqa
clang++-14 -O3 -std=c++20
clang++-15 -O3 -std=c++20
output of
-S -emit-llvm -Xclang -disable-llvm-optzns -o -
: llvm.txt