1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
|
//===-- PrologEpilogInserter.cpp - Insert Prolog/Epilog code in function --===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass is responsible for finalizing the functions frame layout, saving
// callee saved registers, and for emitting prolog & epilog code for the
// function.
//
// This pass must be run after register allocation. After this pass is
// executed, it is illegal to construct MO_FrameIndex operands.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/MRegisterInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
namespace {
struct PEI : public MachineFunctionPass {
const char *getPassName() const {
return "Prolog/Epilog Insertion & Frame Finalization";
}
/// runOnMachineFunction - Insert prolog/epilog code and replace abstract
/// frame indexes with appropriate references.
///
bool runOnMachineFunction(MachineFunction &Fn) {
// Scan the function for modified caller saved registers and insert spill
// code for any caller saved registers that are modified. Also calculate
// the MaxCallFrameSize and HasCalls variables for the function's frame
// information and eliminates call frame pseudo instructions.
saveCallerSavedRegisters(Fn);
// Allow the target machine to make final modifications to the function
// before the frame layout is finalized.
Fn.getTarget().getRegisterInfo()->processFunctionBeforeFrameFinalized(Fn);
// Calculate actual frame offsets for all of the abstract stack objects...
calculateFrameObjectOffsets(Fn);
// Add prolog and epilog code to the function.
insertPrologEpilogCode(Fn);
// Replace all MO_FrameIndex operands with physical register references
// and actual offsets.
//
replaceFrameIndices(Fn);
return true;
}
private:
void saveCallerSavedRegisters(MachineFunction &Fn);
void calculateFrameObjectOffsets(MachineFunction &Fn);
void replaceFrameIndices(MachineFunction &Fn);
void insertPrologEpilogCode(MachineFunction &Fn);
};
}
/// createPrologEpilogCodeInserter - This function returns a pass that inserts
/// prolog and epilog code, and eliminates abstract frame references.
///
FunctionPass *createPrologEpilogCodeInserter() { return new PEI(); }
/// saveCallerSavedRegisters - Scan the function for modified caller saved
/// registers and insert spill code for any caller saved registers that are
/// modified. Also calculate the MaxCallFrameSize and HasCalls variables for
/// the function's frame information and eliminates call frame pseudo
/// instructions.
///
void PEI::saveCallerSavedRegisters(MachineFunction &Fn) {
const MRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo();
const TargetFrameInfo &FrameInfo = Fn.getTarget().getFrameInfo();
// Get the callee saved register list...
const unsigned *CSRegs = RegInfo->getCalleeSaveRegs();
// Get the function call frame set-up and tear-down instruction opcode
int FrameSetupOpcode = RegInfo->getCallFrameSetupOpcode();
int FrameDestroyOpcode = RegInfo->getCallFrameDestroyOpcode();
// Early exit for targets which have no callee saved registers and no call
// frame setup/destroy pseudo instructions.
if ((CSRegs == 0 || CSRegs[0] == 0) &&
FrameSetupOpcode == -1 && FrameDestroyOpcode == -1)
return;
// This bitset contains an entry for each physical register for the target...
std::vector<bool> ModifiedRegs(MRegisterInfo::FirstVirtualRegister);
unsigned MaxCallFrameSize = 0;
bool HasCalls = false;
for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB)
for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); )
if ((*I)->getOpcode() == FrameSetupOpcode ||
(*I)->getOpcode() == FrameDestroyOpcode) {
assert((*I)->getNumOperands() == 1 && "Call Frame Setup/Destroy Pseudo"
" instructions should have a single immediate argument!");
unsigned Size = (*I)->getOperand(0).getImmedValue();
if (Size > MaxCallFrameSize) MaxCallFrameSize = Size;
HasCalls = true;
RegInfo->eliminateCallFramePseudoInstr(Fn, *BB, I);
} else {
for (unsigned i = 0, e = (*I)->getNumOperands(); i != e; ++i) {
MachineOperand &MO = (*I)->getOperand(i);
assert(!MO.isVirtualRegister() &&
"Register allocation must be performed!");
if (MO.isPhysicalRegister() &&
(MO.opIsDefOnly() || MO.opIsDefAndUse()))
ModifiedRegs[MO.getReg()] = true; // Register is modified
}
++I;
}
MachineFrameInfo *FFI = Fn.getFrameInfo();
FFI->setHasCalls(HasCalls);
FFI->setMaxCallFrameSize(MaxCallFrameSize);
// Now figure out which *callee saved* registers are modified by the current
// function, thus needing to be saved and restored in the prolog/epilog.
//
std::vector<unsigned> RegsToSave;
for (unsigned i = 0; CSRegs[i]; ++i) {
unsigned Reg = CSRegs[i];
if (ModifiedRegs[Reg]) {
RegsToSave.push_back(Reg); // If modified register...
} else {
for (const unsigned *AliasSet = RegInfo->getAliasSet(Reg);
*AliasSet; ++AliasSet) { // Check alias registers too...
if (ModifiedRegs[*AliasSet]) {
RegsToSave.push_back(Reg);
break;
}
}
}
}
if (RegsToSave.empty())
return; // Early exit if no caller saved registers are modified!
// Now that we know which registers need to be saved and restored, allocate
// stack slots for them.
std::vector<int> StackSlots;
for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
int FrameIdx = FFI->CreateStackObject(RegInfo->getRegClass(RegsToSave[i]));
StackSlots.push_back(FrameIdx);
}
// Now that we have a stack slot for each register to be saved, insert spill
// code into the entry block...
MachineBasicBlock *MBB = Fn.begin();
MachineBasicBlock::iterator I = MBB->begin();
for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
const TargetRegisterClass *RC = RegInfo->getRegClass(RegsToSave[i]);
// Insert the spill to the stack frame...
RegInfo->storeRegToStackSlot(*MBB, I, RegsToSave[i], StackSlots[i], RC);
}
// Add code to restore the callee-save registers in each exiting block.
const TargetInstrInfo &TII = Fn.getTarget().getInstrInfo();
for (MachineFunction::iterator FI = Fn.begin(), E = Fn.end(); FI != E; ++FI) {
// If last instruction is a return instruction, add an epilogue
if (!FI->empty() && TII.isReturn(FI->back()->getOpcode())) {
MBB = FI; I = MBB->end()-1;
for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) {
const TargetRegisterClass *RC = RegInfo->getRegClass(RegsToSave[i]);
RegInfo->loadRegFromStackSlot(*MBB, I, RegsToSave[i],StackSlots[i], RC);
--I; // Insert in reverse order
}
}
}
}
/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the
/// abstract stack objects...
///
void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) {
const TargetFrameInfo &TFI = Fn.getTarget().getFrameInfo();
bool StackGrowsDown =
TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown;
assert(StackGrowsDown && "Only tested on stack down growing targets!");
// Loop over all of the stack objects, assigning sequential addresses...
MachineFrameInfo *FFI = Fn.getFrameInfo();
unsigned StackAlignment = TFI.getStackAlignment();
// Start at the beginning of the local area...
int Offset = TFI.getOffsetOfLocalArea();
for (unsigned i = 0, e = FFI->getObjectIndexEnd(); i != e; ++i) {
Offset += FFI->getObjectSize(i); // Allocate Size bytes...
unsigned Align = FFI->getObjectAlignment(i);
assert(Align <= StackAlignment && "Cannot align stack object to higher "
"alignment boundary than the stack itself!");
Offset = (Offset+Align-1)/Align*Align; // Adjust to Alignment boundary...
FFI->setObjectOffset(i, -Offset); // Set the computed offset
}
// Align the final stack pointer offset...
Offset = (Offset+StackAlignment-1)/StackAlignment*StackAlignment;
// Set the final value of the stack pointer...
FFI->setStackSize(Offset-TFI.getOffsetOfLocalArea());
}
/// insertPrologEpilogCode - Scan the function for modified caller saved
/// registers, insert spill code for these caller saved registers, then add
/// prolog and epilog code to the function.
///
void PEI::insertPrologEpilogCode(MachineFunction &Fn) {
// Add prologue to the function...
Fn.getTarget().getRegisterInfo()->emitPrologue(Fn);
// Add epilogue to restore the callee-save registers in each exiting block
const TargetInstrInfo &TII = Fn.getTarget().getInstrInfo();
for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) {
// If last instruction is a return instruction, add an epilogue
if (!I->empty() && TII.isReturn(I->back()->getOpcode()))
Fn.getTarget().getRegisterInfo()->emitEpilogue(Fn, *I);
|