1414#include " AArch64Subtarget.h"
1515#include " llvm/CodeGen/CFIInstBuilder.h"
1616#include " llvm/CodeGen/MachineBasicBlock.h"
17+ #include " llvm/CodeGen/MachineFrameInfo.h"
18+ #include " llvm/CodeGen/MachineInstr.h"
1719#include " llvm/CodeGen/MachineInstrBuilder.h"
1820#include " llvm/CodeGen/MachineModuleInfo.h"
21+ #include " llvm/IR/CallingConv.h"
1922
2023using namespace llvm ;
2124using namespace llvm ::AArch64PAuth;
@@ -96,6 +99,9 @@ static void emitPACCFI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
9699 if (!EmitCFI)
97100 return ;
98101
102+ if (MBB.getParent ()->getTarget ().getTargetTriple ().isOSDarwin ())
103+ return ;
104+
99105 auto &MF = *MBB.getParent ();
100106 auto &MFnI = *MF.getInfo <AArch64FunctionInfo>();
101107
@@ -116,7 +122,7 @@ void AArch64PointerAuth::signLR(MachineFunction &MF,
116122 // Debug location must be unknown, see AArch64FrameLowering::emitPrologue.
117123 DebugLoc DL;
118124
119- if (UseBKey) {
125+ if (UseBKey && !MF. getTarget (). getTargetTriple (). isOSDarwin () ) {
120126 BuildMI (MBB, MBBI, DL, TII->get (AArch64::EMITBKEY))
121127 .setMIFlag (MachineInstr::FrameSetup);
122128 }
@@ -133,17 +139,15 @@ void AArch64PointerAuth::signLR(MachineFunction &MF,
133139 if (MFnI.branchProtectionPAuthLR () && Subtarget->hasPAuthLR ()) {
134140 emitPACCFI (MBB, MBBI, MachineInstr::FrameSetup, EmitCFI);
135141 BuildMI (MBB, MBBI, DL,
136- TII->get (MFnI.shouldSignWithBKey () ? AArch64::PACIBSPPC
137- : AArch64::PACIASPPC))
142+ TII->get (UseBKey ? AArch64::PACIBSPPC : AArch64::PACIASPPC))
138143 .setMIFlag (MachineInstr::FrameSetup)
139144 ->setPreInstrSymbol (MF, MFnI.getSigningInstrLabel ());
140145 } else {
141146 BuildPACM (*Subtarget, MBB, MBBI, DL, MachineInstr::FrameSetup);
142147 if (MFnI.branchProtectionPAuthLR ())
143148 emitPACCFI (MBB, MBBI, MachineInstr::FrameSetup, EmitCFI);
144149 BuildMI (MBB, MBBI, DL,
145- TII->get (MFnI.shouldSignWithBKey () ? AArch64::PACIBSP
146- : AArch64::PACIASP))
150+ TII->get (UseBKey ? AArch64::PACIBSP : AArch64::PACIASP))
147151 .setMIFlag (MachineInstr::FrameSetup)
148152 ->setPreInstrSymbol (MF, MFnI.getSigningInstrLabel ());
149153 if (!MFnI.branchProtectionPAuthLR ())
@@ -178,11 +182,41 @@ void AArch64PointerAuth::authenticateLR(
178182 // instructions, namely RETA{A,B}, that can be used instead. In this case the
179183 // DW_CFA_AARCH64_negate_ra_state can't be emitted.
180184 bool TerminatorIsCombinable =
181- TI != MBB.end () && TI->getOpcode () == AArch64::RET;
185+ TI != MBB.end () && (TI->getOpcode () == AArch64::RET ||
186+ TI->getOpcode () == AArch64::RET_ReallyLR);
182187 MCSymbol *PACSym = MFnI->getSigningInstrLabel ();
183188
189+ const MachineFrameInfo &MFI = MF.getFrameInfo ();
190+ bool IsLRSpilled =
191+ llvm::any_of (MFI.getCalleeSavedInfo (), [](const CalleeSavedInfo &Info) {
192+ return Info.getReg () == AArch64::LR;
193+ });
194+
195+ // In functions with popless epilogues (swiftcorocc calling convention with
196+ // llvm.ret.popless), some returns don't restore SP, so we can't use RETAB
197+ // because the authenticating discriminator (SP) won't match the signing
198+ // discriminator. We need to check if this specific block restores SP.
199+ // If SP is restored before the return, we can use RETAB; otherwise we need
200+ // to compute the discriminator from FP and use AUTIB + separate RET.
201+ bool IsSwiftCoroPartialReturn = [&]() {
202+ if (!MFnI->hasPoplessEpilogue ())
203+ return false ;
204+
205+ // Check if any instruction in the epilogue modifies SP.
206+ if (llvm::any_of (make_range (MBB.begin (), MBB.getFirstTerminator ()),
207+ [&](const MachineInstr &I) {
208+ return I.getFlag (MachineInstr::FrameDestroy) &&
209+ I.modifiesRegister (AArch64::SP,
210+ Subtarget->getRegisterInfo ());
211+ }))
212+ return false ;
213+
214+ return true ;
215+ }();
216+
184217 if (Subtarget->hasPAuth () && TerminatorIsCombinable && !NeedsWinCFI &&
185- !MF.getFunction ().hasFnAttribute (Attribute::ShadowCallStack)) {
218+ !MF.getFunction ().hasFnAttribute (Attribute::ShadowCallStack) &&
219+ !IsSwiftCoroPartialReturn) {
186220 if (MFnI->branchProtectionPAuthLR () && Subtarget->hasPAuthLR ()) {
187221 assert (PACSym && " No PAC instruction to refer to" );
188222 emitPACSymOffsetIntoX16 (*TII, MBB, MBBI, DL, PACSym);
@@ -198,6 +232,31 @@ void AArch64PointerAuth::authenticateLR(
198232 .setMIFlag (MachineInstr::FrameDestroy);
199233 }
200234 MBB.erase (TI);
235+ } else if (IsSwiftCoroPartialReturn && IsLRSpilled) {
236+ // For popless epilogues that don't restore SP, we can't use RETAB because
237+ // SP doesn't match. Instead, compute the correct discriminator from FP.
238+ const auto *TRI = Subtarget->getRegisterInfo ();
239+
240+ MachineBasicBlock::iterator EpilogStartI = MBB.getFirstTerminator ();
241+ MachineBasicBlock::iterator Begin = MBB.begin ();
242+ while (EpilogStartI != Begin) {
243+ --EpilogStartI;
244+ if (!EpilogStartI->getFlag (MachineInstr::FrameDestroy)) {
245+ ++EpilogStartI;
246+ break ;
247+ }
248+ if (EpilogStartI->readsRegister (AArch64::X16, TRI) ||
249+ EpilogStartI->modifiesRegister (AArch64::X16, TRI))
250+ report_fatal_error (" unable to use x16 for popless ret LR auth" );
251+ }
252+
253+ emitFrameOffset (MBB, EpilogStartI, DL, AArch64::X16, AArch64::FP,
254+ StackOffset::getFixed (16 ), TII, MachineInstr::FrameDestroy);
255+ emitPACCFI (MBB, MBBI, MachineInstr::FrameDestroy, EmitAsyncCFI);
256+ BuildMI (MBB, TI, DL, TII->get (AArch64::AUTIB), AArch64::LR)
257+ .addUse (AArch64::LR)
258+ .addUse (AArch64::X16)
259+ .setMIFlag (MachineInstr::FrameDestroy);
201260 } else {
202261 if (MFnI->branchProtectionPAuthLR () && Subtarget->hasPAuthLR ()) {
203262 assert (PACSym && " No PAC instruction to refer to" );
0 commit comments