//=- RISCVMachineFunctionInfo.cpp - RISC-V machine function info --*- C++ -*-=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file declares RISCV-specific per-machine-function information. // //===----------------------------------------------------------------------===// #include "RISCVMachineFunctionInfo.h" #include "llvm/IR/Module.h" using namespace llvm; yaml::RISCVMachineFunctionInfo::RISCVMachineFunctionInfo( const llvm::RISCVMachineFunctionInfo &MFI) : VarArgsFrameIndex(MFI.getVarArgsFrameIndex()), VarArgsSaveSize(MFI.getVarArgsSaveSize()) {} MachineFunctionInfo *RISCVMachineFunctionInfo::clone( BumpPtrAllocator &Allocator, MachineFunction &DestMF, const DenseMap &Src2DstMBB) const { return DestMF.cloneInfo(*this); } RISCVMachineFunctionInfo::RISCVMachineFunctionInfo(const Function &F, const RISCVSubtarget *STI) { // The default stack probe size is 4096 if the function has no // stack-probe-size attribute. This is a safe default because it is the // smallest possible guard page size. uint64_t ProbeSize = 4096; if (F.hasFnAttribute("stack-probe-size")) ProbeSize = F.getFnAttributeAsParsedInteger("stack-probe-size"); else if (const auto *PS = mdconst::extract_or_null( F.getParent()->getModuleFlag("stack-probe-size"))) ProbeSize = PS->getZExtValue(); assert(int64_t(ProbeSize) > 0 && "Invalid stack probe size"); // Round down to the stack alignment. uint64_t StackAlign = STI->getFrameLowering()->getTransientStackAlign().value(); ProbeSize = std::max(StackAlign, alignDown(ProbeSize, StackAlign)); StringRef ProbeKind; if (F.hasFnAttribute("probe-stack")) ProbeKind = F.getFnAttribute("probe-stack").getValueAsString(); else if (const auto *PS = dyn_cast_or_null( F.getParent()->getModuleFlag("probe-stack"))) ProbeKind = PS->getString(); if (ProbeKind.size()) { StackProbeSize = ProbeSize; } } RISCVMachineFunctionInfo::InterruptStackKind RISCVMachineFunctionInfo::getInterruptStackKind( const MachineFunction &MF) const { if (!MF.getFunction().hasFnAttribute("interrupt")) return InterruptStackKind::None; assert(VarArgsSaveSize == 0 && "Interrupt functions should not having incoming varargs"); StringRef InterruptVal = MF.getFunction().getFnAttribute("interrupt").getValueAsString(); return StringSwitch( InterruptVal) .Case("qci-nest", InterruptStackKind::QCINest) .Case("qci-nonest", InterruptStackKind::QCINoNest) .Case("SiFive-CLIC-preemptible", InterruptStackKind::SiFiveCLICPreemptible) .Case("SiFive-CLIC-stack-swap", InterruptStackKind::SiFiveCLICStackSwap) .Case("SiFive-CLIC-preemptible-stack-swap", InterruptStackKind::SiFiveCLICPreemptibleStackSwap) .Default(InterruptStackKind::None); } void yaml::RISCVMachineFunctionInfo::mappingImpl(yaml::IO &YamlIO) { MappingTraits::mapping(YamlIO, *this); } RISCVMachineFunctionInfo::PushPopKind RISCVMachineFunctionInfo::getPushPopKind(const MachineFunction &MF) const { // We cannot use fixed locations for the callee saved spill slots if the // function uses a varargs save area. // TODO: Use a separate placement for vararg registers to enable Zcmp. if (VarArgsSaveSize != 0) return PushPopKind::None; // SiFive interrupts are not compatible with push/pop. if (useSiFiveInterrupt(MF)) return PushPopKind::None; // Zcmp is not compatible with the frame pointer convention. if (MF.getSubtarget().hasStdExtZcmp() && !MF.getTarget().Options.DisableFramePointerElim(MF)) return PushPopKind::StdExtZcmp; // Xqccmp is Zcmp but has a push order compatible with the frame-pointer // convention. if (MF.getSubtarget().hasVendorXqccmp()) return PushPopKind::VendorXqccmp; return PushPopKind::None; } bool RISCVMachineFunctionInfo::hasImplicitFPUpdates( const MachineFunction &MF) const { switch (getInterruptStackKind(MF)) { case InterruptStackKind::QCINest: case InterruptStackKind::QCINoNest: // QC.C.MIENTER and QC.C.MIENTER.NEST both update FP on function entry. return true; default: break; } switch (getPushPopKind(MF)) { case PushPopKind::VendorXqccmp: // When using Xqccmp, we will use `QC.CM.PUSHFP` when Frame Pointers are // enabled, which will update FP. return true; default: break; } return false; } void RISCVMachineFunctionInfo::initializeBaseYamlFields( const yaml::RISCVMachineFunctionInfo &YamlMFI) { VarArgsFrameIndex = YamlMFI.VarArgsFrameIndex; VarArgsSaveSize = YamlMFI.VarArgsSaveSize; } void RISCVMachineFunctionInfo::addSExt32Register(Register Reg) { SExt32Registers.push_back(Reg); } bool RISCVMachineFunctionInfo::isSExt32Register(Register Reg) const { return is_contained(SExt32Registers, Reg); }