[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