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