15ffd83dbSDimitry Andric //=- AArch64MachineFunctionInfo.cpp - AArch64 Machine Function Info ---------=// 25ffd83dbSDimitry Andric 35ffd83dbSDimitry Andric // 45ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 55ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 65ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 75ffd83dbSDimitry Andric // 85ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 95ffd83dbSDimitry Andric /// 105ffd83dbSDimitry Andric /// \file 115ffd83dbSDimitry Andric /// This file implements AArch64-specific per-machine-function 125ffd83dbSDimitry Andric /// information. 135ffd83dbSDimitry Andric /// 145ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 155ffd83dbSDimitry Andric 165ffd83dbSDimitry Andric #include "AArch64MachineFunctionInfo.h" 17e8d8bef9SDimitry Andric #include "AArch64InstrInfo.h" 1881ad6265SDimitry Andric #include "AArch64Subtarget.h" 1981ad6265SDimitry Andric #include "llvm/IR/Constants.h" 2081ad6265SDimitry Andric #include "llvm/IR/Metadata.h" 2181ad6265SDimitry Andric #include "llvm/IR/Module.h" 2281ad6265SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 235ffd83dbSDimitry Andric 245ffd83dbSDimitry Andric using namespace llvm; 255ffd83dbSDimitry Andric 265ffd83dbSDimitry Andric yaml::AArch64FunctionInfo::AArch64FunctionInfo( 275ffd83dbSDimitry Andric const llvm::AArch64FunctionInfo &MFI) 285ffd83dbSDimitry Andric : HasRedZone(MFI.hasRedZone()) {} 295ffd83dbSDimitry Andric 305ffd83dbSDimitry Andric void yaml::AArch64FunctionInfo::mappingImpl(yaml::IO &YamlIO) { 315ffd83dbSDimitry Andric MappingTraits<AArch64FunctionInfo>::mapping(YamlIO, *this); 325ffd83dbSDimitry Andric } 335ffd83dbSDimitry Andric 345ffd83dbSDimitry Andric void AArch64FunctionInfo::initializeBaseYamlFields( 355ffd83dbSDimitry Andric const yaml::AArch64FunctionInfo &YamlMFI) { 3681ad6265SDimitry Andric if (YamlMFI.HasRedZone) 375ffd83dbSDimitry Andric HasRedZone = YamlMFI.HasRedZone; 385ffd83dbSDimitry Andric } 39e8d8bef9SDimitry Andric 40e8d8bef9SDimitry Andric static std::pair<bool, bool> GetSignReturnAddress(const Function &F) { 41*36b606aeSDimitry Andric if (F.hasFnAttribute("ptrauth-returns")) 42*36b606aeSDimitry Andric return {true, false}; // non-leaf 43e8d8bef9SDimitry Andric // The function should be signed in the following situations: 44e8d8bef9SDimitry Andric // - sign-return-address=all 45e8d8bef9SDimitry Andric // - sign-return-address=non-leaf and the functions spills the LR 460fca6ea1SDimitry Andric if (!F.hasFnAttribute("sign-return-address")) 47e8d8bef9SDimitry Andric return {false, false}; 48e8d8bef9SDimitry Andric 49e8d8bef9SDimitry Andric StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString(); 500fca6ea1SDimitry Andric if (Scope == "none") 51e8d8bef9SDimitry Andric return {false, false}; 52e8d8bef9SDimitry Andric 530fca6ea1SDimitry Andric if (Scope == "all") 54e8d8bef9SDimitry Andric return {true, true}; 55e8d8bef9SDimitry Andric 560fca6ea1SDimitry Andric assert(Scope == "non-leaf"); 57e8d8bef9SDimitry Andric return {true, false}; 58e8d8bef9SDimitry Andric } 59e8d8bef9SDimitry Andric 60bdd1243dSDimitry Andric static bool ShouldSignWithBKey(const Function &F, const AArch64Subtarget &STI) { 61*36b606aeSDimitry Andric if (F.hasFnAttribute("ptrauth-returns")) 62*36b606aeSDimitry Andric return true; 63e8d8bef9SDimitry Andric if (!F.hasFnAttribute("sign-return-address-key")) { 64bdd1243dSDimitry Andric if (STI.getTargetTriple().isOSWindows()) 65bdd1243dSDimitry Andric return true; 66e8d8bef9SDimitry Andric return false; 67e8d8bef9SDimitry Andric } 68e8d8bef9SDimitry Andric 69e8d8bef9SDimitry Andric const StringRef Key = 70e8d8bef9SDimitry Andric F.getFnAttribute("sign-return-address-key").getValueAsString(); 715f757f3fSDimitry Andric assert(Key == "a_key" || Key == "b_key"); 725f757f3fSDimitry Andric return Key == "b_key"; 73e8d8bef9SDimitry Andric } 74e8d8bef9SDimitry Andric 75bdd1243dSDimitry Andric AArch64FunctionInfo::AArch64FunctionInfo(const Function &F, 76bdd1243dSDimitry Andric const AArch64Subtarget *STI) { 77e8d8bef9SDimitry Andric // If we already know that the function doesn't have a redzone, set 78e8d8bef9SDimitry Andric // HasRedZone here. 79bdd1243dSDimitry Andric if (F.hasFnAttribute(Attribute::NoRedZone)) 80e8d8bef9SDimitry Andric HasRedZone = false; 81e8d8bef9SDimitry Andric std::tie(SignReturnAddress, SignReturnAddressAll) = GetSignReturnAddress(F); 82bdd1243dSDimitry Andric SignWithBKey = ShouldSignWithBKey(F, *STI); 8381ad6265SDimitry Andric // TODO: skip functions that have no instrumented allocas for optimization 8481ad6265SDimitry Andric IsMTETagged = F.hasFnAttribute(Attribute::SanitizeMemTag); 85e8d8bef9SDimitry Andric 860fca6ea1SDimitry Andric // BTI/PAuthLR are set on the function attribute. 870fca6ea1SDimitry Andric BranchTargetEnforcement = F.hasFnAttribute("branch-target-enforcement"); 880fca6ea1SDimitry Andric BranchProtectionPAuthLR = F.hasFnAttribute("branch-protection-pauth-lr"); 895f757f3fSDimitry Andric 905f757f3fSDimitry Andric // The default stack probe size is 4096 if the function has no 915f757f3fSDimitry Andric // stack-probe-size attribute. This is a safe default because it is the 925f757f3fSDimitry Andric // smallest possible guard page size. 935f757f3fSDimitry Andric uint64_t ProbeSize = 4096; 945f757f3fSDimitry Andric if (F.hasFnAttribute("stack-probe-size")) 955f757f3fSDimitry Andric ProbeSize = F.getFnAttributeAsParsedInteger("stack-probe-size"); 965f757f3fSDimitry Andric else if (const auto *PS = mdconst::extract_or_null<ConstantInt>( 975f757f3fSDimitry Andric F.getParent()->getModuleFlag("stack-probe-size"))) 985f757f3fSDimitry Andric ProbeSize = PS->getZExtValue(); 995f757f3fSDimitry Andric assert(int64_t(ProbeSize) > 0 && "Invalid stack probe size"); 1005f757f3fSDimitry Andric 1015f757f3fSDimitry Andric if (STI->isTargetWindows()) { 1025f757f3fSDimitry Andric if (!F.hasFnAttribute("no-stack-arg-probe")) 1035f757f3fSDimitry Andric StackProbeSize = ProbeSize; 1045f757f3fSDimitry Andric } else { 1055f757f3fSDimitry Andric // Round down to the stack alignment. 1065f757f3fSDimitry Andric uint64_t StackAlign = 1075f757f3fSDimitry Andric STI->getFrameLowering()->getTransientStackAlign().value(); 1085f757f3fSDimitry Andric ProbeSize = std::max(StackAlign, ProbeSize & ~(StackAlign - 1U)); 1095f757f3fSDimitry Andric StringRef ProbeKind; 1105f757f3fSDimitry Andric if (F.hasFnAttribute("probe-stack")) 1115f757f3fSDimitry Andric ProbeKind = F.getFnAttribute("probe-stack").getValueAsString(); 1125f757f3fSDimitry Andric else if (const auto *PS = dyn_cast_or_null<MDString>( 1135f757f3fSDimitry Andric F.getParent()->getModuleFlag("probe-stack"))) 1145f757f3fSDimitry Andric ProbeKind = PS->getString(); 1155f757f3fSDimitry Andric if (ProbeKind.size()) { 1165f757f3fSDimitry Andric if (ProbeKind != "inline-asm") 1175f757f3fSDimitry Andric report_fatal_error("Unsupported stack probing method"); 1185f757f3fSDimitry Andric StackProbeSize = ProbeSize; 1195f757f3fSDimitry Andric } 1205f757f3fSDimitry Andric } 121e8d8bef9SDimitry Andric } 122e8d8bef9SDimitry Andric 12381ad6265SDimitry Andric MachineFunctionInfo *AArch64FunctionInfo::clone( 12481ad6265SDimitry Andric BumpPtrAllocator &Allocator, MachineFunction &DestMF, 12581ad6265SDimitry Andric const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) 12681ad6265SDimitry Andric const { 127bdd1243dSDimitry Andric return DestMF.cloneInfo<AArch64FunctionInfo>(*this); 12881ad6265SDimitry Andric } 12981ad6265SDimitry Andric 130e8d8bef9SDimitry Andric bool AArch64FunctionInfo::shouldSignReturnAddress(bool SpillsLR) const { 131e8d8bef9SDimitry Andric if (!SignReturnAddress) 132e8d8bef9SDimitry Andric return false; 133e8d8bef9SDimitry Andric if (SignReturnAddressAll) 134e8d8bef9SDimitry Andric return true; 135e8d8bef9SDimitry Andric return SpillsLR; 136e8d8bef9SDimitry Andric } 137e8d8bef9SDimitry Andric 1385f757f3fSDimitry Andric static bool isLRSpilled(const MachineFunction &MF) { 1395f757f3fSDimitry Andric return llvm::any_of( 1405f757f3fSDimitry Andric MF.getFrameInfo().getCalleeSavedInfo(), 1415f757f3fSDimitry Andric [](const auto &Info) { return Info.getReg() == AArch64::LR; }); 1425f757f3fSDimitry Andric } 1435f757f3fSDimitry Andric 144bdd1243dSDimitry Andric bool AArch64FunctionInfo::shouldSignReturnAddress( 145bdd1243dSDimitry Andric const MachineFunction &MF) const { 1465f757f3fSDimitry Andric return shouldSignReturnAddress(isLRSpilled(MF)); 1475f757f3fSDimitry Andric } 1485f757f3fSDimitry Andric 1495f757f3fSDimitry Andric bool AArch64FunctionInfo::needsShadowCallStackPrologueEpilogue( 1505f757f3fSDimitry Andric MachineFunction &MF) const { 1515f757f3fSDimitry Andric if (!(isLRSpilled(MF) && 1525f757f3fSDimitry Andric MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack))) 1535f757f3fSDimitry Andric return false; 1545f757f3fSDimitry Andric 1555f757f3fSDimitry Andric if (!MF.getSubtarget<AArch64Subtarget>().isXRegisterReserved(18)) 1565f757f3fSDimitry Andric report_fatal_error("Must reserve x18 to use shadow call stack"); 1575f757f3fSDimitry Andric 1585f757f3fSDimitry Andric return true; 159e8d8bef9SDimitry Andric } 16081ad6265SDimitry Andric 161bdd1243dSDimitry Andric bool AArch64FunctionInfo::needsDwarfUnwindInfo( 162bdd1243dSDimitry Andric const MachineFunction &MF) const { 16381ad6265SDimitry Andric if (!NeedsDwarfUnwindInfo) 164bdd1243dSDimitry Andric NeedsDwarfUnwindInfo = MF.needsFrameMoves() && 165bdd1243dSDimitry Andric !MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); 16681ad6265SDimitry Andric 16781ad6265SDimitry Andric return *NeedsDwarfUnwindInfo; 16881ad6265SDimitry Andric } 16981ad6265SDimitry Andric 170bdd1243dSDimitry Andric bool AArch64FunctionInfo::needsAsyncDwarfUnwindInfo( 171bdd1243dSDimitry Andric const MachineFunction &MF) const { 17281ad6265SDimitry Andric if (!NeedsAsyncDwarfUnwindInfo) { 173bdd1243dSDimitry Andric const Function &F = MF.getFunction(); 1740fca6ea1SDimitry Andric const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>(); 17581ad6265SDimitry Andric // The check got "minsize" is because epilogue unwind info is not emitted 17681ad6265SDimitry Andric // (yet) for homogeneous epilogues, outlined functions, and functions 17781ad6265SDimitry Andric // outlined from. 1780fca6ea1SDimitry Andric NeedsAsyncDwarfUnwindInfo = 1790fca6ea1SDimitry Andric needsDwarfUnwindInfo(MF) && 1800fca6ea1SDimitry Andric ((F.getUWTableKind() == UWTableKind::Async && !F.hasMinSize()) || 1810fca6ea1SDimitry Andric AFI->hasStreamingModeChanges()); 18281ad6265SDimitry Andric } 18381ad6265SDimitry Andric return *NeedsAsyncDwarfUnwindInfo; 18481ad6265SDimitry Andric } 185