diff options
author | Gor Nishanov <GorNishanov@gmail.com> | 2017-05-17 03:09:22 +0000 |
---|---|---|
committer | Gor Nishanov <GorNishanov@gmail.com> | 2017-05-17 03:09:22 +0000 |
commit | 7f80f60c16120fb23438cb511d0e20b9c75817ff (patch) | |
tree | 0c115a65115f22f878ae1fa7cd4d0d008237fb59 /lib/Transforms/Coroutines | |
parent | 733dbc6c18d9c834526b0d63878e54412713ba6f (diff) |
[coroutines] Handle spills before catchswitch
If we need to spill the result of the PHI instruction, we insert the spill after
all of the PHIs and EHPads, however, in a catchswitch block there is no
room to insert the spill. Make room by splitting away catchswitch into a separate
block.
Before the fix:
catch.dispatch:
%val = phi i32 [ 1, %if.then ], [ 2, %if.else ]
%switch = catchswitch within none [label %catch] unwind label %cleanuppad
After:
catch.dispatch:
%val = phi i32 [ 1, %if.then ], [ 2, %if.else ]
%tok = cleanuppad within none []
; spill goes here
cleanupret from %tok unwind label %catch.dispatch.switch
catch.dispatch.switch:
%switch = catchswitch within none [label %catch] unwind label %cleanuppad
https://reviews.llvm.org/D31846
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@303232 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/Coroutines')
-rw-r--r-- | lib/Transforms/Coroutines/CoroFrame.cpp | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/lib/Transforms/Coroutines/CoroFrame.cpp b/lib/Transforms/Coroutines/CoroFrame.cpp index 4480220f2cd..417d57f7625 100644 --- a/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/lib/Transforms/Coroutines/CoroFrame.cpp @@ -347,6 +347,27 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, return FrameTy; } +// We need to make room to insert a spill after initial PHIs, but before +// catchswitch instruction. Placing it before violates the requirement that +// catchswitch, like all other EHPads must be the first nonPHI in a block. +// +// Split away catchswitch into a separate block and insert in its place: +// +// cleanuppad <InsertPt> cleanupret. +// +// cleanupret instruction will act as an insert point for the spill. +static Instruction *splitBeforeCatchSwitch(CatchSwitchInst *CatchSwitch) { + BasicBlock *CurrentBlock = CatchSwitch->getParent(); + BasicBlock *NewBlock = CurrentBlock->splitBasicBlock(CatchSwitch); + CurrentBlock->getTerminator()->eraseFromParent(); + + auto *CleanupPad = + CleanupPadInst::Create(CatchSwitch->getParentPad(), {}, "", CurrentBlock); + auto *CleanupRet = + CleanupReturnInst::Create(CleanupPad, NewBlock, CurrentBlock); + return CleanupRet; +} + // 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 @@ -437,8 +458,11 @@ static Instruction *insertSpills(SpillInfo &Spills, coro::Shape &Shape) { InsertPt = NewBB->getTerminator(); } else if (dyn_cast<PHINode>(CurrentValue)) { // Skip the PHINodes and EH pads instructions. - InsertPt = - &*cast<Instruction>(E.def())->getParent()->getFirstInsertionPt(); + BasicBlock *DefBlock = cast<Instruction>(E.def())->getParent(); + if (auto *CSI = dyn_cast<CatchSwitchInst>(DefBlock->getTerminator())) + InsertPt = splitBeforeCatchSwitch(CSI); + else + InsertPt = &*DefBlock->getFirstInsertionPt(); } else { // For all other values, the spill is placed immediately after // the definition. |