brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · baeab6a Raw
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