1//=- AArch64MachineFunctionInfo.cpp - AArch64 Machine Function Info ---------=//
2
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// This file implements AArch64-specific per-machine-function
12/// information.
13///
14//===----------------------------------------------------------------------===//
15
16#include "AArch64MachineFunctionInfo.h"
17#include "AArch64InstrInfo.h"
18#include "AArch64Subtarget.h"
19#include "llvm/ADT/StringSwitch.h"
20#include "llvm/IR/Constants.h"
21#include "llvm/IR/Metadata.h"
22#include "llvm/IR/Module.h"
23#include "llvm/MC/MCAsmInfo.h"
24
25using namespace llvm;
26
27static std::optional<uint64_t>
28getSVEStackSize(const AArch64FunctionInfo &MFI,
29 uint64_t (AArch64FunctionInfo::*GetStackSize)() const) {
30 if (!MFI.hasCalculatedStackSizeSVE())
31 return std::nullopt;
32 return (MFI.*GetStackSize)();
33}
34
35yaml::AArch64FunctionInfo::AArch64FunctionInfo(
36 const llvm::AArch64FunctionInfo &MFI)
37 : HasRedZone(MFI.hasRedZone()),
38 StackSizeZPR(
39 getSVEStackSize(MFI, GetStackSize: &llvm::AArch64FunctionInfo::getStackSizeZPR)),
40 StackSizePPR(
41 getSVEStackSize(MFI, GetStackSize: &llvm::AArch64FunctionInfo::getStackSizePPR)),
42 HasStackFrame(MFI.hasStackFrame()
43 ? std::optional<bool>(MFI.hasStackFrame())
44 : std::nullopt),
45 HasStreamingModeChanges(
46 MFI.hasStreamingModeChanges()
47 ? std::optional<bool>(MFI.hasStreamingModeChanges())
48 : std::nullopt) {}
49
50void yaml::AArch64FunctionInfo::mappingImpl(yaml::IO &YamlIO) {
51 MappingTraits<AArch64FunctionInfo>::mapping(YamlIO, MFI&: *this);
52}
53
54void AArch64FunctionInfo::initializeBaseYamlFields(
55 const yaml::AArch64FunctionInfo &YamlMFI) {
56 if (YamlMFI.HasRedZone)
57 HasRedZone = YamlMFI.HasRedZone;
58 if (YamlMFI.StackSizeZPR || YamlMFI.StackSizePPR)
59 setStackSizeSVE(ZPR: YamlMFI.StackSizeZPR.value_or(u: 0),
60 PPR: YamlMFI.StackSizePPR.value_or(u: 0));
61 if (YamlMFI.HasStackFrame)
62 setHasStackFrame(*YamlMFI.HasStackFrame);
63 if (YamlMFI.HasStreamingModeChanges)
64 setHasStreamingModeChanges(*YamlMFI.HasStreamingModeChanges);
65}
66
67static SignReturnAddress GetSignReturnAddress(const Function &F) {
68 if (F.hasFnAttribute(Kind: "ptrauth-returns"))
69 return SignReturnAddress::NonLeaf;
70
71 // The function should be signed in the following situations:
72 // - sign-return-address=all
73 // - sign-return-address=non-leaf and the functions spills the LR
74 if (!F.hasFnAttribute(Kind: "sign-return-address"))
75 return SignReturnAddress::None;
76
77 StringRef Scope = F.getFnAttribute(Kind: "sign-return-address").getValueAsString();
78 return StringSwitch<SignReturnAddress>(Scope)
79 .Case(S: "none", Value: SignReturnAddress::None)
80 .Case(S: "non-leaf", Value: SignReturnAddress::NonLeaf)
81 .Case(S: "all", Value: SignReturnAddress::All);
82}
83
84static bool ShouldSignWithBKey(const Function &F, const AArch64Subtarget &STI) {
85 if (F.hasFnAttribute(Kind: "ptrauth-returns"))
86 return true;
87 if (!F.hasFnAttribute(Kind: "sign-return-address-key")) {
88 if (STI.getTargetTriple().isOSWindows())
89 return true;
90 return false;
91 }
92
93 const StringRef Key =
94 F.getFnAttribute(Kind: "sign-return-address-key").getValueAsString();
95 assert(Key == "a_key" || Key == "b_key");
96 return Key == "b_key";
97}
98
99static bool hasELFSignedGOTHelper(const Function &F,
100 const AArch64Subtarget *STI) {
101 if (!STI->getTargetTriple().isOSBinFormatELF())
102 return false;
103 const Module *M = F.getParent();
104 const auto *Flag = mdconst::extract_or_null<ConstantInt>(
105 MD: M->getModuleFlag(Key: "ptrauth-elf-got"));
106 if (Flag && Flag->getZExtValue() == 1)
107 return true;
108 return false;
109}
110
111AArch64FunctionInfo::AArch64FunctionInfo(const Function &F,
112 const AArch64Subtarget *STI) {
113 // If we already know that the function doesn't have a redzone, set
114 // HasRedZone here.
115 if (F.hasFnAttribute(Kind: Attribute::NoRedZone))
116 HasRedZone = false;
117 SignCondition = GetSignReturnAddress(F);
118 SignWithBKey = ShouldSignWithBKey(F, STI: *STI);
119 HasELFSignedGOT = hasELFSignedGOTHelper(F, STI);
120 // TODO: skip functions that have no instrumented allocas for optimization
121 IsMTETagged = F.hasFnAttribute(Kind: Attribute::SanitizeMemTag);
122
123 // BTI/PAuthLR are set on the function attribute.
124 BranchTargetEnforcement = F.hasFnAttribute(Kind: "branch-target-enforcement");
125 BranchProtectionPAuthLR = F.hasFnAttribute(Kind: "branch-protection-pauth-lr");
126
127 // Parse the SME function attributes.
128 SMEFnAttrs = SMEAttrs(F);
129
130 // The default stack probe size is 4096 if the function has no
131 // stack-probe-size attribute. This is a safe default because it is the
132 // smallest possible guard page size.
133 uint64_t ProbeSize = 4096;
134 if (F.hasFnAttribute(Kind: "stack-probe-size"))
135 ProbeSize = F.getFnAttributeAsParsedInteger(Kind: "stack-probe-size");
136 else if (const auto *PS = mdconst::extract_or_null<ConstantInt>(
137 MD: F.getParent()->getModuleFlag(Key: "stack-probe-size")))
138 ProbeSize = PS->getZExtValue();
139 assert(int64_t(ProbeSize) > 0 && "Invalid stack probe size");
140
141 if (STI->isTargetWindows()) {
142 if (!F.hasFnAttribute(Kind: "no-stack-arg-probe"))
143 StackProbeSize = ProbeSize;
144 } else {
145 // Round down to the stack alignment.
146 uint64_t StackAlign =
147 STI->getFrameLowering()->getTransientStackAlign().value();
148 ProbeSize = std::max(a: StackAlign, b: ProbeSize & ~(StackAlign - 1U));
149 StringRef ProbeKind;
150 if (F.hasFnAttribute(Kind: "probe-stack"))
151 ProbeKind = F.getFnAttribute(Kind: "probe-stack").getValueAsString();
152 else if (const auto *PS = dyn_cast_or_null<MDString>(
153 Val: F.getParent()->getModuleFlag(Key: "probe-stack")))
154 ProbeKind = PS->getString();
155 if (ProbeKind.size()) {
156 if (ProbeKind != "inline-asm")
157 report_fatal_error(reason: "Unsupported stack probing method");
158 StackProbeSize = ProbeSize;
159 }
160 }
161}
162
163MachineFunctionInfo *AArch64FunctionInfo::clone(
164 BumpPtrAllocator &Allocator, MachineFunction &DestMF,
165 const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB)
166 const {
167 return DestMF.cloneInfo<AArch64FunctionInfo>(Old: *this);
168}
169
170static bool isLRSpilled(const MachineFunction &MF) {
171 return llvm::any_of(
172 Range: MF.getFrameInfo().getCalleeSavedInfo(),
173 P: [](const auto &Info) { return Info.getReg() == AArch64::LR; });
174}
175
176bool AArch64FunctionInfo::shouldSignReturnAddress(SignReturnAddress Condition,
177 bool IsLRSpilled) {
178 switch (Condition) {
179 case SignReturnAddress::None:
180 return false;
181 case SignReturnAddress::NonLeaf:
182 return IsLRSpilled;
183 case SignReturnAddress::All:
184 return true;
185 }
186 llvm_unreachable("Unknown SignReturnAddress enum");
187}
188
189bool AArch64FunctionInfo::shouldSignReturnAddress(
190 const MachineFunction &MF) const {
191 return shouldSignReturnAddress(Condition: SignCondition, IsLRSpilled: isLRSpilled(MF));
192}
193
194bool AArch64FunctionInfo::needsShadowCallStackPrologueEpilogue(
195 MachineFunction &MF) const {
196 if (!(isLRSpilled(MF) &&
197 MF.getFunction().hasFnAttribute(Kind: Attribute::ShadowCallStack)))
198 return false;
199
200 if (!MF.getSubtarget<AArch64Subtarget>().isXRegisterReserved(i: 18))
201 report_fatal_error(reason: "Must reserve x18 to use shadow call stack");
202
203 return true;
204}
205
206bool AArch64FunctionInfo::needsDwarfUnwindInfo(
207 const MachineFunction &MF) const {
208 if (!NeedsDwarfUnwindInfo)
209 NeedsDwarfUnwindInfo = MF.needsFrameMoves() &&
210 !MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
211
212 return *NeedsDwarfUnwindInfo;
213}
214
215bool AArch64FunctionInfo::needsAsyncDwarfUnwindInfo(
216 const MachineFunction &MF) const {
217 if (!NeedsAsyncDwarfUnwindInfo) {
218 const Function &F = MF.getFunction();
219 const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
220 // The check got "minsize" is because epilogue unwind info is not emitted
221 // (yet) for homogeneous epilogues, outlined functions, and functions
222 // outlined from.
223 NeedsAsyncDwarfUnwindInfo =
224 needsDwarfUnwindInfo(MF) &&
225 ((F.getUWTableKind() == UWTableKind::Async && !F.hasMinSize()) ||
226 AFI->hasStreamingModeChanges());
227 }
228 return *NeedsAsyncDwarfUnwindInfo;
229}
230