llvm.org GIT mirror llvm / 0ed4be7
[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". git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@265485 91177308-0d34-0410-b5e6-96231b3b80d8 Sanjoy Das 3 years ago
2 changed file(s) with 66 addition(s) and 18 deletion(s). Raw diff Collapse all Expand all
12771277 class DeferredReplacement {
12781278 AssertingVH Old;
12791279 AssertingVH New;
1280 bool IsDeoptimize = false;
1281
1282 DeferredReplacement() {}
12801283
12811284 public:
12821285 explicit DeferredReplacement(Instruction *Old, Instruction *New) :
12841287 assert(Old != New && "Not allowed!");
12851288 }
12861289
1290 static DeferredReplacement createDeoptimizeReplacement(Instruction *Old) {
1291 #ifndef NDEBUG
1292 auto *F = cast(Old)->getCalledFunction();
1293 assert(F && F->getIntrinsicID() == Intrinsic::experimental_deoptimize &&
1294 "Only way to construct a deoptimize deferred replacement");
1295 #endif
1296 DeferredReplacement D;
1297 D.Old = Old;
1298 D.IsDeoptimize = true;
1299 return D;
1300 }
1301
12871302 /// Does the task represented by this instance.
12881303 void doReplacement() {
12891304 Instruction *OldI = Old;
12901305 Instruction *NewI = New;
12911306
12921307 assert(OldI != NewI && "Disallowed at construction?!");
1308 assert(!IsDeoptimize || !New && "Deoptimize instrinsics are not replaced!");
12931309
12941310 Old = nullptr;
12951311 New = nullptr;
12961312
12971313 if (NewI)
12981314 OldI->replaceAllUsesWith(NewI);
1315
1316 if (IsDeoptimize) {
1317 // Note: we've inserted instructions, so the call to llvm.deoptimize may
1318 // not necessarilly be followed by the matching return.
1319 auto *RI = cast(OldI->getParent()->getTerminator());
1320 new UnreachableInst(RI->getContext(), RI);
1321 RI->eraseFromParent();
1322 }
1323
12991324 OldI->eraseFromParent();
13001325 }
13011326 };
13291354 Flags |= uint32_t(StatepointFlags::GCTransition);
13301355 TransitionArgs = TransitionBundle->Inputs;
13311356 }
1357 bool IsDeoptimize = false;
13321358
13331359 StatepointDirectives SD =
13341360 parseStatepointDirectivesFromAttrs(CS.getAttributes());
13471373 SmallVector DomainTy;
13481374 for (Value *Arg : CallArgs)
13491375 DomainTy.push_back(Arg->getType());
1350 auto *FTy = FunctionType::get(F->getReturnType(), DomainTy,
1376 auto *FTy = FunctionType::get(Type::getVoidTy(F->getContext()), DomainTy,
13511377 /* isVarArg = */ false);
13521378
13531379 // Note: CallTarget can be a bitcast instruction of a symbol if there are
13561382 // was doing when generating this kind of IR.
13571383 CallTarget =
13581384 F->getParent()->getOrInsertFunction("__llvm_deoptimize", FTy);
1385
1386 IsDeoptimize = true;
13591387 }
13601388 }
13611389
14391467 }
14401468 assert(Token && "Should be set in one of the above branches!");
14411469
1442 Token->setName("statepoint_token");
1443 if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) {
1444 StringRef Name =
1445 CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : "";
1446 CallInst *GCResult = Builder.CreateGCResult(Token, CS.getType(), Name);
1447 GCResult->setAttributes(CS.getAttributes().getRetAttributes());
1448
1449 // We cannot RAUW or delete CS.getInstruction() because it could be in the
1450 // live set of some other safepoint, in which case that safepoint's
1451 // PartiallyConstructedSafepointRecord will hold a raw pointer to this
1452 // llvm::Instruction. Instead, we defer the replacement and deletion to
1453 // after the live sets have been made explicit in the IR, and we no longer
1454 // have raw pointers to worry about.
1455 Replacements.emplace_back(CS.getInstruction(), GCResult);
1470 if (IsDeoptimize) {
1471 // If we're wrapping an @llvm.experimental.deoptimize in a statepoint, we
1472 // transform the tail-call like structure to a call to a void function
1473 // followed by unreachable to get better codegen.
1474 Replacements.push_back(
1475 DeferredReplacement::createDeoptimizeReplacement(CS.getInstruction()));
14561476 } else {
1457 Replacements.emplace_back(CS.getInstruction(), nullptr);
1477 Token->setName("statepoint_token");
1478 if (!CS.getType()->isVoidTy() && !CS.getInstruction()->use_empty()) {
1479 StringRef Name =
1480 CS.getInstruction()->hasName() ? CS.getInstruction()->getName() : "";
1481 CallInst *GCResult = Builder.CreateGCResult(Token, CS.getType(), Name);
1482 GCResult->setAttributes(CS.getAttributes().getRetAttributes());
1483
1484 // We cannot RAUW or delete CS.getInstruction() because it could be in the
1485 // live set of some other safepoint, in which case that safepoint's
1486 // PartiallyConstructedSafepointRecord will hold a raw pointer to this
1487 // llvm::Instruction. Instead, we defer the replacement and deletion to
1488 // after the live sets have been made explicit in the IR, and we no longer
1489 // have raw pointers to worry about.
1490 Replacements.emplace_back(CS.getInstruction(), GCResult);
1491 } else {
1492 Replacements.emplace_back(CS.getInstruction(), nullptr);
1493 }
14581494 }
14591495
14601496 Result.StatepointToken = Token;
33 target triple = "x86_64-apple-macosx10.11.0"
44
55 declare i32 @llvm.experimental.deoptimize.i32(...)
6 declare void @llvm.experimental.deoptimize.isVoid(...)
67
78 define i32 @caller_0(i32 addrspace(1)* %ptr) gc "statepoint-example" {
89 ; CHECK-LABEL: @caller_0(
9 ; CHECK: @llvm.experimental.gc.statepoint.p0f_i32f(i64 2882400000, i32 0, i32 ()* @__llvm_deoptimize, i32 0
10 ; CHECK: @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @__llvm_deoptimize, i32 0
11 ; CHECK: unreachable
1012 entry:
1113 %v = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 0, i32 addrspace(1)* %ptr) ]
1214 ret i32 %v
1517
1618 define i32 @caller_1(i32 addrspace(1)* %ptr) gc "statepoint-example" {
1719 ; CHECK-LABEL: @caller_1
18 ; CHECK: @llvm.experimental.gc.statepoint.p0f_i32i32p1i32f(i64 2882400000, i32 0, i32 (i32, i32 addrspace(1)*)* bitcast (i32 ()* @__llvm_deoptimize to i32 (i32, i32 addrspace(1)*)*), i32 2, i32 0, i32 50, i32 addrspace(1)* %ptr
20 ; CHECK: @llvm.experimental.gc.statepoint.p0f_isVoidi32p1i32f(i64 2882400000, i32 0, void (i32, i32 addrspace(1)*)* bitcast (void ()* @__llvm_deoptimize to void (i32, i32 addrspace(1)*)*), i32 2, i32 0, i32 50, i32 addrspace(1)* %ptr
21 ; CHECK: unreachable
1922 entry:
2023 %v = call i32(...) @llvm.experimental.deoptimize.i32(i32 50, i32 addrspace(1)* %ptr) [ "deopt"(i32 0) ]
2124 ret i32 %v
2225 }
26
27 define void @caller_2(i32 addrspace(1)* %ptr) gc "statepoint-example" {
28 ; CHECK-LABEL: @caller_2(
29 ; CHECK: @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @__llvm_deoptimize, i32 0
30 ; CHECK: unreachable
31 entry:
32 call void(...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 0, i32 addrspace(1)* %ptr) ]
33 ret void
34 }