Author: Weibo He Date: 2026-02-02T23:55:36+08:00 New Revision: 17392af48318209eead6c8f7eccfee5c4cf80f3f
URL: https://github.com/llvm/llvm-project/commit/17392af48318209eead6c8f7eccfee5c4cf80f3f DIFF: https://github.com/llvm/llvm-project/commit/17392af48318209eead6c8f7eccfee5c4cf80f3f.diff LOG: Revert "[CoroCleanup] Noop coroutine elision for load-and-call pattern (#179154)" This reverts commit 195a6d0a05a743b8328faa8c7b20abb792bd8b30. Added: llvm/test/Transforms/Coroutines/coro-cleanup-noop-erase.ll Modified: llvm/lib/Transforms/Coroutines/CoroCleanup.cpp Removed: llvm/test/Transforms/Coroutines/coro-cleanup-noop-elide.ll ################################################################################ diff --git a/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp b/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp index fa342fd4717ea..6b68cf5bc2c20 100644 --- a/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp @@ -8,7 +8,6 @@ #include "llvm/Transforms/Coroutines/CoroCleanup.h" #include "CoroInternal.h" -#include "llvm/Analysis/PtrUseVisitor.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" @@ -16,7 +15,6 @@ #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/Transforms/Scalar/SimplifyCFG.h" -#include "llvm/Transforms/Utils/Local.h" using namespace llvm; @@ -32,27 +30,9 @@ struct Lowerer : coro::LowererBase { bool lower(Function &F); private: + void elideCoroNoop(IntrinsicInst *II); void lowerCoroNoop(IntrinsicInst *II); }; - -// Recursively walk and eliminate resume/destroy call on noop coro -class NoopCoroElider : public PtrUseVisitor<NoopCoroElider> { - using Base = PtrUseVisitor<NoopCoroElider>; - - IRBuilder<> Builder; - -public: - NoopCoroElider(const DataLayout &DL, LLVMContext &C) : Base(DL), Builder(C) {} - - void run(IntrinsicInst *II); - - void visitLoadInst(LoadInst &I) { enqueueUsers(I); } - void visitCallBase(CallBase &CB); - void visitIntrinsicInst(IntrinsicInst &II); - -private: - bool tryEraseCallInvoke(Instruction *I); -}; } static void lowerSubFn(IRBuilder<> &Builder, CoroSubFnInst *SubFn) { @@ -93,7 +73,6 @@ bool Lowerer::lower(Function &F) { bool IsPrivateAndUnprocessed = F.isPresplitCoroutine() && F.hasLocalLinkage(); bool Changed = false; - NoopCoroElider NCE(F.getDataLayout(), F.getContext()); SmallPtrSet<Instruction *, 8> DeadInsts{}; for (Instruction &I : instructions(F)) { if (auto *II = dyn_cast<IntrinsicInst>(&I)) { @@ -121,7 +100,7 @@ bool Lowerer::lower(Function &F) { II->replaceAllUsesWith(ConstantTokenNone::get(Context)); break; case Intrinsic::coro_noop: - NCE.run(II); + elideCoroNoop(II); if (!II->user_empty()) lowerCoroNoop(II); break; @@ -163,6 +142,28 @@ bool Lowerer::lower(Function &F) { return Changed; } +void Lowerer::elideCoroNoop(IntrinsicInst *II) { + for (User *U : make_early_inc_range(II->users())) { + auto *Fn = dyn_cast<CoroSubFnInst>(U); + if (Fn == nullptr) + continue; + + auto *User = Fn->getUniqueUndroppableUser(); + if (auto *Call = dyn_cast<CallInst>(User)) { + Call->eraseFromParent(); + Fn->eraseFromParent(); + continue; + } + + if (auto *I = dyn_cast<InvokeInst>(User)) { + Builder.SetInsertPoint(I); + Builder.CreateBr(I->getNormalDest()); + I->eraseFromParent(); + Fn->eraseFromParent(); + } + } +} + void Lowerer::lowerCoroNoop(IntrinsicInst *II) { if (!NoopCoro) { LLVMContext &C = Builder.getContext(); @@ -199,47 +200,6 @@ void Lowerer::lowerCoroNoop(IntrinsicInst *II) { II->replaceAllUsesWith(NoopCoroVoidPtr); } -void NoopCoroElider::run(IntrinsicInst *II) { - visitPtr(*II); - - Worklist.clear(); - VisitedUses.clear(); -} - -void NoopCoroElider::visitCallBase(CallBase &CB) { - auto *V = U->get(); - bool ResumeOrDestroy = V == CB.getCalledOperand(); - if (ResumeOrDestroy) { - [[maybe_unused]] bool Success = tryEraseCallInvoke(&CB); - assert(Success && "Unexpected CallBase"); - RecursivelyDeleteTriviallyDeadInstructions(V); - } -} - -void NoopCoroElider::visitIntrinsicInst(IntrinsicInst &II) { - if (auto *SubFn = dyn_cast<CoroSubFnInst>(&II)) { - auto *User = SubFn->getUniqueUndroppableUser(); - if (!tryEraseCallInvoke(cast<Instruction>(User))) - return; - SubFn->eraseFromParent(); - } -} - -bool NoopCoroElider::tryEraseCallInvoke(Instruction *I) { - if (auto *Call = dyn_cast<CallInst>(I)) { - Call->eraseFromParent(); - return true; - } - - if (auto *II = dyn_cast<InvokeInst>(I)) { - Builder.SetInsertPoint(II); - Builder.CreateBr(II->getNormalDest()); - II->eraseFromParent(); - return true; - } - return false; -} - static bool declaresCoroCleanupIntrinsics(const Module &M) { return coro::declaresIntrinsics( M, diff --git a/llvm/test/Transforms/Coroutines/coro-cleanup-noop-elide.ll b/llvm/test/Transforms/Coroutines/coro-cleanup-noop-elide.ll deleted file mode 100644 index 6d9dd654b914a..0000000000000 --- a/llvm/test/Transforms/Coroutines/coro-cleanup-noop-elide.ll +++ /dev/null @@ -1,51 +0,0 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 -; RUN: opt < %s -S -passes='coro-cleanup' | FileCheck %s - -; Tests that resume or destroy a no-op coroutine can be erased; Finally, erase coro.noop if it has no users. -define void @erase() personality i32 0 { -; CHECK-LABEL: define void @erase() personality i32 0 { -; CHECK-NEXT: [[DONE:.*:]] -; CHECK-NEXT: ret void -; - %frame = call noundef ptr @llvm.coro.noop() - %resume = call ptr @llvm.coro.subfn.addr(ptr %frame, i8 0) - call fastcc void %resume(ptr %frame) - %destroy = call ptr @llvm.coro.subfn.addr(ptr %frame, i8 1) - invoke fastcc void %destroy(ptr %frame) - to label %done unwind label %unwind - -done: - ret void - -unwind: - %pad = landingpad { ptr, i32 } - catch ptr null - call void @terminate() - unreachable -} - -; Tests the load-and-call pattern despite mismatched calling conventions. Prevent instcombine from breaking code. -define void @load() personality i32 0 { -; CHECK-LABEL: define void @load() personality i32 0 { -; CHECK-NEXT: [[DONE:.*:]] -; CHECK-NEXT: ret void -; - %frame = call noundef ptr @llvm.coro.noop() - %resume = load ptr, ptr %frame, align 8 - call void %resume(ptr %frame) - %destroy.addr = getelementptr inbounds nuw i8, ptr %frame, i64 8 - %destroy = load ptr, ptr %destroy.addr, align 8 - invoke void %destroy(ptr %frame) - to label %done unwind label %unwind - -done: - ret void - -unwind: - %pad = landingpad { ptr, i32 } - catch ptr null - call void @terminate() - unreachable -} - -declare void @terminate() noreturn diff --git a/llvm/test/Transforms/Coroutines/coro-cleanup-noop-erase.ll b/llvm/test/Transforms/Coroutines/coro-cleanup-noop-erase.ll new file mode 100644 index 0000000000000..7fd9dc900ddb2 --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-cleanup-noop-erase.ll @@ -0,0 +1,24 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; Tests that resume or destroy a no-op coroutine can be erased; Finally, erase coro.noop if it has no users. +; RUN: opt < %s -S -passes='coro-cleanup' | FileCheck %s + +define void @fn() personality i32 0 { +; CHECK-LABEL: define void @fn() personality i32 0 { +; CHECK-NEXT: [[DONE:.*:]] +; CHECK-NEXT: ret void +; + %frame = call noundef ptr @llvm.coro.noop() + %resume = call ptr @llvm.coro.subfn.addr(ptr %frame, i8 0) + call fastcc void %resume(ptr %frame) + %destroy = call ptr @llvm.coro.subfn.addr(ptr %frame, i8 1) + invoke fastcc void %destroy(ptr %frame) + to label %done unwind label %unwind + +done: + ret void + +unwind: + %pad = landingpad { ptr, i32 } + catch ptr null + unreachable +} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
