1 | //===-- MSP430FrameLowering.cpp - MSP430 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 MSP430 implementation of TargetFrameLowering class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "MSP430FrameLowering.h" |
14 | #include "MSP430InstrInfo.h" |
15 | #include "MSP430MachineFunctionInfo.h" |
16 | #include "MSP430Subtarget.h" |
17 | #include "llvm/CodeGen/MachineFrameInfo.h" |
18 | #include "llvm/CodeGen/MachineFunction.h" |
19 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
20 | #include "llvm/CodeGen/MachineModuleInfo.h" |
21 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
22 | #include "llvm/IR/DataLayout.h" |
23 | #include "llvm/IR/Function.h" |
24 | #include "llvm/Target/TargetOptions.h" |
25 | |
26 | using namespace llvm; |
27 | |
28 | MSP430FrameLowering::MSP430FrameLowering(const MSP430Subtarget &STI) |
29 | : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(2), -2, |
30 | Align(2)), |
31 | STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {} |
32 | |
33 | bool MSP430FrameLowering::hasFP(const MachineFunction &MF) const { |
34 | const MachineFrameInfo &MFI = MF.getFrameInfo(); |
35 | |
36 | return (MF.getTarget().Options.DisableFramePointerElim(MF) || |
37 | MF.getFrameInfo().hasVarSizedObjects() || |
38 | MFI.isFrameAddressTaken()); |
39 | } |
40 | |
41 | bool MSP430FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { |
42 | return !MF.getFrameInfo().hasVarSizedObjects(); |
43 | } |
44 | |
45 | void MSP430FrameLowering::BuildCFI(MachineBasicBlock &MBB, |
46 | MachineBasicBlock::iterator MBBI, |
47 | const DebugLoc &DL, |
48 | const MCCFIInstruction &CFIInst, |
49 | MachineInstr::MIFlag Flag) const { |
50 | MachineFunction &MF = *MBB.getParent(); |
51 | unsigned CFIIndex = MF.addFrameInst(Inst: CFIInst); |
52 | BuildMI(MBB, MBBI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) |
53 | .addCFIIndex(CFIIndex) |
54 | .setMIFlag(Flag); |
55 | } |
56 | |
57 | void MSP430FrameLowering::emitCalleeSavedFrameMoves( |
58 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, |
59 | const DebugLoc &DL, bool IsPrologue) const { |
60 | MachineFunction &MF = *MBB.getParent(); |
61 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
62 | MachineModuleInfo &MMI = MF.getMMI(); |
63 | const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); |
64 | |
65 | // Add callee saved registers to move list. |
66 | const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); |
67 | |
68 | // Calculate offsets. |
69 | for (const CalleeSavedInfo &I : CSI) { |
70 | int64_t Offset = MFI.getObjectOffset(ObjectIdx: I.getFrameIdx()); |
71 | Register Reg = I.getReg(); |
72 | unsigned DwarfReg = MRI->getDwarfRegNum(RegNum: Reg, isEH: true); |
73 | |
74 | if (IsPrologue) { |
75 | BuildCFI(MBB, MBBI, DL, |
76 | CFIInst: MCCFIInstruction::createOffset(L: nullptr, Register: DwarfReg, Offset)); |
77 | } else { |
78 | BuildCFI(MBB, MBBI, DL, |
79 | CFIInst: MCCFIInstruction::createRestore(L: nullptr, Register: DwarfReg)); |
80 | } |
81 | } |
82 | } |
83 | |
84 | void MSP430FrameLowering::emitPrologue(MachineFunction &MF, |
85 | MachineBasicBlock &MBB) const { |
86 | assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported" ); |
87 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
88 | MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>(); |
89 | const MSP430InstrInfo &TII = |
90 | *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); |
91 | |
92 | MachineBasicBlock::iterator MBBI = MBB.begin(); |
93 | DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); |
94 | |
95 | // Get the number of bytes to allocate from the FrameInfo. |
96 | uint64_t StackSize = MFI.getStackSize(); |
97 | int stackGrowth = -2; |
98 | |
99 | uint64_t NumBytes = 0; |
100 | if (hasFP(MF)) { |
101 | // Calculate required stack adjustment |
102 | uint64_t FrameSize = StackSize - 2; |
103 | NumBytes = FrameSize - MSP430FI->getCalleeSavedFrameSize(); |
104 | |
105 | // Get the offset of the stack slot for the EBP register... which is |
106 | // guaranteed to be the last slot by processFunctionBeforeFrameFinalized. |
107 | // Update the frame offset adjustment. |
108 | MFI.setOffsetAdjustment(-NumBytes); |
109 | |
110 | // Save FP into the appropriate stack slot... |
111 | BuildMI(MBB, MBBI, DL, TII.get(MSP430::PUSH16r)) |
112 | .addReg(MSP430::R4, RegState::Kill) |
113 | .setMIFlag(MachineInstr::FrameSetup); |
114 | |
115 | // Mark the place where FP was saved. |
116 | // Define the current CFA rule to use the provided offset. |
117 | BuildCFI(MBB, MBBI, DL, |
118 | CFIInst: MCCFIInstruction::cfiDefCfaOffset(L: nullptr, Offset: -2 * stackGrowth), |
119 | Flag: MachineInstr::FrameSetup); |
120 | |
121 | // Change the rule for the FramePtr to be an "offset" rule. |
122 | unsigned DwarfFramePtr = TRI->getDwarfRegNum(MSP430::R4, true); |
123 | BuildCFI( |
124 | MBB, MBBI, DL, |
125 | CFIInst: MCCFIInstruction::createOffset(L: nullptr, Register: DwarfFramePtr, Offset: 2 * stackGrowth), |
126 | Flag: MachineInstr::FrameSetup); |
127 | |
128 | // Update FP with the new base value... |
129 | BuildMI(MBB, MBBI, DL, TII.get(MSP430::MOV16rr), MSP430::R4) |
130 | .addReg(MSP430::SP) |
131 | .setMIFlag(MachineInstr::FrameSetup); |
132 | |
133 | // Mark effective beginning of when frame pointer becomes valid. |
134 | // Define the current CFA to use the FP register. |
135 | BuildCFI(MBB, MBBI, DL, |
136 | CFIInst: MCCFIInstruction::createDefCfaRegister(L: nullptr, Register: DwarfFramePtr), |
137 | Flag: MachineInstr::FrameSetup); |
138 | |
139 | // Mark the FramePtr as live-in in every block except the entry. |
140 | for (MachineBasicBlock &MBBJ : llvm::drop_begin(RangeOrContainer&: MF)) |
141 | MBBJ.addLiveIn(MSP430::R4); |
142 | } else |
143 | NumBytes = StackSize - MSP430FI->getCalleeSavedFrameSize(); |
144 | |
145 | // Skip the callee-saved push instructions. |
146 | int StackOffset = 2 * stackGrowth; |
147 | while (MBBI != MBB.end() && MBBI->getFlag(Flag: MachineInstr::FrameSetup) && |
148 | (MBBI->getOpcode() == MSP430::PUSH16r)) { |
149 | ++MBBI; |
150 | |
151 | if (!hasFP(MF)) { |
152 | // Mark callee-saved push instruction. |
153 | // Define the current CFA rule to use the provided offset. |
154 | assert(StackSize && "Expected stack frame" ); |
155 | BuildCFI(MBB, MBBI, DL, |
156 | CFIInst: MCCFIInstruction::cfiDefCfaOffset(L: nullptr, Offset: -StackOffset), |
157 | Flag: MachineInstr::FrameSetup); |
158 | StackOffset += stackGrowth; |
159 | } |
160 | } |
161 | |
162 | if (MBBI != MBB.end()) |
163 | DL = MBBI->getDebugLoc(); |
164 | |
165 | if (NumBytes) { // adjust stack pointer: SP -= numbytes |
166 | // If there is an SUB16ri of SP immediately before this instruction, merge |
167 | // the two. |
168 | //NumBytes -= mergeSPUpdates(MBB, MBBI, true); |
169 | // If there is an ADD16ri or SUB16ri of SP immediately after this |
170 | // instruction, merge the two instructions. |
171 | // mergeSPUpdatesDown(MBB, MBBI, &NumBytes); |
172 | |
173 | if (NumBytes) { |
174 | MachineInstr *MI = |
175 | BuildMI(MBB, MBBI, DL, TII.get(MSP430::SUB16ri), MSP430::SP) |
176 | .addReg(MSP430::SP) |
177 | .addImm(NumBytes) |
178 | .setMIFlag(MachineInstr::FrameSetup); |
179 | // The SRW implicit def is dead. |
180 | MI->getOperand(i: 3).setIsDead(); |
181 | } |
182 | if (!hasFP(MF)) { |
183 | // Adjust the previous CFA value if CFA was not redefined by FP |
184 | BuildCFI( |
185 | MBB, MBBI, DL, |
186 | CFIInst: MCCFIInstruction::cfiDefCfaOffset(L: nullptr, Offset: StackSize - stackGrowth), |
187 | Flag: MachineInstr::FrameSetup); |
188 | } |
189 | } |
190 | |
191 | emitCalleeSavedFrameMoves(MBB, MBBI, DL, IsPrologue: true); |
192 | } |
193 | |
194 | void MSP430FrameLowering::emitEpilogue(MachineFunction &MF, |
195 | MachineBasicBlock &MBB) const { |
196 | const MachineFrameInfo &MFI = MF.getFrameInfo(); |
197 | MSP430MachineFunctionInfo *MSP430FI = MF.getInfo<MSP430MachineFunctionInfo>(); |
198 | const MSP430InstrInfo &TII = |
199 | *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); |
200 | |
201 | MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); |
202 | unsigned RetOpcode = MBBI->getOpcode(); |
203 | DebugLoc DL = MBBI->getDebugLoc(); |
204 | |
205 | switch (RetOpcode) { |
206 | case MSP430::RET: |
207 | case MSP430::RETI: break; // These are ok |
208 | default: |
209 | llvm_unreachable("Can only insert epilog into returning blocks" ); |
210 | } |
211 | |
212 | // Get the number of bytes to allocate from the FrameInfo |
213 | uint64_t StackSize = MFI.getStackSize(); |
214 | unsigned CSSize = MSP430FI->getCalleeSavedFrameSize(); |
215 | uint64_t NumBytes = 0; |
216 | |
217 | MachineBasicBlock::iterator AfterPop = MBBI; |
218 | if (hasFP(MF)) { |
219 | // Calculate required stack adjustment |
220 | uint64_t FrameSize = StackSize - 2; |
221 | NumBytes = FrameSize - CSSize; |
222 | |
223 | // pop FP. |
224 | BuildMI(MBB, MBBI, DL, TII.get(MSP430::POP16r), MSP430::R4) |
225 | .setMIFlag(MachineInstr::FrameDestroy); |
226 | unsigned DwarfStackPtr = TRI->getDwarfRegNum(MSP430::SP, true); |
227 | BuildCFI(MBB, MBBI, DL, |
228 | CFIInst: MCCFIInstruction::cfiDefCfa(L: nullptr, Register: DwarfStackPtr, Offset: 2), |
229 | Flag: MachineInstr::FrameDestroy); |
230 | --MBBI; |
231 | if (!MBB.succ_empty() && !MBB.isReturnBlock()) { |
232 | unsigned DwarfFramePtr = TRI->getDwarfRegNum(MSP430::R4, true); |
233 | BuildCFI(MBB, MBBI: AfterPop, DL, |
234 | CFIInst: MCCFIInstruction::createRestore(L: nullptr, Register: DwarfFramePtr), |
235 | Flag: MachineInstr::FrameDestroy); |
236 | --MBBI; |
237 | --AfterPop; |
238 | } |
239 | } else |
240 | NumBytes = StackSize - CSSize; |
241 | |
242 | // Skip the callee-saved pop instructions. |
243 | MachineBasicBlock::iterator FirstCSPop = MBBI; |
244 | while (MBBI != MBB.begin()) { |
245 | MachineBasicBlock::iterator PI = std::prev(x: MBBI); |
246 | unsigned Opc = PI->getOpcode(); |
247 | if ((Opc != MSP430::POP16r || !PI->getFlag(MachineInstr::FrameDestroy)) && |
248 | !PI->isTerminator()) |
249 | break; |
250 | FirstCSPop = PI; |
251 | --MBBI; |
252 | } |
253 | MBBI = FirstCSPop; |
254 | |
255 | DL = MBBI->getDebugLoc(); |
256 | |
257 | // If there is an ADD16ri or SUB16ri of SP immediately before this |
258 | // instruction, merge the two instructions. |
259 | //if (NumBytes || MFI.hasVarSizedObjects()) |
260 | // mergeSPUpdatesUp(MBB, MBBI, StackPtr, &NumBytes); |
261 | |
262 | if (MFI.hasVarSizedObjects()) { |
263 | BuildMI(MBB, MBBI, DL, TII.get(MSP430::MOV16rr), MSP430::SP) |
264 | .addReg(MSP430::R4) |
265 | .setMIFlag(MachineInstr::FrameDestroy); |
266 | if (CSSize) { |
267 | MachineInstr *MI = |
268 | BuildMI(MBB, MBBI, DL, TII.get(MSP430::SUB16ri), MSP430::SP) |
269 | .addReg(MSP430::SP) |
270 | .addImm(CSSize) |
271 | .setMIFlag(MachineInstr::FrameDestroy); |
272 | // The SRW implicit def is dead. |
273 | MI->getOperand(i: 3).setIsDead(); |
274 | } |
275 | } else { |
276 | // adjust stack pointer back: SP += numbytes |
277 | if (NumBytes) { |
278 | MachineInstr *MI = |
279 | BuildMI(MBB, MBBI, DL, TII.get(MSP430::ADD16ri), MSP430::SP) |
280 | .addReg(MSP430::SP) |
281 | .addImm(NumBytes) |
282 | .setMIFlag(MachineInstr::FrameDestroy); |
283 | // The SRW implicit def is dead. |
284 | MI->getOperand(i: 3).setIsDead(); |
285 | |
286 | if (!hasFP(MF)) { |
287 | // Adjust CFA value if it was defined by SP |
288 | BuildCFI(MBB, MBBI, DL, |
289 | CFIInst: MCCFIInstruction::cfiDefCfaOffset(L: nullptr, Offset: CSSize + 2), |
290 | Flag: MachineInstr::FrameDestroy); |
291 | } |
292 | } |
293 | } |
294 | |
295 | if (!hasFP(MF)) { |
296 | MBBI = FirstCSPop; |
297 | int64_t Offset = -CSSize - 2; |
298 | // Mark callee-saved pop instruction. |
299 | // Define the current CFA rule to use the provided offset. |
300 | while (MBBI != MBB.end()) { |
301 | MachineBasicBlock::iterator PI = MBBI; |
302 | unsigned Opc = PI->getOpcode(); |
303 | ++MBBI; |
304 | if (Opc == MSP430::POP16r) { |
305 | Offset += 2; |
306 | BuildCFI(MBB, MBBI, DL, |
307 | CFIInst: MCCFIInstruction::cfiDefCfaOffset(L: nullptr, Offset: -Offset), |
308 | Flag: MachineInstr::FrameDestroy); |
309 | } |
310 | } |
311 | } |
312 | emitCalleeSavedFrameMoves(MBB, MBBI: AfterPop, DL, IsPrologue: false); |
313 | } |
314 | |
315 | // FIXME: Can we eleminate these in favour of generic code? |
316 | bool MSP430FrameLowering::spillCalleeSavedRegisters( |
317 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, |
318 | ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { |
319 | if (CSI.empty()) |
320 | return false; |
321 | |
322 | DebugLoc DL; |
323 | if (MI != MBB.end()) DL = MI->getDebugLoc(); |
324 | |
325 | MachineFunction &MF = *MBB.getParent(); |
326 | const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); |
327 | MSP430MachineFunctionInfo *MFI = MF.getInfo<MSP430MachineFunctionInfo>(); |
328 | MFI->setCalleeSavedFrameSize(CSI.size() * 2); |
329 | |
330 | for (const CalleeSavedInfo &I : CSI) { |
331 | Register Reg = I.getReg(); |
332 | // Add the callee-saved register as live-in. It's killed at the spill. |
333 | MBB.addLiveIn(PhysReg: Reg); |
334 | BuildMI(MBB, MI, DL, TII.get(MSP430::PUSH16r)) |
335 | .addReg(Reg, RegState::Kill) |
336 | .setMIFlag(MachineInstr::FrameSetup); |
337 | } |
338 | return true; |
339 | } |
340 | |
341 | bool MSP430FrameLowering::restoreCalleeSavedRegisters( |
342 | MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, |
343 | MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { |
344 | if (CSI.empty()) |
345 | return false; |
346 | |
347 | DebugLoc DL; |
348 | if (MI != MBB.end()) DL = MI->getDebugLoc(); |
349 | |
350 | MachineFunction &MF = *MBB.getParent(); |
351 | const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); |
352 | |
353 | for (const CalleeSavedInfo &I : llvm::reverse(CSI)) |
354 | BuildMI(MBB, MI, DL, TII.get(MSP430::POP16r), I.getReg()) |
355 | .setMIFlag(MachineInstr::FrameDestroy); |
356 | |
357 | return true; |
358 | } |
359 | |
360 | MachineBasicBlock::iterator MSP430FrameLowering::eliminateCallFramePseudoInstr( |
361 | MachineFunction &MF, MachineBasicBlock &MBB, |
362 | MachineBasicBlock::iterator I) const { |
363 | const MSP430InstrInfo &TII = |
364 | *static_cast<const MSP430InstrInfo *>(MF.getSubtarget().getInstrInfo()); |
365 | if (!hasReservedCallFrame(MF)) { |
366 | // If the stack pointer can be changed after prologue, turn the |
367 | // adjcallstackup instruction into a 'sub SP, <amt>' and the |
368 | // adjcallstackdown instruction into 'add SP, <amt>' |
369 | // TODO: consider using push / pop instead of sub + store / add |
370 | MachineInstr &Old = *I; |
371 | uint64_t Amount = TII.getFrameSize(Old); |
372 | if (Amount != 0) { |
373 | // We need to keep the stack aligned properly. To do this, we round the |
374 | // amount of space needed for the outgoing arguments up to the next |
375 | // alignment boundary. |
376 | Amount = alignTo(Size: Amount, A: getStackAlign()); |
377 | |
378 | MachineInstr *New = nullptr; |
379 | if (Old.getOpcode() == TII.getCallFrameSetupOpcode()) { |
380 | New = |
381 | BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::SUB16ri), MSP430::SP) |
382 | .addReg(MSP430::SP) |
383 | .addImm(Amount); |
384 | } else { |
385 | assert(Old.getOpcode() == TII.getCallFrameDestroyOpcode()); |
386 | // factor out the amount the callee already popped. |
387 | Amount -= TII.getFramePoppedByCallee(I: Old); |
388 | if (Amount) |
389 | New = BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::ADD16ri), |
390 | MSP430::SP) |
391 | .addReg(MSP430::SP) |
392 | .addImm(Amount); |
393 | } |
394 | |
395 | if (New) { |
396 | // The SRW implicit def is dead. |
397 | New->getOperand(i: 3).setIsDead(); |
398 | |
399 | // Replace the pseudo instruction with a new instruction... |
400 | MBB.insert(I, MI: New); |
401 | } |
402 | } |
403 | } else if (I->getOpcode() == TII.getCallFrameDestroyOpcode()) { |
404 | // If we are performing frame pointer elimination and if the callee pops |
405 | // something off the stack pointer, add it back. |
406 | if (uint64_t CalleeAmt = TII.getFramePoppedByCallee(I: *I)) { |
407 | MachineInstr &Old = *I; |
408 | MachineInstr *New = |
409 | BuildMI(MF, Old.getDebugLoc(), TII.get(MSP430::SUB16ri), MSP430::SP) |
410 | .addReg(MSP430::SP) |
411 | .addImm(CalleeAmt); |
412 | if (!hasFP(MF)) { |
413 | DebugLoc DL = I->getDebugLoc(); |
414 | BuildCFI(MBB, MBBI: I, DL, |
415 | CFIInst: MCCFIInstruction::createAdjustCfaOffset(L: nullptr, Adjustment: CalleeAmt)); |
416 | } |
417 | // The SRW implicit def is dead. |
418 | New->getOperand(i: 3).setIsDead(); |
419 | |
420 | MBB.insert(I, MI: New); |
421 | } |
422 | } |
423 | |
424 | return MBB.erase(I); |
425 | } |
426 | |
427 | void |
428 | MSP430FrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF, |
429 | RegScavenger *) const { |
430 | // Create a frame entry for the FP register that must be saved. |
431 | if (hasFP(MF)) { |
432 | int FrameIdx = MF.getFrameInfo().CreateFixedObject(Size: 2, SPOffset: -4, IsImmutable: true); |
433 | (void)FrameIdx; |
434 | assert(FrameIdx == MF.getFrameInfo().getObjectIndexBegin() && |
435 | "Slot for FP register must be last in order to be found!" ); |
436 | } |
437 | } |
438 | |