1//===-- LanaiFrameLowering.cpp - Lanai Frame Information ------------------===//
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 contains the Lanai implementation of TargetFrameLowering class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "LanaiFrameLowering.h"
14
15#include "LanaiAluCode.h"
16#include "LanaiInstrInfo.h"
17#include "LanaiSubtarget.h"
18#include "llvm/CodeGen/MachineFrameInfo.h"
19#include "llvm/CodeGen/MachineFunction.h"
20#include "llvm/CodeGen/MachineInstrBuilder.h"
21
22using namespace llvm;
23
24// Determines the size of the frame and maximum call frame size.
25void LanaiFrameLowering::determineFrameLayout(MachineFunction &MF) const {
26 MachineFrameInfo &MFI = MF.getFrameInfo();
27 const LanaiRegisterInfo *LRI = STI.getRegisterInfo();
28
29 // Get the number of bytes to allocate from the FrameInfo.
30 unsigned FrameSize = MFI.getStackSize();
31
32 // Get the alignment.
33 Align StackAlign =
34 LRI->hasStackRealignment(MF) ? MFI.getMaxAlign() : getStackAlign();
35
36 // Get the maximum call frame size of all the calls.
37 unsigned MaxCallFrameSize = MFI.getMaxCallFrameSize();
38
39 // If we have dynamic alloca then MaxCallFrameSize needs to be aligned so
40 // that allocations will be aligned.
41 if (MFI.hasVarSizedObjects())
42 MaxCallFrameSize = alignTo(Size: MaxCallFrameSize, A: StackAlign);
43
44 // Update maximum call frame size.
45 MFI.setMaxCallFrameSize(MaxCallFrameSize);
46
47 // Include call frame size in total.
48 if (!(hasReservedCallFrame(MF) && MFI.adjustsStack()))
49 FrameSize += MaxCallFrameSize;
50
51 // Make sure the frame is aligned.
52 FrameSize = alignTo(Size: FrameSize, A: StackAlign);
53
54 // Update frame info.
55 MFI.setStackSize(FrameSize);
56}
57
58// Iterates through each basic block in a machine function and replaces
59// ADJDYNALLOC pseudo instructions with a Lanai:ADDI with the
60// maximum call frame size as the immediate.
61void LanaiFrameLowering::replaceAdjDynAllocPseudo(MachineFunction &MF) const {
62 const LanaiInstrInfo &LII = *STI.getInstrInfo();
63 unsigned MaxCallFrameSize = MF.getFrameInfo().getMaxCallFrameSize();
64
65 for (MachineBasicBlock &MBB : MF) {
66 for (MachineInstr &MI : llvm::make_early_inc_range(Range&: MBB)) {
67 if (MI.getOpcode() == Lanai::ADJDYNALLOC) {
68 DebugLoc DL = MI.getDebugLoc();
69 Register Dst = MI.getOperand(i: 0).getReg();
70 Register Src = MI.getOperand(i: 1).getReg();
71
72 BuildMI(BB&: MBB, I&: MI, MIMD: DL, MCID: LII.get(Opcode: Lanai::ADD_I_LO), DestReg: Dst)
73 .addReg(RegNo: Src)
74 .addImm(Val: MaxCallFrameSize);
75 MI.eraseFromParent();
76 }
77 }
78 }
79}
80
81// Generates the following sequence for function entry:
82// st %fp,-4[*%sp] !push old FP
83// add %sp,8,%fp !generate new FP
84// sub %sp,0x4,%sp !allocate stack space (as needed)
85void LanaiFrameLowering::emitPrologue(MachineFunction &MF,
86 MachineBasicBlock &MBB) const {
87 assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
88
89 MachineFrameInfo &MFI = MF.getFrameInfo();
90 const LanaiInstrInfo &LII = *STI.getInstrInfo();
91 MachineBasicBlock::iterator MBBI = MBB.begin();
92
93 // Debug location must be unknown since the first debug location is used
94 // to determine the end of the prologue.
95 DebugLoc DL;
96
97 // Determine the correct frame layout
98 determineFrameLayout(MF);
99
100 // FIXME: This appears to be overallocating. Needs investigation.
101 // Get the number of bytes to allocate from the FrameInfo.
102 unsigned StackSize = MFI.getStackSize();
103
104 // Push old FP
105 // st %fp,-4[*%sp]
106 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: LII.get(Opcode: Lanai::SW_RI))
107 .addReg(RegNo: Lanai::FP)
108 .addReg(RegNo: Lanai::SP)
109 .addImm(Val: -4)
110 .addImm(Val: LPAC::makePreOp(AluOp: LPAC::ADD))
111 .setMIFlag(MachineInstr::FrameSetup);
112
113 // Generate new FP
114 // add %sp,8,%fp
115 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: LII.get(Opcode: Lanai::ADD_I_LO), DestReg: Lanai::FP)
116 .addReg(RegNo: Lanai::SP)
117 .addImm(Val: 8)
118 .setMIFlag(MachineInstr::FrameSetup);
119
120 // Allocate space on the stack if needed
121 // sub %sp,StackSize,%sp
122 if (StackSize != 0) {
123 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: LII.get(Opcode: Lanai::SUB_I_LO), DestReg: Lanai::SP)
124 .addReg(RegNo: Lanai::SP)
125 .addImm(Val: StackSize)
126 .setMIFlag(MachineInstr::FrameSetup);
127 }
128
129 // Replace ADJDYNANALLOC
130 if (MFI.hasVarSizedObjects())
131 replaceAdjDynAllocPseudo(MF);
132}
133
134MachineBasicBlock::iterator LanaiFrameLowering::eliminateCallFramePseudoInstr(
135 MachineFunction & /*MF*/, MachineBasicBlock &MBB,
136 MachineBasicBlock::iterator I) const {
137 // Discard ADJCALLSTACKDOWN, ADJCALLSTACKUP instructions.
138 return MBB.erase(I);
139}
140
141// The function epilogue should not depend on the current stack pointer!
142// It should use the frame pointer only. This is mandatory because
143// of alloca; we also take advantage of it to omit stack adjustments
144// before returning.
145//
146// Note that when we go to restore the preserved register values we must
147// not try to address their slots by using offsets from the stack pointer.
148// That's because the stack pointer may have been moved during the function
149// execution due to a call to alloca(). Rather, we must restore all
150// preserved registers via offsets from the frame pointer value.
151//
152// Note also that when the current frame is being "popped" (by adjusting
153// the value of the stack pointer) on function exit, we must (for the
154// sake of alloca) set the new value of the stack pointer based upon
155// the current value of the frame pointer. We can't just add what we
156// believe to be the (static) frame size to the stack pointer because
157// if we did that, and alloca() had been called during this function,
158// we would end up returning *without* having fully deallocated all of
159// the space grabbed by alloca. If that happened, and a function
160// containing one or more alloca() calls was called over and over again,
161// then the stack would grow without limit!
162//
163// RET is lowered to
164// ld -4[%fp],%pc # modify %pc (two delay slots)
165// as the return address is in the stack frame and mov to pc is allowed.
166// emitEpilogue emits
167// mov %fp,%sp # restore the stack pointer
168// ld -8[%fp],%fp # restore the caller's frame pointer
169// before RET and the delay slot filler will move RET such that these
170// instructions execute in the delay slots of the load to PC.
171void LanaiFrameLowering::emitEpilogue(MachineFunction & /*MF*/,
172 MachineBasicBlock &MBB) const {
173 MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
174 const LanaiInstrInfo &LII = *STI.getInstrInfo();
175 DebugLoc DL = MBBI->getDebugLoc();
176
177 // Restore the stack pointer using the callee's frame pointer value.
178 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: LII.get(Opcode: Lanai::ADD_I_LO), DestReg: Lanai::SP)
179 .addReg(RegNo: Lanai::FP)
180 .addImm(Val: 0);
181
182 // Restore the frame pointer from the stack.
183 BuildMI(BB&: MBB, I: MBBI, MIMD: DL, MCID: LII.get(Opcode: Lanai::LDW_RI), DestReg: Lanai::FP)
184 .addReg(RegNo: Lanai::FP)
185 .addImm(Val: -8)
186 .addImm(Val: LPAC::ADD);
187}
188
189void LanaiFrameLowering::determineCalleeSaves(MachineFunction &MF,
190 BitVector &SavedRegs,
191 RegScavenger *RS) const {
192 TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);
193
194 MachineFrameInfo &MFI = MF.getFrameInfo();
195 const LanaiRegisterInfo *LRI = STI.getRegisterInfo();
196 int Offset = -4;
197
198 // Reserve 4 bytes for the saved RCA
199 MFI.CreateFixedObject(Size: 4, SPOffset: Offset, IsImmutable: true);
200 Offset -= 4;
201
202 // Reserve 4 bytes for the saved FP
203 MFI.CreateFixedObject(Size: 4, SPOffset: Offset, IsImmutable: true);
204 Offset -= 4;
205
206 if (LRI->hasBasePointer(MF)) {
207 MFI.CreateFixedObject(Size: 4, SPOffset: Offset, IsImmutable: true);
208 SavedRegs.reset(Idx: LRI->getBaseRegister());
209 }
210}
211