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 | // The function should be signed in the following situations: |
42 | // - sign-return-address=all |
43 | // - sign-return-address=non-leaf and the functions spills the LR |
44 | if (!F.hasFnAttribute(Kind: "sign-return-address" )) { |
45 | const Module &M = *F.getParent(); |
46 | if (const auto *Sign = mdconst::extract_or_null<ConstantInt>( |
47 | MD: M.getModuleFlag(Key: "sign-return-address" ))) { |
48 | if (Sign->getZExtValue()) { |
49 | if (const auto *All = mdconst::extract_or_null<ConstantInt>( |
50 | MD: M.getModuleFlag(Key: "sign-return-address-all" ))) |
51 | return {true, All->getZExtValue()}; |
52 | return {true, false}; |
53 | } |
54 | } |
55 | return {false, false}; |
56 | } |
57 | |
58 | StringRef Scope = F.getFnAttribute(Kind: "sign-return-address" ).getValueAsString(); |
59 | if (Scope.equals(RHS: "none" )) |
60 | return {false, false}; |
61 | |
62 | if (Scope.equals(RHS: "all" )) |
63 | return {true, true}; |
64 | |
65 | assert(Scope.equals("non-leaf" )); |
66 | return {true, false}; |
67 | } |
68 | |
69 | static bool ShouldSignWithBKey(const Function &F, const AArch64Subtarget &STI) { |
70 | if (!F.hasFnAttribute(Kind: "sign-return-address-key" )) { |
71 | if (const auto *BKey = mdconst::extract_or_null<ConstantInt>( |
72 | MD: F.getParent()->getModuleFlag(Key: "sign-return-address-with-bkey" ))) |
73 | return BKey->getZExtValue(); |
74 | if (STI.getTargetTriple().isOSWindows()) |
75 | return true; |
76 | return false; |
77 | } |
78 | |
79 | const StringRef Key = |
80 | F.getFnAttribute(Kind: "sign-return-address-key" ).getValueAsString(); |
81 | assert(Key == "a_key" || Key == "b_key" ); |
82 | return Key == "b_key" ; |
83 | } |
84 | |
85 | AArch64FunctionInfo::AArch64FunctionInfo(const Function &F, |
86 | const AArch64Subtarget *STI) { |
87 | // If we already know that the function doesn't have a redzone, set |
88 | // HasRedZone here. |
89 | if (F.hasFnAttribute(Attribute::NoRedZone)) |
90 | HasRedZone = false; |
91 | std::tie(args&: SignReturnAddress, args&: SignReturnAddressAll) = GetSignReturnAddress(F); |
92 | SignWithBKey = ShouldSignWithBKey(F, STI: *STI); |
93 | // TODO: skip functions that have no instrumented allocas for optimization |
94 | IsMTETagged = F.hasFnAttribute(Attribute::SanitizeMemTag); |
95 | |
96 | // BTI/PAuthLR may be set either on the function or the module. Set Bool from |
97 | // either the function attribute or module attribute, depending on what is |
98 | // set. |
99 | // Note: the module attributed is numeric (0 or 1) but the function attribute |
100 | // is stringy ("true" or "false"). |
101 | auto TryFnThenModule = [&](StringRef AttrName, bool &Bool) { |
102 | if (F.hasFnAttribute(Kind: AttrName)) { |
103 | const StringRef V = F.getFnAttribute(Kind: AttrName).getValueAsString(); |
104 | assert(V.equals_insensitive("true" ) || V.equals_insensitive("false" )); |
105 | Bool = V.equals_insensitive(RHS: "true" ); |
106 | } else if (const auto *ModVal = mdconst::extract_or_null<ConstantInt>( |
107 | MD: F.getParent()->getModuleFlag(Key: AttrName))) { |
108 | Bool = ModVal->getZExtValue(); |
109 | } |
110 | }; |
111 | |
112 | TryFnThenModule("branch-target-enforcement" , BranchTargetEnforcement); |
113 | TryFnThenModule("branch-protection-pauth-lr" , BranchProtectionPAuthLR); |
114 | |
115 | // The default stack probe size is 4096 if the function has no |
116 | // stack-probe-size attribute. This is a safe default because it is the |
117 | // smallest possible guard page size. |
118 | uint64_t ProbeSize = 4096; |
119 | if (F.hasFnAttribute(Kind: "stack-probe-size" )) |
120 | ProbeSize = F.getFnAttributeAsParsedInteger(Kind: "stack-probe-size" ); |
121 | else if (const auto *PS = mdconst::extract_or_null<ConstantInt>( |
122 | MD: F.getParent()->getModuleFlag(Key: "stack-probe-size" ))) |
123 | ProbeSize = PS->getZExtValue(); |
124 | assert(int64_t(ProbeSize) > 0 && "Invalid stack probe size" ); |
125 | |
126 | if (STI->isTargetWindows()) { |
127 | if (!F.hasFnAttribute(Kind: "no-stack-arg-probe" )) |
128 | StackProbeSize = ProbeSize; |
129 | } else { |
130 | // Round down to the stack alignment. |
131 | uint64_t StackAlign = |
132 | STI->getFrameLowering()->getTransientStackAlign().value(); |
133 | ProbeSize = std::max(a: StackAlign, b: ProbeSize & ~(StackAlign - 1U)); |
134 | StringRef ProbeKind; |
135 | if (F.hasFnAttribute(Kind: "probe-stack" )) |
136 | ProbeKind = F.getFnAttribute(Kind: "probe-stack" ).getValueAsString(); |
137 | else if (const auto *PS = dyn_cast_or_null<MDString>( |
138 | Val: F.getParent()->getModuleFlag(Key: "probe-stack" ))) |
139 | ProbeKind = PS->getString(); |
140 | if (ProbeKind.size()) { |
141 | if (ProbeKind != "inline-asm" ) |
142 | report_fatal_error(reason: "Unsupported stack probing method" ); |
143 | StackProbeSize = ProbeSize; |
144 | } |
145 | } |
146 | } |
147 | |
148 | MachineFunctionInfo *AArch64FunctionInfo::clone( |
149 | BumpPtrAllocator &Allocator, MachineFunction &DestMF, |
150 | const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) |
151 | const { |
152 | return DestMF.cloneInfo<AArch64FunctionInfo>(Old: *this); |
153 | } |
154 | |
155 | bool AArch64FunctionInfo::shouldSignReturnAddress(bool SpillsLR) const { |
156 | if (!SignReturnAddress) |
157 | return false; |
158 | if (SignReturnAddressAll) |
159 | return true; |
160 | return SpillsLR; |
161 | } |
162 | |
163 | static bool isLRSpilled(const MachineFunction &MF) { |
164 | return llvm::any_of( |
165 | Range: MF.getFrameInfo().getCalleeSavedInfo(), |
166 | P: [](const auto &Info) { return Info.getReg() == AArch64::LR; }); |
167 | } |
168 | |
169 | bool AArch64FunctionInfo::shouldSignReturnAddress( |
170 | const MachineFunction &MF) const { |
171 | return shouldSignReturnAddress(SpillsLR: isLRSpilled(MF)); |
172 | } |
173 | |
174 | bool AArch64FunctionInfo::needsShadowCallStackPrologueEpilogue( |
175 | MachineFunction &MF) const { |
176 | if (!(isLRSpilled(MF) && |
177 | MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack))) |
178 | return false; |
179 | |
180 | if (!MF.getSubtarget<AArch64Subtarget>().isXRegisterReserved(i: 18)) |
181 | report_fatal_error(reason: "Must reserve x18 to use shadow call stack" ); |
182 | |
183 | return true; |
184 | } |
185 | |
186 | bool AArch64FunctionInfo::needsDwarfUnwindInfo( |
187 | const MachineFunction &MF) const { |
188 | if (!NeedsDwarfUnwindInfo) |
189 | NeedsDwarfUnwindInfo = MF.needsFrameMoves() && |
190 | !MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); |
191 | |
192 | return *NeedsDwarfUnwindInfo; |
193 | } |
194 | |
195 | bool AArch64FunctionInfo::needsAsyncDwarfUnwindInfo( |
196 | const MachineFunction &MF) const { |
197 | if (!NeedsAsyncDwarfUnwindInfo) { |
198 | const Function &F = MF.getFunction(); |
199 | // The check got "minsize" is because epilogue unwind info is not emitted |
200 | // (yet) for homogeneous epilogues, outlined functions, and functions |
201 | // outlined from. |
202 | NeedsAsyncDwarfUnwindInfo = needsDwarfUnwindInfo(MF) && |
203 | F.getUWTableKind() == UWTableKind::Async && |
204 | !F.hasMinSize(); |
205 | } |
206 | return *NeedsAsyncDwarfUnwindInfo; |
207 | } |
208 | |