ARMFrameLowering.cpp [plain text]
#include "ARMFrameLowering.h"
#include "ARMBaseInstrInfo.h"
#include "ARMBaseRegisterInfo.h"
#include "ARMMachineFunctionInfo.h"
#include "MCTargetDesc/ARMAddressingModes.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;
static cl::opt<bool>
SpillAlignedNEONRegs("align-neon-spills", cl::Hidden, cl::init(true),
cl::desc("Align ARM NEON spills in prolog and epilog"));
static MachineBasicBlock::iterator
skipAlignedDPRCS2Spills(MachineBasicBlock::iterator MI,
unsigned NumAlignedDPRCS2Regs);
bool ARMFrameLowering::hasFP(const MachineFunction &MF) const {
const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo();
if (STI.isTargetIOS())
return true;
const MachineFrameInfo *MFI = MF.getFrameInfo();
return ((MF.getTarget().Options.DisableFramePointerElim(MF) &&
MFI->hasCalls()) ||
RegInfo->needsStackRealignment(MF) ||
MFI->hasVarSizedObjects() ||
MFI->isFrameAddressTaken());
}
bool ARMFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
const MachineFrameInfo *FFI = MF.getFrameInfo();
unsigned CFSize = FFI->getMaxCallFrameSize();
if (CFSize >= ((1 << 12) - 1) / 2) return false;
return !MF.getFrameInfo()->hasVarSizedObjects();
}
bool
ARMFrameLowering::canSimplifyCallFramePseudos(const MachineFunction &MF) const {
return hasReservedCallFrame(MF) || MF.getFrameInfo()->hasVarSizedObjects();
}
static bool isCalleeSavedRegister(unsigned Reg, const unsigned *CSRegs) {
for (unsigned i = 0; CSRegs[i]; ++i)
if (Reg == CSRegs[i])
return true;
return false;
}
static bool isCSRestore(MachineInstr *MI,
const ARMBaseInstrInfo &TII,
const unsigned *CSRegs) {
if (MI->getOpcode() == ARM::LDMIA_RET ||
MI->getOpcode() == ARM::t2LDMIA_RET ||
MI->getOpcode() == ARM::LDMIA_UPD ||
MI->getOpcode() == ARM::t2LDMIA_UPD ||
MI->getOpcode() == ARM::VLDMDIA_UPD) {
for (int i = 5, e = MI->getNumOperands(); i != e; ++i)
if (!isCalleeSavedRegister(MI->getOperand(i).getReg(), CSRegs))
return false;
return true;
}
if ((MI->getOpcode() == ARM::LDR_POST_IMM ||
MI->getOpcode() == ARM::LDR_POST_REG ||
MI->getOpcode() == ARM::t2LDR_POST) &&
isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs) &&
MI->getOperand(1).getReg() == ARM::SP)
return true;
return false;
}
static void
emitSPUpdate(bool isARM,
MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI,
DebugLoc dl, const ARMBaseInstrInfo &TII,
int NumBytes, unsigned MIFlags = MachineInstr::NoFlags) {
if (isARM)
emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, ARM::SP, NumBytes,
ARMCC::AL, 0, TII, MIFlags);
else
emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::SP, ARM::SP, NumBytes,
ARMCC::AL, 0, TII, MIFlags);
}
void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
MachineBasicBlock &MBB = MF.front();
MachineBasicBlock::iterator MBBI = MBB.begin();
MachineFrameInfo *MFI = MF.getFrameInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
const ARMBaseRegisterInfo *RegInfo =
static_cast<const ARMBaseRegisterInfo*>(MF.getTarget().getRegisterInfo());
const ARMBaseInstrInfo &TII =
*static_cast<const ARMBaseInstrInfo*>(MF.getTarget().getInstrInfo());
assert(!AFI->isThumb1OnlyFunction() &&
"This emitPrologue does not support Thumb1!");
bool isARM = !AFI->isThumbFunction();
unsigned VARegSaveSize = AFI->getVarArgsRegSaveSize();
unsigned NumBytes = MFI->getStackSize();
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
unsigned FramePtr = RegInfo->getFrameRegister(MF);
unsigned GPRCS1Size = 0, GPRCS2Size = 0, DPRCSSize = 0;
int FramePtrSpillFI = 0;
int D8SpillFI = 0;
if (VARegSaveSize)
emitSPUpdate(isARM, MBB, MBBI, dl, TII, -VARegSaveSize,
MachineInstr::FrameSetup);
if (!AFI->hasStackFrame()) {
if (NumBytes != 0)
emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes,
MachineInstr::FrameSetup);
return;
}
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
unsigned Reg = CSI[i].getReg();
int FI = CSI[i].getFrameIdx();
switch (Reg) {
case ARM::R4:
case ARM::R5:
case ARM::R6:
case ARM::R7:
case ARM::LR:
if (Reg == FramePtr)
FramePtrSpillFI = FI;
AFI->addGPRCalleeSavedArea1Frame(FI);
GPRCS1Size += 4;
break;
case ARM::R8:
case ARM::R9:
case ARM::R10:
case ARM::R11:
if (Reg == FramePtr)
FramePtrSpillFI = FI;
if (STI.isTargetIOS()) {
AFI->addGPRCalleeSavedArea2Frame(FI);
GPRCS2Size += 4;
} else {
AFI->addGPRCalleeSavedArea1Frame(FI);
GPRCS1Size += 4;
}
break;
default:
if (Reg == ARM::D8)
D8SpillFI = FI;
if (Reg < ARM::D8 || Reg >= ARM::D8 + AFI->getNumAlignedDPRCS2Regs()) {
AFI->addDPRCalleeSavedAreaFrame(FI);
DPRCSSize += 8;
}
}
}
if (GPRCS1Size > 0) MBBI++;
bool HasFP = hasFP(MF);
if (HasFP) {
unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : ARM::t2ADDri;
MachineInstrBuilder MIB =
BuildMI(MBB, MBBI, dl, TII.get(ADDriOpc), FramePtr)
.addFrameIndex(FramePtrSpillFI).addImm(0)
.setMIFlag(MachineInstr::FrameSetup);
AddDefaultCC(AddDefaultPred(MIB));
}
if (GPRCS2Size > 0) MBBI++;
unsigned DPRCSOffset = NumBytes - (GPRCS1Size + GPRCS2Size + DPRCSSize);
unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize;
unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size;
if (HasFP)
AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) +
NumBytes);
AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset);
AFI->setGPRCalleeSavedArea2Offset(GPRCS2Offset);
AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset);
if (DPRCSSize > 0) {
MBBI++;
while (MBBI->getOpcode() == ARM::VSTMDDB_UPD)
MBBI++;
}
if (AFI->getNumAlignedDPRCS2Regs() > 0) {
MBBI = skipAlignedDPRCS2Spills(MBBI, AFI->getNumAlignedDPRCS2Regs());
NumBytes += MFI->getObjectOffset(D8SpillFI);
} else
NumBytes = DPRCSOffset;
if (NumBytes) {
emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes,
MachineInstr::FrameSetup);
if (HasFP && isARM)
AFI->setShouldRestoreSPFromFP(true);
}
if (STI.isTargetELF() && hasFP(MF))
MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() -
AFI->getFramePtrSpillOffset());
AFI->setGPRCalleeSavedArea1Size(GPRCS1Size);
AFI->setGPRCalleeSavedArea2Size(GPRCS2Size);
AFI->setDPRCalleeSavedAreaSize(DPRCSSize);
if (!AFI->getNumAlignedDPRCS2Regs() && RegInfo->needsStackRealignment(MF)) {
unsigned MaxAlign = MFI->getMaxAlignment();
assert (!AFI->isThumb1OnlyFunction());
if (!AFI->isThumbFunction()) {
AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl,
TII.get(ARM::BICri), ARM::SP)
.addReg(ARM::SP, RegState::Kill)
.addImm(MaxAlign-1)));
} else {
AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), ARM::R4)
.addReg(ARM::SP, RegState::Kill));
AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl,
TII.get(ARM::t2BICri), ARM::R4)
.addReg(ARM::R4, RegState::Kill)
.addImm(MaxAlign-1)));
AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), ARM::SP)
.addReg(ARM::R4, RegState::Kill));
}
AFI->setShouldRestoreSPFromFP(true);
}
if (RegInfo->hasBasePointer(MF)) {
if (isARM)
BuildMI(MBB, MBBI, dl,
TII.get(ARM::MOVr), RegInfo->getBaseRegister())
.addReg(ARM::SP)
.addImm((unsigned)ARMCC::AL).addReg(0).addReg(0);
else
AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr),
RegInfo->getBaseRegister())
.addReg(ARM::SP));
}
if (MFI->hasVarSizedObjects())
AFI->setShouldRestoreSPFromFP(true);
}
void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
assert(MBBI->isReturn() && "Can only insert epilog into returning blocks");
unsigned RetOpcode = MBBI->getOpcode();
DebugLoc dl = MBBI->getDebugLoc();
MachineFrameInfo *MFI = MF.getFrameInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo();
const ARMBaseInstrInfo &TII =
*static_cast<const ARMBaseInstrInfo*>(MF.getTarget().getInstrInfo());
assert(!AFI->isThumb1OnlyFunction() &&
"This emitEpilogue does not support Thumb1!");
bool isARM = !AFI->isThumbFunction();
unsigned VARegSaveSize = AFI->getVarArgsRegSaveSize();
int NumBytes = (int)MFI->getStackSize();
unsigned FramePtr = RegInfo->getFrameRegister(MF);
if (!AFI->hasStackFrame()) {
if (NumBytes != 0)
emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes);
} else {
const unsigned *CSRegs = RegInfo->getCalleeSavedRegs();
if (MBBI != MBB.begin()) {
do
--MBBI;
while (MBBI != MBB.begin() && isCSRestore(MBBI, TII, CSRegs));
if (!isCSRestore(MBBI, TII, CSRegs))
++MBBI;
}
NumBytes -= (AFI->getGPRCalleeSavedArea1Size() +
AFI->getGPRCalleeSavedArea2Size() +
AFI->getDPRCalleeSavedAreaSize());
if (AFI->shouldRestoreSPFromFP()) {
NumBytes = AFI->getFramePtrSpillOffset() - NumBytes;
if (NumBytes) {
if (isARM)
emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes,
ARMCC::AL, 0, TII);
else {
assert(MF.getRegInfo().isPhysRegUsed(ARM::R4) &&
"No scratch register to restore SP from FP!");
emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes,
ARMCC::AL, 0, TII);
AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr),
ARM::SP)
.addReg(ARM::R4));
}
} else {
if (isARM)
BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), ARM::SP)
.addReg(FramePtr).addImm((unsigned)ARMCC::AL).addReg(0).addReg(0);
else
AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr),
ARM::SP)
.addReg(FramePtr));
}
} else if (NumBytes)
emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes);
if (AFI->getDPRCalleeSavedAreaSize()) {
MBBI++;
while (MBBI->getOpcode() == ARM::VLDMDIA_UPD)
MBBI++;
}
if (AFI->getGPRCalleeSavedArea2Size()) MBBI++;
if (AFI->getGPRCalleeSavedArea1Size()) MBBI++;
}
if (RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNdiND ||
RetOpcode == ARM::TCRETURNri || RetOpcode == ARM::TCRETURNriND) {
MBBI = MBB.getLastNonDebugInstr();
MachineOperand &JumpTarget = MBBI->getOperand(0);
if (RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNdiND) {
unsigned TCOpcode = (RetOpcode == ARM::TCRETURNdi)
? (STI.isThumb() ? ARM::tTAILJMPd : ARM::TAILJMPd)
: (STI.isThumb() ? ARM::tTAILJMPdND : ARM::TAILJMPdND);
MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(TCOpcode));
if (JumpTarget.isGlobal())
MIB.addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(),
JumpTarget.getTargetFlags());
else {
assert(JumpTarget.isSymbol());
MIB.addExternalSymbol(JumpTarget.getSymbolName(),
JumpTarget.getTargetFlags());
}
if (STI.isThumb()) MIB.addImm(ARMCC::AL).addReg(0);
} else if (RetOpcode == ARM::TCRETURNri) {
BuildMI(MBB, MBBI, dl,
TII.get(STI.isThumb() ? ARM::tTAILJMPr : ARM::TAILJMPr)).
addReg(JumpTarget.getReg(), RegState::Kill);
} else if (RetOpcode == ARM::TCRETURNriND) {
BuildMI(MBB, MBBI, dl,
TII.get(STI.isThumb() ? ARM::tTAILJMPrND : ARM::TAILJMPrND)).
addReg(JumpTarget.getReg(), RegState::Kill);
}
MachineInstr *NewMI = prior(MBBI);
for (unsigned i = 1, e = MBBI->getNumOperands(); i != e; ++i)
NewMI->addOperand(MBBI->getOperand(i));
MBB.erase(MBBI);
MBBI = NewMI;
}
if (VARegSaveSize)
emitSPUpdate(isARM, MBB, MBBI, dl, TII, VARegSaveSize);
}
int
ARMFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
unsigned &FrameReg) const {
return ResolveFrameIndexReference(MF, FI, FrameReg, 0);
}
int
ARMFrameLowering::ResolveFrameIndexReference(const MachineFunction &MF,
int FI, unsigned &FrameReg,
int SPAdj) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
const ARMBaseRegisterInfo *RegInfo =
static_cast<const ARMBaseRegisterInfo*>(MF.getTarget().getRegisterInfo());
const ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
int Offset = MFI->getObjectOffset(FI) + MFI->getStackSize();
int FPOffset = Offset - AFI->getFramePtrSpillOffset();
bool isFixed = MFI->isFixedObjectIndex(FI);
FrameReg = ARM::SP;
Offset += SPAdj;
if (AFI->isGPRCalleeSavedArea1Frame(FI))
return Offset - AFI->getGPRCalleeSavedArea1Offset();
else if (AFI->isGPRCalleeSavedArea2Frame(FI))
return Offset - AFI->getGPRCalleeSavedArea2Offset();
else if (AFI->isDPRCalleeSavedAreaFrame(FI))
return Offset - AFI->getDPRCalleeSavedAreaOffset();
bool hasMovingSP = MFI->hasVarSizedObjects() || !hasReservedCallFrame(MF);
if (RegInfo->needsStackRealignment(MF)) {
assert (hasFP(MF) && "dynamic stack realignment without a FP!");
if (isFixed) {
FrameReg = RegInfo->getFrameRegister(MF);
Offset = FPOffset;
} else if (hasMovingSP) {
assert(RegInfo->hasBasePointer(MF) &&
"VLAs and dynamic stack alignment, but missing base pointer!");
FrameReg = RegInfo->getBaseRegister();
}
return Offset;
}
if (hasFP(MF) && AFI->hasStackFrame()) {
if (isFixed || (hasMovingSP && !RegInfo->hasBasePointer(MF))) {
FrameReg = RegInfo->getFrameRegister(MF);
return FPOffset;
} else if (hasMovingSP) {
assert(RegInfo->hasBasePointer(MF) && "missing base pointer!");
if (AFI->isThumb2Function()) {
if (FPOffset >= -255 && FPOffset < 0) {
FrameReg = RegInfo->getFrameRegister(MF);
return FPOffset;
}
}
} else if (AFI->isThumb2Function()) {
if (Offset >= 0 && (Offset & 3) == 0 && Offset <= 1020)
return Offset;
if (FPOffset >= -255 && FPOffset < 0) {
FrameReg = RegInfo->getFrameRegister(MF);
return FPOffset;
}
} else if (Offset > (FPOffset < 0 ? -FPOffset : FPOffset)) {
FrameReg = RegInfo->getFrameRegister(MF);
return FPOffset;
}
}
if (RegInfo->hasBasePointer(MF))
FrameReg = RegInfo->getBaseRegister();
return Offset;
}
int ARMFrameLowering::getFrameIndexOffset(const MachineFunction &MF,
int FI) const {
unsigned FrameReg;
return getFrameIndexReference(MF, FI, FrameReg);
}
void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
unsigned StmOpc, unsigned StrOpc,
bool NoGap,
bool(*Func)(unsigned, bool),
unsigned NumAlignedDPRCS2Regs,
unsigned MIFlags) const {
MachineFunction &MF = *MBB.getParent();
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
DebugLoc DL;
if (MI != MBB.end()) DL = MI->getDebugLoc();
SmallVector<std::pair<unsigned,bool>, 4> Regs;
unsigned i = CSI.size();
while (i != 0) {
unsigned LastReg = 0;
for (; i != 0; --i) {
unsigned Reg = CSI[i-1].getReg();
if (!(Func)(Reg, STI.isTargetIOS())) continue;
if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs)
continue;
bool isKill = true;
if (Reg == ARM::LR) {
if (MF.getFrameInfo()->isReturnAddressTaken() &&
MF.getRegInfo().isLiveIn(Reg))
isKill = false;
}
if (isKill)
MBB.addLiveIn(Reg);
if (NoGap && LastReg && LastReg != Reg-1)
break;
LastReg = Reg;
Regs.push_back(std::make_pair(Reg, isKill));
}
if (Regs.empty())
continue;
if (Regs.size() > 1 || StrOpc== 0) {
MachineInstrBuilder MIB =
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(StmOpc), ARM::SP)
.addReg(ARM::SP).setMIFlags(MIFlags));
for (unsigned i = 0, e = Regs.size(); i < e; ++i)
MIB.addReg(Regs[i].first, getKillRegState(Regs[i].second));
} else if (Regs.size() == 1) {
MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(StrOpc),
ARM::SP)
.addReg(Regs[0].first, getKillRegState(Regs[0].second))
.addReg(ARM::SP).setMIFlags(MIFlags)
.addImm(-4);
AddDefaultPred(MIB);
}
Regs.clear();
}
}
void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
unsigned LdmOpc, unsigned LdrOpc,
bool isVarArg, bool NoGap,
bool(*Func)(unsigned, bool),
unsigned NumAlignedDPRCS2Regs) const {
MachineFunction &MF = *MBB.getParent();
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
DebugLoc DL = MI->getDebugLoc();
unsigned RetOpcode = MI->getOpcode();
bool isTailCall = (RetOpcode == ARM::TCRETURNdi ||
RetOpcode == ARM::TCRETURNdiND ||
RetOpcode == ARM::TCRETURNri ||
RetOpcode == ARM::TCRETURNriND);
SmallVector<unsigned, 4> Regs;
unsigned i = CSI.size();
while (i != 0) {
unsigned LastReg = 0;
bool DeleteRet = false;
for (; i != 0; --i) {
unsigned Reg = CSI[i-1].getReg();
if (!(Func)(Reg, STI.isTargetIOS())) continue;
if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs)
continue;
if (Reg == ARM::LR && !isTailCall && !isVarArg && STI.hasV5TOps()) {
Reg = ARM::PC;
LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET;
DeleteRet = true;
}
if (NoGap && LastReg && LastReg != Reg-1)
break;
LastReg = Reg;
Regs.push_back(Reg);
}
if (Regs.empty())
continue;
if (Regs.size() > 1 || LdrOpc == 0) {
MachineInstrBuilder MIB =
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(LdmOpc), ARM::SP)
.addReg(ARM::SP));
for (unsigned i = 0, e = Regs.size(); i < e; ++i)
MIB.addReg(Regs[i], getDefRegState(true));
if (DeleteRet) {
MIB->copyImplicitOps(&*MI);
MI->eraseFromParent();
}
MI = MIB;
} else if (Regs.size() == 1) {
if (Regs[0] == ARM::PC)
Regs[0] = ARM::LR;
MachineInstrBuilder MIB =
BuildMI(MBB, MI, DL, TII.get(LdrOpc), Regs[0])
.addReg(ARM::SP, RegState::Define)
.addReg(ARM::SP);
if (LdrOpc == ARM::LDR_POST_REG || LdrOpc == ARM::LDR_POST_IMM) {
MIB.addReg(0);
MIB.addImm(ARM_AM::getAM2Opc(ARM_AM::add, 4, ARM_AM::no_shift));
} else
MIB.addImm(4);
AddDefaultPred(MIB);
}
Regs.clear();
}
}
static void emitAlignedDPRCS2Spills(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
unsigned NumAlignedDPRCS2Regs,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) {
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
DebugLoc DL = MI->getDebugLoc();
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
MachineFrameInfo &MFI = *MF.getFrameInfo();
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
unsigned DNum = CSI[i].getReg() - ARM::D8;
if (DNum >= 8)
continue;
int FI = CSI[i].getFrameIdx();
MFI.setObjectAlignment(FI, DNum % 2 ? 8 : 16);
if (DNum == 0)
MFI.setObjectAlignment(FI, MFI.getMaxAlignment());
}
bool isThumb = AFI->isThumbFunction();
assert(!AFI->isThumb1OnlyFunction() && "Can't realign stack for thumb1");
AFI->setShouldRestoreSPFromFP(true);
unsigned Opc = isThumb ? ARM::t2SUBri : ARM::SUBri;
AddDefaultCC(AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(Opc), ARM::R4)
.addReg(ARM::SP)
.addImm(8 * NumAlignedDPRCS2Regs)));
Opc = isThumb ? ARM::t2BICri : ARM::BICri;
unsigned MaxAlign = MF.getFrameInfo()->getMaxAlignment();
AddDefaultCC(AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(Opc), ARM::R4)
.addReg(ARM::R4, RegState::Kill)
.addImm(MaxAlign - 1)));
Opc = isThumb ? ARM::tMOVr : ARM::MOVr;
MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(Opc), ARM::SP)
.addReg(ARM::R4);
MIB = AddDefaultPred(MIB);
if (!isThumb)
AddDefaultCC(MIB);
unsigned NextReg = ARM::D8;
if (NumAlignedDPRCS2Regs >= 6) {
unsigned SupReg = TRI->getMatchingSuperReg(NextReg, ARM::dsub_0,
ARM::QQPRRegisterClass);
MBB.addLiveIn(SupReg);
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(ARM::VST1d64Qwb_fixed),
ARM::R4)
.addReg(ARM::R4, RegState::Kill).addImm(16)
.addReg(NextReg)
.addReg(SupReg, RegState::ImplicitKill));
NextReg += 4;
NumAlignedDPRCS2Regs -= 4;
}
unsigned R4BaseReg = NextReg;
if (NumAlignedDPRCS2Regs >= 4) {
unsigned SupReg = TRI->getMatchingSuperReg(NextReg, ARM::dsub_0,
ARM::QQPRRegisterClass);
MBB.addLiveIn(SupReg);
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(ARM::VST1d64Q))
.addReg(ARM::R4).addImm(16).addReg(NextReg)
.addReg(SupReg, RegState::ImplicitKill));
NextReg += 4;
NumAlignedDPRCS2Regs -= 4;
}
if (NumAlignedDPRCS2Regs >= 2) {
unsigned SupReg = TRI->getMatchingSuperReg(NextReg, ARM::dsub_0,
ARM::QPRRegisterClass);
MBB.addLiveIn(SupReg);
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(ARM::VST1q64))
.addReg(ARM::R4).addImm(16).addReg(NextReg)
.addReg(SupReg, RegState::ImplicitKill));
NextReg += 2;
NumAlignedDPRCS2Regs -= 2;
}
if (NumAlignedDPRCS2Regs) {
MBB.addLiveIn(NextReg);
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(ARM::VSTRD))
.addReg(NextReg)
.addReg(ARM::R4).addImm((NextReg-R4BaseReg)*2));
}
llvm::prior(MI)->addRegisterKilled(ARM::R4, TRI);
}
static MachineBasicBlock::iterator
skipAlignedDPRCS2Spills(MachineBasicBlock::iterator MI,
unsigned NumAlignedDPRCS2Regs) {
++MI; ++MI; ++MI;
assert(MI->mayStore() && "Expecting spill instruction");
switch(NumAlignedDPRCS2Regs) {
case 7:
++MI;
assert(MI->mayStore() && "Expecting spill instruction");
default:
++MI;
assert(MI->mayStore() && "Expecting spill instruction");
case 1:
case 2:
case 4:
assert(MI->killsRegister(ARM::R4) && "Missed kill flag");
++MI;
}
return MI;
}
static void emitAlignedDPRCS2Restores(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
unsigned NumAlignedDPRCS2Regs,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) {
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
DebugLoc DL = MI->getDebugLoc();
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
int D8SpillFI = 0;
for (unsigned i = 0, e = CSI.size(); i != e; ++i)
if (CSI[i].getReg() == ARM::D8) {
D8SpillFI = CSI[i].getFrameIdx();
break;
}
bool isThumb = AFI->isThumbFunction();
assert(!AFI->isThumb1OnlyFunction() && "Can't realign stack for thumb1");
unsigned Opc = isThumb ? ARM::t2ADDri : ARM::ADDri;
AddDefaultCC(AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(Opc), ARM::R4)
.addFrameIndex(D8SpillFI).addImm(0)));
unsigned NextReg = ARM::D8;
if (NumAlignedDPRCS2Regs >= 6) {
unsigned SupReg = TRI->getMatchingSuperReg(NextReg, ARM::dsub_0,
ARM::QQPRRegisterClass);
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(ARM::VLD1d64Qwb_fixed), NextReg)
.addReg(ARM::R4, RegState::Define)
.addReg(ARM::R4, RegState::Kill).addImm(16)
.addReg(SupReg, RegState::ImplicitDefine));
NextReg += 4;
NumAlignedDPRCS2Regs -= 4;
}
unsigned R4BaseReg = NextReg;
if (NumAlignedDPRCS2Regs >= 4) {
unsigned SupReg = TRI->getMatchingSuperReg(NextReg, ARM::dsub_0,
ARM::QQPRRegisterClass);
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(ARM::VLD1d64Q), NextReg)
.addReg(ARM::R4).addImm(16)
.addReg(SupReg, RegState::ImplicitDefine));
NextReg += 4;
NumAlignedDPRCS2Regs -= 4;
}
if (NumAlignedDPRCS2Regs >= 2) {
unsigned SupReg = TRI->getMatchingSuperReg(NextReg, ARM::dsub_0,
ARM::QPRRegisterClass);
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(ARM::VLD1q64), NextReg)
.addReg(ARM::R4).addImm(16)
.addReg(SupReg, RegState::ImplicitDefine));
NextReg += 2;
NumAlignedDPRCS2Regs -= 2;
}
if (NumAlignedDPRCS2Regs)
AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(ARM::VLDRD), NextReg)
.addReg(ARM::R4).addImm(2*(NextReg-R4BaseReg)));
llvm::prior(MI)->addRegisterKilled(ARM::R4, TRI);
}
bool ARMFrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const {
if (CSI.empty())
return false;
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
unsigned PushOpc = AFI->isThumbFunction() ? ARM::t2STMDB_UPD : ARM::STMDB_UPD;
unsigned PushOneOpc = AFI->isThumbFunction() ?
ARM::t2STR_PRE : ARM::STR_PRE_IMM;
unsigned FltOpc = ARM::VSTMDDB_UPD;
unsigned NumAlignedDPRCS2Regs = AFI->getNumAlignedDPRCS2Regs();
emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea1Register, 0,
MachineInstr::FrameSetup);
emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea2Register, 0,
MachineInstr::FrameSetup);
emitPushInst(MBB, MI, CSI, FltOpc, 0, true, &isARMArea3Register,
NumAlignedDPRCS2Regs, MachineInstr::FrameSetup);
if (NumAlignedDPRCS2Regs)
emitAlignedDPRCS2Spills(MBB, MI, NumAlignedDPRCS2Regs, CSI, TRI);
return true;
}
bool ARMFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const {
if (CSI.empty())
return false;
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
bool isVarArg = AFI->getVarArgsRegSaveSize() > 0;
unsigned NumAlignedDPRCS2Regs = AFI->getNumAlignedDPRCS2Regs();
if (NumAlignedDPRCS2Regs)
emitAlignedDPRCS2Restores(MBB, MI, NumAlignedDPRCS2Regs, CSI, TRI);
unsigned PopOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_UPD : ARM::LDMIA_UPD;
unsigned LdrOpc = AFI->isThumbFunction() ? ARM::t2LDR_POST :ARM::LDR_POST_IMM;
unsigned FltOpc = ARM::VLDMDIA_UPD;
emitPopInst(MBB, MI, CSI, FltOpc, 0, isVarArg, true, &isARMArea3Register,
NumAlignedDPRCS2Regs);
emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
&isARMArea2Register, 0);
emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
&isARMArea1Register, 0);
return true;
}
static unsigned GetFunctionSizeInBytes(const MachineFunction &MF,
const ARMBaseInstrInfo &TII) {
unsigned FnSize = 0;
for (MachineFunction::const_iterator MBBI = MF.begin(), E = MF.end();
MBBI != E; ++MBBI) {
const MachineBasicBlock &MBB = *MBBI;
for (MachineBasicBlock::const_iterator I = MBB.begin(),E = MBB.end();
I != E; ++I)
FnSize += TII.GetInstSizeInBytes(I);
}
return FnSize;
}
static unsigned estimateStackSize(MachineFunction &MF) {
const MachineFrameInfo *MFI = MF.getFrameInfo();
const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo();
unsigned MaxAlign = MFI->getMaxAlignment();
int Offset = 0;
for (int i = MFI->getObjectIndexBegin(); i != 0; ++i) {
int FixedOff = -MFI->getObjectOffset(i);
if (FixedOff > Offset) Offset = FixedOff;
}
for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) {
if (MFI->isDeadObjectIndex(i))
continue;
Offset += MFI->getObjectSize(i);
unsigned Align = MFI->getObjectAlignment(i);
Offset = (Offset+Align-1)/Align*Align;
MaxAlign = std::max(Align, MaxAlign);
}
if (MFI->adjustsStack() && TFI->hasReservedCallFrame(MF))
Offset += MFI->getMaxCallFrameSize();
unsigned StackAlign;
if (MFI->adjustsStack() || MFI->hasVarSizedObjects() ||
(RegInfo->needsStackRealignment(MF) && MFI->getObjectIndexEnd() != 0))
StackAlign = TFI->getStackAlignment();
else
StackAlign = TFI->getTransientStackAlignment();
StackAlign = std::max(StackAlign, MaxAlign);
unsigned AlignMask = StackAlign - 1;
Offset = (Offset + AlignMask) & ~uint64_t(AlignMask);
return (unsigned)Offset;
}
static unsigned estimateRSStackSizeLimit(MachineFunction &MF,
const TargetFrameLowering *TFI) {
const ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
unsigned Limit = (1 << 12) - 1;
for (MachineFunction::iterator BB = MF.begin(),E = MF.end(); BB != E; ++BB) {
for (MachineBasicBlock::iterator I = BB->begin(), E = BB->end();
I != E; ++I) {
for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
if (!I->getOperand(i).isFI()) continue;
if (I->getOpcode() == ARM::ADDri) {
Limit = std::min(Limit, (1U << 8) - 1);
break;
}
switch (I->getDesc().TSFlags & ARMII::AddrModeMask) {
case ARMII::AddrMode3:
case ARMII::AddrModeT2_i8:
Limit = std::min(Limit, (1U << 8) - 1);
break;
case ARMII::AddrMode5:
case ARMII::AddrModeT2_i8s4:
Limit = std::min(Limit, ((1U << 8) - 1) * 4);
break;
case ARMII::AddrModeT2_i12:
if (TFI->hasFP(MF) && AFI->hasStackFrame())
Limit = std::min(Limit, (1U << 8) - 1);
break;
case ARMII::AddrMode4:
case ARMII::AddrMode6:
return 0;
default:
break;
}
break; }
}
}
return Limit;
}
static void checkNumAlignedDPRCS2Regs(MachineFunction &MF) {
MF.getInfo<ARMFunctionInfo>()->setNumAlignedDPRCS2Regs(0);
if (!SpillAlignedNEONRegs)
return;
if (MF.getFunction()->hasFnAttr(Attribute::Naked))
return;
if (!MF.getTarget().getSubtarget<ARMSubtarget>().hasNEON())
return;
if (MF.getTarget().getFrameLowering()->getStackAlignment() >= 8)
return;
const ARMBaseRegisterInfo *RegInfo =
static_cast<const ARMBaseRegisterInfo*>(MF.getTarget().getRegisterInfo());
if (!RegInfo->canRealignStack(MF))
return;
MachineRegisterInfo &MRI = MF.getRegInfo();
unsigned NumSpills = 0;
for (; NumSpills < 8; ++NumSpills)
if (!MRI.isPhysRegOrOverlapUsed(ARM::D8 + NumSpills))
break;
if (NumSpills < 2)
return;
MF.getInfo<ARMFunctionInfo>()->setNumAlignedDPRCS2Regs(NumSpills);
MF.getRegInfo().setPhysRegUsed(ARM::R4);
}
void
ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
RegScavenger *RS) const {
bool CanEliminateFrame = true;
bool CS1Spilled = false;
bool LRSpilled = false;
unsigned NumGPRSpills = 0;
SmallVector<unsigned, 4> UnspilledCS1GPRs;
SmallVector<unsigned, 4> UnspilledCS2GPRs;
const ARMBaseRegisterInfo *RegInfo =
static_cast<const ARMBaseRegisterInfo*>(MF.getTarget().getRegisterInfo());
const ARMBaseInstrInfo &TII =
*static_cast<const ARMBaseInstrInfo*>(MF.getTarget().getInstrInfo());
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
MachineFrameInfo *MFI = MF.getFrameInfo();
unsigned FramePtr = RegInfo->getFrameRegister(MF);
if (AFI->isThumb2Function() &&
(MFI->hasVarSizedObjects() || RegInfo->needsStackRealignment(MF)))
MF.getRegInfo().setPhysRegUsed(ARM::R4);
if (AFI->isThumb1OnlyFunction()) {
if (AFI->getVarArgsRegSaveSize() > 0)
MF.getRegInfo().setPhysRegUsed(ARM::LR);
unsigned StackSize = estimateStackSize(MF);
if (MFI->hasVarSizedObjects() || StackSize > 508)
MF.getRegInfo().setPhysRegUsed(ARM::R4);
}
checkNumAlignedDPRCS2Regs(MF);
if (RegInfo->hasBasePointer(MF))
MF.getRegInfo().setPhysRegUsed(RegInfo->getBaseRegister());
const unsigned *CSRegs = RegInfo->getCalleeSavedRegs();
for (unsigned i = 0; CSRegs[i]; ++i) {
unsigned Reg = CSRegs[i];
bool Spilled = false;
if (MF.getRegInfo().isPhysRegOrOverlapUsed(Reg)) {
Spilled = true;
CanEliminateFrame = false;
}
if (!ARM::GPRRegisterClass->contains(Reg))
continue;
if (Spilled) {
NumGPRSpills++;
if (!STI.isTargetIOS()) {
if (Reg == ARM::LR)
LRSpilled = true;
CS1Spilled = true;
continue;
}
switch (Reg) {
case ARM::LR:
LRSpilled = true;
case ARM::R4: case ARM::R5:
case ARM::R6: case ARM::R7:
CS1Spilled = true;
break;
default:
break;
}
} else {
if (!STI.isTargetIOS()) {
UnspilledCS1GPRs.push_back(Reg);
continue;
}
switch (Reg) {
case ARM::R4: case ARM::R5:
case ARM::R6: case ARM::R7:
case ARM::LR:
UnspilledCS1GPRs.push_back(Reg);
break;
default:
UnspilledCS2GPRs.push_back(Reg);
break;
}
}
}
bool ForceLRSpill = false;
if (!LRSpilled && AFI->isThumb1OnlyFunction()) {
unsigned FnSize = GetFunctionSizeInBytes(MF, TII);
if (FnSize >= (1 << 11)) {
CanEliminateFrame = false;
ForceLRSpill = true;
}
}
bool BigStack =
(RS &&
(estimateStackSize(MF) + ((hasFP(MF) && AFI->hasStackFrame()) ? 4:0) >=
estimateRSStackSizeLimit(MF, this)))
|| MFI->hasVarSizedObjects()
|| (MFI->adjustsStack() && !canSimplifyCallFramePseudos(MF));
bool ExtraCSSpill = false;
if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF)) {
AFI->setHasStackFrame(true);
if (!LRSpilled && CS1Spilled) {
MF.getRegInfo().setPhysRegUsed(ARM::LR);
NumGPRSpills++;
UnspilledCS1GPRs.erase(std::find(UnspilledCS1GPRs.begin(),
UnspilledCS1GPRs.end(), (unsigned)ARM::LR));
ForceLRSpill = false;
ExtraCSSpill = true;
}
if (hasFP(MF)) {
MF.getRegInfo().setPhysRegUsed(FramePtr);
NumGPRSpills++;
}
unsigned TargetAlign = getStackAlignment();
if (TargetAlign == 8 && (NumGPRSpills & 1)) {
if (CS1Spilled && !UnspilledCS1GPRs.empty()) {
for (unsigned i = 0, e = UnspilledCS1GPRs.size(); i != e; ++i) {
unsigned Reg = UnspilledCS1GPRs[i];
if (!AFI->isThumb1OnlyFunction() ||
isARMLowRegister(Reg) || Reg == ARM::LR) {
MF.getRegInfo().setPhysRegUsed(Reg);
if (!RegInfo->isReservedReg(MF, Reg))
ExtraCSSpill = true;
break;
}
}
} else if (!UnspilledCS2GPRs.empty() && !AFI->isThumb1OnlyFunction()) {
unsigned Reg = UnspilledCS2GPRs.front();
MF.getRegInfo().setPhysRegUsed(Reg);
if (!RegInfo->isReservedReg(MF, Reg))
ExtraCSSpill = true;
}
}
if (BigStack && !ExtraCSSpill) {
unsigned NumExtras = TargetAlign / 4;
SmallVector<unsigned, 2> Extras;
while (NumExtras && !UnspilledCS1GPRs.empty()) {
unsigned Reg = UnspilledCS1GPRs.back();
UnspilledCS1GPRs.pop_back();
if (!RegInfo->isReservedReg(MF, Reg) &&
(!AFI->isThumb1OnlyFunction() || isARMLowRegister(Reg) ||
Reg == ARM::LR)) {
Extras.push_back(Reg);
NumExtras--;
}
}
if (!AFI->isThumb1OnlyFunction()) {
while (NumExtras && !UnspilledCS2GPRs.empty()) {
unsigned Reg = UnspilledCS2GPRs.back();
UnspilledCS2GPRs.pop_back();
if (!RegInfo->isReservedReg(MF, Reg)) {
Extras.push_back(Reg);
NumExtras--;
}
}
}
if (Extras.size() && NumExtras == 0) {
for (unsigned i = 0, e = Extras.size(); i != e; ++i) {
MF.getRegInfo().setPhysRegUsed(Extras[i]);
}
} else if (!AFI->isThumb1OnlyFunction()) {
const TargetRegisterClass *RC = ARM::GPRRegisterClass;
RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(),
RC->getAlignment(),
false));
}
}
}
if (ForceLRSpill) {
MF.getRegInfo().setPhysRegUsed(ARM::LR);
AFI->setLRIsSpilledForFarJump(true);
}
}