Index: llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -518,6 +518,10 @@ // function has the optnone attribute. bool EnableOpts = false; + /// True when the block contains a tail call. This allows the IRTranslator to + /// stop translating such blocks early. + bool HasTailCall = false; + /// Switch analysis and optimization. class GISelSwitchLowering : public SwitchCG::SwitchLowering { public: Index: llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -32,6 +32,7 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/StackProtector.h" #include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/CodeGen/TargetRegisterInfo.h" @@ -1568,6 +1569,12 @@ CLI->lowerCall(MIRBuilder, CS, Res, Args, SwiftErrorVReg, [&]() { return getOrCreateVReg(*CS.getCalledValue()); }); + // Check if we just inserted a tail call. + if (Success) { + const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); + HasTailCall = TII->isTailCall(*std::prev(MIRBuilder.getInsertPt())); + } + return Success; } @@ -2276,8 +2283,15 @@ // Set the insertion point of all the following translations to // the end of this basic block. CurBuilder->setMBB(MBB); - + HasTailCall = false; for (const Instruction &Inst : *BB) { + // If we translated a tail call in the last step, then we know + // everything after the call is either a return, or something that is + // handled by the call itself. (E.g. a lifetime marker or assume + // intrinsic.) In this case, we should stop translating the block and + // move on. + if (HasTailCall) + break; #ifndef NDEBUG Verifier.setCurrentInst(&Inst); #endif // ifndef NDEBUG Index: llvm/lib/Target/AArch64/AArch64CallLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64CallLowering.cpp +++ llvm/lib/Target/AArch64/AArch64CallLowering.cpp @@ -233,17 +233,6 @@ const Value *Val, ArrayRef VRegs, Register SwiftErrorVReg) const { - - // Check if a tail call was lowered in this block. If so, we already handled - // the terminator. - MachineFunction &MF = MIRBuilder.getMF(); - if (MF.getFrameInfo().hasTailCall()) { - MachineBasicBlock &MBB = MIRBuilder.getMBB(); - auto FirstTerm = MBB.getFirstTerminator(); - if (FirstTerm != MBB.end() && FirstTerm->isCall()) - return true; - } - auto MIB = MIRBuilder.buildInstrNoInsert(AArch64::RET_ReallyLR); assert(((Val && !VRegs.empty()) || (!Val && VRegs.empty())) && "Return value without a vreg"); Index: llvm/test/CodeGen/AArch64/GlobalISel/call-translator-tail-call.ll =================================================================== --- llvm/test/CodeGen/AArch64/GlobalISel/call-translator-tail-call.ll +++ llvm/test/CodeGen/AArch64/GlobalISel/call-translator-tail-call.ll @@ -188,3 +188,33 @@ tail call fastcc void @fast_fn() ret void } + +; Verify that lifetime markers and llvm.assume don't impact tail calling. +declare void @llvm.assume(i1) +define void @test_assume() local_unnamed_addr { + ; COMMON-LABEL: name: test_assume + ; COMMON: bb.1.entry: + ; COMMON: TCRETURNdi @nonvoid_ret, 0, csr_aarch64_aapcs, implicit $sp +entry: + %x = tail call i32 @nonvoid_ret() + %y = icmp ne i32 %x, 0 + tail call void @llvm.assume(i1 %y) + ret void +} + +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) +define void @test_lifetime() local_unnamed_addr { + ; COMMON-LABEL: name: test_lifetime + ; COMMON: bb.1.entry: + ; COMMON: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.t + ; COMMON: LIFETIME_START %stack.0.t + ; COMMON: TCRETURNdi @nonvoid_ret, 0, csr_aarch64_aapcs, implicit $sp +entry: + %t = alloca i8, align 1 + call void @llvm.lifetime.start.p0i8(i64 1, i8* %t) + %x = tail call i32 @nonvoid_ret() + %y = icmp ne i32 %x, 0 + tail call void @llvm.lifetime.end.p0i8(i64 1, i8* %t) + ret void +}