Skip to content

Commit 39998ff

Browse files
ahmedbougachanate-chandler
authored andcommitted
Define @llvm.ret.popless intrinsic, a ret that doesn't restore SP.
Marks the following ret instruction as a "popless" return, one that does not not restore SP to its function-entry value (i.e., does not deallocate the stack frame), allowing allocations made in the function to be accessible by the caller. The function must be annotated with an appropriate target-specific calling convention, so the caller can generate stack accesses accordingly, generally by treating the call as a variably-sized alloca, so using FP-based addressing for its own frame rather than relying on statically known SP offsets. The single argument is forwarded as a return value, that must then be used as the operand to the following ret instruction. Calls to this intrinsic need to be musttail, but don't follow the other ABI requirements for musttail calls, since this is really annotating the ret. This doesn't implement any lowering, but only adds the intrinsic definition, basic verifier checks, and an inliner opt-out. rdar://135984630
1 parent b5b6dce commit 39998ff

File tree

6 files changed

+52
-0
lines changed

6 files changed

+52
-0
lines changed

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,20 @@ def int_localrecover : DefaultAttrsIntrinsic<[llvm_ptr_ty],
838838
[llvm_ptr_ty, llvm_ptr_ty, llvm_i32_ty],
839839
[IntrNoMem, ImmArg<ArgIndex<2>>]>;
840840

841+
// Marks the following ret instruction as a "popless" return, one that does not
842+
// not restore SP to its function-entry value (i.e., does not deallocate the
843+
// stack frame), allowing allocations made in the function to be accessible
844+
// by the caller.
845+
//
846+
// The function must be annotated with an appropriate target-specific calling
847+
// convention, so the caller can generate stack accesses accordingly, generally
848+
// by treating the call as a variably-sized alloca, so using FP-based addressing
849+
// for its own frame rather than relying on statically known SP offsets.
850+
//
851+
// Calls to this intrinsic need to be musttail, but don't follow the other ABI
852+
// requirements for musttail calls, since this is really annotating the ret.
853+
def int_ret_popless : DefaultAttrsIntrinsic<[], [], [IntrNoMem]>;
854+
841855
// Given the frame pointer passed into an SEH filter function, returns a
842856
// pointer to the local variable area suitable for use with llvm.localrecover.
843857
def int_eh_recoverfp : DefaultAttrsIntrinsic<[llvm_ptr_ty],

llvm/lib/Analysis/InlineCost.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2363,6 +2363,7 @@ bool CallAnalyzer::visitCallBase(CallBase &Call) {
23632363
return false;
23642364
case Intrinsic::icall_branch_funnel:
23652365
case Intrinsic::localescape:
2366+
case Intrinsic::ret_popless:
23662367
HasUninlineableIntrinsic = true;
23672368
return false;
23682369
case Intrinsic::vastart:

llvm/lib/IR/BasicBlock.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,14 @@ const CallInst *BasicBlock::getTerminatingMustTailCall() const {
306306
if (!Prev)
307307
return nullptr;
308308

309+
// Some musttail intrinsic calls are special in being really simply ret
310+
// annotations, and only need to be the last instruction before the ret.
311+
// We don't need to look through the return value in those cases.
312+
// FIXME: we should generalize getTerminatingDeoptimizeCall for this case.
313+
if (auto *CI = dyn_cast<CallInst>(Prev))
314+
if (CI->isMustTailCall() && CI->getIntrinsicID() == Intrinsic::ret_popless)
315+
return CI;
316+
309317
if (Value *RV = RI->getReturnValue()) {
310318
if (RV != Prev)
311319
return nullptr;

llvm/lib/IR/Verifier.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3912,6 +3912,15 @@ void Verifier::verifyMustTailCall(CallInst &CI) {
39123912
&CI);
39133913
}
39143914
#endif
3915+
Check(CI.getIntrinsicID() != Intrinsic::ret_popless,
3916+
"llvm.ret.popless call must be musttail", &CI);
3917+
return;
3918+
}
3919+
3920+
// Some musttail intrinsic calls are special, and don't have all the rules.
3921+
if (CI.getIntrinsicID() == Intrinsic::ret_popless) {
3922+
ReturnInst *Ret = dyn_cast_or_null<ReturnInst>(CI.getNextNode());
3923+
Check(Ret, "musttail intrinsic call must precede a ret", &CI);
39153924
return;
39163925
}
39173926

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,12 @@ static bool isSafeToHoistInstr(Instruction *I, unsigned Flags) {
14811481
if (CB->getIntrinsicID() == Intrinsic::experimental_deoptimize)
14821482
return false;
14831483

1484+
// Similarly for llvm.ret.popless (and likely generalizable to all musttail
1485+
// intrinsics).
1486+
if (auto *CB = dyn_cast<CallBase>(I))
1487+
if (CB->getIntrinsicID() == Intrinsic::ret_popless)
1488+
return false;
1489+
14841490
// It's also unsafe/illegal to hoist an instruction above its instruction
14851491
// operands
14861492
BasicBlock *BB = I->getParent();

llvm/test/Verifier/ret_popless.ll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
; RUN: not opt -passes=verify < %s 2>&1 | FileCheck %s
2+
3+
define void @test_ret_popless_not_musttail() {
4+
; CHECK: llvm.ret.popless call must be musttail
5+
call void @llvm.ret.popless()
6+
ret void
7+
}
8+
9+
define i64 @test_ret_popless_not_returned(i64 %a) {
10+
; CHECK: musttail intrinsic call must precede a ret
11+
musttail call void @llvm.ret.popless()
12+
%res = bitcast i64 %a to i64
13+
ret i64 %res
14+
}

0 commit comments

Comments
 (0)