#include "ARMMachineFunctionInfo.h"
#include "ARMRegisterInfo.h"
#include "ARMSubtarget.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLocation.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
-#include "llvm/Type.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
if (!AFI->isThumbFunction() || CSI.empty())
return false;
+ bool isVarArg = AFI->getVarArgsRegSaveSize() > 0;
MachineInstr *PopMI = new MachineInstr(TII.get(ARM::tPOP));
MBB.insert(MI, PopMI);
for (unsigned i = CSI.size(); i != 0; --i) {
unsigned Reg = CSI[i-1].getReg();
if (Reg == ARM::LR) {
+ // Special epilogue for vararg functions. See emitEpilogue
+ if (isVarArg)
+ continue;
Reg = ARM::PC;
PopMI->setInstrDescriptor(TII.get(ARM::tPOP_RET));
MBB.erase(MI);
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
if (AFI->isThumbFunction())
- BuildMI(MBB, I, TII.get(ARM::tSTRspi)).addReg(SrcReg)
+ BuildMI(MBB, I, TII.get(ARM::tSpill)).addReg(SrcReg)
.addFrameIndex(FI).addImm(0);
else
BuildMI(MBB, I, TII.get(ARM::STR)).addReg(SrcReg)
MachineFunction &MF = *MBB.getParent();
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
if (AFI->isThumbFunction())
- BuildMI(MBB, I, TII.get(ARM::tLDRspi), DestReg)
+ BuildMI(MBB, I, TII.get(ARM::tRestore), DestReg)
.addFrameIndex(FI).addImm(0);
else
BuildMI(MBB, I, TII.get(ARM::LDR), DestReg)
abort();
}
+/// isLowRegister - Returns true if the register is low register r0-r7.
+///
+static bool isLowRegister(unsigned Reg) {
+ using namespace ARM;
+ switch (Reg) {
+ case R0: case R1: case R2: case R3:
+ case R4: case R5: case R6: case R7:
+ return true;
+ default:
+ return false;
+ }
+}
+
MachineInstr *ARMRegisterInfo::foldMemoryOperand(MachineInstr *MI,
unsigned OpNum, int FI) const {
unsigned Opc = MI->getOpcode();
case ARM::tMOVrr: {
if (OpNum == 0) { // move -> store
unsigned SrcReg = MI->getOperand(1).getReg();
- NewMI = BuildMI(TII.get(ARM::tSTRspi)).addReg(SrcReg).addFrameIndex(FI)
+ if (!isLowRegister(SrcReg))
+ // tSpill cannot take a high register operand.
+ break;
+ NewMI = BuildMI(TII.get(ARM::tSpill)).addReg(SrcReg).addFrameIndex(FI)
.addImm(0);
} else { // move -> load
unsigned DstReg = MI->getOperand(0).getReg();
- NewMI = BuildMI(TII.get(ARM::tLDRspi), DstReg).addFrameIndex(FI)
+ if (!isLowRegister(DstReg))
+ // tRestore cannot target a high register operand.
+ break;
+ NewMI = BuildMI(TII.get(ARM::tRestore), DstReg).addFrameIndex(FI)
.addImm(0);
}
break;
return NoFramePointerElim || MF.getFrameInfo()->hasVarSizedObjects();
}
-/// emitARMRegPlusImmediate - Emit a series of instructions to materialize
+/// emitARMRegPlusImmediate - Emits a series of instructions to materialize
/// a destreg = basereg + immediate in ARM code.
static
void emitARMRegPlusImmediate(MachineBasicBlock &MBB,
}
}
-/// isLowRegister - Returns true if the register is low register r0-r7.
-///
-static bool isLowRegister(unsigned Reg) {
- using namespace ARM;
- switch (Reg) {
- case R0: case R1: case R2: case R3:
- case R4: case R5: case R6: case R7:
- return true;
- default:
- return false;
+/// calcNumMI - Returns the number of instructions required to materialize
+/// the specific add / sub r, c instruction.
+static unsigned calcNumMI(int Opc, int ExtraOpc, unsigned Bytes,
+ unsigned NumBits, unsigned Scale) {
+ unsigned NumMIs = 0;
+ unsigned Chunk = ((1 << NumBits) - 1) * Scale;
+
+ if (Opc == ARM::tADDrSPi) {
+ unsigned ThisVal = (Bytes > Chunk) ? Chunk : Bytes;
+ Bytes -= ThisVal;
+ NumMIs++;
+ NumBits = 8;
+ Scale = 1;
+ Chunk = ((1 << NumBits) - 1) * Scale;
}
+
+ NumMIs += Bytes / Chunk;
+ if ((Bytes % Chunk) != 0)
+ NumMIs++;
+ if (ExtraOpc)
+ NumMIs++;
+ return NumMIs;
+}
+
+/// emitThumbRegPlusConstPool - Emits a series of instructions to materialize
+/// a destreg = basereg + immediate in Thumb code. Load the immediate from a
+/// constpool entry.
+static
+void emitThumbRegPlusConstPool(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator &MBBI,
+ unsigned DestReg, unsigned BaseReg,
+ int NumBytes, const TargetInstrInfo &TII) {
+ MachineFunction &MF = *MBB.getParent();
+ MachineConstantPool *ConstantPool = MF.getConstantPool();
+ bool isHigh = !isLowRegister(DestReg) || !isLowRegister(BaseReg);
+ bool isSub = false;
+ // Subtract doesn't have high register version. Load the negative value
+ // if either base or dest register is a high register.
+ if (NumBytes < 0 && !isHigh) {
+ isSub = true;
+ NumBytes = -NumBytes;
+ }
+ Constant *C = ConstantInt::get(Type::Int32Ty, NumBytes);
+ unsigned Idx = ConstantPool->getConstantPoolIndex(C, 2);
+ unsigned LdReg = DestReg;
+ if (DestReg == ARM::SP) {
+ assert(BaseReg == ARM::SP && "Unexpected!");
+ LdReg = ARM::R3;
+ BuildMI(MBB, MBBI, TII.get(ARM::tMOVrr), ARM::R12).addReg(ARM::R3);
+ }
+ // Load the constant.
+ BuildMI(MBB, MBBI, TII.get(ARM::tLDRpci), LdReg).addConstantPoolIndex(Idx);
+ // Emit add / sub.
+ int Opc = (isSub) ? ARM::tSUBrr : (isHigh ? ARM::tADDhirr : ARM::tADDrr);
+ const MachineInstrBuilder MIB = BuildMI(MBB, MBBI, TII.get(Opc), DestReg);
+ if (DestReg == ARM::SP)
+ MIB.addReg(BaseReg).addReg(LdReg);
+ else if (isSub)
+ MIB.addReg(BaseReg).addReg(LdReg);
+ else
+ MIB.addReg(LdReg).addReg(BaseReg);
+ if (DestReg == ARM::SP)
+ BuildMI(MBB, MBBI, TII.get(ARM::tMOVrr), ARM::R3).addReg(ARM::R12);
}
-/// emitThumbRegPlusImmediate - Emit a series of instructions to materialize
+/// emitThumbRegPlusImmediate - Emits a series of instructions to materialize
/// a destreg = basereg + immediate in Thumb code.
static
void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
if (isSub) Bytes = -NumBytes;
bool isMul4 = (Bytes & 3) == 0;
bool isTwoAddr = false;
+ bool DstNotEqBase = false;
unsigned NumBits = 1;
- unsigned Opc = 0;
- unsigned ExtraOpc = 0;
+ unsigned Scale = 1;
+ int Opc = 0;
+ int ExtraOpc = 0;
if (DestReg == BaseReg && BaseReg == ARM::SP) {
assert(isMul4 && "Thumb sp inc / dec size must be multiple of 4!");
- Bytes >>= 2; // Implicitly multiplied by 4.
NumBits = 7;
+ Scale = 4;
Opc = isSub ? ARM::tSUBspi : ARM::tADDspi;
isTwoAddr = true;
} else if (!isSub && BaseReg == ARM::SP) {
+ // r1 = add sp, 403
+ // =>
+ // r1 = add sp, 100 * 4
+ // r1 = add r1, 3
if (!isMul4) {
Bytes &= ~3;
ExtraOpc = ARM::tADDi3;
}
- Bytes >>= 2; // Implicitly multiplied by 4.
NumBits = 8;
+ Scale = 4;
Opc = ARM::tADDrSPi;
} else {
- if (DestReg != BaseReg) {
- if (isLowRegister(DestReg) && isLowRegister(BaseReg)) {
- // If both are low registers, emit DestReg = add BaseReg, max(Imm, 7)
- unsigned Chunk = (1 << 3) - 1;
- unsigned ThisVal = (Bytes > Chunk) ? Chunk : Bytes;
- Bytes -= ThisVal;
- BuildMI(MBB, MBBI, TII.get(isSub ? ARM::tSUBi3 : ARM::tADDi3), DestReg)
- .addReg(BaseReg).addImm(ThisVal);
- } else {
- BuildMI(MBB, MBBI, TII.get(ARM::tMOVrr), DestReg).addReg(BaseReg);
- }
- BaseReg = DestReg;
- }
+ // sp = sub sp, c
+ // r1 = sub sp, c
+ // r8 = sub sp, c
+ if (DestReg != BaseReg)
+ DstNotEqBase = true;
NumBits = 8;
Opc = isSub ? ARM::tSUBi8 : ARM::tADDi8;
isTwoAddr = true;
}
- unsigned Chunk = (1 << NumBits) - 1;
+ unsigned NumMIs = calcNumMI(Opc, ExtraOpc, Bytes, NumBits, Scale);
+ unsigned Threshold = (DestReg == ARM::SP) ? 3 : 2;
+ if (NumMIs > Threshold) {
+ // This will expand into too many instructions. Load the immediate from a
+ // constpool entry.
+ emitThumbRegPlusConstPool(MBB, MBBI, DestReg, BaseReg, NumBytes, TII);
+ return;
+ }
+
+ if (DstNotEqBase) {
+ if (isLowRegister(DestReg) && isLowRegister(BaseReg)) {
+ // If both are low registers, emit DestReg = add BaseReg, max(Imm, 7)
+ unsigned Chunk = (1 << 3) - 1;
+ unsigned ThisVal = (Bytes > Chunk) ? Chunk : Bytes;
+ Bytes -= ThisVal;
+ BuildMI(MBB, MBBI, TII.get(isSub ? ARM::tSUBi3 : ARM::tADDi3), DestReg)
+ .addReg(BaseReg).addImm(ThisVal);
+ } else {
+ BuildMI(MBB, MBBI, TII.get(ARM::tMOVrr), DestReg).addReg(BaseReg);
+ }
+ BaseReg = DestReg;
+ }
+
+ unsigned Chunk = ((1 << NumBits) - 1) * Scale;
while (Bytes) {
unsigned ThisVal = (Bytes > Chunk) ? Chunk : Bytes;
- Bytes -= ThisVal;
+ Bytes -= ThisVal;
+ ThisVal /= Scale;
// Build the new tADD / tSUB.
if (isTwoAddr)
BuildMI(MBB, MBBI, TII.get(Opc), DestReg).addReg(DestReg).addImm(ThisVal);
// r4 = add r4, imm
// ...
NumBits = 8;
+ Scale = 1;
+ Chunk = ((1 << NumBits) - 1) * Scale;
Opc = isSub ? ARM::tSUBi8 : ARM::tADDi8;
isTwoAddr = true;
}
// There is alloca()'s in this function, must reference off the frame
// pointer instead.
FrameReg = getFrameRegister(MF);
- if (STI.isTargetDarwin())
- Offset -= AFI->getFramePtrSpillOffset();
+ Offset -= AFI->getFramePtrSpillOffset();
}
unsigned Opcode = MI.getOpcode();
} else if (Opcode == ARM::tADDrSPi) {
Offset += MI.getOperand(i+1).getImm();
assert((Offset & 3) == 0 &&
- "add/sub sp, #imm immediate must be multiple of 4!");
- Offset >>= 2;
+ "Thumb add/sub sp, #imm immediate must be multiple of 4!");
if (Offset == 0) {
// Turn it into a move.
MI.setInstrDescriptor(TII.get(ARM::tMOVrr));
}
// Common case: small offset, fits into instruction.
- if ((Offset & ~255U) == 0) {
+ if (((Offset >> 2) & ~255U) == 0) {
// Replace the FrameIndex with sp / fp
MI.getOperand(i).ChangeToRegister(FrameReg, false);
- MI.getOperand(i+1).ChangeToImmediate(Offset);
+ MI.getOperand(i+1).ChangeToImmediate(Offset >> 2);
return;
}
unsigned DestReg = MI.getOperand(0).getReg();
+ unsigned Bytes = (Offset > 0) ? Offset : -Offset;
+ unsigned NumMIs = calcNumMI(Opcode, 0, Bytes, 8, 1);
+ // MI would expand into a large number of instructions. Don't try to
+ // simplify the immediate.
+ if (NumMIs > 2) {
+ emitThumbRegPlusImmediate(MBB, II, DestReg, FrameReg, Offset, TII);
+ MBB.erase(II);
+ return;
+ }
+
if (Offset > 0) {
// Translate r0 = add sp, imm to
// r0 = add sp, 255*4
// r0 = add r0, (imm - 255*4)
MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.getOperand(i+1).ChangeToImmediate(255);
- Offset = (Offset - 255) << 2;
+ Offset = (Offset - 255 * 4);
MachineBasicBlock::iterator NII = next(II);
emitThumbRegPlusImmediate(MBB, NII, DestReg, DestReg, Offset, TII);
} else {
// Translate r0 = add sp, -imm to
// r0 = -imm (this is then translated into a series of instructons)
// r0 = add r0, sp
- Offset <<= 2;
emitThumbConstant(MBB, II, DestReg, Offset, TII);
MI.setInstrDescriptor(TII.get(ARM::tADDhirr));
MI.getOperand(i).ChangeToRegister(DestReg, false);
case ARMII::AddrModeTs: {
ImmIdx = i+1;
InstrOffs = MI.getOperand(ImmIdx).getImm();
- NumBits = 8;
+ NumBits = (FrameReg == ARM::SP) ? 8 : 5;
Scale = 4;
break;
}
}
Offset += InstrOffs * Scale;
- assert((Scale == 1 || (Offset & (Scale-1)) == 0) &&
- "Can't encode this offset!");
+ assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
if (Offset < 0) {
Offset = -Offset;
isSub = true;
return;
}
- // Otherwise, it didn't fit. Pull in what we can to simplify the immediate.
- ImmedOffset = ImmedOffset & Mask;
- if (isSub)
- ImmedOffset |= 1 << NumBits;
- ImmOp.ChangeToImmediate(ImmedOffset);
- Offset &= ~(Mask*Scale);
+ if (!isThumb) {
+ // Otherwise, it didn't fit. Pull in what we can to simplify the immed.
+ ImmedOffset = ImmedOffset & Mask;
+ if (isSub)
+ ImmedOffset |= 1 << NumBits;
+ ImmOp.ChangeToImmediate(ImmedOffset);
+ Offset &= ~(Mask*Scale);
+ }
}
// If we get here, the immediate doesn't fit into the instruction. We folded
if (TII.isLoad(Opcode)) {
// Use the destination register to materialize sp + offset.
unsigned TmpReg = MI.getOperand(0).getReg();
- emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg,
- isSub ? -Offset : Offset, TII);
+ if (Opcode == ARM::tRestore)
+ emitThumbRegPlusConstPool(MBB, II, TmpReg, FrameReg,
+ isSub ? -Offset : Offset, TII);
+ else
+ emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg,
+ isSub ? -Offset : Offset, TII);
+ MI.setInstrDescriptor(TII.get(ARM::tLDR));
MI.getOperand(i).ChangeToRegister(TmpReg, false);
+ MI.addRegOperand(0, false); // tLDR has an extra register operand.
} else if (TII.isStore(Opcode)) {
// FIXME! This is horrific!!! We need register scavenging.
// Our temporary workaround has marked r3 unavailable. Of course, r3 is
// Use r2 to materialize sp + offset
// str r12, r2
// r2 = r12
- unsigned DestReg = MI.getOperand(0).getReg();
+ unsigned ValReg = MI.getOperand(0).getReg();
unsigned TmpReg = ARM::R3;
- if (DestReg == ARM::R3) {
+ if (ValReg == ARM::R3) {
BuildMI(MBB, II, TII.get(ARM::tMOVrr), ARM::R12).addReg(ARM::R2);
TmpReg = ARM::R2;
}
- emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg,
- isSub ? -Offset : Offset, TII);
- MI.getOperand(i).ChangeToRegister(DestReg, false);
- if (DestReg == ARM::R3)
+ if (Opcode == ARM::tSpill)
+ emitThumbRegPlusConstPool(MBB, II, TmpReg, FrameReg,
+ isSub ? -Offset : Offset, TII);
+ else
+ emitThumbRegPlusImmediate(MBB, II, TmpReg, FrameReg,
+ isSub ? -Offset : Offset, TII);
+ MI.setInstrDescriptor(TII.get(ARM::tSTR));
+ MI.getOperand(i).ChangeToRegister(TmpReg, false);
+ MI.addRegOperand(0, false); // tSTR has an extra register operand.
+ if (ValReg == ARM::R3)
BuildMI(MBB, II, TII.get(ARM::tMOVrr), ARM::R2).addReg(ARM::R12);
} else
assert(false && "Unexpected opcode!");
}
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
- if (!CanEliminateFrame) {
+ bool ForceLRSpill = false;
+ if (!LRSpilled && AFI->isThumbFunction()) {
+ unsigned FnSize = ARM::GetFunctionSize(MF);
+ // Force LR spill if the Thumb function size is > 2048. This enables the
+ // use of BL to implement far jump. If it turns out that it's not needed
+ // the branch fix up path will undo it.
+ if (FnSize >= (1 << 11)) {
+ CanEliminateFrame = false;
+ ForceLRSpill = true;
+ }
+ }
+
+ if (!CanEliminateFrame || hasFP(MF)) {
AFI->setHasStackFrame(true);
// If LR is not spilled, but at least one of R4, R5, R6, and R7 is spilled.
// Spill LR as well so we can fold BX_RET to the registers restore (LDM).
if (!LRSpilled && CS1Spilled) {
- LRSpilled = true;
MF.changePhyRegUsed(ARM::LR, true);
NumGPRSpills++;
UnspilledCS1GPRs.erase(std::find(UnspilledCS1GPRs.begin(),
UnspilledCS1GPRs.end(), (unsigned)ARM::LR));
+ ForceLRSpill = false;
}
- if (STI.isTargetDarwin()) {
+ // Darwin ABI requires FP to point to the stack slot that contains the
+ // previous FP.
+ if (STI.isTargetDarwin() || hasFP(MF)) {
MF.changePhyRegUsed(FramePtr, true);
NumGPRSpills++;
}
}
}
- // Remembe if LR has been spilled.
- AFI->setLRIsSpilled(LRSpilled);
+ if (ForceLRSpill) {
+ MF.changePhyRegUsed(ARM::LR, true);
+ AFI->setLRIsForceSpilled(true);
+ }
}
/// Move iterator pass the next bunch of callee save load / store ops for
unsigned NumBytes = MFI->getStackSize();
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
+ if (isThumb) {
+ // Thumb add/sub sp, imm8 instructions implicitly multiply the offset by 4.
+ NumBytes = (NumBytes + 3) & ~3;
+ MFI->setStackSize(NumBytes);
+ }
+
// Determine the sizes of each callee-save spill areas and record which frame
// belongs to which callee-save spill areas.
unsigned GPRCS1Size = 0, GPRCS2Size = 0, DPRCSSize = 0;
int FramePtrSpillFI = 0;
- if (AFI->hasStackFrame()) {
- if (VARegSaveSize)
- emitSPUpdate(MBB, MBBI, -VARegSaveSize, isThumb, TII);
-
- 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;
+ if (!AFI->hasStackFrame()) {
+ if (NumBytes != 0)
+ emitSPUpdate(MBB, MBBI, -NumBytes, isThumb, TII);
+ return;
+ }
+
+ if (VARegSaveSize)
+ emitSPUpdate(MBB, MBBI, -VARegSaveSize, isThumb, TII);
+
+ 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.isTargetDarwin()) {
+ AFI->addGPRCalleeSavedArea2Frame(FI);
+ GPRCS2Size += 4;
+ } else {
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.isTargetDarwin()) {
- AFI->addGPRCalleeSavedArea2Frame(FI);
- GPRCS2Size += 4;
- } else {
- AFI->addGPRCalleeSavedArea1Frame(FI);
- GPRCS1Size += 4;
- }
- break;
- default:
- AFI->addDPRCalleeSavedAreaFrame(FI);
- DPRCSSize += 8;
}
+ break;
+ default:
+ AFI->addDPRCalleeSavedAreaFrame(FI);
+ DPRCSSize += 8;
}
+ }
- if (Align == 8 && (GPRCS1Size & 7) != 0)
- // Pad CS1 to ensure proper alignment.
- GPRCS1Size += 4;
+ if (Align == 8 && (GPRCS1Size & 7) != 0)
+ // Pad CS1 to ensure proper alignment.
+ GPRCS1Size += 4;
- if (!isThumb) {
- // Build the new SUBri to adjust SP for integer callee-save spill area 1.
- emitSPUpdate(MBB, MBBI, -GPRCS1Size, isThumb, TII);
- movePastCSLoadStoreOps(MBB, MBBI, ARM::STR, 1, STI);
- } else if (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tPUSH)
- ++MBBI;
+ if (!isThumb) {
+ // Build the new SUBri to adjust SP for integer callee-save spill area 1.
+ emitSPUpdate(MBB, MBBI, -GPRCS1Size, isThumb, TII);
+ movePastCSLoadStoreOps(MBB, MBBI, ARM::STR, 1, STI);
+ } else if (MBBI != MBB.end() && MBBI->getOpcode() == ARM::tPUSH)
+ ++MBBI;
- // Point FP to the stack slot that contains the previous FP.
- if (STI.isTargetDarwin())
- BuildMI(MBB, MBBI, TII.get(isThumb ? ARM::tADDrSPi : ARM::ADDri), FramePtr)
- .addFrameIndex(FramePtrSpillFI).addImm(0);
+ // Darwin ABI requires FP to point to the stack slot that contains the
+ // previous FP.
+ if (STI.isTargetDarwin() || hasFP(MF))
+ BuildMI(MBB, MBBI, TII.get(isThumb ? ARM::tADDrSPi : ARM::ADDri), FramePtr)
+ .addFrameIndex(FramePtrSpillFI).addImm(0);
- if (!isThumb) {
- // Build the new SUBri to adjust SP for integer callee-save spill area 2.
- emitSPUpdate(MBB, MBBI, -GPRCS2Size, false, TII);
+ if (!isThumb) {
+ // Build the new SUBri to adjust SP for integer callee-save spill area 2.
+ emitSPUpdate(MBB, MBBI, -GPRCS2Size, false, TII);
- // Build the new SUBri to adjust SP for FP callee-save spill area.
- movePastCSLoadStoreOps(MBB, MBBI, ARM::STR, 2, STI);
- emitSPUpdate(MBB, MBBI, -DPRCSSize, false, TII);
- }
+ // Build the new SUBri to adjust SP for FP callee-save spill area.
+ movePastCSLoadStoreOps(MBB, MBBI, ARM::STR, 2, STI);
+ emitSPUpdate(MBB, MBBI, -DPRCSSize, false, TII);
}
// Determine starting offsets of spill areas.
- if (AFI->hasStackFrame()) {
- unsigned DPRCSOffset = NumBytes - (GPRCS1Size + GPRCS2Size + DPRCSSize);
- unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize;
- unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size;
- AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) + NumBytes);
- AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset);
- AFI->setGPRCalleeSavedArea2Offset(GPRCS2Offset);
- AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset);
+ unsigned DPRCSOffset = NumBytes - (GPRCS1Size + GPRCS2Size + DPRCSSize);
+ unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize;
+ unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size;
+ AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) + NumBytes);
+ AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset);
+ AFI->setGPRCalleeSavedArea2Offset(GPRCS2Offset);
+ AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset);
- NumBytes = DPRCSOffset;
- if (NumBytes) {
- // Insert it after all the callee-save spills.
- if (!isThumb)
- movePastCSLoadStoreOps(MBB, MBBI, ARM::FSTD, 3, STI);
- emitSPUpdate(MBB, MBBI, -NumBytes, isThumb, TII);
- }
- } else
+ NumBytes = DPRCSOffset;
+ if (NumBytes) {
+ // Insert it after all the callee-save spills.
+ if (!isThumb)
+ movePastCSLoadStoreOps(MBB, MBBI, ARM::FSTD, 3, STI);
emitSPUpdate(MBB, MBBI, -NumBytes, isThumb, TII);
+ }
AFI->setGPRCalleeSavedArea1Size(GPRCS1Size);
AFI->setGPRCalleeSavedArea2Size(GPRCS2Size);
static bool isCSRestore(MachineInstr *MI, const unsigned *CSRegs) {
return ((MI->getOpcode() == ARM::FLDD ||
MI->getOpcode() == ARM::LDR ||
- MI->getOpcode() == ARM::tLDRspi) &&
+ MI->getOpcode() == ARM::tRestore) &&
MI->getOperand(1).isFrameIndex() &&
isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs));
}
bool isThumb = AFI->isThumbFunction();
unsigned VARegSaveSize = AFI->getVarArgsRegSaveSize();
int NumBytes = (int)MFI->getStackSize();
- if (AFI->hasStackFrame()) {
- // Unwind MBBI to point to first LDR / FLDD.
- const unsigned *CSRegs = getCalleeSavedRegs();
- if (MBBI != MBB.begin()) {
- do
- --MBBI;
- while (MBBI != MBB.begin() && isCSRestore(MBBI, CSRegs));
- if (!isCSRestore(MBBI, CSRegs))
- ++MBBI;
- }
+ if (!AFI->hasStackFrame()) {
+ if (NumBytes != 0)
+ emitSPUpdate(MBB, MBBI, NumBytes, isThumb, TII);
+ return;
+ }
- // Move SP to start of FP callee save spill area.
- NumBytes -= (AFI->getGPRCalleeSavedArea1Size() +
- AFI->getGPRCalleeSavedArea2Size() +
- AFI->getDPRCalleeSavedAreaSize());
- if (isThumb)
+ // Unwind MBBI to point to first LDR / FLDD.
+ const unsigned *CSRegs = getCalleeSavedRegs();
+ if (MBBI != MBB.begin()) {
+ do
+ --MBBI;
+ while (MBBI != MBB.begin() && isCSRestore(MBBI, CSRegs));
+ if (!isCSRestore(MBBI, CSRegs))
+ ++MBBI;
+ }
+
+ // Move SP to start of FP callee save spill area.
+ NumBytes -= (AFI->getGPRCalleeSavedArea1Size() +
+ AFI->getGPRCalleeSavedArea2Size() +
+ AFI->getDPRCalleeSavedAreaSize());
+ if (isThumb) {
+ if (MBBI->getOpcode() == ARM::tBX_RET &&
+ &MBB.front() != MBBI &&
+ prior(MBBI)->getOpcode() == ARM::tPOP) {
+ MachineBasicBlock::iterator PMBBI = prior(MBBI);
+ emitSPUpdate(MBB, PMBBI, NumBytes, isThumb, TII);
+ } else
emitSPUpdate(MBB, MBBI, NumBytes, isThumb, TII);
- else {
- if (STI.isTargetDarwin()) {
- NumBytes = AFI->getFramePtrSpillOffset() - NumBytes;
- // Reset SP based on frame pointer only if the stack frame extends beyond
- // frame pointer stack slot.
- if (AFI->getGPRCalleeSavedArea2Size() ||
- AFI->getDPRCalleeSavedAreaSize() ||
- AFI->getDPRCalleeSavedAreaOffset())
- if (NumBytes)
- BuildMI(MBB, MBBI, TII.get(ARM::SUBri), ARM::SP).addReg(FramePtr)
- .addImm(NumBytes);
- else
- BuildMI(MBB, MBBI, TII.get(ARM::MOVrr), ARM::SP).addReg(FramePtr);
- } else if (NumBytes) {
- emitSPUpdate(MBB, MBBI, NumBytes, false, TII);
- }
+ } else {
+ // Darwin ABI requires FP to point to the stack slot that contains the
+ // previous FP.
+ if (STI.isTargetDarwin() || hasFP(MF)) {
+ NumBytes = AFI->getFramePtrSpillOffset() - NumBytes;
+ // Reset SP based on frame pointer only if the stack frame extends beyond
+ // frame pointer stack slot or target is ELF and the function has FP.
+ if (AFI->getGPRCalleeSavedArea2Size() ||
+ AFI->getDPRCalleeSavedAreaSize() ||
+ AFI->getDPRCalleeSavedAreaOffset()||
+ hasFP(MF))
+ if (NumBytes)
+ BuildMI(MBB, MBBI, TII.get(ARM::SUBri), ARM::SP).addReg(FramePtr)
+ .addImm(NumBytes);
+ else
+ BuildMI(MBB, MBBI, TII.get(ARM::MOVrr), ARM::SP).addReg(FramePtr);
+ } else if (NumBytes) {
+ emitSPUpdate(MBB, MBBI, NumBytes, false, TII);
+ }
- // Move SP to start of integer callee save spill area 2.
- movePastCSLoadStoreOps(MBB, MBBI, ARM::FLDD, 3, STI);
- emitSPUpdate(MBB, MBBI, AFI->getDPRCalleeSavedAreaSize(), false, TII);
+ // Move SP to start of integer callee save spill area 2.
+ movePastCSLoadStoreOps(MBB, MBBI, ARM::FLDD, 3, STI);
+ emitSPUpdate(MBB, MBBI, AFI->getDPRCalleeSavedAreaSize(), false, TII);
- // Move SP to start of integer callee save spill area 1.
- movePastCSLoadStoreOps(MBB, MBBI, ARM::LDR, 2, STI);
- emitSPUpdate(MBB, MBBI, AFI->getGPRCalleeSavedArea2Size(), false, TII);
+ // Move SP to start of integer callee save spill area 1.
+ movePastCSLoadStoreOps(MBB, MBBI, ARM::LDR, 2, STI);
+ emitSPUpdate(MBB, MBBI, AFI->getGPRCalleeSavedArea2Size(), false, TII);
- // Move SP to SP upon entry to the function.
- movePastCSLoadStoreOps(MBB, MBBI, ARM::LDR, 1, STI);
- emitSPUpdate(MBB, MBBI, AFI->getGPRCalleeSavedArea1Size(), false, TII);
- }
+ // Move SP to SP upon entry to the function.
+ movePastCSLoadStoreOps(MBB, MBBI, ARM::LDR, 1, STI);
+ emitSPUpdate(MBB, MBBI, AFI->getGPRCalleeSavedArea1Size(), false, TII);
+ }
- if (VARegSaveSize)
- emitSPUpdate(MBB, MBBI, VARegSaveSize, isThumb, TII);
- } else if (NumBytes != 0) {
- emitSPUpdate(MBB, MBBI, NumBytes, isThumb, TII);
+ if (VARegSaveSize) {
+ if (isThumb)
+ // Epilogue for vararg functions: pop LR to R3 and branch off it.
+ // FIXME: Verify this is still ok when R3 is no longer being reserved.
+ BuildMI(MBB, MBBI, TII.get(ARM::tPOP)).addReg(ARM::R3);
+
+ emitSPUpdate(MBB, MBBI, VARegSaveSize, isThumb, TII);
+
+ if (isThumb) {
+ BuildMI(MBB, MBBI, TII.get(ARM::tBX_RET_vararg)).addReg(ARM::R3);
+ MBB.erase(MBBI);
+ }
}
}