[llvm] [Coroutines] Inline the `.noalloc` ramp function marked coro_safe_elide (PR #114004)
Yuxuan Chen via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 7 13:35:41 PST 2024
https://github.com/yuxuanchen1997 updated https://github.com/llvm/llvm-project/pull/114004
>From 61005bfd62b0970843dee196d9de829e18434a59 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Mon, 28 Oct 2024 20:28:54 -0700
Subject: [PATCH 1/6] Revert "[LLVM][Coroutines] Switch CoroAnnotationElidePass
to a FunctionPass (#107897)"
This reverts commit 761bf333e378b52614cf36cd5db2837d5e4e0ae4.
---
.../Coroutines/CoroAnnotationElide.h | 10 +-
llvm/lib/Passes/PassBuilderPipelines.cpp | 6 +-
llvm/lib/Passes/PassRegistry.def | 2 +-
.../Coroutines/CoroAnnotationElide.cpp | 122 ++++++++++--------
4 files changed, 79 insertions(+), 61 deletions(-)
diff --git a/llvm/include/llvm/Transforms/Coroutines/CoroAnnotationElide.h b/llvm/include/llvm/Transforms/Coroutines/CoroAnnotationElide.h
index 986a5dbd1ed0fe..352c9e14526697 100644
--- a/llvm/include/llvm/Transforms/Coroutines/CoroAnnotationElide.h
+++ b/llvm/include/llvm/Transforms/Coroutines/CoroAnnotationElide.h
@@ -17,14 +17,18 @@
#ifndef LLVM_TRANSFORMS_COROUTINES_COROANNOTATIONELIDE_H
#define LLVM_TRANSFORMS_COROUTINES_COROANNOTATIONELIDE_H
+#include "llvm/Analysis/CGSCCPassManager.h"
+#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/IR/PassManager.h"
namespace llvm {
-class Function;
-
struct CoroAnnotationElidePass : PassInfoMixin<CoroAnnotationElidePass> {
- PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+ CoroAnnotationElidePass() {}
+
+ PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG, CGSCCUpdateResult &UR);
+
static bool isRequired() { return false; }
};
} // end namespace llvm
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index af99ce5cd835bb..785aa9bca88191 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -984,8 +984,7 @@ PassBuilder::buildInlinerPipeline(OptimizationLevel Level,
if (Phase != ThinOrFullLTOPhase::ThinLTOPreLink) {
MainCGPipeline.addPass(CoroSplitPass(Level != OptimizationLevel::O0));
- MainCGPipeline.addPass(
- createCGSCCToFunctionPassAdaptor(CoroAnnotationElidePass()));
+ MainCGPipeline.addPass(CoroAnnotationElidePass());
}
// Make sure we don't affect potential future NoRerun CGSCC adaptors.
@@ -1036,7 +1035,8 @@ PassBuilder::buildModuleInlinerPipeline(OptimizationLevel Level,
if (Phase != ThinOrFullLTOPhase::ThinLTOPreLink) {
MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(
CoroSplitPass(Level != OptimizationLevel::O0)));
- MPM.addPass(createModuleToFunctionPassAdaptor(CoroAnnotationElidePass()));
+ MPM.addPass(
+ createModuleToPostOrderCGSCCPassAdaptor(CoroAnnotationElidePass()));
}
return MPM;
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index e7b48369922ffc..ca3fea4ef61ff1 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -245,6 +245,7 @@ CGSCC_PASS("attributor-light-cgscc", AttributorLightCGSCCPass())
CGSCC_PASS("invalidate<all>", InvalidateAllAnalysesPass())
CGSCC_PASS("no-op-cgscc", NoOpCGSCCPass())
CGSCC_PASS("openmp-opt-cgscc", OpenMPOptCGSCCPass())
+CGSCC_PASS("coro-annotation-elide", CoroAnnotationElidePass())
#undef CGSCC_PASS
#ifndef CGSCC_PASS_WITH_PARAMS
@@ -346,7 +347,6 @@ FUNCTION_PASS("complex-deinterleaving", ComplexDeinterleavingPass(TM))
FUNCTION_PASS("consthoist", ConstantHoistingPass())
FUNCTION_PASS("constraint-elimination", ConstraintEliminationPass())
FUNCTION_PASS("coro-elide", CoroElidePass())
-FUNCTION_PASS("coro-annotation-elide", CoroAnnotationElidePass())
FUNCTION_PASS("correlated-propagation", CorrelatedValuePropagationPass())
FUNCTION_PASS("count-visits", CountVisitsPass())
FUNCTION_PASS("dce", DCEPass())
diff --git a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp
index 5e82ed2e98184e..4cfe61776873bc 100644
--- a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp
@@ -16,6 +16,7 @@
#include "llvm/Transforms/Coroutines/CoroAnnotationElide.h"
+#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/IR/Analysis.h"
@@ -40,10 +41,10 @@ static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) {
// Create an alloca in the caller, using FrameSize and FrameAlign as the callee
// coroutine's activation frame.
static Value *allocateFrameInCaller(Function *Caller, uint64_t FrameSize,
- Align FrameAlign) {
+ Align FrameAlign) {
LLVMContext &C = Caller->getContext();
BasicBlock::iterator InsertPt =
- getFirstNonAllocaInTheEntryBlock(Caller)->getIterator();
+ getFirstNonAllocaInTheEntryBlock(Caller)->getIterator();
const DataLayout &DL = Caller->getDataLayout();
auto FrameTy = ArrayType::get(Type::getInt8Ty(C), FrameSize);
auto *Frame = new AllocaInst(FrameTy, DL.getAllocaAddrSpace(), "", InsertPt);
@@ -57,7 +58,7 @@ static Value *allocateFrameInCaller(Function *Caller, uint64_t FrameSize,
// - Replace the old CB with a new Call or Invoke to `NewCallee`, with the
// pointer to the frame as an additional argument to NewCallee.
static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
- uint64_t FrameSize, Align FrameAlign) {
+ uint64_t FrameSize, Align FrameAlign) {
// TODO: generate the lifetime intrinsics for the new frame. This will require
// introduction of two pesudo lifetime intrinsics in the frontend around the
// `co_await` expression and convert them to real lifetime intrinsics here.
@@ -70,13 +71,13 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
if (auto *CI = dyn_cast<CallInst>(CB)) {
auto *NewCI = CallInst::Create(NewCallee->getFunctionType(), NewCallee,
- NewArgs, "", NewCBInsertPt);
+ NewArgs, "", NewCBInsertPt);
NewCI->setTailCallKind(CI->getTailCallKind());
NewCB = NewCI;
} else if (auto *II = dyn_cast<InvokeInst>(CB)) {
NewCB = InvokeInst::Create(NewCallee->getFunctionType(), NewCallee,
- II->getNormalDest(), II->getUnwindDest(),
- NewArgs, {}, "", NewCBInsertPt);
+ II->getNormalDest(), II->getUnwindDest(),
+ NewArgs, {}, "", NewCBInsertPt);
} else {
llvm_unreachable("CallBase should either be Call or Invoke!");
}
@@ -86,65 +87,78 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
NewCB->setAttributes(CB->getAttributes());
NewCB->setDebugLoc(CB->getDebugLoc());
std::copy(CB->bundle_op_info_begin(), CB->bundle_op_info_end(),
- NewCB->bundle_op_info_begin());
+ NewCB->bundle_op_info_begin());
NewCB->removeFnAttr(llvm::Attribute::CoroElideSafe);
CB->replaceAllUsesWith(NewCB);
CB->eraseFromParent();
}
-PreservedAnalyses CoroAnnotationElidePass::run(Function &F,
- FunctionAnalysisManager &FAM) {
+PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C,
+ CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG,
+ CGSCCUpdateResult &UR) {
bool Changed = false;
+ CallGraphUpdater CGUpdater;
+ CGUpdater.initialize(CG, C, AM, UR);
- Function *NewCallee =
- F.getParent()->getFunction((F.getName() + ".noalloc").str());
+ auto &FAM =
+ AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
- if (!NewCallee)
- return PreservedAnalyses::all();
-
- auto FramePtrArgPosition = NewCallee->arg_size() - 1;
- auto FrameSize = NewCallee->getParamDereferenceableBytes(FramePtrArgPosition);
- auto FrameAlign = NewCallee->getParamAlign(FramePtrArgPosition).valueOrOne();
-
- SmallVector<CallBase *, 4> Users;
- for (auto *U : F.users()) {
- if (auto *CB = dyn_cast<CallBase>(U)) {
- if (CB->getCalledFunction() == &F)
- Users.push_back(CB);
- }
- }
-
- auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
-
- for (auto *CB : Users) {
- auto *Caller = CB->getFunction();
- if (!Caller)
+ for (LazyCallGraph::Node &N : C) {
+ Function *Callee = &N.getFunction();
+ Function *NewCallee = Callee->getParent()->getFunction(
+ (Callee->getName() + ".noalloc").str());
+ if (!NewCallee)
continue;
- bool IsCallerPresplitCoroutine = Caller->isPresplitCoroutine();
- bool HasAttr = CB->hasFnAttr(llvm::Attribute::CoroElideSafe);
- if (IsCallerPresplitCoroutine && HasAttr) {
- processCall(CB, Caller, NewCallee, FrameSize, FrameAlign);
-
- ORE.emit([&]() {
- return OptimizationRemark(DEBUG_TYPE, "CoroAnnotationElide", Caller)
- << "'" << ore::NV("callee", F.getName()) << "' elided in '"
- << ore::NV("caller", Caller->getName()) << "'";
- });
-
- FAM.invalidate(*Caller, PreservedAnalyses::none());
- Changed = true;
- } else {
- ORE.emit([&]() {
- return OptimizationRemarkMissed(DEBUG_TYPE, "CoroAnnotationElide",
- Caller)
- << "'" << ore::NV("callee", F.getName()) << "' not elided in '"
- << ore::NV("caller", Caller->getName()) << "' (caller_presplit="
- << ore::NV("caller_presplit", IsCallerPresplitCoroutine)
- << ", elide_safe_attr=" << ore::NV("elide_safe_attr", HasAttr)
- << ")";
- });
+ SmallVector<CallBase *, 4> Users;
+ for (auto *U : Callee->users()) {
+ if (auto *CB = dyn_cast<CallBase>(U)) {
+ if (CB->getCalledFunction() == Callee)
+ Users.push_back(CB);
+ }
+ }
+ auto FramePtrArgPosition = NewCallee->arg_size() - 1;
+ auto FrameSize = NewCallee->getParamDereferenceableBytes(FramePtrArgPosition);
+ auto FrameAlign = NewCallee->getParamAlign(FramePtrArgPosition).valueOrOne();
+
+ auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(*Callee);
+
+ for (auto *CB : Users) {
+ auto *Caller = CB->getFunction();
+ if (!Caller)
+ continue;
+
+ bool IsCallerPresplitCoroutine = Caller->isPresplitCoroutine();
+ bool HasAttr = CB->hasFnAttr(llvm::Attribute::CoroElideSafe);
+ if (IsCallerPresplitCoroutine && HasAttr) {
+ auto *CallerN = CG.lookup(*Caller);
+ auto *CallerC = CG.lookupSCC(*CallerN);
+ processCall(CB, Caller, NewCallee, FrameSize, FrameAlign);
+
+ ORE.emit([&]() {
+ return OptimizationRemark(DEBUG_TYPE, "CoroAnnotationElide", Caller)
+ << "'" << ore::NV("callee", Callee->getName()) << "' elided in '"
+ << ore::NV("caller", Caller->getName()) << "'";
+ });
+
+ FAM.invalidate(*Caller, PreservedAnalyses::none());
+ Changed = true;
+ updateCGAndAnalysisManagerForCGSCCPass(CG, *CallerC, *CallerN, AM, UR,
+ FAM);
+
+ } else {
+ ORE.emit([&]() {
+ return OptimizationRemarkMissed(DEBUG_TYPE, "CoroAnnotationElide",
+ Caller)
+ << "'" << ore::NV("callee", Callee->getName()) << "' not elided in '"
+ << ore::NV("caller", Caller->getName()) << "' (caller_presplit="
+ << ore::NV("caller_presplit", IsCallerPresplitCoroutine)
+ << ", elide_safe_attr=" << ore::NV("elide_safe_attr", HasAttr)
+ << ")";
+ });
+ }
}
}
>From 00b1d1b9c99e0b6442d66ff6ca8dd9c58d504498 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Mon, 28 Oct 2024 20:38:40 -0700
Subject: [PATCH 2/6] inline new call to caller
---
.../Transforms/Coroutines/CoroAnnotationElide.cpp | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp
index 4cfe61776873bc..9cf8854cdbf2d2 100644
--- a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp
@@ -24,6 +24,8 @@
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
+#include "llvm/Transforms/Utils/CallGraphUpdater.h"
+#include "llvm/Transforms/Utils/Cloning.h"
#include <cassert>
@@ -91,7 +93,15 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
NewCB->removeFnAttr(llvm::Attribute::CoroElideSafe);
CB->replaceAllUsesWith(NewCB);
- CB->eraseFromParent();
+
+ InlineFunctionInfo IFI;
+ InlineResult IR = InlineFunction(*NewCB, IFI);
+ if (IR.isSuccess()) {
+ CB->eraseFromParent();
+ } else {
+ NewCB->replaceAllUsesWith(CB);
+ NewCB->eraseFromParent();
+ }
}
PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C,
>From 62131d5c578f6c246ea242b6e1589df28b7038c0 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Thu, 31 Oct 2024 16:09:52 -0700
Subject: [PATCH 3/6] add test case
---
.../Coroutines/gh114487-crash-in-cgscc.ll | 32 +++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 llvm/test/Transforms/Coroutines/gh114487-crash-in-cgscc.ll
diff --git a/llvm/test/Transforms/Coroutines/gh114487-crash-in-cgscc.ll b/llvm/test/Transforms/Coroutines/gh114487-crash-in-cgscc.ll
new file mode 100644
index 00000000000000..228e722940e18f
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/gh114487-crash-in-cgscc.ll
@@ -0,0 +1,32 @@
+; Verify that we don't crash when eliding coro_elide_safe callsites.
+; RUN: opt < %s -passes='cgscc(function<>(simplifycfg<>),function-attrs,coro-split,coro-annotation-elide)' -S | FileCheck %s
+
+; CHECK-LABEL: define void @foo()
+define void @foo() presplitcoroutine personality ptr null {
+entry:
+ %0 = call token @llvm.coro.save(ptr null)
+ br label %branch
+
+branch:
+; Check that we don't call bar at all.
+; CHECK-NOT: call void @bar{{.*}}
+ call void @bar() coro_elide_safe
+; CHECK: call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr @bar.resumers)
+ ret void
+}
+
+; CHECK-LABEL: define void @bar()
+define void @bar() presplitcoroutine personality ptr null {
+entry:
+ %0 = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
+ %1 = call ptr @llvm.coro.begin(token %0, ptr null)
+ %2 = call token @llvm.coro.save(ptr null)
+ %3 = call i8 @llvm.coro.suspend(token none, i1 false)
+ ret void
+}
+
+declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) nounwind
+declare ptr @llvm.coro.begin(token, ptr writeonly) nounwind
+declare token @llvm.coro.save(ptr) nomerge nounwind
+declare i8 @llvm.coro.suspend(token, i1) nounwind
+
>From 1fea9e0856729250f25a8ccb42dc9f1457ae7eb8 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Thu, 31 Oct 2024 16:41:49 -0700
Subject: [PATCH 4/6] git clang-format
---
.../Coroutines/CoroAnnotationElide.cpp | 56 ++++++++++---------
1 file changed, 30 insertions(+), 26 deletions(-)
diff --git a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp
index 9cf8854cdbf2d2..7dbf501b817010 100644
--- a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp
@@ -43,10 +43,10 @@ static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) {
// Create an alloca in the caller, using FrameSize and FrameAlign as the callee
// coroutine's activation frame.
static Value *allocateFrameInCaller(Function *Caller, uint64_t FrameSize,
- Align FrameAlign) {
+ Align FrameAlign) {
LLVMContext &C = Caller->getContext();
BasicBlock::iterator InsertPt =
- getFirstNonAllocaInTheEntryBlock(Caller)->getIterator();
+ getFirstNonAllocaInTheEntryBlock(Caller)->getIterator();
const DataLayout &DL = Caller->getDataLayout();
auto FrameTy = ArrayType::get(Type::getInt8Ty(C), FrameSize);
auto *Frame = new AllocaInst(FrameTy, DL.getAllocaAddrSpace(), "", InsertPt);
@@ -60,7 +60,7 @@ static Value *allocateFrameInCaller(Function *Caller, uint64_t FrameSize,
// - Replace the old CB with a new Call or Invoke to `NewCallee`, with the
// pointer to the frame as an additional argument to NewCallee.
static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
- uint64_t FrameSize, Align FrameAlign) {
+ uint64_t FrameSize, Align FrameAlign) {
// TODO: generate the lifetime intrinsics for the new frame. This will require
// introduction of two pesudo lifetime intrinsics in the frontend around the
// `co_await` expression and convert them to real lifetime intrinsics here.
@@ -73,13 +73,13 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
if (auto *CI = dyn_cast<CallInst>(CB)) {
auto *NewCI = CallInst::Create(NewCallee->getFunctionType(), NewCallee,
- NewArgs, "", NewCBInsertPt);
+ NewArgs, "", NewCBInsertPt);
NewCI->setTailCallKind(CI->getTailCallKind());
NewCB = NewCI;
} else if (auto *II = dyn_cast<InvokeInst>(CB)) {
NewCB = InvokeInst::Create(NewCallee->getFunctionType(), NewCallee,
- II->getNormalDest(), II->getUnwindDest(),
- NewArgs, {}, "", NewCBInsertPt);
+ II->getNormalDest(), II->getUnwindDest(),
+ NewArgs, {}, "", NewCBInsertPt);
} else {
llvm_unreachable("CallBase should either be Call or Invoke!");
}
@@ -89,7 +89,7 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
NewCB->setAttributes(CB->getAttributes());
NewCB->setDebugLoc(CB->getDebugLoc());
std::copy(CB->bundle_op_info_begin(), CB->bundle_op_info_end(),
- NewCB->bundle_op_info_begin());
+ NewCB->bundle_op_info_begin());
NewCB->removeFnAttr(llvm::Attribute::CoroElideSafe);
CB->replaceAllUsesWith(NewCB);
@@ -105,15 +105,15 @@ static void processCall(CallBase *CB, Function *Caller, Function *NewCallee,
}
PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C,
- CGSCCAnalysisManager &AM,
- LazyCallGraph &CG,
- CGSCCUpdateResult &UR) {
+ CGSCCAnalysisManager &AM,
+ LazyCallGraph &CG,
+ CGSCCUpdateResult &UR) {
bool Changed = false;
CallGraphUpdater CGUpdater;
CGUpdater.initialize(CG, C, AM, UR);
auto &FAM =
- AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
+ AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
for (LazyCallGraph::Node &N : C) {
Function *Callee = &N.getFunction();
@@ -130,8 +130,10 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C,
}
}
auto FramePtrArgPosition = NewCallee->arg_size() - 1;
- auto FrameSize = NewCallee->getParamDereferenceableBytes(FramePtrArgPosition);
- auto FrameAlign = NewCallee->getParamAlign(FramePtrArgPosition).valueOrOne();
+ auto FrameSize =
+ NewCallee->getParamDereferenceableBytes(FramePtrArgPosition);
+ auto FrameAlign =
+ NewCallee->getParamAlign(FramePtrArgPosition).valueOrOne();
auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(*Callee);
@@ -148,26 +150,28 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C,
processCall(CB, Caller, NewCallee, FrameSize, FrameAlign);
ORE.emit([&]() {
- return OptimizationRemark(DEBUG_TYPE, "CoroAnnotationElide", Caller)
- << "'" << ore::NV("callee", Callee->getName()) << "' elided in '"
- << ore::NV("caller", Caller->getName()) << "'";
- });
+ return OptimizationRemark(DEBUG_TYPE, "CoroAnnotationElide", Caller)
+ << "'" << ore::NV("callee", Callee->getName())
+ << "' elided in '" << ore::NV("caller", Caller->getName())
+ << "'";
+ });
FAM.invalidate(*Caller, PreservedAnalyses::none());
Changed = true;
updateCGAndAnalysisManagerForCGSCCPass(CG, *CallerC, *CallerN, AM, UR,
- FAM);
+ FAM);
} else {
ORE.emit([&]() {
- return OptimizationRemarkMissed(DEBUG_TYPE, "CoroAnnotationElide",
- Caller)
- << "'" << ore::NV("callee", Callee->getName()) << "' not elided in '"
- << ore::NV("caller", Caller->getName()) << "' (caller_presplit="
- << ore::NV("caller_presplit", IsCallerPresplitCoroutine)
- << ", elide_safe_attr=" << ore::NV("elide_safe_attr", HasAttr)
- << ")";
- });
+ return OptimizationRemarkMissed(DEBUG_TYPE, "CoroAnnotationElide",
+ Caller)
+ << "'" << ore::NV("callee", Callee->getName())
+ << "' not elided in '" << ore::NV("caller", Caller->getName())
+ << "' (caller_presplit="
+ << ore::NV("caller_presplit", IsCallerPresplitCoroutine)
+ << ", elide_safe_attr=" << ore::NV("elide_safe_attr", HasAttr)
+ << ")";
+ });
}
}
}
>From 28a4c3d0f4bee3a74b7d2524cafbc7359d5dba63 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Thu, 7 Nov 2024 11:45:46 -0800
Subject: [PATCH 5/6] add non-inlineable test case
---
.../Coroutines/gh114487-non-inlinable.ll | 33 +++++++++++++++++++
1 file changed, 33 insertions(+)
create mode 100644 llvm/test/Transforms/Coroutines/gh114487-non-inlinable.ll
diff --git a/llvm/test/Transforms/Coroutines/gh114487-non-inlinable.ll b/llvm/test/Transforms/Coroutines/gh114487-non-inlinable.ll
new file mode 100644
index 00000000000000..a8bc95669413e3
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/gh114487-non-inlinable.ll
@@ -0,0 +1,33 @@
+; Verify that we don't crash when eliding coro_elide_safe callsites.
+; RUN: opt < %s -passes='cgscc(function<>(simplifycfg<>),function-attrs,coro-annotation-elide)' -S | FileCheck %s
+
+; CHECK-LABEL: define void @foo()
+define void @foo() presplitcoroutine personality ptr null {
+entry:
+ %0 = call token @llvm.coro.save(ptr null)
+ br label %branch
+
+branch:
+; Check that we still call bar() because we can't inline bar.noalloc()
+; CHECK: call void @bar()
+ call void @bar() coro_elide_safe
+ ret void
+}
+
+; CHECK-LABEL: define void @bar()
+define void @bar() personality ptr null {
+entry:
+ %0 = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
+ %1 = call ptr @llvm.coro.begin(token %0, ptr null)
+ %2 = call token @llvm.coro.save(ptr null)
+ %3 = call i8 @llvm.coro.suspend(token none, i1 false)
+ ret void
+}
+
+declare void @bar.noalloc(ptr)
+
+declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) nounwind
+declare ptr @llvm.coro.begin(token, ptr writeonly) nounwind
+declare token @llvm.coro.save(ptr) nomerge nounwind
+declare i8 @llvm.coro.suspend(token, i1) nounwind
+
>From 2cb9dd7d4498353c7a97064c969b5b5bdbd38c16 Mon Sep 17 00:00:00 2001
From: Yuxuan Chen <ych at meta.com>
Date: Thu, 7 Nov 2024 13:32:33 -0800
Subject: [PATCH 6/6] fix existing test due to inlining
---
.../Transforms/Coroutines/coro-transform-must-elide.ll | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/llvm/test/Transforms/Coroutines/coro-transform-must-elide.ll b/llvm/test/Transforms/Coroutines/coro-transform-must-elide.ll
index a4e575f6c03816..d2c4f57478b529 100644
--- a/llvm/test/Transforms/Coroutines/coro-transform-must-elide.ll
+++ b/llvm/test/Transforms/Coroutines/coro-transform-must-elide.ll
@@ -59,9 +59,13 @@ define ptr @caller() #0 {
entry:
%task = call ptr @callee(i8 0) #1
ret ptr %task
-
- ; CHECK: %[[FRAME:.+]] = alloca [32 x i8], align 8
- ; CHECK-NEXT: %[[TASK:.+]] = call ptr @callee.noalloc(i8 0, ptr %[[FRAME]])
+ ; CHECK: %[[TASK:.+]] = alloca %struct.Task, align 8
+ ; CHECK-NEXT: %[[FRAME:.+]] = alloca [32 x i8], align 8
+ ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr %[[TASK]])
+ ; CHECK-NEXT: %[[ID:.+]] = call token @llvm.coro.id(i32 0, ptr null, ptr @callee, ptr @callee.resumers)
+ ; CHECK-NEXT: %[[HDL:.+]] = call ptr @llvm.coro.begin(token %[[ID]], ptr null)
+ ; CHECK-NEXT: store ptr %[[HDL]], ptr %[[TASK]], align 8
+ ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr %[[TASK]])
; CHECK-NEXT: ret ptr %[[TASK]]
}
More information about the llvm-commits
mailing list