230 lines · cpp
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-exception7//8//===----------------------------------------------------------------------===//9///10/// \file11/// This file implements AArch64-specific per-machine-function12/// 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, &llvm::AArch64FunctionInfo::getStackSizeZPR)),40 StackSizePPR(41 getSVEStackSize(MFI, &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, *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(YamlMFI.StackSizeZPR.value_or(0),60 YamlMFI.StackSizePPR.value_or(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("ptrauth-returns"))69 return SignReturnAddress::NonLeaf;70 71 // The function should be signed in the following situations:72 // - sign-return-address=all73 // - sign-return-address=non-leaf and the functions spills the LR74 if (!F.hasFnAttribute("sign-return-address"))75 return SignReturnAddress::None;76 77 StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString();78 return StringSwitch<SignReturnAddress>(Scope)79 .Case("none", SignReturnAddress::None)80 .Case("non-leaf", SignReturnAddress::NonLeaf)81 .Case("all", SignReturnAddress::All);82}83 84static bool ShouldSignWithBKey(const Function &F, const AArch64Subtarget &STI) {85 if (F.hasFnAttribute("ptrauth-returns"))86 return true;87 if (!F.hasFnAttribute("sign-return-address-key")) {88 if (STI.getTargetTriple().isOSWindows())89 return true;90 return false;91 }92 93 const StringRef Key =94 F.getFnAttribute("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 M->getModuleFlag("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, set114 // HasRedZone here.115 if (F.hasFnAttribute(Attribute::NoRedZone))116 HasRedZone = false;117 SignCondition = GetSignReturnAddress(F);118 SignWithBKey = ShouldSignWithBKey(F, *STI);119 HasELFSignedGOT = hasELFSignedGOTHelper(F, STI);120 // TODO: skip functions that have no instrumented allocas for optimization121 IsMTETagged = F.hasFnAttribute(Attribute::SanitizeMemTag);122 123 // BTI/PAuthLR are set on the function attribute.124 BranchTargetEnforcement = F.hasFnAttribute("branch-target-enforcement");125 BranchProtectionPAuthLR = F.hasFnAttribute("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 no131 // stack-probe-size attribute. This is a safe default because it is the132 // smallest possible guard page size.133 uint64_t ProbeSize = 4096;134 if (F.hasFnAttribute("stack-probe-size"))135 ProbeSize = F.getFnAttributeAsParsedInteger("stack-probe-size");136 else if (const auto *PS = mdconst::extract_or_null<ConstantInt>(137 F.getParent()->getModuleFlag("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("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(StackAlign, ProbeSize & ~(StackAlign - 1U));149 StringRef ProbeKind;150 if (F.hasFnAttribute("probe-stack"))151 ProbeKind = F.getFnAttribute("probe-stack").getValueAsString();152 else if (const auto *PS = dyn_cast_or_null<MDString>(153 F.getParent()->getModuleFlag("probe-stack")))154 ProbeKind = PS->getString();155 if (ProbeKind.size()) {156 if (ProbeKind != "inline-asm")157 report_fatal_error("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>(*this);168}169 170static bool isLRSpilled(const MachineFunction &MF) {171 return llvm::any_of(172 MF.getFrameInfo().getCalleeSavedInfo(),173 [](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(SignCondition, isLRSpilled(MF));192}193 194bool AArch64FunctionInfo::needsShadowCallStackPrologueEpilogue(195 MachineFunction &MF) const {196 if (!(isLRSpilled(MF) &&197 MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack)))198 return false;199 200 if (!MF.getSubtarget<AArch64Subtarget>().isXRegisterReserved(18))201 report_fatal_error("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 emitted221 // (yet) for homogeneous epilogues, outlined functions, and functions222 // outlined from.223 NeedsAsyncDwarfUnwindInfo =224 needsDwarfUnwindInfo(MF) &&225 ((F.getUWTableKind() == UWTableKind::Async && !F.hasMinSize()) ||226 AFI->hasStreamingModeChanges());227 }228 return *NeedsAsyncDwarfUnwindInfo;229}230