10b57cec5SDimitry Andric //===-- MipsFrameLowering.cpp - Mips Frame Information --------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains the Mips implementation of TargetFrameLowering class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "MipsFrameLowering.h"
140b57cec5SDimitry Andric #include "MCTargetDesc/MipsBaseInfo.h"
150b57cec5SDimitry Andric #include "MipsInstrInfo.h"
160b57cec5SDimitry Andric #include "MipsMachineFunction.h"
170b57cec5SDimitry Andric #include "MipsTargetMachine.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
230b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h"
240b57cec5SDimitry Andric #include "llvm/IR/Function.h"
250b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h"
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric using namespace llvm;
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric
300b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
310b57cec5SDimitry Andric //
320b57cec5SDimitry Andric // Stack Frame Processing methods
330b57cec5SDimitry Andric // +----------------------------+
340b57cec5SDimitry Andric //
350b57cec5SDimitry Andric // The stack is allocated decrementing the stack pointer on
360b57cec5SDimitry Andric // the first instruction of a function prologue. Once decremented,
370b57cec5SDimitry Andric // all stack references are done thought a positive offset
380b57cec5SDimitry Andric // from the stack/frame pointer, so the stack is considering
390b57cec5SDimitry Andric // to grow up! Otherwise terrible hacks would have to be made
400b57cec5SDimitry Andric // to get this stack ABI compliant :)
410b57cec5SDimitry Andric //
420b57cec5SDimitry Andric // The stack frame required by the ABI (after call):
430b57cec5SDimitry Andric // Offset
440b57cec5SDimitry Andric //
450b57cec5SDimitry Andric // 0 ----------
460b57cec5SDimitry Andric // 4 Args to pass
470b57cec5SDimitry Andric // . saved $GP (used in PIC)
480b57cec5SDimitry Andric // . Alloca allocations
490b57cec5SDimitry Andric // . Local Area
500b57cec5SDimitry Andric // . CPU "Callee Saved" Registers
510b57cec5SDimitry Andric // . saved FP
520b57cec5SDimitry Andric // . saved RA
530b57cec5SDimitry Andric // . FPU "Callee Saved" Registers
540b57cec5SDimitry Andric // StackSize -----------
550b57cec5SDimitry Andric //
560b57cec5SDimitry Andric // Offset - offset from sp after stack allocation on function prologue
570b57cec5SDimitry Andric //
580b57cec5SDimitry Andric // The sp is the stack pointer subtracted/added from the stack size
590b57cec5SDimitry Andric // at the Prologue/Epilogue
600b57cec5SDimitry Andric //
610b57cec5SDimitry Andric // References to the previous stack (to obtain arguments) are done
620b57cec5SDimitry Andric // with offsets that exceeds the stack size: (stacksize+(4*(num_arg-1))
630b57cec5SDimitry Andric //
640b57cec5SDimitry Andric // Examples:
650b57cec5SDimitry Andric // - reference to the actual stack frame
660b57cec5SDimitry Andric // for any local area var there is smt like : FI >= 0, StackOffset: 4
670b57cec5SDimitry Andric // sw REGX, 4(SP)
680b57cec5SDimitry Andric //
690b57cec5SDimitry Andric // - reference to previous stack frame
700b57cec5SDimitry Andric // suppose there's a load to the 5th arguments : FI < 0, StackOffset: 16.
710b57cec5SDimitry Andric // The emitted instruction will be something like:
720b57cec5SDimitry Andric // lw REGX, 16+StackSize(SP)
730b57cec5SDimitry Andric //
740b57cec5SDimitry Andric // Since the total stack size is unknown on LowerFormalArguments, all
750b57cec5SDimitry Andric // stack references (ObjectOffset) created to reference the function
760b57cec5SDimitry Andric // arguments, are negative numbers. This way, on eliminateFrameIndex it's
770b57cec5SDimitry Andric // possible to detect those references and the offsets are adjusted to
780b57cec5SDimitry Andric // their real location.
790b57cec5SDimitry Andric //
800b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
810b57cec5SDimitry Andric
create(const MipsSubtarget & ST)820b57cec5SDimitry Andric const MipsFrameLowering *MipsFrameLowering::create(const MipsSubtarget &ST) {
830b57cec5SDimitry Andric if (ST.inMips16Mode())
840b57cec5SDimitry Andric return llvm::createMips16FrameLowering(ST);
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric return llvm::createMipsSEFrameLowering(ST);
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric // hasFP - Return true if the specified function should have a dedicated frame
900b57cec5SDimitry Andric // pointer register. This is true if the function has variable sized allocas,
910b57cec5SDimitry Andric // if it needs dynamic stack realignment, if frame pointer elimination is
920b57cec5SDimitry Andric // disabled, or if the frame address is taken.
hasFP(const MachineFunction & MF) const930b57cec5SDimitry Andric bool MipsFrameLowering::hasFP(const MachineFunction &MF) const {
940b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo();
950b57cec5SDimitry Andric const TargetRegisterInfo *TRI = STI.getRegisterInfo();
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric return MF.getTarget().Options.DisableFramePointerElim(MF) ||
980b57cec5SDimitry Andric MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken() ||
99*fe6060f1SDimitry Andric TRI->hasStackRealignment(MF);
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric
hasBP(const MachineFunction & MF) const1020b57cec5SDimitry Andric bool MipsFrameLowering::hasBP(const MachineFunction &MF) const {
1030b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo();
1040b57cec5SDimitry Andric const TargetRegisterInfo *TRI = STI.getRegisterInfo();
1050b57cec5SDimitry Andric
106*fe6060f1SDimitry Andric return MFI.hasVarSizedObjects() && TRI->hasStackRealignment(MF);
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andric // Estimate the size of the stack, including the incoming arguments. We need to
1100b57cec5SDimitry Andric // account for register spills, local objects, reserved call frame and incoming
1110b57cec5SDimitry Andric // arguments. This is required to determine the largest possible positive offset
1120b57cec5SDimitry Andric // from $sp so that it can be determined if an emergency spill slot for stack
1130b57cec5SDimitry Andric // addresses is required.
estimateStackSize(const MachineFunction & MF) const1140b57cec5SDimitry Andric uint64_t MipsFrameLowering::estimateStackSize(const MachineFunction &MF) const {
1150b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF.getFrameInfo();
1160b57cec5SDimitry Andric const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric int64_t Size = 0;
1190b57cec5SDimitry Andric
1200b57cec5SDimitry Andric // Iterate over fixed sized objects which are incoming arguments.
1210b57cec5SDimitry Andric for (int I = MFI.getObjectIndexBegin(); I != 0; ++I)
1220b57cec5SDimitry Andric if (MFI.getObjectOffset(I) > 0)
1230b57cec5SDimitry Andric Size += MFI.getObjectSize(I);
1240b57cec5SDimitry Andric
1250b57cec5SDimitry Andric // Conservatively assume all callee-saved registers will be saved.
1260b57cec5SDimitry Andric for (const MCPhysReg *R = TRI.getCalleeSavedRegs(&MF); *R; ++R) {
1270b57cec5SDimitry Andric unsigned RegSize = TRI.getSpillSize(*TRI.getMinimalPhysRegClass(*R));
1280b57cec5SDimitry Andric Size = alignTo(Size + RegSize, RegSize);
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric // Get the size of the rest of the frame objects and any possible reserved
1320b57cec5SDimitry Andric // call frame, accounting for alignment.
1330b57cec5SDimitry Andric return Size + MFI.estimateStackSize(MF);
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions
1370b57cec5SDimitry Andric MachineBasicBlock::iterator MipsFrameLowering::
eliminateCallFramePseudoInstr(MachineFunction & MF,MachineBasicBlock & MBB,MachineBasicBlock::iterator I) const1380b57cec5SDimitry Andric eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
1390b57cec5SDimitry Andric MachineBasicBlock::iterator I) const {
1400b57cec5SDimitry Andric unsigned SP = STI.getABI().IsN64() ? Mips::SP_64 : Mips::SP;
1410b57cec5SDimitry Andric
1420b57cec5SDimitry Andric if (!hasReservedCallFrame(MF)) {
1430b57cec5SDimitry Andric int64_t Amount = I->getOperand(0).getImm();
1440b57cec5SDimitry Andric if (I->getOpcode() == Mips::ADJCALLSTACKDOWN)
1450b57cec5SDimitry Andric Amount = -Amount;
1460b57cec5SDimitry Andric
1470b57cec5SDimitry Andric STI.getInstrInfo()->adjustStackPtr(SP, Amount, MBB, I);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric return MBB.erase(I);
1510b57cec5SDimitry Andric }
152