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