[X86] lowerV4F64Shuffle - prefer lowerShuffleAsDecomposedShuffleMerge if we're blendi...
[llvm-project.git] / llvm / lib / Target / AArch64 / AArch64PointerAuth.cpp
blobc3bc70ad6f4275177de11629765a4810b744bf9f
1 //===-- AArch64PointerAuth.cpp -- Harden code using PAuth ------------------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "AArch64PointerAuth.h"
11 #include "AArch64.h"
12 #include "AArch64InstrInfo.h"
13 #include "AArch64MachineFunctionInfo.h"
14 #include "AArch64Subtarget.h"
15 #include "llvm/CodeGen/MachineBasicBlock.h"
16 #include "llvm/CodeGen/MachineInstrBuilder.h"
17 #include "llvm/CodeGen/MachineModuleInfo.h"
19 using namespace llvm;
20 using namespace llvm::AArch64PAuth;
22 #define AARCH64_POINTER_AUTH_NAME "AArch64 Pointer Authentication"
24 namespace {
26 class AArch64PointerAuth : public MachineFunctionPass {
27 public:
28 static char ID;
30 AArch64PointerAuth() : MachineFunctionPass(ID) {}
32 bool runOnMachineFunction(MachineFunction &MF) override;
34 StringRef getPassName() const override { return AARCH64_POINTER_AUTH_NAME; }
36 private:
37 const AArch64Subtarget *Subtarget = nullptr;
38 const AArch64InstrInfo *TII = nullptr;
40 void signLR(MachineFunction &MF, MachineBasicBlock::iterator MBBI) const;
42 void authenticateLR(MachineFunction &MF,
43 MachineBasicBlock::iterator MBBI) const;
45 /// Stores blend(AddrDisc, IntDisc) to the Result register.
46 void emitBlend(MachineBasicBlock::iterator MBBI, Register Result,
47 Register AddrDisc, unsigned IntDisc) const;
49 /// Expands PAUTH_BLEND pseudo instruction.
50 void expandPAuthBlend(MachineBasicBlock::iterator MBBI) const;
52 bool checkAuthenticatedLR(MachineBasicBlock::iterator TI) const;
55 } // end anonymous namespace
57 INITIALIZE_PASS(AArch64PointerAuth, "aarch64-ptrauth",
58 AARCH64_POINTER_AUTH_NAME, false, false)
60 FunctionPass *llvm::createAArch64PointerAuthPass() {
61 return new AArch64PointerAuth();
64 char AArch64PointerAuth::ID = 0;
66 static void emitPACSymOffsetIntoX16(const TargetInstrInfo &TII,
67 MachineBasicBlock &MBB,
68 MachineBasicBlock::iterator I, DebugLoc DL,
69 MCSymbol *PACSym) {
70 BuildMI(MBB, I, DL, TII.get(AArch64::ADRP), AArch64::X16)
71 .addSym(PACSym, AArch64II::MO_PAGE);
72 BuildMI(MBB, I, DL, TII.get(AArch64::ADDXri), AArch64::X16)
73 .addReg(AArch64::X16)
74 .addSym(PACSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC)
75 .addImm(0);
78 // Where PAuthLR support is not known at compile time, it is supported using
79 // PACM. PACM is in the hint space so has no effect when PAuthLR is not
80 // supported by the hardware, but will alter the behaviour of PACI*SP, AUTI*SP
81 // and RETAA/RETAB if the hardware supports PAuthLR.
82 static void BuildPACM(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB,
83 MachineBasicBlock::iterator MBBI, DebugLoc DL,
84 MachineInstr::MIFlag Flags, MCSymbol *PACSym = nullptr) {
85 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
86 auto &MFnI = *MBB.getParent()->getInfo<AArch64FunctionInfo>();
88 // Offset to PAC*SP using ADRP + ADD.
89 if (PACSym) {
90 assert(Flags == MachineInstr::FrameDestroy);
91 emitPACSymOffsetIntoX16(*TII, MBB, MBBI, DL, PACSym);
94 // Only emit PACM if -mbranch-protection has +pc and the target does not
95 // have feature +pauth-lr.
96 if (MFnI.branchProtectionPAuthLR() && !Subtarget.hasPAuthLR())
97 BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACM)).setMIFlag(Flags);
100 static void emitPACCFI(const AArch64Subtarget &Subtarget,
101 MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
102 DebugLoc DL, MachineInstr::MIFlag Flags, bool EmitCFI) {
103 if (!EmitCFI)
104 return;
106 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
107 auto &MF = *MBB.getParent();
108 auto &MFnI = *MF.getInfo<AArch64FunctionInfo>();
110 auto CFIInst = MFnI.branchProtectionPAuthLR()
111 ? MCCFIInstruction::createNegateRAStateWithPC(nullptr)
112 : MCCFIInstruction::createNegateRAState(nullptr);
114 unsigned CFIIndex = MF.addFrameInst(CFIInst);
115 BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
116 .addCFIIndex(CFIIndex)
117 .setMIFlags(Flags);
120 void AArch64PointerAuth::signLR(MachineFunction &MF,
121 MachineBasicBlock::iterator MBBI) const {
122 auto &MFnI = *MF.getInfo<AArch64FunctionInfo>();
123 bool UseBKey = MFnI.shouldSignWithBKey();
124 bool EmitCFI = MFnI.needsDwarfUnwindInfo(MF);
125 bool NeedsWinCFI = MF.hasWinCFI();
127 MachineBasicBlock &MBB = *MBBI->getParent();
129 // Debug location must be unknown, see AArch64FrameLowering::emitPrologue.
130 DebugLoc DL;
132 if (UseBKey) {
133 BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY))
134 .setMIFlag(MachineInstr::FrameSetup);
137 // PAuthLR authentication instructions need to know the value of PC at the
138 // point of signing (PACI*).
139 if (MFnI.branchProtectionPAuthLR()) {
140 MCSymbol *PACSym = MF.getContext().createTempSymbol();
141 MFnI.setSigningInstrLabel(PACSym);
144 // No SEH opcode for this one; it doesn't materialize into an
145 // instruction on Windows.
146 if (MFnI.branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
147 emitPACCFI(*Subtarget, MBB, MBBI, DL, MachineInstr::FrameSetup, EmitCFI);
148 BuildMI(MBB, MBBI, DL,
149 TII->get(MFnI.shouldSignWithBKey() ? AArch64::PACIBSPPC
150 : AArch64::PACIASPPC))
151 .setMIFlag(MachineInstr::FrameSetup)
152 ->setPreInstrSymbol(MF, MFnI.getSigningInstrLabel());
153 } else {
154 BuildPACM(*Subtarget, MBB, MBBI, DL, MachineInstr::FrameSetup);
155 emitPACCFI(*Subtarget, MBB, MBBI, DL, MachineInstr::FrameSetup, EmitCFI);
156 BuildMI(MBB, MBBI, DL,
157 TII->get(MFnI.shouldSignWithBKey() ? AArch64::PACIBSP
158 : AArch64::PACIASP))
159 .setMIFlag(MachineInstr::FrameSetup)
160 ->setPreInstrSymbol(MF, MFnI.getSigningInstrLabel());
163 if (!EmitCFI && NeedsWinCFI) {
164 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR))
165 .setMIFlag(MachineInstr::FrameSetup);
169 void AArch64PointerAuth::authenticateLR(
170 MachineFunction &MF, MachineBasicBlock::iterator MBBI) const {
171 const AArch64FunctionInfo *MFnI = MF.getInfo<AArch64FunctionInfo>();
172 bool UseBKey = MFnI->shouldSignWithBKey();
173 bool EmitAsyncCFI = MFnI->needsAsyncDwarfUnwindInfo(MF);
174 bool NeedsWinCFI = MF.hasWinCFI();
176 MachineBasicBlock &MBB = *MBBI->getParent();
177 DebugLoc DL = MBBI->getDebugLoc();
178 // MBBI points to a PAUTH_EPILOGUE instruction to be replaced and
179 // TI points to a terminator instruction that may or may not be combined.
180 // Note that inserting new instructions "before MBBI" and "before TI" is
181 // not the same because if ShadowCallStack is enabled, its instructions
182 // are placed between MBBI and TI.
183 MachineBasicBlock::iterator TI = MBB.getFirstInstrTerminator();
185 // The AUTIASP instruction assembles to a hint instruction before v8.3a so
186 // this instruction can safely used for any v8a architecture.
187 // From v8.3a onwards there are optimised authenticate LR and return
188 // instructions, namely RETA{A,B}, that can be used instead. In this case the
189 // DW_CFA_AARCH64_negate_ra_state can't be emitted.
190 bool TerminatorIsCombinable =
191 TI != MBB.end() && TI->getOpcode() == AArch64::RET;
192 MCSymbol *PACSym = MFnI->getSigningInstrLabel();
194 if (Subtarget->hasPAuth() && TerminatorIsCombinable && !NeedsWinCFI &&
195 !MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack)) {
196 if (MFnI->branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
197 assert(PACSym && "No PAC instruction to refer to");
198 emitPACSymOffsetIntoX16(*TII, MBB, MBBI, DL, PACSym);
199 BuildMI(MBB, TI, DL,
200 TII->get(UseBKey ? AArch64::RETABSPPCi : AArch64::RETAASPPCi))
201 .addSym(PACSym)
202 .copyImplicitOps(*MBBI)
203 .setMIFlag(MachineInstr::FrameDestroy);
204 } else {
205 BuildPACM(*Subtarget, MBB, TI, DL, MachineInstr::FrameDestroy, PACSym);
206 BuildMI(MBB, TI, DL, TII->get(UseBKey ? AArch64::RETAB : AArch64::RETAA))
207 .copyImplicitOps(*MBBI)
208 .setMIFlag(MachineInstr::FrameDestroy);
210 MBB.erase(TI);
211 } else {
212 if (MFnI->branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
213 assert(PACSym && "No PAC instruction to refer to");
214 emitPACSymOffsetIntoX16(*TII, MBB, MBBI, DL, PACSym);
215 emitPACCFI(*Subtarget, MBB, MBBI, DL, MachineInstr::FrameDestroy,
216 EmitAsyncCFI);
217 BuildMI(MBB, MBBI, DL,
218 TII->get(UseBKey ? AArch64::AUTIBSPPCi : AArch64::AUTIASPPCi))
219 .addSym(PACSym)
220 .setMIFlag(MachineInstr::FrameDestroy);
221 } else {
222 BuildPACM(*Subtarget, MBB, MBBI, DL, MachineInstr::FrameDestroy, PACSym);
223 emitPACCFI(*Subtarget, MBB, MBBI, DL, MachineInstr::FrameDestroy,
224 EmitAsyncCFI);
225 BuildMI(MBB, MBBI, DL,
226 TII->get(UseBKey ? AArch64::AUTIBSP : AArch64::AUTIASP))
227 .setMIFlag(MachineInstr::FrameDestroy);
230 if (NeedsWinCFI) {
231 BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR))
232 .setMIFlag(MachineInstr::FrameDestroy);
237 unsigned llvm::AArch64PAuth::getCheckerSizeInBytes(AuthCheckMethod Method) {
238 switch (Method) {
239 case AuthCheckMethod::None:
240 return 0;
241 case AuthCheckMethod::DummyLoad:
242 return 4;
243 case AuthCheckMethod::HighBitsNoTBI:
244 return 12;
245 case AuthCheckMethod::XPACHint:
246 case AuthCheckMethod::XPAC:
247 return 20;
249 llvm_unreachable("Unknown AuthCheckMethod enum");
252 void AArch64PointerAuth::emitBlend(MachineBasicBlock::iterator MBBI,
253 Register Result, Register AddrDisc,
254 unsigned IntDisc) const {
255 MachineBasicBlock &MBB = *MBBI->getParent();
256 DebugLoc DL = MBBI->getDebugLoc();
258 if (Result != AddrDisc)
259 BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrs), Result)
260 .addReg(AArch64::XZR)
261 .addReg(AddrDisc)
262 .addImm(0);
264 BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVKXi), Result)
265 .addReg(Result)
266 .addImm(IntDisc)
267 .addImm(48);
270 void AArch64PointerAuth::expandPAuthBlend(
271 MachineBasicBlock::iterator MBBI) const {
272 Register ResultReg = MBBI->getOperand(0).getReg();
273 Register AddrDisc = MBBI->getOperand(1).getReg();
274 unsigned IntDisc = MBBI->getOperand(2).getImm();
275 emitBlend(MBBI, ResultReg, AddrDisc, IntDisc);
278 bool AArch64PointerAuth::runOnMachineFunction(MachineFunction &MF) {
279 Subtarget = &MF.getSubtarget<AArch64Subtarget>();
280 TII = Subtarget->getInstrInfo();
282 SmallVector<MachineBasicBlock::instr_iterator> PAuthPseudoInstrs;
284 bool Modified = false;
286 for (auto &MBB : MF) {
287 for (auto &MI : MBB) {
288 switch (MI.getOpcode()) {
289 default:
290 break;
291 case AArch64::PAUTH_PROLOGUE:
292 case AArch64::PAUTH_EPILOGUE:
293 case AArch64::PAUTH_BLEND:
294 PAuthPseudoInstrs.push_back(MI.getIterator());
295 break;
300 for (auto It : PAuthPseudoInstrs) {
301 switch (It->getOpcode()) {
302 case AArch64::PAUTH_PROLOGUE:
303 signLR(MF, It);
304 break;
305 case AArch64::PAUTH_EPILOGUE:
306 authenticateLR(MF, It);
307 break;
308 case AArch64::PAUTH_BLEND:
309 expandPAuthBlend(It);
310 break;
311 default:
312 llvm_unreachable("Unhandled opcode");
314 It->eraseFromParent();
315 Modified = true;
318 return Modified;