aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/Coroutines
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-16 16:01:22 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-16 16:01:22 +0000
commit71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch)
tree5343938942df402b49ec7300a1c25a2d4ccd5821 /lib/Transforms/Coroutines
parent31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff)
Diffstat (limited to 'lib/Transforms/Coroutines')
-rw-r--r--lib/Transforms/Coroutines/CoroElide.cpp5
-rw-r--r--lib/Transforms/Coroutines/CoroFrame.cpp40
-rw-r--r--lib/Transforms/Coroutines/CoroInstr.h5
-rw-r--r--lib/Transforms/Coroutines/CoroSplit.cpp58
-rw-r--r--lib/Transforms/Coroutines/Coroutines.cpp6
5 files changed, 85 insertions, 29 deletions
diff --git a/lib/Transforms/Coroutines/CoroElide.cpp b/lib/Transforms/Coroutines/CoroElide.cpp
index 99974d8da64c..c6ac3f614ff7 100644
--- a/lib/Transforms/Coroutines/CoroElide.cpp
+++ b/lib/Transforms/Coroutines/CoroElide.cpp
@@ -92,7 +92,7 @@ static void removeTailCallAttribute(AllocaInst *Frame, AAResults &AA) {
// Given a resume function @f.resume(%f.frame* %frame), returns %f.frame type.
static Type *getFrameType(Function *Resume) {
- auto *ArgType = Resume->getArgumentList().front().getType();
+ auto *ArgType = Resume->arg_begin()->getType();
return cast<PointerType>(ArgType)->getElementType();
}
@@ -127,7 +127,8 @@ void Lowerer::elideHeapAllocations(Function *F, Type *FrameTy, AAResults &AA) {
// is spilled into the coroutine frame and recreate the alignment information
// here. Possibly we will need to do a mini SROA here and break the coroutine
// frame into individual AllocaInst recreating the original alignment.
- auto *Frame = new AllocaInst(FrameTy, "", InsertPt);
+ const DataLayout &DL = F->getParent()->getDataLayout();
+ auto *Frame = new AllocaInst(FrameTy, DL.getAllocaAddrSpace(), "", InsertPt);
auto *FrameVoidPtr =
new BitCastInst(Frame, Type::getInt8PtrTy(C), "vFrame", InsertPt);
diff --git a/lib/Transforms/Coroutines/CoroFrame.cpp b/lib/Transforms/Coroutines/CoroFrame.cpp
index bb28558a29e2..19e6789dfa74 100644
--- a/lib/Transforms/Coroutines/CoroFrame.cpp
+++ b/lib/Transforms/Coroutines/CoroFrame.cpp
@@ -133,6 +133,7 @@ struct SuspendCrossingInfo {
};
} // end anonymous namespace
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void SuspendCrossingInfo::dump(StringRef Label,
BitVector const &BV) const {
dbgs() << Label << ":";
@@ -151,6 +152,7 @@ LLVM_DUMP_METHOD void SuspendCrossingInfo::dump() const {
}
dbgs() << "\n";
}
+#endif
SuspendCrossingInfo::SuspendCrossingInfo(Function &F, coro::Shape &Shape)
: Mapping(F) {
@@ -420,15 +422,31 @@ static Instruction *insertSpills(SpillInfo &Spills, coro::Shape &Shape) {
report_fatal_error("Coroutines cannot handle non static allocas yet");
} else {
// Otherwise, create a store instruction storing the value into the
- // coroutine frame. For, argument, we will place the store instruction
- // right after the coroutine frame pointer instruction, i.e. bitcase of
- // coro.begin from i8* to %f.frame*. For all other values, the spill is
- // placed immediately after the definition.
- Builder.SetInsertPoint(
- isa<Argument>(CurrentValue)
- ? FramePtr->getNextNode()
- : dyn_cast<Instruction>(E.def())->getNextNode());
+ // coroutine frame.
+
+ Instruction *InsertPt = nullptr;
+ if (isa<Argument>(CurrentValue)) {
+ // For arguments, we will place the store instruction right after
+ // the coroutine frame pointer instruction, i.e. bitcast of
+ // coro.begin from i8* to %f.frame*.
+ InsertPt = FramePtr->getNextNode();
+ } else if (auto *II = dyn_cast<InvokeInst>(CurrentValue)) {
+ // If we are spilling the result of the invoke instruction, split the
+ // normal edge and insert the spill in the new block.
+ auto NewBB = SplitEdge(II->getParent(), II->getNormalDest());
+ InsertPt = NewBB->getTerminator();
+ } else if (dyn_cast<PHINode>(CurrentValue)) {
+ // Skip the PHINodes and EH pads instructions.
+ InsertPt =
+ &*cast<Instruction>(E.def())->getParent()->getFirstInsertionPt();
+ } else {
+ // For all other values, the spill is placed immediately after
+ // the definition.
+ assert(!isa<TerminatorInst>(E.def()) && "unexpected terminator");
+ InsertPt = cast<Instruction>(E.def())->getNextNode();
+ }
+ Builder.SetInsertPoint(InsertPt);
auto *G = Builder.CreateConstInBoundsGEP2_32(
FrameTy, FramePtr, 0, Index,
CurrentValue->getName() + Twine(".spill.addr"));
@@ -484,7 +502,7 @@ static void rewritePHIs(BasicBlock &BB) {
// loop:
// %n.val = phi i32[%n, %entry], [%inc, %loop]
//
- // It will create:
+ // It will create:
//
// loop.from.entry:
// %n.loop.pre = phi i32 [%n, %entry]
@@ -687,13 +705,12 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) {
Spills.emplace_back(&I, U);
// Rewrite materializable instructions to be materialized at the use point.
- std::sort(Spills.begin(), Spills.end());
DEBUG(dump("Materializations", Spills));
rewriteMaterializableInstructions(Builder, Spills);
// Collect the spills for arguments and other not-materializable values.
Spills.clear();
- for (Argument &A : F.getArgumentList())
+ for (Argument &A : F.args())
for (User *U : A.users())
if (Checker.isDefinitionAcrossSuspend(A, U))
Spills.emplace_back(&A, U);
@@ -719,7 +736,6 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) {
Spills.emplace_back(&I, U);
}
}
- std::sort(Spills.begin(), Spills.end());
DEBUG(dump("Spills", Spills));
moveSpillUsesAfterCoroBegin(F, Spills, Shape.CoroBegin);
Shape.FrameTy = buildFrameType(F, Shape, Spills);
diff --git a/lib/Transforms/Coroutines/CoroInstr.h b/lib/Transforms/Coroutines/CoroInstr.h
index e03cef4bfc46..5c666bdfea1f 100644
--- a/lib/Transforms/Coroutines/CoroInstr.h
+++ b/lib/Transforms/Coroutines/CoroInstr.h
@@ -23,6 +23,9 @@
// the Coroutine library.
//===----------------------------------------------------------------------===//
+#ifndef LLVM_LIB_TRANSFORMS_COROUTINES_COROINSTR_H
+#define LLVM_LIB_TRANSFORMS_COROUTINES_COROINSTR_H
+
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IntrinsicInst.h"
@@ -316,3 +319,5 @@ public:
};
} // End namespace llvm.
+
+#endif
diff --git a/lib/Transforms/Coroutines/CoroSplit.cpp b/lib/Transforms/Coroutines/CoroSplit.cpp
index 7a3f4f60bae9..ab648f884c5b 100644
--- a/lib/Transforms/Coroutines/CoroSplit.cpp
+++ b/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -22,6 +22,7 @@
#include "CoroInternal.h"
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/InstIterator.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Verifier.h"
@@ -144,6 +145,33 @@ static void replaceFallthroughCoroEnd(IntrinsicInst *End,
BB->getTerminator()->eraseFromParent();
}
+// In Resumers, we replace unwind coro.end with True to force the immediate
+// unwind to caller.
+static void replaceUnwindCoroEnds(coro::Shape &Shape, ValueToValueMapTy &VMap) {
+ if (Shape.CoroEnds.empty())
+ return;
+
+ LLVMContext &Context = Shape.CoroEnds.front()->getContext();
+ auto *True = ConstantInt::getTrue(Context);
+ for (CoroEndInst *CE : Shape.CoroEnds) {
+ if (!CE->isUnwind())
+ continue;
+
+ auto *NewCE = cast<IntrinsicInst>(VMap[CE]);
+
+ // If coro.end has an associated bundle, add cleanupret instruction.
+ if (auto Bundle = NewCE->getOperandBundle(LLVMContext::OB_funclet)) {
+ Value *FromPad = Bundle->Inputs[0];
+ auto *CleanupRet = CleanupReturnInst::Create(FromPad, nullptr, NewCE);
+ NewCE->getParent()->splitBasicBlock(NewCE);
+ CleanupRet->getParent()->getTerminator()->eraseFromParent();
+ }
+
+ NewCE->replaceAllUsesWith(True);
+ NewCE->eraseFromParent();
+ }
+}
+
// Rewrite final suspend point handling. We do not use suspend index to
// represent the final suspend point. Instead we zero-out ResumeFnAddr in the
// coroutine frame, since it is undefined behavior to resume a coroutine
@@ -157,9 +185,9 @@ static void handleFinalSuspend(IRBuilder<> &Builder, Value *FramePtr,
coro::Shape &Shape, SwitchInst *Switch,
bool IsDestroy) {
assert(Shape.HasFinalSuspend);
- auto FinalCase = --Switch->case_end();
- BasicBlock *ResumeBB = FinalCase.getCaseSuccessor();
- Switch->removeCase(FinalCase);
+ auto FinalCaseIt = std::prev(Switch->case_end());
+ BasicBlock *ResumeBB = FinalCaseIt->getCaseSuccessor();
+ Switch->removeCase(FinalCaseIt);
if (IsDestroy) {
BasicBlock *OldSwitchBB = Switch->getParent();
auto *NewSwitchBB = OldSwitchBB->splitBasicBlock(Switch, "Switch");
@@ -195,7 +223,7 @@ static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape,
// Replace all args with undefs. The buildCoroutineFrame algorithm already
// rewritten access to the args that occurs after suspend points with loads
// and stores to/from the coroutine frame.
- for (Argument &A : F.getArgumentList())
+ for (Argument &A : F.args())
VMap[&A] = UndefValue::get(A.getType());
SmallVector<ReturnInst *, 4> Returns;
@@ -216,9 +244,9 @@ static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape,
// Remove old return attributes.
NewF->removeAttributes(
- AttributeSet::ReturnIndex,
- AttributeSet::get(
- NewF->getContext(), AttributeSet::ReturnIndex,
+ AttributeList::ReturnIndex,
+ AttributeList::get(
+ NewF->getContext(), AttributeList::ReturnIndex,
AttributeFuncs::typeIncompatible(NewF->getReturnType())));
// Make AllocaSpillBlock the new entry block.
@@ -236,7 +264,7 @@ static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape,
IRBuilder<> Builder(&NewF->getEntryBlock().front());
// Remap frame pointer.
- Argument *NewFramePtr = &NewF->getArgumentList().front();
+ Argument *NewFramePtr = &*NewF->arg_begin();
Value *OldFramePtr = cast<Value>(VMap[Shape.FramePtr]);
NewFramePtr->takeName(OldFramePtr);
OldFramePtr->replaceAllUsesWith(NewFramePtr);
@@ -270,9 +298,7 @@ static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape,
// Remove coro.end intrinsics.
replaceFallthroughCoroEnd(Shape.CoroEnds.front(), VMap);
- // FIXME: coming in upcoming patches:
- // replaceUnwindCoroEnds(Shape.CoroEnds, VMap);
-
+ replaceUnwindCoroEnds(Shape, VMap);
// Eliminate coro.free from the clones, replacing it with 'null' in cleanup,
// to suppress deallocation code.
coro::replaceCoroFree(cast<CoroIdInst>(VMap[Shape.CoroBegin->getId()]),
@@ -284,8 +310,16 @@ static Function *createClone(Function &F, Twine Suffix, coro::Shape &Shape,
}
static void removeCoroEnds(coro::Shape &Shape) {
- for (CoroEndInst *CE : Shape.CoroEnds)
+ if (Shape.CoroEnds.empty())
+ return;
+
+ LLVMContext &Context = Shape.CoroEnds.front()->getContext();
+ auto *False = ConstantInt::getFalse(Context);
+
+ for (CoroEndInst *CE : Shape.CoroEnds) {
+ CE->replaceAllUsesWith(False);
CE->eraseFromParent();
+ }
}
static void replaceFrameSize(coro::Shape &Shape) {
diff --git a/lib/Transforms/Coroutines/Coroutines.cpp b/lib/Transforms/Coroutines/Coroutines.cpp
index 877ec34b4d3b..ea48043f9381 100644
--- a/lib/Transforms/Coroutines/Coroutines.cpp
+++ b/lib/Transforms/Coroutines/Coroutines.cpp
@@ -245,9 +245,9 @@ void coro::Shape::buildFrom(Function &F) {
if (CoroBegin)
report_fatal_error(
"coroutine should have exactly one defining @llvm.coro.begin");
- CB->addAttribute(AttributeSet::ReturnIndex, Attribute::NonNull);
- CB->addAttribute(AttributeSet::ReturnIndex, Attribute::NoAlias);
- CB->removeAttribute(AttributeSet::FunctionIndex,
+ CB->addAttribute(AttributeList::ReturnIndex, Attribute::NonNull);
+ CB->addAttribute(AttributeList::ReturnIndex, Attribute::NoAlias);
+ CB->removeAttribute(AttributeList::FunctionIndex,
Attribute::NoDuplicate);
CoroBegin = CB;
}