[llvm] 11053a1 - Revert new pass manager coro-split and coro-elide
Brian Gesiak via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 17 20:56:26 PST 2020
Author: Brian Gesiak
Date: 2020-02-17T23:55:10-05:00
New Revision: 11053a1cc61afaabf2df2b8345d8d392c88cd508
URL: https://github.com/llvm/llvm-project/commit/11053a1cc61afaabf2df2b8345d8d392c88cd508
DIFF: https://github.com/llvm/llvm-project/commit/11053a1cc61afaabf2df2b8345d8d392c88cd508.diff
LOG: Revert new pass manager coro-split and coro-elide
This reverts
https://reviews.llvm.org/rG7125d66f9969605d886b5286780101a45b5bed67 and
https://reviews.llvm.org/rG00fec8004aca6588d8d695a2c3827c3754c380a0 due
to buildbot failures:
http://lab.llvm.org:8011/builders/clang-cmake-x86_64-sde-avx512-linux/builds/34004
Added:
llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll
llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll
llvm/test/Transforms/Coroutines/coro-split-eh.ll
Modified:
llvm/lib/Passes/PassBuilder.cpp
llvm/lib/Passes/PassRegistry.def
llvm/lib/Transforms/Coroutines/CoroElide.cpp
llvm/lib/Transforms/Coroutines/CoroSplit.cpp
llvm/test/Transforms/Coroutines/coro-catchswitch.ll
llvm/test/Transforms/Coroutines/coro-debug.ll
llvm/test/Transforms/Coroutines/coro-elide.ll
llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll
llvm/test/Transforms/Coroutines/coro-frame-unreachable.ll
llvm/test/Transforms/Coroutines/coro-frame.ll
llvm/test/Transforms/Coroutines/coro-heap-elide.ll
llvm/test/Transforms/Coroutines/coro-materialize.ll
llvm/test/Transforms/Coroutines/coro-padding.ll
llvm/test/Transforms/Coroutines/coro-param-copy.ll
llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll
llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll
llvm/test/Transforms/Coroutines/coro-split-00.ll
llvm/test/Transforms/Coroutines/coro-split-02.ll
llvm/test/Transforms/Coroutines/coro-split-alloc.ll
llvm/test/Transforms/Coroutines/coro-split-dbg.ll
llvm/test/Transforms/Coroutines/coro-split-hidden.ll
llvm/test/Transforms/Coroutines/coro-split-musttail.ll
llvm/test/Transforms/Coroutines/coro-split-musttail1.ll
llvm/test/Transforms/Coroutines/no-suspend.ll
llvm/test/Transforms/Coroutines/restart-trigger.ll
Removed:
################################################################################
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 3e42b501da00..6f56d7f482ab 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -68,8 +68,6 @@
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h"
#include "llvm/Transforms/Coroutines/CoroEarly.h"
-#include "llvm/Transforms/Coroutines/CoroElide.h"
-#include "llvm/Transforms/Coroutines/CoroSplit.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/ArgumentPromotion.h"
#include "llvm/Transforms/IPO/Attributor.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index fca3ebb76e82..26888bd3263d 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -111,7 +111,6 @@ CGSCC_PASS("function-attrs", PostOrderFunctionAttrsPass())
CGSCC_PASS("attributor-cgscc", AttributorCGSCCPass())
CGSCC_PASS("inline", InlinerPass())
CGSCC_PASS("openmpopt", OpenMPOptPass())
-CGSCC_PASS("coro-split", CoroSplitPass())
CGSCC_PASS("no-op-cgscc", NoOpCGSCCPass())
#undef CGSCC_PASS
@@ -172,7 +171,6 @@ FUNCTION_PASS("callsite-splitting", CallSiteSplittingPass())
FUNCTION_PASS("consthoist", ConstantHoistingPass())
FUNCTION_PASS("chr", ControlHeightReductionPass())
FUNCTION_PASS("coro-early", CoroEarlyPass())
-FUNCTION_PASS("coro-elide", CoroElidePass())
FUNCTION_PASS("correlated-propagation", CorrelatedValuePropagationPass())
FUNCTION_PASS("dce", DCEPass())
FUNCTION_PASS("div-rem-pairs", DivRemPairsPass())
diff --git a/llvm/lib/Transforms/Coroutines/CoroElide.cpp b/llvm/lib/Transforms/Coroutines/CoroElide.cpp
index b491634d64c8..23d22e23861a 100644
--- a/llvm/lib/Transforms/Coroutines/CoroElide.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroElide.cpp
@@ -5,8 +5,11 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+// This pass replaces dynamic allocation of coroutine frame with alloca and
+// replaces calls to llvm.coro.resume and llvm.coro.destroy with direct calls
+// to coroutine sub-functions.
+//===----------------------------------------------------------------------===//
-#include "llvm/Transforms/Coroutines/CoroElide.h"
#include "CoroInternal.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/InstructionSimplify.h"
@@ -34,7 +37,6 @@ struct Lowerer : coro::LowererBase {
void elideHeapAllocations(Function *F, Type *FrameTy, AAResults &AA);
bool shouldElide(Function *F, DominatorTree &DT) const;
- void collectPostSplitCoroIds(Function *F);
bool processCoroId(CoroIdInst *, AAResults &AA, DominatorTree &DT);
};
} // end anonymous namespace
@@ -186,16 +188,6 @@ bool Lowerer::shouldElide(Function *F, DominatorTree &DT) const {
return ReferencedCoroBegins.size() == CoroBegins.size();
}
-void Lowerer::collectPostSplitCoroIds(Function *F) {
- CoroIds.clear();
- for (auto &I : instructions(F))
- if (auto *CII = dyn_cast<CoroIdInst>(&I))
- if (CII->getInfo().isPostSplit())
- // If it is the coroutine itself, don't touch it.
- if (CII->getCoroutine() != CII->getFunction())
- CoroIds.push_back(CII);
-}
-
bool Lowerer::processCoroId(CoroIdInst *CoroId, AAResults &AA,
DominatorTree &DT) {
CoroBegins.clear();
@@ -280,31 +272,9 @@ static bool replaceDevirtTrigger(Function &F) {
return true;
}
-static bool declaresCoroElideIntrinsics(Module &M) {
- return coro::declaresIntrinsics(M, {"llvm.coro.id"});
-}
-
-PreservedAnalyses CoroElidePass::run(Function &F, FunctionAnalysisManager &AM) {
- auto &M = *F.getParent();
- if (!declaresCoroElideIntrinsics(M))
- return PreservedAnalyses::all();
-
- Lowerer L(M);
- L.CoroIds.clear();
- L.collectPostSplitCoroIds(&F);
- // If we did not find any coro.id, there is nothing to do.
- if (L.CoroIds.empty())
- return PreservedAnalyses::all();
-
- AAResults &AA = AM.getResult<AAManager>(F);
- DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F);
-
- bool Changed = false;
- for (auto *CII : L.CoroIds)
- Changed |= L.processCoroId(CII, AA, DT);
-
- return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
-}
+//===----------------------------------------------------------------------===//
+// Top Level Driver
+//===----------------------------------------------------------------------===//
namespace {
struct CoroElideLegacy : FunctionPass {
@@ -316,7 +286,7 @@ struct CoroElideLegacy : FunctionPass {
std::unique_ptr<Lowerer> L;
bool doInitialization(Module &M) override {
- if (declaresCoroElideIntrinsics(M))
+ if (coro::declaresIntrinsics(M, {"llvm.coro.id"}))
L = std::make_unique<Lowerer>(M);
return false;
}
@@ -331,7 +301,15 @@ struct CoroElideLegacy : FunctionPass {
Changed = replaceDevirtTrigger(F);
L->CoroIds.clear();
- L->collectPostSplitCoroIds(&F);
+
+ // Collect all PostSplit coro.ids.
+ for (auto &I : instructions(F))
+ if (auto *CII = dyn_cast<CoroIdInst>(&I))
+ if (CII->getInfo().isPostSplit())
+ // If it is the coroutine itself, don't touch it.
+ if (CII->getCoroutine() != CII->getFunction())
+ L->CoroIds.push_back(CII);
+
// If we did not find any coro.id, there is nothing to do.
if (L->CoroIds.empty())
return Changed;
diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
index 04c06e3653d7..9638b7a05725 100644
--- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -18,7 +18,6 @@
// coroutine.
//===----------------------------------------------------------------------===//
-#include "llvm/Transforms/Coroutines/CoroSplit.h"
#include "CoroInstr.h"
#include "CoroInternal.h"
#include "llvm/ADT/DenseMap.h"
@@ -60,7 +59,6 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
-#include "llvm/Transforms/Utils/CallGraphUpdater.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
@@ -1344,8 +1342,19 @@ namespace {
};
}
-static coro::Shape splitCoroutine(Function &F,
- SmallVectorImpl<Function *> &Clones) {
+static void splitCoroutine(Function &F, coro::Shape &Shape,
+ SmallVectorImpl<Function *> &Clones) {
+ switch (Shape.ABI) {
+ case coro::ABI::Switch:
+ return splitSwitchCoroutine(F, Shape, Clones);
+ case coro::ABI::Retcon:
+ case coro::ABI::RetconOnce:
+ return splitRetconCoroutine(F, Shape, Clones);
+ }
+ llvm_unreachable("bad ABI kind");
+}
+
+static void splitCoroutine(Function &F, CallGraph &CG, CallGraphSCC &SCC) {
PrettyStackTraceFunction prettyStackTrace(F);
// The suspend-crossing algorithm in buildCoroutineFrame get tripped
@@ -1354,42 +1363,26 @@ static coro::Shape splitCoroutine(Function &F,
coro::Shape Shape(F);
if (!Shape.CoroBegin)
- return Shape;
+ return;
simplifySuspendPoints(Shape);
buildCoroutineFrame(F, Shape);
replaceFrameSize(Shape);
+ SmallVector<Function*, 4> Clones;
+
// If there are no suspend points, no split required, just remove
// the allocation and deallocation blocks, they are not needed.
if (Shape.CoroSuspends.empty()) {
handleNoSuspendCoroutine(Shape);
} else {
- switch (Shape.ABI) {
- case coro::ABI::Switch:
- splitSwitchCoroutine(F, Shape, Clones);
- break;
- case coro::ABI::Retcon:
- case coro::ABI::RetconOnce:
- splitRetconCoroutine(F, Shape, Clones);
- break;
- }
+ splitCoroutine(F, Shape, Clones);
}
// Replace all the swifterror operations in the original function.
// This invalidates SwiftErrorOps in the Shape.
replaceSwiftErrorOps(F, Shape, nullptr);
- return Shape;
-}
-
-static void
-updateCallGraphAfterCoroutineSplit(Function &F, const coro::Shape &Shape,
- const SmallVectorImpl<Function *> &Clones,
- CallGraph &CG, CallGraphSCC &SCC) {
- if (!Shape.CoroBegin)
- return;
-
removeCoroEnds(Shape, &CG);
postSplitCleanup(F);
@@ -1397,43 +1390,6 @@ updateCallGraphAfterCoroutineSplit(Function &F, const coro::Shape &Shape,
coro::updateCallGraph(F, Clones, CG, SCC);
}
-static void updateCallGraphAfterCoroutineSplit(
- LazyCallGraph::Node &N, const coro::Shape &Shape,
- const SmallVectorImpl<Function *> &Clones, LazyCallGraph::SCC &C,
- LazyCallGraph &CG, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR) {
- if (!Shape.CoroBegin)
- return;
-
- for (llvm::CoroEndInst *End : Shape.CoroEnds) {
- auto &Context = End->getContext();
- End->replaceAllUsesWith(ConstantInt::getFalse(Context));
- End->eraseFromParent();
- }
-
- postSplitCleanup(N.getFunction());
-
- // To insert the newly created coroutine funclets 'f.resume', 'f.destroy', and
- // 'f.cleanup' into the same SCC as the coroutine 'f' they were outlined from,
- // we make use of the CallGraphUpdater class, which can modify the internal
- // state of the LazyCallGraph.
- for (Function *Clone : Clones)
- CG.addNewFunctionIntoRefSCC(*Clone, C.getOuterRefSCC());
-
- // We've inserted instructions into coroutine 'f' that reference the three new
- // coroutine funclets. We must now update the call graph so that reference
- // edges between 'f' and its funclets are added to it. LazyCallGraph only
- // allows CGSCC passes to insert "trivial" reference edges. We've ensured
- // above, by inserting the funclets into the same SCC as the corutine, that
- // the edges are trivial.
- //
- // N.B.: If we didn't update the call graph here, a CGSCCToFunctionPassAdaptor
- // later in this CGSCC pass pipeline may be run, triggering a call graph
- // update of its own. Function passes run by the adaptor are not permitted to
- // add new edges of any kind to the graph, and the new edges inserted by this
- // pass would be misattributed to that unrelated function pass.
- updateCGAndAnalysisManagerForCGSCCPass(CG, C, N, AM, UR);
-}
-
// When we see the coroutine the first time, we insert an indirect call to a
// devirt trigger function and mark the coroutine that it is now ready for
// split.
@@ -1565,86 +1521,12 @@ static bool replaceAllPrepares(Function *PrepareFn, CallGraph &CG) {
return Changed;
}
-static bool declaresCoroSplitIntrinsics(const Module &M) {
- return coro::declaresIntrinsics(
- M, {"llvm.coro.begin", "llvm.coro.prepare.retcon"});
-}
-
-PreservedAnalyses CoroSplitPass::run(LazyCallGraph::SCC &C,
- CGSCCAnalysisManager &AM,
- LazyCallGraph &CG, CGSCCUpdateResult &UR) {
- // NB: One invariant of a valid LazyCallGraph::SCC is that it must contain a
- // non-zero number of nodes, so we assume that here and grab the first
- // node's function's module.
- Module &M = *C.begin()->getFunction().getParent();
- if (!declaresCoroSplitIntrinsics(M))
- return PreservedAnalyses::all();
-
- // Check for uses of llvm.coro.prepare.retcon.
- const auto *PrepareFn = M.getFunction("llvm.coro.prepare.retcon");
- if (PrepareFn && PrepareFn->use_empty())
- PrepareFn = nullptr;
-
- // Find coroutines for processing.
- SmallVector<LazyCallGraph::Node *, 4> Coroutines;
- for (LazyCallGraph::Node &N : C)
- if (N.getFunction().hasFnAttribute(CORO_PRESPLIT_ATTR))
- Coroutines.push_back(&N);
-
- if (Coroutines.empty() && !PrepareFn)
- return PreservedAnalyses::all();
-
- if (Coroutines.empty())
- llvm_unreachable("new pass manager cannot yet handle "
- "'llvm.coro.prepare.retcon'");
-
- // Split all the coroutines.
- for (LazyCallGraph::Node *N : Coroutines) {
- Function &F = N->getFunction();
- Attribute Attr = F.getFnAttribute(CORO_PRESPLIT_ATTR);
- StringRef Value = Attr.getValueAsString();
- LLVM_DEBUG(dbgs() << "CoroSplit: Processing coroutine '" << F.getName()
- << "' state: " << Value << "\n");
- if (Value == UNPREPARED_FOR_SPLIT) {
- // Enqueue a second iteration of the CGSCC pipeline.
- // N.B.:
- // The CoroSplitLegacy pass "triggers" a restart of the CGSCC pass
- // pipeline by inserting an indirect function call that the
- // CoroElideLegacy pass then replaces with a direct function call. The
- // legacy CGSCC pipeline's implicit behavior was as if wrapped in the new
- // pass manager abstraction DevirtSCCRepeatedPass.
- //
- // This pass does not need to "trigger" another run of the pipeline.
- // Instead, it simply enqueues the same RefSCC onto the pipeline's
- // worklist.
- UR.CWorklist.insert(&C);
- F.addFnAttr(CORO_PRESPLIT_ATTR, PREPARED_FOR_SPLIT);
- continue;
- }
- F.removeFnAttr(CORO_PRESPLIT_ATTR);
-
- SmallVector<Function *, 4> Clones;
- const coro::Shape Shape = splitCoroutine(F, Clones);
- updateCallGraphAfterCoroutineSplit(*N, Shape, Clones, C, CG, AM, UR);
- }
-
- if (PrepareFn)
- llvm_unreachable("new pass manager cannot yet handle "
- "'llvm.coro.prepare.retcon'");
-
- return PreservedAnalyses::none();
-}
+//===----------------------------------------------------------------------===//
+// Top Level Driver
+//===----------------------------------------------------------------------===//
namespace {
-// We present a coroutine to LLVM as an ordinary function with suspension
-// points marked up with intrinsics. We let the optimizer party on the coroutine
-// as a single function for as long as possible. Shortly before the coroutine is
-// eligible to be inlined into its callers, we split up the coroutine into parts
-// corresponding to initial, resume and destroy invocations of the coroutine,
-// add them to the current SCC and restart the IPO pipeline to optimize the
-// coroutine subfunctions we extracted before proceeding to the caller of the
-// coroutine.
struct CoroSplitLegacy : public CallGraphSCCPass {
static char ID; // Pass identification, replacement for typeid
@@ -1657,7 +1539,9 @@ struct CoroSplitLegacy : public CallGraphSCCPass {
// A coroutine is identified by the presence of coro.begin intrinsic, if
// we don't have any, this pass has nothing to do.
bool doInitialization(CallGraph &CG) override {
- Run = declaresCoroSplitIntrinsics(CG.getModule());
+ Run = coro::declaresIntrinsics(CG.getModule(),
+ {"llvm.coro.begin",
+ "llvm.coro.prepare.retcon"});
return CallGraphSCCPass::doInitialization(CG);
}
@@ -1699,10 +1583,7 @@ struct CoroSplitLegacy : public CallGraphSCCPass {
continue;
}
F->removeFnAttr(CORO_PRESPLIT_ATTR);
-
- SmallVector<Function *, 4> Clones;
- const coro::Shape Shape = splitCoroutine(*F, Clones);
- updateCallGraphAfterCoroutineSplit(*F, Shape, Clones, CG, SCC);
+ splitCoroutine(*F, CG, SCC);
}
if (PrepareFn)
diff --git a/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll b/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll
new file mode 100644
index 000000000000..ce0975f108d8
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll
@@ -0,0 +1,96 @@
+; Check that we can handle the case when both alloc function and
+; the user body consume the same argument.
+; RUN: opt < %s -coro-split -S | FileCheck %s
+
+; using this directly (as it would happen under -O2)
+define i8* @f_direct(i64 %this) "coroutine.presplit"="1" {
+entry:
+ %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
+ %size = call i32 @llvm.coro.size.i32()
+ %alloc = call i8* @myAlloc(i64 %this, i32 %size)
+ %hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
+ %0 = call i8 @llvm.coro.suspend(token none, i1 false)
+ switch i8 %0, label %suspend [i8 0, label %resume
+ i8 1, label %cleanup]
+resume:
+ call void @print2(i64 %this)
+ br label %cleanup
+
+cleanup:
+ %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
+ call void @free(i8* %mem)
+ br label %suspend
+suspend:
+ call i1 @llvm.coro.end(i8* %hdl, i1 0)
+ ret i8* %hdl
+}
+
+; using copy of this (as it would happen under -O0)
+define i8* @f_copy(i64 %this_arg) "coroutine.presplit"="1" {
+entry:
+ %this.addr = alloca i64
+ store i64 %this_arg, i64* %this.addr
+ %this = load i64, i64* %this.addr
+ %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
+ %size = call i32 @llvm.coro.size.i32()
+ %alloc = call i8* @myAlloc(i64 %this, i32 %size)
+ %hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
+ %0 = call i8 @llvm.coro.suspend(token none, i1 false)
+ switch i8 %0, label %suspend [i8 0, label %resume
+ i8 1, label %cleanup]
+resume:
+ call void @print2(i64 %this)
+ br label %cleanup
+
+cleanup:
+ %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
+ call void @free(i8* %mem)
+ br label %suspend
+suspend:
+ call i1 @llvm.coro.end(i8* %hdl, i1 0)
+ ret i8* %hdl
+}
+
+; See if %this was added to the frame
+; CHECK: %f_direct.Frame = type { void (%f_direct.Frame*)*, void (%f_direct.Frame*)*, i1, i1, i64 }
+; CHECK: %f_copy.Frame = type { void (%f_copy.Frame*)*, void (%f_copy.Frame*)*, i1, i1, i64 }
+
+; See that %this is spilled into the frame
+; CHECK-LABEL: define i8* @f_direct(i64 %this)
+; CHECK: %this.spill.addr = getelementptr inbounds %f_direct.Frame, %f_direct.Frame* %FramePtr, i32 0, i32 4
+; CHECK: store i64 %this, i64* %this.spill.addr
+; CHECK: ret i8* %hdl
+
+; See that %this is spilled into the frame
+; CHECK-LABEL: define i8* @f_copy(i64 %this_arg)
+; CHECK: %this.spill.addr = getelementptr inbounds %f_copy.Frame, %f_copy.Frame* %FramePtr, i32 0, i32 4
+; CHECK: store i64 %this_arg, i64* %this.spill.addr
+; CHECK: ret i8* %hdl
+
+; See that %this was loaded from the frame
+; CHECK-LABEL: @f_direct.resume(
+; CHECK: %this.reload = load i64, i64* %this.reload.addr
+; CHECK: call void @print2(i64 %this.reload)
+; CHECK: ret void
+
+; See that %this was loaded from the frame
+; CHECK-LABEL: @f_copy.resume(
+; CHECK: %this.reload = load i64, i64* %this.reload.addr
+; CHECK: call void @print2(i64 %this.reload)
+; CHECK: ret void
+
+declare i8* @llvm.coro.free(token, i8*)
+declare i32 @llvm.coro.size.i32()
+declare i8 @llvm.coro.suspend(token, i1)
+declare void @llvm.coro.resume(i8*)
+declare void @llvm.coro.destroy(i8*)
+
+declare token @llvm.coro.id(i32, i8*, i8*, i8*)
+declare i1 @llvm.coro.alloc(token)
+declare i8* @llvm.coro.begin(token, i8*)
+declare i1 @llvm.coro.end(i8*, i1)
+
+declare noalias i8* @myAlloc(i64, i32)
+declare double @print(double)
+declare void @print2(i64)
+declare void @free(i8*)
diff --git a/llvm/test/Transforms/Coroutines/coro-catchswitch.ll b/llvm/test/Transforms/Coroutines/coro-catchswitch.ll
index 0eb4b1ee64e8..dd06f1280cae 100644
--- a/llvm/test/Transforms/Coroutines/coro-catchswitch.ll
+++ b/llvm/test/Transforms/Coroutines/coro-catchswitch.ll
@@ -1,6 +1,5 @@
; Verifies that we can insert the spill for a PHI preceding the catchswitch
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc"
diff --git a/llvm/test/Transforms/Coroutines/coro-debug.ll b/llvm/test/Transforms/Coroutines/coro-debug.ll
index 3c9d1a8673ea..1d40ddd67173 100644
--- a/llvm/test/Transforms/Coroutines/coro-debug.ll
+++ b/llvm/test/Transforms/Coroutines/coro-debug.ll
@@ -1,6 +1,5 @@
; Tests that debug information is sane after coro-split
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
source_filename = "simple-repro.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll b/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll
new file mode 100644
index 000000000000..5da0e3c199db
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll
@@ -0,0 +1,218 @@
+; Check that we can handle edge splits leading into a landingpad
+; RUN: opt < %s -coro-split -S | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK-LABEL: define internal fastcc void @f.resume(
+define void @f(i1 %cond) "coroutine.presplit"="1" personality i32 0 {
+entry:
+ %id = call token @llvm.coro.id(i32 16, i8* null, i8* null, i8* null)
+ %size = tail call i64 @llvm.coro.size.i64()
+ %alloc = call i8* @malloc(i64 %size)
+ %hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
+ %sp = call i8 @llvm.coro.suspend(token none, i1 false)
+ switch i8 %sp, label %coro.ret [
+ i8 0, label %resume
+ i8 1, label %cleanup
+ ]
+
+resume:
+ br i1 %cond, label %invoke1, label %invoke2
+
+invoke1:
+ invoke void @may_throw1()
+ to label %unreach unwind label %pad.with.phi
+invoke2:
+ invoke void @may_throw2()
+ to label %unreach unwind label %pad.with.phi
+
+; Verify that we cloned landing pad on every edge and inserted a reload of the spilled value
+
+; CHECK: pad.with.phi.from.invoke2:
+; CHECK: %0 = landingpad { i8*, i32 }
+; CHECK: catch i8* null
+; CHECK: br label %pad.with.phi
+
+; CHECK: pad.with.phi.from.invoke1:
+; CHECK: %1 = landingpad { i8*, i32 }
+; CHECK: catch i8* null
+; CHECK: br label %pad.with.phi
+
+; CHECK: pad.with.phi:
+; CHECK: %val = phi i32 [ 0, %pad.with.phi.from.invoke1 ], [ 1, %pad.with.phi.from.invoke2 ]
+; CHECK: %lp = phi { i8*, i32 } [ %0, %pad.with.phi.from.invoke2 ], [ %1, %pad.with.phi.from.invoke1 ]
+; CHECK: %exn = extractvalue { i8*, i32 } %lp, 0
+; CHECK: call i8* @__cxa_begin_catch(i8* %exn)
+; CHECK: call void @use_val(i32 %val)
+; CHECK: call void @__cxa_end_catch()
+; CHECK: call void @free(i8* %vFrame)
+; CHECK: ret void
+
+pad.with.phi:
+ %val = phi i32 [ 0, %invoke1 ], [ 1, %invoke2 ]
+ %lp = landingpad { i8*, i32 }
+ catch i8* null
+ %exn = extractvalue { i8*, i32 } %lp, 0
+ call i8* @__cxa_begin_catch(i8* %exn)
+ call void @use_val(i32 %val)
+ call void @__cxa_end_catch()
+ br label %cleanup
+
+cleanup: ; preds = %invoke.cont15, %if.else, %if.then, %ehcleanup21, %init.suspend
+ %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
+ call void @free(i8* %mem)
+ br label %coro.ret
+
+coro.ret:
+ call i1 @llvm.coro.end(i8* null, i1 false)
+ ret void
+
+unreach:
+ unreachable
+}
+
+; CHECK-LABEL: define internal fastcc void @g.resume(
+define void @g(i1 %cond, i32 %x, i32 %y) "coroutine.presplit"="1" personality i32 0 {
+entry:
+ %id = call token @llvm.coro.id(i32 16, i8* null, i8* null, i8* null)
+ %size = tail call i64 @llvm.coro.size.i64()
+ %alloc = call i8* @malloc(i64 %size)
+ %hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
+ %sp = call i8 @llvm.coro.suspend(token none, i1 false)
+ switch i8 %sp, label %coro.ret [
+ i8 0, label %resume
+ i8 1, label %cleanup
+ ]
+
+resume:
+ br i1 %cond, label %invoke1, label %invoke2
+
+invoke1:
+ invoke void @may_throw1()
+ to label %unreach unwind label %pad.with.phi
+invoke2:
+ invoke void @may_throw2()
+ to label %unreach unwind label %pad.with.phi
+
+; Verify that we created cleanuppads on every edge and inserted a reload of the spilled value
+
+; CHECK: pad.with.phi.from.invoke2:
+; CHECK: %0 = cleanuppad within none []
+; CHECK: %y.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 6
+; CHECK: %y.reload = load i32, i32* %y.reload.addr
+; CHECK: cleanupret from %0 unwind label %pad.with.phi
+
+; CHECK: pad.with.phi.from.invoke1:
+; CHECK: %1 = cleanuppad within none []
+; CHECK: %x.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 5
+; CHECK: %x.reload = load i32, i32* %x.reload.addr
+; CHECK: cleanupret from %1 unwind label %pad.with.phi
+
+; CHECK: pad.with.phi:
+; CHECK: %val = phi i32 [ %x.reload, %pad.with.phi.from.invoke1 ], [ %y.reload, %pad.with.phi.from.invoke2 ]
+; CHECK: %tok = cleanuppad within none []
+; CHECK: call void @use_val(i32 %val)
+; CHECK: cleanupret from %tok unwind to caller
+
+pad.with.phi:
+ %val = phi i32 [ %x, %invoke1 ], [ %y, %invoke2 ]
+ %tok = cleanuppad within none []
+ call void @use_val(i32 %val)
+ cleanupret from %tok unwind to caller
+
+cleanup: ; preds = %invoke.cont15, %if.else, %if.then, %ehcleanup21, %init.suspend
+ %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
+ call void @free(i8* %mem)
+ br label %coro.ret
+
+coro.ret:
+ call i1 @llvm.coro.end(i8* null, i1 false)
+ ret void
+
+unreach:
+ unreachable
+}
+
+; CHECK-LABEL: define internal fastcc void @h.resume(
+define void @h(i1 %cond, i32 %x, i32 %y) "coroutine.presplit"="1" personality i32 0 {
+entry:
+ %id = call token @llvm.coro.id(i32 16, i8* null, i8* null, i8* null)
+ %size = tail call i64 @llvm.coro.size.i64()
+ %alloc = call i8* @malloc(i64 %size)
+ %hdl = call i8* @llvm.coro.begin(token %id, i8* %alloc)
+ %sp = call i8 @llvm.coro.suspend(token none, i1 false)
+ switch i8 %sp, label %coro.ret [
+ i8 0, label %resume
+ i8 1, label %cleanup
+ ]
+
+resume:
+ br i1 %cond, label %invoke1, label %invoke2
+
+invoke1:
+ invoke void @may_throw1()
+ to label %coro.ret unwind label %pad.with.phi
+invoke2:
+ invoke void @may_throw2()
+ to label %coro.ret unwind label %pad.with.phi
+
+; Verify that we created cleanuppads on every edge and inserted a reload of the spilled value
+
+; CHECK: pad.with.phi.from.invoke2:
+; CHECK: %0 = cleanuppad within none []
+; CHECK: %y.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 6
+; CHECK: %y.reload = load i32, i32* %y.reload.addr
+; CHECK: cleanupret from %0 unwind label %pad.with.phi
+
+; CHECK: pad.with.phi.from.invoke1:
+; CHECK: %1 = cleanuppad within none []
+; CHECK: %x.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 5
+; CHECK: %x.reload = load i32, i32* %x.reload.addr
+; CHECK: cleanupret from %1 unwind label %pad.with.phi
+
+; CHECK: pad.with.phi:
+; CHECK: %val = phi i32 [ %x.reload, %pad.with.phi.from.invoke1 ], [ %y.reload, %pad.with.phi.from.invoke2 ]
+; CHECK: %switch = catchswitch within none [label %catch] unwind to caller
+pad.with.phi:
+ %val = phi i32 [ %x, %invoke1 ], [ %y, %invoke2 ]
+ %switch = catchswitch within none [label %catch] unwind to caller
+
+catch: ; preds = %catch.dispatch
+ %pad = catchpad within %switch [i8* null, i32 64, i8* null]
+ call void @use_val(i32 %val)
+ catchret from %pad to label %coro.ret
+
+cleanup: ; preds = %invoke.cont15, %if.else, %if.then, %ehcleanup21, %init.suspend
+ %mem = call i8* @llvm.coro.free(token %id, i8* %hdl)
+ call void @free(i8* %mem)
+ br label %coro.ret
+
+coro.ret:
+ call i1 @llvm.coro.end(i8* null, i1 false)
+ ret void
+}
+
+; Function Attrs: argmemonly nounwind readonly
+declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*)
+declare noalias i8* @malloc(i64)
+declare i64 @llvm.coro.size.i64()
+declare i8* @llvm.coro.begin(token, i8* writeonly)
+
+; Function Attrs: nounwind
+declare token @llvm.coro.save(i8*)
+declare i8 @llvm.coro.suspend(token, i1)
+
+; Function Attrs: argmemonly nounwind
+declare void @may_throw1()
+declare void @may_throw2()
+
+declare i8* @__cxa_begin_catch(i8*)
+
+declare void @use_val(i32)
+declare void @__cxa_end_catch()
+
+; Function Attrs: nounwind
+declare i1 @llvm.coro.end(i8*, i1)
+declare void @free(i8*)
+declare i8* @llvm.coro.free(token, i8* nocapture readonly)
diff --git a/llvm/test/Transforms/Coroutines/coro-elide.ll b/llvm/test/Transforms/Coroutines/coro-elide.ll
index ae0e30ab50ef..371d7f1b9401 100644
--- a/llvm/test/Transforms/Coroutines/coro-elide.ll
+++ b/llvm/test/Transforms/Coroutines/coro-elide.ll
@@ -1,9 +1,6 @@
; Tests that the coro.destroy and coro.resume are devirtualized where possible,
; SCC pipeline restarts and inlines the direct calls.
; RUN: opt < %s -S -inline -coro-elide -dce | FileCheck %s
-; RUN: opt < %s -S \
-; RUN: -passes='cgscc(repeat<2>(inline,function(coro-elide,dce)))' \
-; RUN: | FileCheck %s
declare void @print(i32) nounwind
diff --git a/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll b/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll
index 56c1113f2404..d01120e379ce 100644
--- a/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll
+++ b/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll
@@ -1,6 +1,5 @@
; Check that we can handle spills of array allocas
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
declare void @consume.double.ptr(double*)
declare void @consume.i32.ptr(i32*)
diff --git a/llvm/test/Transforms/Coroutines/coro-frame-unreachable.ll b/llvm/test/Transforms/Coroutines/coro-frame-unreachable.ll
index 9813017609c0..9d6bae668799 100644
--- a/llvm/test/Transforms/Coroutines/coro-frame-unreachable.ll
+++ b/llvm/test/Transforms/Coroutines/coro-frame-unreachable.ll
@@ -1,6 +1,5 @@
; Check that coro-split doesn't choke on intrinsics in unreachable blocks
; RUN: opt < %s -coro-split -S
-; RUN: opt < %s -passes=coro-split -S
define i8* @f(i1 %arg) "coroutine.presplit"="1" personality i32 0 {
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-frame.ll b/llvm/test/Transforms/Coroutines/coro-frame.ll
index f19e9024fc4e..826d3a04fa1e 100644
--- a/llvm/test/Transforms/Coroutines/coro-frame.ll
+++ b/llvm/test/Transforms/Coroutines/coro-frame.ll
@@ -1,6 +1,5 @@
; Check that we can handle spills of the result of the invoke instruction
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
define i8* @f(i64 %this) "coroutine.presplit"="1" personality i32 0 {
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-heap-elide.ll b/llvm/test/Transforms/Coroutines/coro-heap-elide.ll
index f03d4277687a..5ce2b693bc5e 100644
--- a/llvm/test/Transforms/Coroutines/coro-heap-elide.ll
+++ b/llvm/test/Transforms/Coroutines/coro-heap-elide.ll
@@ -2,9 +2,6 @@
; elided and any tail calls referencing the coroutine frame has the tail
; call attribute removed.
; RUN: opt < %s -S -inline -coro-elide -instsimplify -simplifycfg | FileCheck %s
-; RUN: opt < %s -S \
-; RUN: -passes='cgscc(inline,function(coro-elide,instsimplify,simplify-cfg))' \
-; RUN: -aa-pipeline='basic-aa' | FileCheck %s
declare void @print(i32) nounwind
diff --git a/llvm/test/Transforms/Coroutines/coro-materialize.ll b/llvm/test/Transforms/Coroutines/coro-materialize.ll
index 88076470f459..95e8a049ad2f 100644
--- a/llvm/test/Transforms/Coroutines/coro-materialize.ll
+++ b/llvm/test/Transforms/Coroutines/coro-materialize.ll
@@ -1,6 +1,5 @@
; Verifies that we materialize instruction across suspend points
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
define i8* @f(i32 %n) "coroutine.presplit"="1" {
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-padding.ll b/llvm/test/Transforms/Coroutines/coro-padding.ll
index f79f9c98ca74..87b5bf732d9d 100644
--- a/llvm/test/Transforms/Coroutines/coro-padding.ll
+++ b/llvm/test/Transforms/Coroutines/coro-padding.ll
@@ -1,7 +1,6 @@
; Check that we will insert the correct padding if natural alignment of the
; spilled data does not match the alignment specified in alloca instruction.
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
%PackedStruct = type <{ i64 }>
diff --git a/llvm/test/Transforms/Coroutines/coro-param-copy.ll b/llvm/test/Transforms/Coroutines/coro-param-copy.ll
index 739c4cc74181..6f4d0f3b2248 100644
--- a/llvm/test/Transforms/Coroutines/coro-param-copy.ll
+++ b/llvm/test/Transforms/Coroutines/coro-param-copy.ll
@@ -1,7 +1,6 @@
; Check that we create copy the data from the alloca into the coroutine
; frame slot if it was written to.
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
define i8* @f() "coroutine.presplit"="1" {
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll b/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll
index a22d82434336..3c7e050c09e9 100644
--- a/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll
+++ b/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll
@@ -1,6 +1,5 @@
; Verifies that we insert spills of PHI instruction _after) all PHI Nodes
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
define i8* @f(i1 %n) "coroutine.presplit"="1" {
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll b/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll
index 0caea1c90fbb..e57e2f28ed3c 100644
--- a/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll
+++ b/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll
@@ -1,6 +1,5 @@
; Check that we can spills coro.begin from an inlined inner coroutine.
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
%g.Frame = type { void (%g.Frame*)*, void (%g.Frame*)*, i32, i1, i32 }
diff --git a/llvm/test/Transforms/Coroutines/coro-split-00.ll b/llvm/test/Transforms/Coroutines/coro-split-00.ll
index 539d515cf5e1..0461b7dddb6c 100644
--- a/llvm/test/Transforms/Coroutines/coro-split-00.ll
+++ b/llvm/test/Transforms/Coroutines/coro-split-00.ll
@@ -1,6 +1,5 @@
; Tests that coro-split pass splits the coroutine into f, f.resume and f.destroy
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
define i8* @f() "coroutine.presplit"="1" {
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-split-02.ll b/llvm/test/Transforms/Coroutines/coro-split-02.ll
index 0309c0db2010..4dc8921cd69a 100644
--- a/llvm/test/Transforms/Coroutines/coro-split-02.ll
+++ b/llvm/test/Transforms/Coroutines/coro-split-02.ll
@@ -2,7 +2,6 @@
; a value produces between coro.save and coro.suspend (%Result.i19)
; and checks whether stray coro.saves are properly removed
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
%"struct.std::coroutine_handle" = type { i8* }
%"struct.std::coroutine_handle.0" = type { %"struct.std::coroutine_handle" }
diff --git a/llvm/test/Transforms/Coroutines/coro-split-alloc.ll b/llvm/test/Transforms/Coroutines/coro-split-alloc.ll
index c8f6c4543d4c..a0ec0509c773 100644
--- a/llvm/test/Transforms/Coroutines/coro-split-alloc.ll
+++ b/llvm/test/Transforms/Coroutines/coro-split-alloc.ll
@@ -1,6 +1,5 @@
; Tests that coro-split passes initialized values to coroutine frame allocator.
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
define i8* @f(i32 %argument) "coroutine.presplit"="1" {
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-split-dbg.ll b/llvm/test/Transforms/Coroutines/coro-split-dbg.ll
index ae9c3129ca0c..5f767935ed73 100644
--- a/llvm/test/Transforms/Coroutines/coro-split-dbg.ll
+++ b/llvm/test/Transforms/Coroutines/coro-split-dbg.ll
@@ -1,7 +1,6 @@
; Make sure that coro-split correctly deals with debug information.
; The test here is simply that it does not result in bad IR that will crash opt.
; RUN: opt < %s -coro-split -disable-output
-; RUN: opt < %s -passes=coro-split -disable-output
source_filename = "coro.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/llvm/test/Transforms/Coroutines/coro-split-eh.ll b/llvm/test/Transforms/Coroutines/coro-split-eh.ll
new file mode 100644
index 000000000000..7fc97e261e81
--- /dev/null
+++ b/llvm/test/Transforms/Coroutines/coro-split-eh.ll
@@ -0,0 +1,145 @@
+; Tests that coro-split removes cleanup code after coro.end in resume functions
+; and retains it in the start function.
+; RUN: opt < %s -coro-split -S | FileCheck %s
+
+define i8* @f(i1 %val) "coroutine.presplit"="1" personality i32 3 {
+entry:
+ %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
+ %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
+ call void @print(i32 0)
+ br i1 %val, label %resume, label %susp
+
+susp:
+ %0 = call i8 @llvm.coro.suspend(token none, i1 false)
+ switch i8 %0, label %suspend [i8 0, label %resume
+ i8 1, label %suspend]
+resume:
+ invoke void @print(i32 1) to label %suspend unwind label %lpad
+
+suspend:
+ call i1 @llvm.coro.end(i8* %hdl, i1 0)
+ call void @print(i32 0) ; should not be present in f.resume
+ ret i8* %hdl
+
+lpad:
+ %lpval = landingpad { i8*, i32 }
+ cleanup
+
+ call void @print(i32 2)
+ %need.resume = call i1 @llvm.coro.end(i8* null, i1 true)
+ br i1 %need.resume, label %eh.resume, label %cleanup.cont
+
+cleanup.cont:
+ call void @print(i32 3) ; should not be present in f.resume
+ br label %eh.resume
+
+eh.resume:
+ resume { i8*, i32 } %lpval
+}
+
+; Verify that start function contains both print calls the one before and after coro.end
+; CHECK-LABEL: define i8* @f(
+; CHECK: invoke void @print(i32 1)
+; CHECK: to label %AfterCoroEnd unwind label %lpad
+
+; CHECK: AfterCoroEnd:
+; CHECK: call void @print(i32 0)
+; CHECK: ret i8* %hdl
+
+; CHECK: lpad:
+; CHECK-NEXT: %lpval = landingpad { i8*, i32 }
+; CHECK-NEXT: cleanup
+; CHECK-NEXT: call void @print(i32 2)
+; CHECK-NEXT: call void @print(i32 3)
+; CHECK-NEXT: resume { i8*, i32 } %lpval
+
+define i8* @f2(i1 %val) "coroutine.presplit"="1" personality i32 4 {
+entry:
+ %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
+ %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
+ call void @print(i32 0)
+ br i1 %val, label %resume, label %susp
+
+susp:
+ %0 = call i8 @llvm.coro.suspend(token none, i1 false)
+ switch i8 %0, label %suspend [i8 0, label %resume
+ i8 1, label %suspend]
+resume:
+ invoke void @print(i32 1) to label %suspend unwind label %lpad
+
+suspend:
+ call i1 @llvm.coro.end(i8* %hdl, i1 0)
+ call void @print(i32 0) ; should not be present in f.resume
+ ret i8* %hdl
+
+lpad:
+ %tok = cleanuppad within none []
+ call void @print(i32 2)
+ %unused = call i1 @llvm.coro.end(i8* null, i1 true) [ "funclet"(token %tok) ]
+ cleanupret from %tok unwind label %cleanup.cont
+
+cleanup.cont:
+ %tok2 = cleanuppad within none []
+ call void @print(i32 3) ; should not be present in f.resume
+ cleanupret from %tok2 unwind to caller
+}
+
+; Verify that start function contains both print calls the one before and after coro.end
+; CHECK-LABEL: define i8* @f2(
+; CHECK: invoke void @print(i32 1)
+; CHECK: to label %AfterCoroEnd unwind label %lpad
+
+; CHECK: AfterCoroEnd:
+; CHECK: call void @print(i32 0)
+; CHECK: ret i8* %hdl
+
+; CHECK: lpad:
+; CHECK-NEXT: %tok = cleanuppad within none []
+; CHECK-NEXT: call void @print(i32 2)
+; CHECK-NEXT: call void @print(i32 3)
+; CHECK-NEXT: cleanupret from %tok unwind to caller
+
+; VERIFY Resume Parts
+
+; Verify that resume function does not contains both print calls appearing after coro.end
+; CHECK-LABEL: define internal fastcc void @f.resume
+; CHECK: invoke void @print(i32 1)
+; CHECK: to label %CoroEnd unwind label %lpad
+
+; CHECK: CoroEnd:
+; CHECK-NEXT: ret void
+
+; CHECK: lpad:
+; CHECK-NEXT: %lpval = landingpad { i8*, i32 }
+; CHECK-NEXT: cleanup
+; CHECK-NEXT: call void @print(i32 2)
+; CHECK-NEXT: resume { i8*, i32 } %lpval
+
+; Verify that resume function does not contains both print calls appearing after coro.end
+; CHECK-LABEL: define internal fastcc void @f2.resume
+; CHECK: invoke void @print(i32 1)
+; CHECK: to label %CoroEnd unwind label %lpad
+
+; CHECK: CoroEnd:
+; CHECK-NEXT: ret void
+
+; CHECK: lpad:
+; CHECK-NEXT: %tok = cleanuppad within none []
+; CHECK-NEXT: call void @print(i32 2)
+; CHECK-NEXT: cleanupret from %tok unwind to caller
+
+declare i8* @llvm.coro.free(token, i8*)
+declare i32 @llvm.coro.size.i32()
+declare i8 @llvm.coro.suspend(token, i1)
+declare void @llvm.coro.resume(i8*)
+declare void @llvm.coro.destroy(i8*)
+
+declare token @llvm.coro.id(i32, i8*, i8*, i8*)
+declare i8* @llvm.coro.alloc(token)
+declare i8* @llvm.coro.begin(token, i8*)
+declare i1 @llvm.coro.end(i8*, i1)
+
+declare noalias i8* @malloc(i32)
+declare void @print(i32)
+declare void @free(i8*)
+
diff --git a/llvm/test/Transforms/Coroutines/coro-split-hidden.ll b/llvm/test/Transforms/Coroutines/coro-split-hidden.ll
index 9a306cbc2688..4d080db1696b 100644
--- a/llvm/test/Transforms/Coroutines/coro-split-hidden.ll
+++ b/llvm/test/Transforms/Coroutines/coro-split-hidden.ll
@@ -2,7 +2,6 @@
; These may be generated by a frontend such as Clang, when inlining with
; '-fvisibility-inlines-hidden'.
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
define hidden i8* @f() "coroutine.presplit"="1" {
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-split-musttail.ll b/llvm/test/Transforms/Coroutines/coro-split-musttail.ll
index deee841db9c9..d5af91b0ffe5 100644
--- a/llvm/test/Transforms/Coroutines/coro-split-musttail.ll
+++ b/llvm/test/Transforms/Coroutines/coro-split-musttail.ll
@@ -1,7 +1,6 @@
; Tests that coro-split will convert coro.resume followed by a suspend to a
; musttail call.
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
define void @f() #0 {
entry:
diff --git a/llvm/test/Transforms/Coroutines/coro-split-musttail1.ll b/llvm/test/Transforms/Coroutines/coro-split-musttail1.ll
index 7c9ba87fd665..f831041e8ef1 100644
--- a/llvm/test/Transforms/Coroutines/coro-split-musttail1.ll
+++ b/llvm/test/Transforms/Coroutines/coro-split-musttail1.ll
@@ -1,7 +1,6 @@
; Tests that coro-split will convert coro.resume followed by a suspend to a
; musttail call.
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
define void @f() #0 {
entry:
diff --git a/llvm/test/Transforms/Coroutines/no-suspend.ll b/llvm/test/Transforms/Coroutines/no-suspend.ll
index be48c2ab09fe..fca096fa48bb 100644
--- a/llvm/test/Transforms/Coroutines/no-suspend.ll
+++ b/llvm/test/Transforms/Coroutines/no-suspend.ll
@@ -1,6 +1,5 @@
; Test no suspend coroutines
; RUN: opt < %s -coro-split -S | FileCheck %s
-; RUN: opt < %s -passes=coro-split -S | FileCheck %s
; Coroutine with no-suspends will turn into:
;
diff --git a/llvm/test/Transforms/Coroutines/restart-trigger.ll b/llvm/test/Transforms/Coroutines/restart-trigger.ll
index b1ffcc7e1ef1..f7f203f2fb5c 100644
--- a/llvm/test/Transforms/Coroutines/restart-trigger.ll
+++ b/llvm/test/Transforms/Coroutines/restart-trigger.ll
@@ -1,6 +1,5 @@
-; Verifies that the restart trigger that is used by legacy coroutine passes
-; forces the legacy pass manager to restart IPO pipelines, thereby causing the
-; same coroutine to be looked at by CoroSplit pass twice.
+; Verifies that restart trigger forces IPO pipelines restart and the same
+; coroutine is looked at by CoroSplit pass twice.
; REQUIRES: asserts
; RUN: opt < %s -S -O0 -enable-coroutines -debug-only=coro-split 2>&1 | FileCheck %s
; RUN: opt < %s -S -O1 -enable-coroutines -debug-only=coro-split 2>&1 | FileCheck %s
More information about the llvm-commits
mailing list