| 1 | //=- RISCVMachineFunctionInfo.cpp - RISC-V machine function info --*- C++ -*-=// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file declares RISCV-specific per-machine-function information. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "RISCVMachineFunctionInfo.h" |
| 14 | #include "llvm/IR/Module.h" |
| 15 | |
| 16 | using namespace llvm; |
| 17 | |
| 18 | yaml::RISCVMachineFunctionInfo::RISCVMachineFunctionInfo( |
| 19 | const llvm::RISCVMachineFunctionInfo &MFI) |
| 20 | : VarArgsFrameIndex(MFI.getVarArgsFrameIndex()), |
| 21 | VarArgsSaveSize(MFI.getVarArgsSaveSize()) {} |
| 22 | |
| 23 | MachineFunctionInfo *RISCVMachineFunctionInfo::clone( |
| 24 | BumpPtrAllocator &Allocator, MachineFunction &DestMF, |
| 25 | const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) |
| 26 | const { |
| 27 | return DestMF.cloneInfo<RISCVMachineFunctionInfo>(Old: *this); |
| 28 | } |
| 29 | |
| 30 | RISCVMachineFunctionInfo::RISCVMachineFunctionInfo(const Function &F, |
| 31 | const RISCVSubtarget *STI) { |
| 32 | |
| 33 | // The default stack probe size is 4096 if the function has no |
| 34 | // stack-probe-size attribute. This is a safe default because it is the |
| 35 | // smallest possible guard page size. |
| 36 | uint64_t ProbeSize = 4096; |
| 37 | if (F.hasFnAttribute(Kind: "stack-probe-size" )) |
| 38 | ProbeSize = F.getFnAttributeAsParsedInteger(Kind: "stack-probe-size" ); |
| 39 | else if (const auto *PS = mdconst::extract_or_null<ConstantInt>( |
| 40 | MD: F.getParent()->getModuleFlag(Key: "stack-probe-size" ))) |
| 41 | ProbeSize = PS->getZExtValue(); |
| 42 | assert(int64_t(ProbeSize) > 0 && "Invalid stack probe size" ); |
| 43 | |
| 44 | // Round down to the stack alignment. |
| 45 | uint64_t StackAlign = |
| 46 | STI->getFrameLowering()->getTransientStackAlign().value(); |
| 47 | ProbeSize = std::max(a: StackAlign, b: alignDown(Value: ProbeSize, Align: StackAlign)); |
| 48 | StringRef ProbeKind; |
| 49 | if (F.hasFnAttribute(Kind: "probe-stack" )) |
| 50 | ProbeKind = F.getFnAttribute(Kind: "probe-stack" ).getValueAsString(); |
| 51 | else if (const auto *PS = dyn_cast_or_null<MDString>( |
| 52 | Val: F.getParent()->getModuleFlag(Key: "probe-stack" ))) |
| 53 | ProbeKind = PS->getString(); |
| 54 | if (ProbeKind.size()) { |
| 55 | StackProbeSize = ProbeSize; |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | RISCVMachineFunctionInfo::InterruptStackKind |
| 60 | RISCVMachineFunctionInfo::getInterruptStackKind( |
| 61 | const MachineFunction &MF) const { |
| 62 | if (!MF.getFunction().hasFnAttribute(Kind: "interrupt" )) |
| 63 | return InterruptStackKind::None; |
| 64 | |
| 65 | assert(VarArgsSaveSize == 0 && |
| 66 | "Interrupt functions should not having incoming varargs" ); |
| 67 | |
| 68 | StringRef InterruptVal = |
| 69 | MF.getFunction().getFnAttribute(Kind: "interrupt" ).getValueAsString(); |
| 70 | |
| 71 | return StringSwitch<RISCVMachineFunctionInfo::InterruptStackKind>( |
| 72 | InterruptVal) |
| 73 | .Case(S: "qci-nest" , Value: InterruptStackKind::QCINest) |
| 74 | .Case(S: "qci-nonest" , Value: InterruptStackKind::QCINoNest) |
| 75 | .Case(S: "SiFive-CLIC-preemptible" , |
| 76 | Value: InterruptStackKind::SiFiveCLICPreemptible) |
| 77 | .Case(S: "SiFive-CLIC-stack-swap" , Value: InterruptStackKind::SiFiveCLICStackSwap) |
| 78 | .Case(S: "SiFive-CLIC-preemptible-stack-swap" , |
| 79 | Value: InterruptStackKind::SiFiveCLICPreemptibleStackSwap) |
| 80 | .Default(Value: InterruptStackKind::None); |
| 81 | } |
| 82 | |
| 83 | void yaml::RISCVMachineFunctionInfo::mappingImpl(yaml::IO &YamlIO) { |
| 84 | MappingTraits<RISCVMachineFunctionInfo>::mapping(YamlIO, MFI&: *this); |
| 85 | } |
| 86 | |
| 87 | RISCVMachineFunctionInfo::PushPopKind |
| 88 | RISCVMachineFunctionInfo::getPushPopKind(const MachineFunction &MF) const { |
| 89 | // We cannot use fixed locations for the callee saved spill slots if the |
| 90 | // function uses a varargs save area. |
| 91 | // TODO: Use a separate placement for vararg registers to enable Zcmp. |
| 92 | if (VarArgsSaveSize != 0) |
| 93 | return PushPopKind::None; |
| 94 | |
| 95 | // SiFive interrupts are not compatible with push/pop. |
| 96 | if (useSiFiveInterrupt(MF)) |
| 97 | return PushPopKind::None; |
| 98 | |
| 99 | // Zcmp is not compatible with the frame pointer convention. |
| 100 | if (MF.getSubtarget<RISCVSubtarget>().hasStdExtZcmp() && |
| 101 | !MF.getTarget().Options.DisableFramePointerElim(MF)) |
| 102 | return PushPopKind::StdExtZcmp; |
| 103 | |
| 104 | // Xqccmp is Zcmp but has a push order compatible with the frame-pointer |
| 105 | // convention. |
| 106 | if (MF.getSubtarget<RISCVSubtarget>().hasVendorXqccmp()) |
| 107 | return PushPopKind::VendorXqccmp; |
| 108 | |
| 109 | return PushPopKind::None; |
| 110 | } |
| 111 | |
| 112 | bool RISCVMachineFunctionInfo::hasImplicitFPUpdates( |
| 113 | const MachineFunction &MF) const { |
| 114 | switch (getInterruptStackKind(MF)) { |
| 115 | case InterruptStackKind::QCINest: |
| 116 | case InterruptStackKind::QCINoNest: |
| 117 | // QC.C.MIENTER and QC.C.MIENTER.NEST both update FP on function entry. |
| 118 | return true; |
| 119 | default: |
| 120 | break; |
| 121 | } |
| 122 | |
| 123 | switch (getPushPopKind(MF)) { |
| 124 | case PushPopKind::VendorXqccmp: |
| 125 | // When using Xqccmp, we will use `QC.CM.PUSHFP` when Frame Pointers are |
| 126 | // enabled, which will update FP. |
| 127 | return true; |
| 128 | default: |
| 129 | break; |
| 130 | } |
| 131 | |
| 132 | return false; |
| 133 | } |
| 134 | |
| 135 | void RISCVMachineFunctionInfo::initializeBaseYamlFields( |
| 136 | const yaml::RISCVMachineFunctionInfo &YamlMFI) { |
| 137 | VarArgsFrameIndex = YamlMFI.VarArgsFrameIndex; |
| 138 | VarArgsSaveSize = YamlMFI.VarArgsSaveSize; |
| 139 | } |
| 140 | |
| 141 | void RISCVMachineFunctionInfo::addSExt32Register(Register Reg) { |
| 142 | SExt32Registers.push_back(Elt: Reg); |
| 143 | } |
| 144 | |
| 145 | bool RISCVMachineFunctionInfo::isSExt32Register(Register Reg) const { |
| 146 | return is_contained(Range: SExt32Registers, Element: Reg); |
| 147 | } |
| 148 | |