xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/MachineFrameInfo.cpp (revision 36b606ae6aa4b24061096ba18582e0a08ccd5dba)
10b57cec5SDimitry Andric //===-- MachineFrameInfo.cpp ---------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file Implements MachineFrameInfo that manages the stack frame.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
220b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
230b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
250b57cec5SDimitry Andric #include <cassert>
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #define DEBUG_TYPE "codegen"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace llvm;
300b57cec5SDimitry Andric 
ensureMaxAlignment(Align Alignment)318bcb0991SDimitry Andric void MachineFrameInfo::ensureMaxAlignment(Align Alignment) {
320b57cec5SDimitry Andric   if (!StackRealignable)
338bcb0991SDimitry Andric     assert(Alignment <= StackAlignment &&
348bcb0991SDimitry Andric            "For targets without stack realignment, Alignment is out of limit!");
358bcb0991SDimitry Andric   if (MaxAlignment < Alignment)
368bcb0991SDimitry Andric     MaxAlignment = Alignment;
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric /// Clamp the alignment if requested and emit a warning.
clampStackAlignment(bool ShouldClamp,Align Alignment,Align StackAlignment)408bcb0991SDimitry Andric static inline Align clampStackAlignment(bool ShouldClamp, Align Alignment,
418bcb0991SDimitry Andric                                         Align StackAlignment) {
428bcb0991SDimitry Andric   if (!ShouldClamp || Alignment <= StackAlignment)
438bcb0991SDimitry Andric     return Alignment;
445ffd83dbSDimitry Andric   LLVM_DEBUG(dbgs() << "Warning: requested alignment " << DebugStr(Alignment)
455ffd83dbSDimitry Andric                     << " exceeds the stack alignment "
465ffd83dbSDimitry Andric                     << DebugStr(StackAlignment)
470b57cec5SDimitry Andric                     << " when stack realignment is off" << '\n');
488bcb0991SDimitry Andric   return StackAlignment;
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
CreateStackObject(uint64_t Size,Align Alignment,bool IsSpillSlot,const AllocaInst * Alloca,uint8_t StackID)518bcb0991SDimitry Andric int MachineFrameInfo::CreateStackObject(uint64_t Size, Align Alignment,
520b57cec5SDimitry Andric                                         bool IsSpillSlot,
530b57cec5SDimitry Andric                                         const AllocaInst *Alloca,
540b57cec5SDimitry Andric                                         uint8_t StackID) {
550b57cec5SDimitry Andric   assert(Size != 0 && "Cannot allocate zero size stack objects!");
560b57cec5SDimitry Andric   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
570b57cec5SDimitry Andric   Objects.push_back(StackObject(Size, Alignment, 0, false, IsSpillSlot, Alloca,
580b57cec5SDimitry Andric                                 !IsSpillSlot, StackID));
590b57cec5SDimitry Andric   int Index = (int)Objects.size() - NumFixedObjects - 1;
600b57cec5SDimitry Andric   assert(Index >= 0 && "Bad frame index!");
61bdd1243dSDimitry Andric   if (contributesToMaxAlignment(StackID))
620b57cec5SDimitry Andric     ensureMaxAlignment(Alignment);
630b57cec5SDimitry Andric   return Index;
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
CreateSpillStackObject(uint64_t Size,Align Alignment)668bcb0991SDimitry Andric int MachineFrameInfo::CreateSpillStackObject(uint64_t Size, Align Alignment) {
670b57cec5SDimitry Andric   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
680b57cec5SDimitry Andric   CreateStackObject(Size, Alignment, true);
690b57cec5SDimitry Andric   int Index = (int)Objects.size() - NumFixedObjects - 1;
700b57cec5SDimitry Andric   ensureMaxAlignment(Alignment);
710b57cec5SDimitry Andric   return Index;
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric 
CreateVariableSizedObject(Align Alignment,const AllocaInst * Alloca)748bcb0991SDimitry Andric int MachineFrameInfo::CreateVariableSizedObject(Align Alignment,
750b57cec5SDimitry Andric                                                 const AllocaInst *Alloca) {
760b57cec5SDimitry Andric   HasVarSizedObjects = true;
770b57cec5SDimitry Andric   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
780b57cec5SDimitry Andric   Objects.push_back(StackObject(0, Alignment, 0, false, false, Alloca, true));
790b57cec5SDimitry Andric   ensureMaxAlignment(Alignment);
800b57cec5SDimitry Andric   return (int)Objects.size()-NumFixedObjects-1;
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
CreateFixedObject(uint64_t Size,int64_t SPOffset,bool IsImmutable,bool IsAliased)830b57cec5SDimitry Andric int MachineFrameInfo::CreateFixedObject(uint64_t Size, int64_t SPOffset,
840b57cec5SDimitry Andric                                         bool IsImmutable, bool IsAliased) {
850b57cec5SDimitry Andric   assert(Size != 0 && "Cannot allocate zero size fixed stack objects!");
860b57cec5SDimitry Andric   // The alignment of the frame index can be determined from its offset from
870b57cec5SDimitry Andric   // the incoming frame position.  If the frame object is at offset 32 and
880b57cec5SDimitry Andric   // the stack is guaranteed to be 16-byte aligned, then we know that the
890b57cec5SDimitry Andric   // object is 16-byte aligned. Note that unlike the non-fixed case, if the
900b57cec5SDimitry Andric   // stack needs realignment, we can't assume that the stack will in fact be
910b57cec5SDimitry Andric   // aligned.
928bcb0991SDimitry Andric   Align Alignment =
935ffd83dbSDimitry Andric       commonAlignment(ForcedRealign ? Align(1) : StackAlignment, SPOffset);
940b57cec5SDimitry Andric   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
950b57cec5SDimitry Andric   Objects.insert(Objects.begin(),
960b57cec5SDimitry Andric                  StackObject(Size, Alignment, SPOffset, IsImmutable,
970b57cec5SDimitry Andric                              /*IsSpillSlot=*/false, /*Alloca=*/nullptr,
980b57cec5SDimitry Andric                              IsAliased));
990b57cec5SDimitry Andric   return -++NumFixedObjects;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
CreateFixedSpillStackObject(uint64_t Size,int64_t SPOffset,bool IsImmutable)1020b57cec5SDimitry Andric int MachineFrameInfo::CreateFixedSpillStackObject(uint64_t Size,
1030b57cec5SDimitry Andric                                                   int64_t SPOffset,
1040b57cec5SDimitry Andric                                                   bool IsImmutable) {
1058bcb0991SDimitry Andric   Align Alignment =
1065ffd83dbSDimitry Andric       commonAlignment(ForcedRealign ? Align(1) : StackAlignment, SPOffset);
1070b57cec5SDimitry Andric   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
1080b57cec5SDimitry Andric   Objects.insert(Objects.begin(),
1090b57cec5SDimitry Andric                  StackObject(Size, Alignment, SPOffset, IsImmutable,
1100b57cec5SDimitry Andric                              /*IsSpillSlot=*/true, /*Alloca=*/nullptr,
1110b57cec5SDimitry Andric                              /*IsAliased=*/false));
1120b57cec5SDimitry Andric   return -++NumFixedObjects;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
getPristineRegs(const MachineFunction & MF) const1150b57cec5SDimitry Andric BitVector MachineFrameInfo::getPristineRegs(const MachineFunction &MF) const {
1160b57cec5SDimitry Andric   const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
1170b57cec5SDimitry Andric   BitVector BV(TRI->getNumRegs());
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   // Before CSI is calculated, no registers are considered pristine. They can be
1200b57cec5SDimitry Andric   // freely used and PEI will make sure they are saved.
1210b57cec5SDimitry Andric   if (!isCalleeSavedInfoValid())
1220b57cec5SDimitry Andric     return BV;
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   const MachineRegisterInfo &MRI = MF.getRegInfo();
1250b57cec5SDimitry Andric   for (const MCPhysReg *CSR = MRI.getCalleeSavedRegs(); CSR && *CSR;
1260b57cec5SDimitry Andric        ++CSR)
1270b57cec5SDimitry Andric     BV.set(*CSR);
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   // Saved CSRs are not pristine.
130fcaf7f86SDimitry Andric   for (const auto &I : getCalleeSavedInfo())
13106c3fb27SDimitry Andric     for (MCPhysReg S : TRI->subregs_inclusive(I.getReg()))
13206c3fb27SDimitry Andric       BV.reset(S);
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   return BV;
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
estimateStackSize(const MachineFunction & MF) const137480093f4SDimitry Andric uint64_t MachineFrameInfo::estimateStackSize(const MachineFunction &MF) const {
1380b57cec5SDimitry Andric   const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
1390b57cec5SDimitry Andric   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
1405ffd83dbSDimitry Andric   Align MaxAlign = getMaxAlign();
141480093f4SDimitry Andric   int64_t Offset = 0;
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   // This code is very, very similar to PEI::calculateFrameObjectOffsets().
1440b57cec5SDimitry Andric   // It really should be refactored to share code. Until then, changes
1450b57cec5SDimitry Andric   // should keep in mind that there's tight coupling between the two.
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   for (int i = getObjectIndexBegin(); i != 0; ++i) {
1480b57cec5SDimitry Andric     // Only estimate stack size of default stack.
1490b57cec5SDimitry Andric     if (getStackID(i) != TargetStackID::Default)
1500b57cec5SDimitry Andric       continue;
151480093f4SDimitry Andric     int64_t FixedOff = -getObjectOffset(i);
1520b57cec5SDimitry Andric     if (FixedOff > Offset) Offset = FixedOff;
1530b57cec5SDimitry Andric   }
1540b57cec5SDimitry Andric   for (unsigned i = 0, e = getObjectIndexEnd(); i != e; ++i) {
1550b57cec5SDimitry Andric     // Only estimate stack size of live objects on default stack.
1560b57cec5SDimitry Andric     if (isDeadObjectIndex(i) || getStackID(i) != TargetStackID::Default)
1570b57cec5SDimitry Andric       continue;
1580b57cec5SDimitry Andric     Offset += getObjectSize(i);
1595ffd83dbSDimitry Andric     Align Alignment = getObjectAlign(i);
1600b57cec5SDimitry Andric     // Adjust to alignment boundary
1615ffd83dbSDimitry Andric     Offset = alignTo(Offset, Alignment);
1620b57cec5SDimitry Andric 
1635ffd83dbSDimitry Andric     MaxAlign = std::max(Alignment, MaxAlign);
1640b57cec5SDimitry Andric   }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   if (adjustsStack() && TFI->hasReservedCallFrame(MF))
1670b57cec5SDimitry Andric     Offset += getMaxCallFrameSize();
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric   // Round up the size to a multiple of the alignment.  If the function has
1700b57cec5SDimitry Andric   // any calls or alloca's, align to the target's StackAlignment value to
1710b57cec5SDimitry Andric   // ensure that the callee's frame or the alloca data is suitably aligned;
1720b57cec5SDimitry Andric   // otherwise, for leaf functions, align to the TransientStackAlignment
1730b57cec5SDimitry Andric   // value.
1745ffd83dbSDimitry Andric   Align StackAlign;
1750b57cec5SDimitry Andric   if (adjustsStack() || hasVarSizedObjects() ||
176fe6060f1SDimitry Andric       (RegInfo->hasStackRealignment(MF) && getObjectIndexEnd() != 0))
1775ffd83dbSDimitry Andric     StackAlign = TFI->getStackAlign();
1780b57cec5SDimitry Andric   else
1795ffd83dbSDimitry Andric     StackAlign = TFI->getTransientStackAlign();
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric   // If the frame pointer is eliminated, all frame offsets will be relative to
1820b57cec5SDimitry Andric   // SP not FP. Align to MaxAlign so this works.
1830b57cec5SDimitry Andric   StackAlign = std::max(StackAlign, MaxAlign);
1845ffd83dbSDimitry Andric   return alignTo(Offset, StackAlign);
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric 
computeMaxCallFrameSize(MachineFunction & MF,std::vector<MachineBasicBlock::iterator> * FrameSDOps)1870fca6ea1SDimitry Andric void MachineFrameInfo::computeMaxCallFrameSize(
1880fca6ea1SDimitry Andric     MachineFunction &MF, std::vector<MachineBasicBlock::iterator> *FrameSDOps) {
1890b57cec5SDimitry Andric   const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
1900b57cec5SDimitry Andric   unsigned FrameSetupOpcode = TII.getCallFrameSetupOpcode();
1910b57cec5SDimitry Andric   unsigned FrameDestroyOpcode = TII.getCallFrameDestroyOpcode();
1920b57cec5SDimitry Andric   assert(FrameSetupOpcode != ~0u && FrameDestroyOpcode != ~0u &&
1930b57cec5SDimitry Andric          "Can only compute MaxCallFrameSize if Setup/Destroy opcode are known");
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric   MaxCallFrameSize = 0;
1960fca6ea1SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
1970fca6ea1SDimitry Andric     for (MachineInstr &MI : MBB) {
1980b57cec5SDimitry Andric       unsigned Opcode = MI.getOpcode();
1990b57cec5SDimitry Andric       if (Opcode == FrameSetupOpcode || Opcode == FrameDestroyOpcode) {
200*36b606aeSDimitry Andric         uint64_t Size = TII.getFrameSize(MI);
2010b57cec5SDimitry Andric         MaxCallFrameSize = std::max(MaxCallFrameSize, Size);
2020fca6ea1SDimitry Andric         if (FrameSDOps != nullptr)
2030fca6ea1SDimitry Andric           FrameSDOps->push_back(&MI);
2040b57cec5SDimitry Andric       }
2050b57cec5SDimitry Andric     }
2060b57cec5SDimitry Andric   }
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric 
print(const MachineFunction & MF,raw_ostream & OS) const2090b57cec5SDimitry Andric void MachineFrameInfo::print(const MachineFunction &MF, raw_ostream &OS) const{
2100b57cec5SDimitry Andric   if (Objects.empty()) return;
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric   const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering();
2130b57cec5SDimitry Andric   int ValOffset = (FI ? FI->getOffsetOfLocalArea() : 0);
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric   OS << "Frame Objects:\n";
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric   for (unsigned i = 0, e = Objects.size(); i != e; ++i) {
2180b57cec5SDimitry Andric     const StackObject &SO = Objects[i];
2190b57cec5SDimitry Andric     OS << "  fi#" << (int)(i-NumFixedObjects) << ": ";
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric     if (SO.StackID != 0)
2220b57cec5SDimitry Andric       OS << "id=" << static_cast<unsigned>(SO.StackID) << ' ';
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric     if (SO.Size == ~0ULL) {
2250b57cec5SDimitry Andric       OS << "dead\n";
2260b57cec5SDimitry Andric       continue;
2270b57cec5SDimitry Andric     }
2280b57cec5SDimitry Andric     if (SO.Size == 0)
2290b57cec5SDimitry Andric       OS << "variable sized";
2300b57cec5SDimitry Andric     else
2310b57cec5SDimitry Andric       OS << "size=" << SO.Size;
2328bcb0991SDimitry Andric     OS << ", align=" << SO.Alignment.value();
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric     if (i < NumFixedObjects)
2350b57cec5SDimitry Andric       OS << ", fixed";
2360b57cec5SDimitry Andric     if (i < NumFixedObjects || SO.SPOffset != -1) {
2370b57cec5SDimitry Andric       int64_t Off = SO.SPOffset - ValOffset;
2380b57cec5SDimitry Andric       OS << ", at location [SP";
2390b57cec5SDimitry Andric       if (Off > 0)
2400b57cec5SDimitry Andric         OS << "+" << Off;
2410b57cec5SDimitry Andric       else if (Off < 0)
2420b57cec5SDimitry Andric         OS << Off;
2430b57cec5SDimitry Andric       OS << "]";
2440b57cec5SDimitry Andric     }
2450b57cec5SDimitry Andric     OS << "\n";
2460b57cec5SDimitry Andric   }
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump(const MachineFunction & MF) const2500b57cec5SDimitry Andric LLVM_DUMP_METHOD void MachineFrameInfo::dump(const MachineFunction &MF) const {
2510b57cec5SDimitry Andric   print(MF, dbgs());
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric #endif
254