[llvm] [Coroutines] fix coroutines + std::unique_ptr with async exceptions validation errors (PR #149691)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 19 22:55:43 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: None (tzuralon)
<details>
<summary>Changes</summary>
Fixes #<!-- -->148035
---
Patch is 502.39 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/149691.diff
7 Files Affected:
- (modified) llvm/lib/Transforms/Coroutines/CoroFrame.cpp (+156)
- (modified) llvm/lib/Transforms/Coroutines/CoroSplit.cpp (+10-1)
- (added) llvm/test/Transforms/Coroutines/pr148035_0_coroutine.ll (+7609)
- (added) llvm/test/Transforms/Coroutines/pr148035_1_coroutine_w_std_unique.ll (+866)
- (added) llvm/test/Transforms/Coroutines/pr148035_2_coroutine_w_arg_w_move_ctor_and_deleter.ll (+727)
- (added) llvm/test/Transforms/Coroutines/pr148035_inst_does_not_dominate.ll (+76)
- (added) llvm/test/Transforms/Coroutines/pr148035_unwind_edges_not_having_same_dest.ll (+74)
``````````diff
diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
index a65d0fb54c212..a3ec5d3cb06ea 100644
--- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp
@@ -35,6 +35,7 @@
#include "llvm/Transforms/Coroutines/SpillUtils.h"
#include "llvm/Transforms/Coroutines/SuspendCrossingInfo.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
#include <algorithm>
@@ -974,6 +975,159 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape,
return FrameTy;
}
+// Fixer for the "Instruction does not dominate all uses!" bug
+// The fix consists of mapping problematic paths (where CoroBegin does not
+// dominate cleanup BBs) and clones them to 2 flows - the one that insertSpills
+// intended to create (using the spill) and another one, preserving the logics
+// of pre-splitting, which would be triggered if unwinding happened before
+// CoroBegin
+static void
+splitBasicBlocksNotDominatedByCoroBegin(const FrameDataInfo &FrameData,
+ coro::Shape &Shape, Function *F,
+ DominatorTree &DT) {
+ ValueToValueMapTy VMap;
+ DenseMap<BasicBlock *, BasicBlock *>
+ProcessedSpillBlockToAlternativeUnspilledBlockMap;
+ bool FunctionHasSomeBlockNotDominatedByCoroBegin;
+ SmallVector<BasicBlock *> SpillUserBlocks;
+
+ for (const auto &E : FrameData.Spills) {
+ for (auto *U : E.second) {
+ if (std::find(SpillUserBlocks.begin(), SpillUserBlocks.end(),
+U->getParent()) == SpillUserBlocks.end()) {
+ SpillUserBlocks.push_back(U->getParent());
+ }
+ }
+ }
+ SpillUserBlocks.push_back(Shape.AllocaSpillBlock);
+
+ do {
+ FunctionHasSomeBlockNotDominatedByCoroBegin = false;
+ // We want to traverse the function post-order (predecessors first),
+ // and check dominance starting CoroBegin
+ bool HaveTraversedCoroBegin = false;
+ for (BasicBlock *CurrentBlock : ReversePostOrderTraversal<Function *>(F)) {
+ if (!HaveTraversedCoroBegin &&
+CurrentBlock != Shape.CoroBegin->getParent()) {
+ continue;
+ }
+ HaveTraversedCoroBegin = true;
+
+ // Focus on 2 types of users that produce errors - those in
+ // FrameData.Spills, and decendants of Shape.AllocaSpillBlocks
+ if (!DT.dominates(Shape.CoroBegin, CurrentBlock) &&
+std::find(SpillUserBlocks.begin(), SpillUserBlocks.end(),
+CurrentBlock) != SpillUserBlocks.end()) {
+ // Mark another iteration of the loop is needed, to verify that no more
+ // dominance issues after current run
+ FunctionHasSomeBlockNotDominatedByCoroBegin = true;
+
+ // Clone (preserve) the current basic block, before it will be modified
+ // by insertSpills
+ auto UnspilledAlternativeBlock =
+CloneBasicBlock(CurrentBlock, VMap, ".unspilled_alternative", F);
+
+ // Remap the instructions, VMap here aggregates instructions across
+ // multiple BasicBlocks, and we assume that traversal is post-order,
+ // therefore successor blocks (for example instructions having funclet
+ // tags) will be mapped correctly to the new cloned cleanuppad
+ for (Instruction &I : *UnspilledAlternativeBlock) {
+ RemapInstruction(&I, VMap,
+RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
+ }
+
+ // Keep track between the processed spill basic block and the cloned
+ // alternative unspilled basic block Will help us fix instructions that
+ // their context is complex (for example cleanuppad of funclet is
+ // defined in another BB)
+ ProcessedSpillBlockToAlternativeUnspilledBlockMap[CurrentBlock] =
+UnspilledAlternativeBlock;
+
+ SmallVector<Instruction *> FixUpPredTerminators;
+
+ // Find the specific predecessors that does not dominated by
+ // Shape.CoroBegin We don't fix them here but later because it's not
+ // safe while using predecessors as iterator function
+ for (BasicBlock *Pred : predecessors(CurrentBlock)) {
+ if (!DT.dominates(Shape.CoroBegin, Pred)) {
+ FixUpPredTerminators.push_back(Pred->getTerminator());
+ }
+ }
+
+ // Fixups for current block terminator
+ const auto &CurrentBlockTerminator = CurrentBlock->getTerminator();
+
+ // If it's cleanupret, find the correspondant cleanuppad (use the map to
+ // find it)
+ if (auto CurrentBlockCleanupReturnTerminator =
+dyn_cast<CleanupReturnInst>(CurrentBlockTerminator)) {
+ BasicBlock *CBCPBB =
+CurrentBlockCleanupReturnTerminator->getCleanupPad()->getParent();
+ CleanupReturnInst *DBT = dyn_cast<CleanupReturnInst>(
+UnspilledAlternativeBlock->getTerminator());
+
+ // Again assuming post-order traversal - if we mapped the predecessing
+ // cleanuppad block before, we should find it here If not, do nothing
+ if (ProcessedSpillBlockToAlternativeUnspilledBlockMap.contains(
+CBCPBB)) {
+ Instruction *DCPr =
+&ProcessedSpillBlockToAlternativeUnspilledBlockMap[CBCPBB]
+->front();
+ CleanupPadInst *DCP = cast<CleanupPadInst>(DCPr);
+ DBT->setCleanupPad(DCP);
+ }
+
+ // If it's a branch/invoke, keep track of its successors, we want to
+ // calculate dominance between CoroBegin and them also They might need
+ // clone as well
+ } else if (auto CurrentBlockBranchTerminator =
+dyn_cast<BranchInst>(CurrentBlockTerminator)) {
+ for (unsigned int successorIdx = 0;
+successorIdx < CurrentBlockBranchTerminator->getNumSuccessors();
+++successorIdx) {
+ SpillUserBlocks.push_back(
+CurrentBlockBranchTerminator->getSuccessor(successorIdx));
+ }
+ } else if (auto CurrentBlockInvokeTerminator =
+dyn_cast<InvokeInst>(CurrentBlockTerminator)) {
+ SpillUserBlocks.push_back(
+CurrentBlockInvokeTerminator->getUnwindDest());
+ } else {
+ report_fatal_error("Not implemented terminator for this specific "
+ "instruction fixup in current block fixups");
+ }
+
+ // Fixups on the predecessors terminator - direct them to out untouched
+ // alternative block to break dominance error.
+ for (auto FixUpPredTerminator : FixUpPredTerminators) {
+ if (auto FixUpPredTerminatorInvoke =
+dyn_cast<InvokeInst>(FixUpPredTerminator)) {
+ FixUpPredTerminatorInvoke->setUnwindDest(UnspilledAlternativeBlock);
+ } else if (auto FixUpPredTerminatorBranch =
+dyn_cast<BranchInst>(FixUpPredTerminator)) {
+ for (unsigned int successorIdx = 0;
+ successorIdx < FixUpPredTerminatorBranch->getNumSuccessors();
+ ++successorIdx) {
+ if (CurrentBlock ==
+FixUpPredTerminatorBranch->getSuccessor(successorIdx)) {
+ FixUpPredTerminatorBranch->setSuccessor(
+successorIdx, UnspilledAlternativeBlock);
+ }
+ }
+ } else {
+ report_fatal_error("Not implemented terminator for this specific "
+ "instruction in pred fixups");
+ }
+ }
+
+ // We changed dominance tree, so recalculate.
+ DT.recalculate(*F);
+ continue;
+ }
+ }
+ } while (FunctionHasSomeBlockNotDominatedByCoroBegin);
+}
+
// Replace all alloca and SSA values that are accessed across suspend points
// with GetElementPointer from coroutine frame + loads and stores. Create an
// AllocaSpillBB that will become the new entry block for the resume parts of
@@ -1053,6 +1207,8 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
return GEP;
};
+ splitBasicBlocksNotDominatedByCoroBegin(FrameData, Shape, F, DT);
+
for (auto const &E : FrameData.Spills) {
Value *Def = E.first;
auto SpillAlignment = Align(FrameData.getAlign(Def));
diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
index 64b33e46404f0..37b3d61c9f8f2 100644
--- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -376,7 +376,16 @@ static void replaceUnwindCoroEnd(AnyCoroEndInst *End, const coro::Shape &Shape,
// If coro.end has an associated bundle, add cleanupret instruction.
if (auto Bundle = End->getOperandBundle(LLVMContext::OB_funclet)) {
auto *FromPad = cast<CleanupPadInst>(Bundle->Inputs[0]);
- auto *CleanupRet = Builder.CreateCleanupRet(FromPad, nullptr);
+
+ // If the terminator is an invoke,
+ // set the cleanupret unwind destination the same as the other edges, to
+ // avoid validation errors
+ BasicBlock *UBB = nullptr;
+ if (auto II = dyn_cast<InvokeInst>(FromPad->getParent()->getTerminator())) {
+ UBB = II->getUnwindDest();
+ }
+
+ auto *CleanupRet = Builder.CreateCleanupRet(FromPad, UBB);
End->getParent()->splitBasicBlock(End);
CleanupRet->getParent()->getTerminator()->eraseFromParent();
}
diff --git a/llvm/test/Transforms/Coroutines/pr148035_0_coroutine.ll b/llvm/test/Transforms/Coroutines/pr148035_0_coroutine.ll
new file mode 100644
index 0000000000000..2457bc3045cec
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/pr148035_0_coroutine.ll
@@ -0,0 +1,7609 @@
+; This is the cppreference example for coroutines, in llvm IR form, built with async exceptions flag.
+; crashed before fix because of the validation mismatch of Unwind edges out of a funclet pad must have the same unwind dest
+; RUN: opt < %s -passes=coro-split -S | FileCheck %s
+; CHECK: define
+
+; ModuleID = 'coroutine.cpp'
+source_filename = "coroutine.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.38.33135"
+
+%"class.std::basic_ostream" = type { ptr, [4 x i8], i32, %"class.std::basic_ios" }
+%"class.std::basic_ios" = type { %"class.std::ios_base", ptr, ptr, i8 }
+%"class.std::ios_base" = type { ptr, i64, i32, i32, i32, i64, i64, ptr, ptr, ptr }
+%rtti.TypeDescriptor23 = type { ptr, ptr, [24 x i8] }
+%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
+%rtti.TypeDescriptor19 = type { ptr, ptr, [20 x i8] }
+%eh.CatchableTypeArray.2 = type { i32, [2 x i32] }
+%eh.ThrowInfo = type { i32, i32, i32, i32 }
+%rtti.CompleteObjectLocator = type { i32, i32, i32, i32, i32, i32 }
+%rtti.ClassHierarchyDescriptor = type { i32, i32, i32, i32 }
+%rtti.BaseClassDescriptor = type { i32, i32, i32, i32, i32, i32, i32 }
+%"struct.std::nostopstate_t" = type { i8 }
+%rtti.TypeDescriptor26 = type { ptr, ptr, [27 x i8] }
+%rtti.TypeDescriptor22 = type { ptr, ptr, [23 x i8] }
+%eh.CatchableTypeArray.5 = type { i32, [5 x i32] }
+%"union.std::error_category::_Addr_storage" = type { i64 }
+%rtti.TypeDescriptor35 = type { ptr, ptr, [36 x i8] }
+%rtti.TypeDescriptor24 = type { ptr, ptr, [25 x i8] }
+%"struct.std::_Fake_allocator" = type { i8 }
+%rtti.TypeDescriptor30 = type { ptr, ptr, [31 x i8] }
+%eh.CatchableTypeArray.3 = type { i32, [3 x i32] }
+%struct.awaitable = type { ptr }
+%struct.task = type { i8 }
+%"struct.task::promise_type" = type { i8 }
+%"struct.std::suspend_never" = type { i8 }
+%"class.std::thread::id" = type { i32 }
+%"struct.std::coroutine_handle" = type { ptr }
+%"struct.std::coroutine_handle.0" = type { ptr }
+%"class.std::basic_ostream<char>::sentry" = type { %"class.std::basic_ostream<char>::_Sentry_base", i8 }
+%"class.std::basic_ostream<char>::_Sentry_base" = type { ptr }
+%"class.std::runtime_error" = type { %"class.std::exception" }
+%"class.std::exception" = type { ptr, %struct.__std_exception_data }
+%struct.__std_exception_data = type { ptr, i8 }
+%"class.std::jthread" = type { %"class.std::thread", %"class.std::stop_source" }
+%"class.std::thread" = type { %struct._Thrd_t }
+%struct._Thrd_t = type { ptr, i32 }
+%"class.std::stop_source" = type { ptr }
+%class.anon = type { %"struct.std::coroutine_handle" }
+%"class.std::unique_ptr" = type { %"class.std::_Compressed_pair" }
+%"class.std::_Compressed_pair" = type { ptr }
+%"struct.std::_Stop_state" = type { %"struct.std::atomic", %"struct.std::atomic", %"class.std::_Locked_pointer", %"struct.std::atomic.6", i32 }
+%"struct.std::atomic" = type { %"struct.std::_Atomic_integral_facade" }
+%"struct.std::_Atomic_integral_facade" = type { %"struct.std::_Atomic_integral" }
+%"struct.std::_Atomic_integral" = type { %"struct.std::_Atomic_storage" }
+%"struct.std::_Atomic_storage" = type { %"struct.std::_Atomic_padded" }
+%"struct.std::_Atomic_padded" = type { i32 }
+%"class.std::_Locked_pointer" = type { %"struct.std::atomic.1" }
+%"struct.std::atomic.1" = type { %"struct.std::_Atomic_integral_facade.2" }
+%"struct.std::_Atomic_integral_facade.2" = type { %"struct.std::_Atomic_integral.3" }
+%"struct.std::_Atomic_integral.3" = type { %"struct.std::_Atomic_storage.4" }
+%"struct.std::_Atomic_storage.4" = type { %"struct.std::_Atomic_padded.5" }
+%"struct.std::_Atomic_padded.5" = type { i64 }
+%"struct.std::atomic.6" = type { %"struct.std::_Atomic_pointer" }
+%"struct.std::_Atomic_pointer" = type { %"struct.std::_Atomic_storage.7" }
+%"struct.std::_Atomic_storage.7" = type { %"struct.std::_Atomic_padded.8" }
+%"struct.std::_Atomic_padded.8" = type { ptr }
+%"struct.std::_Exact_args_t" = type { i8 }
+%"struct.std::_Zero_then_variadic_args_t" = type { i8 }
+%"class.std::tuple" = type { %"struct.std::_Tuple_val" }
+%"struct.std::_Tuple_val" = type { %class.anon }
+%"class.std::_Stop_callback_base" = type { ptr, ptr, ptr, ptr }
+%"class.std::basic_streambuf" = type { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, i32, i32, ptr, ptr, ptr }
+%"class.std::ios_base::failure" = type { %"class.std::system_error" }
+%"class.std::system_error" = type { %"class.std::_System_error" }
+%"class.std::_System_error" = type { %"class.std::runtime_error", %"class.std::error_code" }
+%"class.std::error_code" = type { i32, ptr }
+%"class.std::basic_string" = type { %"class.std::_Compressed_pair.10" }
+%"class.std::_Compressed_pair.10" = type { %"class.std::_String_val" }
+%"class.std::_String_val" = type { %"union.std::_String_val<std::_Simple_types<char>>::_Bxty", i64, i64 }
+%"union.std::_String_val<std::_Simple_types<char>>::_Bxty" = type { ptr, [8 x i8] }
+%"class.std::error_condition" = type { i32, ptr }
+%"struct.std::_Fake_proxy_ptr_impl" = type { i8 }
+%"class.std::bad_array_new_length" = type { %"class.std::bad_alloc" }
+%"class.std::bad_alloc" = type { %"class.std::exception" }
+%"class.std::error_category" = type { ptr, %"union.std::error_category::_Addr_storage" }
+%"class.std::allocator" = type { i8 }
+%"struct.std::_One_then_variadic_args_t" = type { i8 }
+%class.anon.11 = type { i8 }
+
+$"?get_return_object at promise_type@task@@QEAA?AU2 at XZ" = comdat any
+
+$"?initial_suspend at promise_type@task@@QEAA?AUsuspend_never at std@@XZ" = comdat any
+
+$"?await_ready at suspend_never@std@@QEBA_NXZ" = comdat any
+
+$"?await_suspend at suspend_never@std@@QEBAXU?$coroutine_handle at X@2@@Z" = comdat any
+
+$"?from_address@?$coroutine_handle at Upromise_type@task@@@std@@SA?AU12 at QEAX@Z" = comdat any
+
+$"??B?$coroutine_handle at Upromise_type@task@@@std@@QEBA?AU?$coroutine_handle at X@1 at XZ" = comdat any
+
+$"?await_resume at suspend_never@std@@QEBAXXZ" = comdat any
+
+$"??$?6U?$char_traits at D@std@@@std@@YAAEAV?$basic_ostream at DU?$char_traits at D@std@@@0 at AEAV10@D at Z" = comdat any
+
+$"??$?6DU?$char_traits at D@std@@@std@@YAAEAV?$basic_ostream at DU?$char_traits at D@std@@@0 at AEAV10@Vid at thread@0@@Z" = comdat any
+
+$"??$?6U?$char_traits at D@std@@@std@@YAAEAV?$basic_ostream at DU?$char_traits at D@std@@@0 at AEAV10@PEBD at Z" = comdat any
+
+$"?get_id at this_thread@std@@YA?AVid at thread@2 at XZ" = comdat any
+
+$"?return_void at promise_type@task@@QEAAXXZ" = comdat any
+
+$"?unhandled_exception at promise_type@task@@QEAAXXZ" = comdat any
+
+$"?final_suspend at promise_type@task@@QEAA?AUsuspend_never at std@@XZ" = comdat any
+
+$"??0jthread at std@@QEAA at XZ" = comdat any
+
+$"??1jthread at std@@QEAA at XZ" = comdat any
+
+$"??0?$coroutine_handle at Upromise_type@task@@@std@@QEAA at XZ" = comdat any
+
+$"?from_address@?$coroutine_handle at X@std@@SA?AU12 at QEAX@Z" = comdat any
+
+$"??0?$coroutine_handle at X@std@@QEAA at XZ" = comdat any
+
+$"??0id at thread@std@@AEAA at I@Z" = comdat any
+
+$"?joinable at jthread@std@@QEBA_NXZ" = comdat any
+
+$"??0runtime_error at std@@QEAA at PEBD@Z" = comdat any
+
+$"??0runtime_error at std@@QEAA at AEBV01@@Z" = comdat any
+
+$"??0exception at std@@QEAA at AEBV01@@Z" = comdat any
+
+$"??1runtime_error at std@@UEAA at XZ" = comdat any
+
+$"??4jthread at std@@QEAAAEAV01@$$QEAV01@@Z" = comdat any
+
+$"?get_id at jthread@std@@QEBA?AVid at thread@2 at XZ" = comdat any
+
+$"?joinable at thread@std@@QEBA_NXZ" = comdat any
+
+$"??0exception at std@@QEAA at QEBD@Z" = comdat any
+
+$"??1exception at std@@UEAA at XZ" = comdat any
+
+$"??_Gruntime_error at std@@UEAAPEAXI at Z" = comdat any
+
+$"?what at exception@std@@UEBAPEBDXZ" = comdat any
+
+$"??_Gexception at std@@UEAAPEAXI at Z" = comdat any
+
+$"??0thread at std@@QEAA at XZ" = comdat any
+
+$"??0stop_source at std@@QEAA at XZ" = comdat any
+
+$"??1stop_source at std@@QEAA at XZ" = comdat any
+
+$"??1thread at std@@QEAA at XZ" = comdat any
+
+$"??0_Stop_state at std@@QEAA at XZ" = comdat any
+
+$"??0?$_Locked_pointer at V_Stop_callback_base@std@@@std@@QEAA at XZ" = comdat any
+
+$"??0?$_Atomic_storage at I$03 at std@@QEAA at I@Z" = comdat any
+
+$"??0?$atomic at _K@std@@QEAA at XZ" = comdat any
+
+$"??0?$_Atomic_storage at PEBV_Stop_callback_base@std@@$07 at std@@QEAA at QEBV_Stop_callback_base@1@@Z" = comdat any
+
+$"??$?0U_Exact_args_t at std@@$0A@@?$tuple@$$V at std@@QEAA at U_Exact_args_t@1@@Z" = comdat any
+
+$"?resume@?$coroutine_handle at X@std@@QEBAXXZ" = comdat any
+
+$"?fetch_sub@?$_Atomic_integral_facade at I@std@@QEAAIIW4memory_order at 2@@Z" = comdat any
+
+$"?fetch_add@?$_Atomic_integral at I$03 at std@@QEAAIIW4memory_order at 2@@Z" = comdat any
+
+$"?_Negate@?$_Atomic_integral_facade at I@std@@SAII at Z" = comdat any
+
+$_Check_memory_order = comdat any
+
+$"??$_Atomic_address_as at JU?$_Atomic_padded at I@std@@@std@@YAPECJAEAU?$_Atomic_padded at I@0@@Z" = comdat any
+
+$"?_Try_cancel_and_join at jthread@std@@AEAAXXZ" = comdat any
+
+$"??4thread at std@@QEAAAEAV01@$$QEAV01@@Z" = comdat any
+
+$"??4stop_source at std@@QEAAAEAV01@$$QEAV01@@Z" = comdat any
+
+$"?request_stop at stop_source@std@@QEAA_NXZ" = comdat any
+
+$"?join at thread@std@@QEAAXXZ" = comdat any
+
+$"?_Request_stop at _Stop_state@std@@QEAA_NXZ" = comdat any
+
+$"?fetch_or@?$_Atomic_integral at I$03 at std@@QEAAIIW4memory_order at 2@@Z" = comdat any
+
+$"?_Lock_and_load@?$_Locked_pointer at V_Stop_callback_base@std@@@std@@QEAAPEAV_Stop_callback_base at 2@XZ" = comdat any
+
+$"?store@?$_Atomic_storage at PEBV_Stop_callback_base@std@@$07 at std@@QEAAXQEBV_Stop_callback_base at 2@W4memory_order at 2@@Z" = comdat any
+
+$"?notify_all@?$_Atomic_storage at PEBV_Stop_callback_base@std@@$07 at std@@QEAAXXZ" = comdat any
+
+$"?_Store_and_unlock@?$_Locked_pointer at V_Stop_callback_base@std@@@std@@QEAAXQEAV_Stop_callback_base at 2@@Z" = comdat any
+
+$"??$exchange at PEAV_Stop_callback_base@std@@$$T at std@@YAPEAV_Stop_callback_base at 0@AEAPEAV10@$$QEA$$T at Z" = comdat any
+
+$"?load@?$_Atomic_storage at _K$07 at std@@QEBA_KW4memory_order at 2@@Z" = comdat any
+
+$"?compare_exchange_weak@?$atomic at _K@std@@QEAA_NAEA_K_K at Z" = comdat any
+
+$"?wait@?$_Atomic_storage at _K$07 at std@@QEBAX_KW4memory_order at 2@@Z" = comdat any
+
+$"??$_Atomic_address_as at _JU?$_Atomic_padded at _K@std@@@std@@YAPED_JAEBU?$_Atomic_padded at _K@0@@Z" = comdat any
+
+$"?compare_exchange_strong@?$_Atomic_storage at _K$07 at std@@QEAA_NAEA_K_KW4memory_order at 2@@Z" = comdat any
+
+$"??$_Atomic_reinterpret_as at _J_K@std@@YA_JAEB_K at Z" = comdat any
+
+$"??$_Atomic_address_as at _JU?$_Atomic_padded at _K@std@@@std@@YAPEC_JAEAU?$_Atomic_padded at _K@0@@Z" = comdat any
+
+$"??$_Atomic_wait_direct at _K_J@std@@YAXQEBU?$_Atomic_storage at _K$07 at 0@_JW4memory_order at 0@@Z" = comdat any
+
+$"??$_Atomic_address_as at _JU?$_Atomic_padded at PEBV_Stop_callback_base@std@@@std@@@std@@YAPEC_JAEAU?$_Atomic_padded at PEBV_Stop_callback_base@std@@@0@@Z" = comdat any
+
+$"??$_Atomic_reinterpret_as at _JPEBV_Stop_callback_base@std@@@std@@YA_JAEBQEBV_Stop_callback_base at 0@@Z" = comdat any
+
+$"?store@?$_Atomic_storage at PEBV_Stop_callback_base@std@@$07 at std@@QEAAXQEBV_Stop_callback_base at 2@@Z" = comdat any
+
+$"?exchange@?$_Atomic_storage at _K$07 at std@@QEAA_K_KW4memory_order at 2@@Z" = comdat any
+
+$"?notify_all@?$_Atomic_storage at _K...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/149691
More information about the llvm-commits
mailing list