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/IR/Constants.h" |
20 | #include "llvm/IR/Metadata.h" |
21 | #include "llvm/IR/Module.h" |
22 | #include "llvm/MC/MCAsmInfo.h" |
23 | |
24 | using namespace llvm; |
25 | |
26 | yaml::AArch64FunctionInfo::AArch64FunctionInfo( |
27 | const llvm::AArch64FunctionInfo &MFI) |
28 | : HasRedZone(MFI.hasRedZone()) {} |
29 | |
30 | void yaml::AArch64FunctionInfo::mappingImpl(yaml::IO &YamlIO) { |
31 | MappingTraits<AArch64FunctionInfo>::mapping(YamlIO, MFI&: *this); |
32 | } |
33 | |
34 | void AArch64FunctionInfo::initializeBaseYamlFields( |
35 | const yaml::AArch64FunctionInfo &YamlMFI) { |
36 | if (YamlMFI.HasRedZone) |
37 | HasRedZone = YamlMFI.HasRedZone; |
38 | } |
39 | |
40 | static std::pair<bool, bool> GetSignReturnAddress(const Function &F) { |
41 | if (F.hasFnAttribute(Kind: "ptrauth-returns" )) |
42 | return {true, false}; // non-leaf |
43 | // The function should be signed in the following situations: |
44 | // - sign-return-address=all |
45 | // - sign-return-address=non-leaf and the functions spills the LR |
46 | if (!F.hasFnAttribute(Kind: "sign-return-address" )) |
47 | return {false, false}; |
48 | |
49 | StringRef Scope = F.getFnAttribute(Kind: "sign-return-address" ).getValueAsString(); |
50 | if (Scope == "none" ) |
51 | return {false, false}; |
52 | |
53 | if (Scope == "all" ) |
54 | return {true, true}; |
55 | |
56 | assert(Scope == "non-leaf" ); |
57 | return {true, false}; |
58 | } |
59 | |
60 | static bool ShouldSignWithBKey(const Function &F, const AArch64Subtarget &STI) { |
61 | if (F.hasFnAttribute(Kind: "ptrauth-returns" )) |
62 | return true; |
63 | if (!F.hasFnAttribute(Kind: "sign-return-address-key" )) { |
64 | if (STI.getTargetTriple().isOSWindows()) |
65 | return true; |
66 | return false; |
67 | } |
68 | |
69 | const StringRef Key = |
70 | F.getFnAttribute(Kind: "sign-return-address-key" ).getValueAsString(); |
71 | assert(Key == "a_key" || Key == "b_key" ); |
72 | return Key == "b_key" ; |
73 | } |
74 | |
75 | AArch64FunctionInfo::AArch64FunctionInfo(const Function &F, |
76 | const AArch64Subtarget *STI) { |
77 | // If we already know that the function doesn't have a redzone, set |
78 | // HasRedZone here. |
79 | if (F.hasFnAttribute(Kind: Attribute::NoRedZone)) |
80 | HasRedZone = false; |
81 | std::tie(args&: SignReturnAddress, args&: SignReturnAddressAll) = GetSignReturnAddress(F); |
82 | SignWithBKey = ShouldSignWithBKey(F, STI: *STI); |
83 | // TODO: skip functions that have no instrumented allocas for optimization |
84 | IsMTETagged = F.hasFnAttribute(Kind: Attribute::SanitizeMemTag); |
85 | |
86 | // BTI/PAuthLR are set on the function attribute. |
87 | BranchTargetEnforcement = F.hasFnAttribute(Kind: "branch-target-enforcement" ); |
88 | BranchProtectionPAuthLR = F.hasFnAttribute(Kind: "branch-protection-pauth-lr" ); |
89 | |
90 | // The default stack probe size is 4096 if the function has no |
91 | // stack-probe-size attribute. This is a safe default because it is the |
92 | // smallest possible guard page size. |
93 | uint64_t ProbeSize = 4096; |
94 | if (F.hasFnAttribute(Kind: "stack-probe-size" )) |
95 | ProbeSize = F.getFnAttributeAsParsedInteger(Kind: "stack-probe-size" ); |
96 | else if (const auto *PS = mdconst::extract_or_null<ConstantInt>( |
97 | MD: F.getParent()->getModuleFlag(Key: "stack-probe-size" ))) |
98 | ProbeSize = PS->getZExtValue(); |
99 | assert(int64_t(ProbeSize) > 0 && "Invalid stack probe size" ); |
100 | |
101 | if (STI->isTargetWindows()) { |
102 | if (!F.hasFnAttribute(Kind: "no-stack-arg-probe" )) |
103 | StackProbeSize = ProbeSize; |
104 | } else { |
105 | // Round down to the stack alignment. |
106 | uint64_t StackAlign = |
107 | STI->getFrameLowering()->getTransientStackAlign().value(); |
108 | ProbeSize = std::max(a: StackAlign, b: ProbeSize & ~(StackAlign - 1U)); |
109 | StringRef ProbeKind; |
110 | if (F.hasFnAttribute(Kind: "probe-stack" )) |
111 | ProbeKind = F.getFnAttribute(Kind: "probe-stack" ).getValueAsString(); |
112 | else if (const auto *PS = dyn_cast_or_null<MDString>( |
113 | Val: F.getParent()->getModuleFlag(Key: "probe-stack" ))) |
114 | ProbeKind = PS->getString(); |
115 | if (ProbeKind.size()) { |
116 | if (ProbeKind != "inline-asm" ) |
117 | report_fatal_error(reason: "Unsupported stack probing method" ); |
118 | StackProbeSize = ProbeSize; |
119 | } |
120 | } |
121 | } |
122 | |
123 | MachineFunctionInfo *AArch64FunctionInfo::clone( |
124 | BumpPtrAllocator &Allocator, MachineFunction &DestMF, |
125 | const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) |
126 | const { |
127 | return DestMF.cloneInfo<AArch64FunctionInfo>(Old: *this); |
128 | } |
129 | |
130 | bool AArch64FunctionInfo::shouldSignReturnAddress(bool SpillsLR) const { |
131 | if (!SignReturnAddress) |
132 | return false; |
133 | if (SignReturnAddressAll) |
134 | return true; |
135 | return SpillsLR; |
136 | } |
137 | |
138 | static bool isLRSpilled(const MachineFunction &MF) { |
139 | return llvm::any_of( |
140 | Range: MF.getFrameInfo().getCalleeSavedInfo(), |
141 | P: [](const auto &Info) { return Info.getReg() == AArch64::LR; }); |
142 | } |
143 | |
144 | bool AArch64FunctionInfo::shouldSignReturnAddress( |
145 | const MachineFunction &MF) const { |
146 | return shouldSignReturnAddress(SpillsLR: isLRSpilled(MF)); |
147 | } |
148 | |
149 | bool AArch64FunctionInfo::needsShadowCallStackPrologueEpilogue( |
150 | MachineFunction &MF) const { |
151 | if (!(isLRSpilled(MF) && |
152 | MF.getFunction().hasFnAttribute(Kind: Attribute::ShadowCallStack))) |
153 | return false; |
154 | |
155 | if (!MF.getSubtarget<AArch64Subtarget>().isXRegisterReserved(i: 18)) |
156 | report_fatal_error(reason: "Must reserve x18 to use shadow call stack" ); |
157 | |
158 | return true; |
159 | } |
160 | |
161 | bool AArch64FunctionInfo::needsDwarfUnwindInfo( |
162 | const MachineFunction &MF) const { |
163 | if (!NeedsDwarfUnwindInfo) |
164 | NeedsDwarfUnwindInfo = MF.needsFrameMoves() && |
165 | !MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); |
166 | |
167 | return *NeedsDwarfUnwindInfo; |
168 | } |
169 | |
170 | bool AArch64FunctionInfo::needsAsyncDwarfUnwindInfo( |
171 | const MachineFunction &MF) const { |
172 | if (!NeedsAsyncDwarfUnwindInfo) { |
173 | const Function &F = MF.getFunction(); |
174 | const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>(); |
175 | // The check got "minsize" is because epilogue unwind info is not emitted |
176 | // (yet) for homogeneous epilogues, outlined functions, and functions |
177 | // outlined from. |
178 | NeedsAsyncDwarfUnwindInfo = |
179 | needsDwarfUnwindInfo(MF) && |
180 | ((F.getUWTableKind() == UWTableKind::Async && !F.hasMinSize()) || |
181 | AFI->hasStreamingModeChanges()); |
182 | } |
183 | return *NeedsAsyncDwarfUnwindInfo; |
184 | } |
185 | |