1f37b6182SDimitry Andric //===-- MachineFrameInfo.cpp ---------------------------------------------===//
2f37b6182SDimitry Andric //
3f37b6182SDimitry Andric //                     The LLVM Compiler Infrastructure
4f37b6182SDimitry Andric //
5f37b6182SDimitry Andric // This file is distributed under the University of Illinois Open Source
6f37b6182SDimitry Andric // License. See LICENSE.TXT for details.
7f37b6182SDimitry Andric //
8f37b6182SDimitry Andric //===----------------------------------------------------------------------===//
9f37b6182SDimitry Andric //
10f37b6182SDimitry Andric /// \file Implements MachineFrameInfo that manages the stack frame.
11f37b6182SDimitry Andric //
12f37b6182SDimitry Andric //===----------------------------------------------------------------------===//
13f37b6182SDimitry Andric 
14f37b6182SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
15f37b6182SDimitry Andric 
16f37b6182SDimitry Andric #include "llvm/ADT/BitVector.h"
17f37b6182SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
18f37b6182SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
192cab237bSDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
202cab237bSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
212cab237bSDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
222cab237bSDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
23*4ba319b5SDimitry Andric #include "llvm/Config/llvm-config.h"
24f37b6182SDimitry Andric #include "llvm/Support/Debug.h"
25f37b6182SDimitry Andric #include "llvm/Support/raw_ostream.h"
26f37b6182SDimitry Andric #include <cassert>
27f37b6182SDimitry Andric 
28f37b6182SDimitry Andric #define DEBUG_TYPE "codegen"
29f37b6182SDimitry Andric 
30f37b6182SDimitry Andric using namespace llvm;
31f37b6182SDimitry Andric 
ensureMaxAlignment(unsigned Align)32f37b6182SDimitry Andric void MachineFrameInfo::ensureMaxAlignment(unsigned Align) {
33f37b6182SDimitry Andric   if (!StackRealignable)
34f37b6182SDimitry Andric     assert(Align <= StackAlignment &&
35f37b6182SDimitry Andric            "For targets without stack realignment, Align is out of limit!");
36f37b6182SDimitry Andric   if (MaxAlignment < Align) MaxAlignment = Align;
37f37b6182SDimitry Andric }
38f37b6182SDimitry Andric 
39f37b6182SDimitry Andric /// Clamp the alignment if requested and emit a warning.
clampStackAlignment(bool ShouldClamp,unsigned Align,unsigned StackAlign)40f37b6182SDimitry Andric static inline unsigned clampStackAlignment(bool ShouldClamp, unsigned Align,
41f37b6182SDimitry Andric                                            unsigned StackAlign) {
42f37b6182SDimitry Andric   if (!ShouldClamp || Align <= StackAlign)
43f37b6182SDimitry Andric     return Align;
44*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "Warning: requested alignment " << Align
45f37b6182SDimitry Andric                     << " exceeds the stack alignment " << StackAlign
46f37b6182SDimitry Andric                     << " when stack realignment is off" << '\n');
47f37b6182SDimitry Andric   return StackAlign;
48f37b6182SDimitry Andric }
49f37b6182SDimitry Andric 
CreateStackObject(uint64_t Size,unsigned Alignment,bool IsSpillSlot,const AllocaInst * Alloca,uint8_t StackID)50f37b6182SDimitry Andric int MachineFrameInfo::CreateStackObject(uint64_t Size, unsigned Alignment,
512cab237bSDimitry Andric                                         bool IsSpillSlot,
522cab237bSDimitry Andric                                         const AllocaInst *Alloca,
532cab237bSDimitry Andric                                         uint8_t StackID) {
54f37b6182SDimitry Andric   assert(Size != 0 && "Cannot allocate zero size stack objects!");
55f37b6182SDimitry Andric   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
562cab237bSDimitry Andric   Objects.push_back(StackObject(Size, Alignment, 0, false, IsSpillSlot, Alloca,
572cab237bSDimitry Andric                                 !IsSpillSlot, StackID));
58f37b6182SDimitry Andric   int Index = (int)Objects.size() - NumFixedObjects - 1;
59f37b6182SDimitry Andric   assert(Index >= 0 && "Bad frame index!");
60f37b6182SDimitry Andric   ensureMaxAlignment(Alignment);
61f37b6182SDimitry Andric   return Index;
62f37b6182SDimitry Andric }
63f37b6182SDimitry Andric 
CreateSpillStackObject(uint64_t Size,unsigned Alignment)64f37b6182SDimitry Andric int MachineFrameInfo::CreateSpillStackObject(uint64_t Size,
65f37b6182SDimitry Andric                                              unsigned Alignment) {
66f37b6182SDimitry Andric   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
67f37b6182SDimitry Andric   CreateStackObject(Size, Alignment, true);
68f37b6182SDimitry Andric   int Index = (int)Objects.size() - NumFixedObjects - 1;
69f37b6182SDimitry Andric   ensureMaxAlignment(Alignment);
70f37b6182SDimitry Andric   return Index;
71f37b6182SDimitry Andric }
72f37b6182SDimitry Andric 
CreateVariableSizedObject(unsigned Alignment,const AllocaInst * Alloca)73f37b6182SDimitry Andric int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment,
74f37b6182SDimitry Andric                                                 const AllocaInst *Alloca) {
75f37b6182SDimitry Andric   HasVarSizedObjects = true;
76f37b6182SDimitry Andric   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
77f37b6182SDimitry Andric   Objects.push_back(StackObject(0, Alignment, 0, false, false, Alloca, true));
78f37b6182SDimitry Andric   ensureMaxAlignment(Alignment);
79f37b6182SDimitry Andric   return (int)Objects.size()-NumFixedObjects-1;
80f37b6182SDimitry Andric }
81f37b6182SDimitry Andric 
CreateFixedObject(uint64_t Size,int64_t SPOffset,bool IsImmutable,bool IsAliased)82f37b6182SDimitry Andric int MachineFrameInfo::CreateFixedObject(uint64_t Size, int64_t SPOffset,
832cab237bSDimitry Andric                                         bool IsImmutable, bool IsAliased) {
84f37b6182SDimitry Andric   assert(Size != 0 && "Cannot allocate zero size fixed stack objects!");
85f37b6182SDimitry Andric   // The alignment of the frame index can be determined from its offset from
86f37b6182SDimitry Andric   // the incoming frame position.  If the frame object is at offset 32 and
87f37b6182SDimitry Andric   // the stack is guaranteed to be 16-byte aligned, then we know that the
88f37b6182SDimitry Andric   // object is 16-byte aligned. Note that unlike the non-fixed case, if the
89f37b6182SDimitry Andric   // stack needs realignment, we can't assume that the stack will in fact be
90f37b6182SDimitry Andric   // aligned.
912cab237bSDimitry Andric   unsigned Alignment = MinAlign(SPOffset, ForcedRealign ? 1 : StackAlignment);
922cab237bSDimitry Andric   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
932cab237bSDimitry Andric   Objects.insert(Objects.begin(),
942cab237bSDimitry Andric                  StackObject(Size, Alignment, SPOffset, IsImmutable,
952cab237bSDimitry Andric                              /*isSpillSlot=*/false, /*Alloca=*/nullptr,
962cab237bSDimitry Andric                              IsAliased));
97f37b6182SDimitry Andric   return -++NumFixedObjects;
98f37b6182SDimitry Andric }
99f37b6182SDimitry Andric 
CreateFixedSpillStackObject(uint64_t Size,int64_t SPOffset,bool IsImmutable)100f37b6182SDimitry Andric int MachineFrameInfo::CreateFixedSpillStackObject(uint64_t Size,
101f37b6182SDimitry Andric                                                   int64_t SPOffset,
1022cab237bSDimitry Andric                                                   bool IsImmutable) {
1032cab237bSDimitry Andric   unsigned Alignment = MinAlign(SPOffset, ForcedRealign ? 1 : StackAlignment);
1042cab237bSDimitry Andric   Alignment = clampStackAlignment(!StackRealignable, Alignment, StackAlignment);
1052cab237bSDimitry Andric   Objects.insert(Objects.begin(),
1062cab237bSDimitry Andric                  StackObject(Size, Alignment, SPOffset, IsImmutable,
1072cab237bSDimitry Andric                              /*IsSpillSlot=*/true, /*Alloca=*/nullptr,
1082cab237bSDimitry Andric                              /*IsAliased=*/false));
109f37b6182SDimitry Andric   return -++NumFixedObjects;
110f37b6182SDimitry Andric }
111f37b6182SDimitry Andric 
getPristineRegs(const MachineFunction & MF) const112f37b6182SDimitry Andric BitVector MachineFrameInfo::getPristineRegs(const MachineFunction &MF) const {
113f37b6182SDimitry Andric   const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
114f37b6182SDimitry Andric   BitVector BV(TRI->getNumRegs());
115f37b6182SDimitry Andric 
116f37b6182SDimitry Andric   // Before CSI is calculated, no registers are considered pristine. They can be
117f37b6182SDimitry Andric   // freely used and PEI will make sure they are saved.
118f37b6182SDimitry Andric   if (!isCalleeSavedInfoValid())
119f37b6182SDimitry Andric     return BV;
120f37b6182SDimitry Andric 
121f37b6182SDimitry Andric   const MachineRegisterInfo &MRI = MF.getRegInfo();
122f37b6182SDimitry Andric   for (const MCPhysReg *CSR = MRI.getCalleeSavedRegs(); CSR && *CSR;
123f37b6182SDimitry Andric        ++CSR)
124f37b6182SDimitry Andric     BV.set(*CSR);
125f37b6182SDimitry Andric 
126f37b6182SDimitry Andric   // Saved CSRs are not pristine.
127f37b6182SDimitry Andric   for (auto &I : getCalleeSavedInfo())
128f37b6182SDimitry Andric     for (MCSubRegIterator S(I.getReg(), TRI, true); S.isValid(); ++S)
129f37b6182SDimitry Andric       BV.reset(*S);
130f37b6182SDimitry Andric 
131f37b6182SDimitry Andric   return BV;
132f37b6182SDimitry Andric }
133f37b6182SDimitry Andric 
estimateStackSize(const MachineFunction & MF) const134f37b6182SDimitry Andric unsigned MachineFrameInfo::estimateStackSize(const MachineFunction &MF) const {
135f37b6182SDimitry Andric   const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
136f37b6182SDimitry Andric   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
137f37b6182SDimitry Andric   unsigned MaxAlign = getMaxAlignment();
138f37b6182SDimitry Andric   int Offset = 0;
139f37b6182SDimitry Andric 
140f37b6182SDimitry Andric   // This code is very, very similar to PEI::calculateFrameObjectOffsets().
141f37b6182SDimitry Andric   // It really should be refactored to share code. Until then, changes
142f37b6182SDimitry Andric   // should keep in mind that there's tight coupling between the two.
143f37b6182SDimitry Andric 
144f37b6182SDimitry Andric   for (int i = getObjectIndexBegin(); i != 0; ++i) {
145f37b6182SDimitry Andric     int FixedOff = -getObjectOffset(i);
146f37b6182SDimitry Andric     if (FixedOff > Offset) Offset = FixedOff;
147f37b6182SDimitry Andric   }
148f37b6182SDimitry Andric   for (unsigned i = 0, e = getObjectIndexEnd(); i != e; ++i) {
149f37b6182SDimitry Andric     if (isDeadObjectIndex(i))
150f37b6182SDimitry Andric       continue;
151f37b6182SDimitry Andric     Offset += getObjectSize(i);
152f37b6182SDimitry Andric     unsigned Align = getObjectAlignment(i);
153f37b6182SDimitry Andric     // Adjust to alignment boundary
154f37b6182SDimitry Andric     Offset = (Offset+Align-1)/Align*Align;
155f37b6182SDimitry Andric 
156f37b6182SDimitry Andric     MaxAlign = std::max(Align, MaxAlign);
157f37b6182SDimitry Andric   }
158f37b6182SDimitry Andric 
159f37b6182SDimitry Andric   if (adjustsStack() && TFI->hasReservedCallFrame(MF))
160f37b6182SDimitry Andric     Offset += getMaxCallFrameSize();
161f37b6182SDimitry Andric 
162f37b6182SDimitry Andric   // Round up the size to a multiple of the alignment.  If the function has
163f37b6182SDimitry Andric   // any calls or alloca's, align to the target's StackAlignment value to
164f37b6182SDimitry Andric   // ensure that the callee's frame or the alloca data is suitably aligned;
165f37b6182SDimitry Andric   // otherwise, for leaf functions, align to the TransientStackAlignment
166f37b6182SDimitry Andric   // value.
167f37b6182SDimitry Andric   unsigned StackAlign;
168f37b6182SDimitry Andric   if (adjustsStack() || hasVarSizedObjects() ||
169f37b6182SDimitry Andric       (RegInfo->needsStackRealignment(MF) && getObjectIndexEnd() != 0))
170f37b6182SDimitry Andric     StackAlign = TFI->getStackAlignment();
171f37b6182SDimitry Andric   else
172f37b6182SDimitry Andric     StackAlign = TFI->getTransientStackAlignment();
173f37b6182SDimitry Andric 
174f37b6182SDimitry Andric   // If the frame pointer is eliminated, all frame offsets will be relative to
175f37b6182SDimitry Andric   // SP not FP. Align to MaxAlign so this works.
176f37b6182SDimitry Andric   StackAlign = std::max(StackAlign, MaxAlign);
177f37b6182SDimitry Andric   unsigned AlignMask = StackAlign - 1;
178f37b6182SDimitry Andric   Offset = (Offset + AlignMask) & ~uint64_t(AlignMask);
179f37b6182SDimitry Andric 
180f37b6182SDimitry Andric   return (unsigned)Offset;
181f37b6182SDimitry Andric }
182f37b6182SDimitry Andric 
computeMaxCallFrameSize(const MachineFunction & MF)1830f5676f4SDimitry Andric void MachineFrameInfo::computeMaxCallFrameSize(const MachineFunction &MF) {
1840f5676f4SDimitry Andric   const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
1850f5676f4SDimitry Andric   unsigned FrameSetupOpcode = TII.getCallFrameSetupOpcode();
1860f5676f4SDimitry Andric   unsigned FrameDestroyOpcode = TII.getCallFrameDestroyOpcode();
1870f5676f4SDimitry Andric   assert(FrameSetupOpcode != ~0u && FrameDestroyOpcode != ~0u &&
1880f5676f4SDimitry Andric          "Can only compute MaxCallFrameSize if Setup/Destroy opcode are known");
1890f5676f4SDimitry Andric 
1900f5676f4SDimitry Andric   MaxCallFrameSize = 0;
1910f5676f4SDimitry Andric   for (const MachineBasicBlock &MBB : MF) {
1920f5676f4SDimitry Andric     for (const MachineInstr &MI : MBB) {
1930f5676f4SDimitry Andric       unsigned Opcode = MI.getOpcode();
1940f5676f4SDimitry Andric       if (Opcode == FrameSetupOpcode || Opcode == FrameDestroyOpcode) {
1950f5676f4SDimitry Andric         unsigned Size = TII.getFrameSize(MI);
1960f5676f4SDimitry Andric         MaxCallFrameSize = std::max(MaxCallFrameSize, Size);
1970f5676f4SDimitry Andric         AdjustsStack = true;
1980f5676f4SDimitry Andric       } else if (MI.isInlineAsm()) {
1990f5676f4SDimitry Andric         // Some inline asm's need a stack frame, as indicated by operand 1.
2000f5676f4SDimitry Andric         unsigned ExtraInfo = MI.getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
2010f5676f4SDimitry Andric         if (ExtraInfo & InlineAsm::Extra_IsAlignStack)
2020f5676f4SDimitry Andric           AdjustsStack = true;
2030f5676f4SDimitry Andric       }
2040f5676f4SDimitry Andric     }
2050f5676f4SDimitry Andric   }
2060f5676f4SDimitry Andric }
2070f5676f4SDimitry Andric 
print(const MachineFunction & MF,raw_ostream & OS) const208f37b6182SDimitry Andric void MachineFrameInfo::print(const MachineFunction &MF, raw_ostream &OS) const{
209f37b6182SDimitry Andric   if (Objects.empty()) return;
210f37b6182SDimitry Andric 
211f37b6182SDimitry Andric   const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering();
212f37b6182SDimitry Andric   int ValOffset = (FI ? FI->getOffsetOfLocalArea() : 0);
213f37b6182SDimitry Andric 
214f37b6182SDimitry Andric   OS << "Frame Objects:\n";
215f37b6182SDimitry Andric 
216f37b6182SDimitry Andric   for (unsigned i = 0, e = Objects.size(); i != e; ++i) {
217f37b6182SDimitry Andric     const StackObject &SO = Objects[i];
218f37b6182SDimitry Andric     OS << "  fi#" << (int)(i-NumFixedObjects) << ": ";
2192cab237bSDimitry Andric 
2202cab237bSDimitry Andric     if (SO.StackID != 0)
221*4ba319b5SDimitry Andric       OS << "id=" << static_cast<unsigned>(SO.StackID) << ' ';
2222cab237bSDimitry Andric 
223f37b6182SDimitry Andric     if (SO.Size == ~0ULL) {
224f37b6182SDimitry Andric       OS << "dead\n";
225f37b6182SDimitry Andric       continue;
226f37b6182SDimitry Andric     }
227f37b6182SDimitry Andric     if (SO.Size == 0)
228f37b6182SDimitry Andric       OS << "variable sized";
229f37b6182SDimitry Andric     else
230f37b6182SDimitry Andric       OS << "size=" << SO.Size;
231f37b6182SDimitry Andric     OS << ", align=" << SO.Alignment;
232f37b6182SDimitry Andric 
233f37b6182SDimitry Andric     if (i < NumFixedObjects)
234f37b6182SDimitry Andric       OS << ", fixed";
235f37b6182SDimitry Andric     if (i < NumFixedObjects || SO.SPOffset != -1) {
236f37b6182SDimitry Andric       int64_t Off = SO.SPOffset - ValOffset;
237f37b6182SDimitry Andric       OS << ", at location [SP";
238f37b6182SDimitry Andric       if (Off > 0)
239f37b6182SDimitry Andric         OS << "+" << Off;
240f37b6182SDimitry Andric       else if (Off < 0)
241f37b6182SDimitry Andric         OS << Off;
242f37b6182SDimitry Andric       OS << "]";
243f37b6182SDimitry Andric     }
244f37b6182SDimitry Andric     OS << "\n";
245f37b6182SDimitry Andric   }
246f37b6182SDimitry Andric }
247f37b6182SDimitry Andric 
248f37b6182SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump(const MachineFunction & MF) const249f37b6182SDimitry Andric LLVM_DUMP_METHOD void MachineFrameInfo::dump(const MachineFunction &MF) const {
250f37b6182SDimitry Andric   print(MF, dbgs());
251f37b6182SDimitry Andric }
252f37b6182SDimitry Andric #endif
253