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) { 41e8d8bef9SDimitry Andric // The function should be signed in the following situations: 42e8d8bef9SDimitry Andric // - sign-return-address=all 43e8d8bef9SDimitry Andric // - sign-return-address=non-leaf and the functions spills the LR 44*0fca6ea1SDimitry Andric if (!F.hasFnAttribute("sign-return-address")) 45e8d8bef9SDimitry Andric return {false, false}; 46e8d8bef9SDimitry Andric 47e8d8bef9SDimitry Andric StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString(); 48*0fca6ea1SDimitry Andric if (Scope == "none") 49e8d8bef9SDimitry Andric return {false, false}; 50e8d8bef9SDimitry Andric 51*0fca6ea1SDimitry Andric if (Scope == "all") 52e8d8bef9SDimitry Andric return {true, true}; 53e8d8bef9SDimitry Andric 54*0fca6ea1SDimitry Andric assert(Scope == "non-leaf"); 55e8d8bef9SDimitry Andric return {true, false}; 56e8d8bef9SDimitry Andric } 57e8d8bef9SDimitry Andric 58bdd1243dSDimitry Andric static bool ShouldSignWithBKey(const Function &F, const AArch64Subtarget &STI) { 59e8d8bef9SDimitry Andric if (!F.hasFnAttribute("sign-return-address-key")) { 60bdd1243dSDimitry Andric if (STI.getTargetTriple().isOSWindows()) 61bdd1243dSDimitry Andric return true; 62e8d8bef9SDimitry Andric return false; 63e8d8bef9SDimitry Andric } 64e8d8bef9SDimitry Andric 65e8d8bef9SDimitry Andric const StringRef Key = 66e8d8bef9SDimitry Andric F.getFnAttribute("sign-return-address-key").getValueAsString(); 675f757f3fSDimitry Andric assert(Key == "a_key" || Key == "b_key"); 685f757f3fSDimitry Andric return Key == "b_key"; 69e8d8bef9SDimitry Andric } 70e8d8bef9SDimitry Andric 71bdd1243dSDimitry Andric AArch64FunctionInfo::AArch64FunctionInfo(const Function &F, 72bdd1243dSDimitry Andric const AArch64Subtarget *STI) { 73e8d8bef9SDimitry Andric // If we already know that the function doesn't have a redzone, set 74e8d8bef9SDimitry Andric // HasRedZone here. 75bdd1243dSDimitry Andric if (F.hasFnAttribute(Attribute::NoRedZone)) 76e8d8bef9SDimitry Andric HasRedZone = false; 77e8d8bef9SDimitry Andric std::tie(SignReturnAddress, SignReturnAddressAll) = GetSignReturnAddress(F); 78bdd1243dSDimitry Andric SignWithBKey = ShouldSignWithBKey(F, *STI); 7981ad6265SDimitry Andric // TODO: skip functions that have no instrumented allocas for optimization 8081ad6265SDimitry Andric IsMTETagged = F.hasFnAttribute(Attribute::SanitizeMemTag); 81e8d8bef9SDimitry Andric 82*0fca6ea1SDimitry Andric // BTI/PAuthLR are set on the function attribute. 83*0fca6ea1SDimitry Andric BranchTargetEnforcement = F.hasFnAttribute("branch-target-enforcement"); 84*0fca6ea1SDimitry Andric BranchProtectionPAuthLR = F.hasFnAttribute("branch-protection-pauth-lr"); 855f757f3fSDimitry Andric 865f757f3fSDimitry Andric // The default stack probe size is 4096 if the function has no 875f757f3fSDimitry Andric // stack-probe-size attribute. This is a safe default because it is the 885f757f3fSDimitry Andric // smallest possible guard page size. 895f757f3fSDimitry Andric uint64_t ProbeSize = 4096; 905f757f3fSDimitry Andric if (F.hasFnAttribute("stack-probe-size")) 915f757f3fSDimitry Andric ProbeSize = F.getFnAttributeAsParsedInteger("stack-probe-size"); 925f757f3fSDimitry Andric else if (const auto *PS = mdconst::extract_or_null<ConstantInt>( 935f757f3fSDimitry Andric F.getParent()->getModuleFlag("stack-probe-size"))) 945f757f3fSDimitry Andric ProbeSize = PS->getZExtValue(); 955f757f3fSDimitry Andric assert(int64_t(ProbeSize) > 0 && "Invalid stack probe size"); 965f757f3fSDimitry Andric 975f757f3fSDimitry Andric if (STI->isTargetWindows()) { 985f757f3fSDimitry Andric if (!F.hasFnAttribute("no-stack-arg-probe")) 995f757f3fSDimitry Andric StackProbeSize = ProbeSize; 1005f757f3fSDimitry Andric } else { 1015f757f3fSDimitry Andric // Round down to the stack alignment. 1025f757f3fSDimitry Andric uint64_t StackAlign = 1035f757f3fSDimitry Andric STI->getFrameLowering()->getTransientStackAlign().value(); 1045f757f3fSDimitry Andric ProbeSize = std::max(StackAlign, ProbeSize & ~(StackAlign - 1U)); 1055f757f3fSDimitry Andric StringRef ProbeKind; 1065f757f3fSDimitry Andric if (F.hasFnAttribute("probe-stack")) 1075f757f3fSDimitry Andric ProbeKind = F.getFnAttribute("probe-stack").getValueAsString(); 1085f757f3fSDimitry Andric else if (const auto *PS = dyn_cast_or_null<MDString>( 1095f757f3fSDimitry Andric F.getParent()->getModuleFlag("probe-stack"))) 1105f757f3fSDimitry Andric ProbeKind = PS->getString(); 1115f757f3fSDimitry Andric if (ProbeKind.size()) { 1125f757f3fSDimitry Andric if (ProbeKind != "inline-asm") 1135f757f3fSDimitry Andric report_fatal_error("Unsupported stack probing method"); 1145f757f3fSDimitry Andric StackProbeSize = ProbeSize; 1155f757f3fSDimitry Andric } 1165f757f3fSDimitry Andric } 117e8d8bef9SDimitry Andric } 118e8d8bef9SDimitry Andric 11981ad6265SDimitry Andric MachineFunctionInfo *AArch64FunctionInfo::clone( 12081ad6265SDimitry Andric BumpPtrAllocator &Allocator, MachineFunction &DestMF, 12181ad6265SDimitry Andric const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) 12281ad6265SDimitry Andric const { 123bdd1243dSDimitry Andric return DestMF.cloneInfo<AArch64FunctionInfo>(*this); 12481ad6265SDimitry Andric } 12581ad6265SDimitry Andric 126e8d8bef9SDimitry Andric bool AArch64FunctionInfo::shouldSignReturnAddress(bool SpillsLR) const { 127e8d8bef9SDimitry Andric if (!SignReturnAddress) 128e8d8bef9SDimitry Andric return false; 129e8d8bef9SDimitry Andric if (SignReturnAddressAll) 130e8d8bef9SDimitry Andric return true; 131e8d8bef9SDimitry Andric return SpillsLR; 132e8d8bef9SDimitry Andric } 133e8d8bef9SDimitry Andric 1345f757f3fSDimitry Andric static bool isLRSpilled(const MachineFunction &MF) { 1355f757f3fSDimitry Andric return llvm::any_of( 1365f757f3fSDimitry Andric MF.getFrameInfo().getCalleeSavedInfo(), 1375f757f3fSDimitry Andric [](const auto &Info) { return Info.getReg() == AArch64::LR; }); 1385f757f3fSDimitry Andric } 1395f757f3fSDimitry Andric 140bdd1243dSDimitry Andric bool AArch64FunctionInfo::shouldSignReturnAddress( 141bdd1243dSDimitry Andric const MachineFunction &MF) const { 1425f757f3fSDimitry Andric return shouldSignReturnAddress(isLRSpilled(MF)); 1435f757f3fSDimitry Andric } 1445f757f3fSDimitry Andric 1455f757f3fSDimitry Andric bool AArch64FunctionInfo::needsShadowCallStackPrologueEpilogue( 1465f757f3fSDimitry Andric MachineFunction &MF) const { 1475f757f3fSDimitry Andric if (!(isLRSpilled(MF) && 1485f757f3fSDimitry Andric MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack))) 1495f757f3fSDimitry Andric return false; 1505f757f3fSDimitry Andric 1515f757f3fSDimitry Andric if (!MF.getSubtarget<AArch64Subtarget>().isXRegisterReserved(18)) 1525f757f3fSDimitry Andric report_fatal_error("Must reserve x18 to use shadow call stack"); 1535f757f3fSDimitry Andric 1545f757f3fSDimitry Andric return true; 155e8d8bef9SDimitry Andric } 15681ad6265SDimitry Andric 157bdd1243dSDimitry Andric bool AArch64FunctionInfo::needsDwarfUnwindInfo( 158bdd1243dSDimitry Andric const MachineFunction &MF) const { 15981ad6265SDimitry Andric if (!NeedsDwarfUnwindInfo) 160bdd1243dSDimitry Andric NeedsDwarfUnwindInfo = MF.needsFrameMoves() && 161bdd1243dSDimitry Andric !MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); 16281ad6265SDimitry Andric 16381ad6265SDimitry Andric return *NeedsDwarfUnwindInfo; 16481ad6265SDimitry Andric } 16581ad6265SDimitry Andric 166bdd1243dSDimitry Andric bool AArch64FunctionInfo::needsAsyncDwarfUnwindInfo( 167bdd1243dSDimitry Andric const MachineFunction &MF) const { 16881ad6265SDimitry Andric if (!NeedsAsyncDwarfUnwindInfo) { 169bdd1243dSDimitry Andric const Function &F = MF.getFunction(); 170*0fca6ea1SDimitry Andric const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>(); 17181ad6265SDimitry Andric // The check got "minsize" is because epilogue unwind info is not emitted 17281ad6265SDimitry Andric // (yet) for homogeneous epilogues, outlined functions, and functions 17381ad6265SDimitry Andric // outlined from. 174*0fca6ea1SDimitry Andric NeedsAsyncDwarfUnwindInfo = 175*0fca6ea1SDimitry Andric needsDwarfUnwindInfo(MF) && 176*0fca6ea1SDimitry Andric ((F.getUWTableKind() == UWTableKind::Async && !F.hasMinSize()) || 177*0fca6ea1SDimitry Andric AFI->hasStreamingModeChanges()); 17881ad6265SDimitry Andric } 17981ad6265SDimitry Andric return *NeedsAsyncDwarfUnwindInfo; 18081ad6265SDimitry Andric } 181