diff options
| author | Sanjoy Das <sanjoy@playingwithpointers.com> | 2016-04-05 23:18:35 +0000 |
|---|---|---|
| committer | Sanjoy Das <sanjoy@playingwithpointers.com> | 2016-04-05 23:18:35 +0000 |
| commit | 49e974b33b3107c1a35c7216f3fbbf8a27b736fe (patch) | |
| tree | 0b1f73cd0e72bd0634f623272566292defb01b12 /llvm/lib | |
| parent | 6ae3b78df643f18c67f4a77334a3d855a04e1f6a (diff) | |
| download | bcm5719-llvm-49e974b33b3107c1a35c7216f3fbbf8a27b736fe.tar.gz bcm5719-llvm-49e974b33b3107c1a35c7216f3fbbf8a27b736fe.zip | |
[RS4GC] Better codegen for deoptimize calls
Don't emit a gc.result for a statepoint lowered from
@llvm.experimental.deoptimize since the call into __llvm_deoptimize is
effectively noreturn. Instead follow the corresponding gc.statepoint
with an "unreachable".
llvm-svn: 265485
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp | 68 |
1 files changed, 52 insertions, 16 deletions
diff --git a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index 9377c7a2b94..8c331547428 100644 --- a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1278,6 +1278,9 @@ namespace { class DeferredReplacement { AssertingVH<Instruction> Old; AssertingVH<Instruction> New; + bool IsDeoptimize = false; + + DeferredReplacement() {} public: explicit DeferredReplacement(Instruction *Old, Instruction *New) : @@ -1285,18 +1288,40 @@ public: assert(Old != New && "Not allowed!"); } + static DeferredReplacement createDeoptimizeReplacement(Instruction *Old) { +#ifndef NDEBUG + auto *F = cast<CallInst>(Old)->getCalledFunction(); + assert(F && F->getIntrinsicID() == Intrinsic::experimental_deoptimize && + "Only way to construct a deoptimize deferred replacement"); +#endif + DeferredReplacement D; + D.Old = Old; + D.IsDeoptimize = true; + return D; + } + /// Does the task represented by this instance. void doReplacement() { Instruction *OldI = Old; Instruction *NewI = New; assert(OldI != NewI && "Disallowed at construction?!"); + assert(!IsDeoptimize || !New && "Deoptimize instrinsics are not replaced!"); Old = nullptr; New = nullptr; if (NewI) OldI->replaceAllUsesWith(NewI); + + if (IsDeoptimize) { + // Note: we've inserted instructions, so the call to llvm.deoptimize may + // not necessarilly be followed by the matching return. + auto *RI = cast<ReturnInst>(OldI->getParent()->getTerminator()); + new UnreachableInst(RI->getContext(), RI); + RI->eraseFromParent(); + } + OldI->eraseFromParent(); } }; @@ -1330,6 +1355,7 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ Flags |= uint32_t(StatepointFlags::GCTransition); TransitionArgs = TransitionBundle->Inputs; } + bool IsDeoptimize = false; StatepointDirectives SD = parseStatepointDirectivesFromAttrs(CS.getAttributes()); @@ -1348,7 +1374,7 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ SmallVector<Type *, 8> DomainTy; for (Value *Arg : CallArgs) DomainTy.push_back(Arg->getType()); - auto *FTy = FunctionType::get(F->getReturnType(), DomainTy, + auto *FTy = FunctionType::get(Type::getVoidTy(F->getContext()), DomainTy, /* isVarArg = */ false); // Note: CallTarget can be a bitcast instruction of a symbol if there are @@ -1357,6 +1383,8 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ // was doing when generating this kind of IR. CallTarget = F->getParent()->getOrInsertFunction("__llvm_deoptimize", FTy); + + IsDeoptimize = true; } } @@ -1440,22 +1468,30 @@ makeStatepointExplicitImpl(const CallSite CS, /* to replace */ } assert(Token && "Should be set in one of the above branches!"); - Token->setName("statepoint_token"); - if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) { - StringRef Name = - CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : ""; - CallInst *GCResult = Builder.CreateGCResult(Token, CS.getType(), Name); - GCResult->setAttributes(CS.getAttributes().getRetAttributes()); - - // We cannot RAUW or delete CS.getInstruction() because it could be in the - // live set of some other safepoint, in which case that safepoint's - // PartiallyConstructedSafepointRecord will hold a raw pointer to this - // llvm::Instruction. Instead, we defer the replacement and deletion to - // after the live sets have been made explicit in the IR, and we no longer - // have raw pointers to worry about. - Replacements.emplace_back(CS.getInstruction(), GCResult); + if (IsDeoptimize) { + // If we're wrapping an @llvm.experimental.deoptimize in a statepoint, we + // transform the tail-call like structure to a call to a void function + // followed by unreachable to get better codegen. + Replacements.push_back( + DeferredReplacement::createDeoptimizeReplacement(CS.getInstruction())); } else { - Replacements.emplace_back(CS.getInstruction(), nullptr); + Token->setName("statepoint_token"); + if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) { + StringRef Name = + CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : ""; + CallInst *GCResult = Builder.CreateGCResult(Token, CS.getType(), Name); + GCResult->setAttributes(CS.getAttributes().getRetAttributes()); + + // We cannot RAUW or delete CS.getInstruction() because it could be in the + // live set of some other safepoint, in which case that safepoint's + // PartiallyConstructedSafepointRecord will hold a raw pointer to this + // llvm::Instruction. Instead, we defer the replacement and deletion to + // after the live sets have been made explicit in the IR, and we no longer + // have raw pointers to worry about. + Replacements.emplace_back(CS.getInstruction(), GCResult); + } else { + Replacements.emplace_back(CS.getInstruction(), nullptr); + } } Result.StatepointToken = Token; |

