summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorSanjoy Das <sanjoy@playingwithpointers.com>2016-04-05 23:18:35 +0000
committerSanjoy Das <sanjoy@playingwithpointers.com>2016-04-05 23:18:35 +0000
commit49e974b33b3107c1a35c7216f3fbbf8a27b736fe (patch)
tree0b1f73cd0e72bd0634f623272566292defb01b12 /llvm/lib
parent6ae3b78df643f18c67f4a77334a3d855a04e1f6a (diff)
downloadbcm5719-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.cpp68
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;
OpenPOWER on IntegriCloud