+bool ARMInstrInfo::copyRegToReg(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I,
+ unsigned DestReg, unsigned SrcReg,
+ const TargetRegisterClass *DestRC,
+ const TargetRegisterClass *SrcRC) const {
+ if (DestRC != SrcRC) {
+ // Not yet supported!
+ return false;
+ }
+
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ if (I != MBB.end()) DL = I->getDebugLoc();
+
+ if (DestRC == ARM::GPRRegisterClass) {
+ MachineFunction &MF = *MBB.getParent();
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ if (AFI->isThumbFunction())
+ BuildMI(MBB, I, DL, get(ARM::tMOVr), DestReg).addReg(SrcReg);
+ else
+ AddDefaultCC(AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::MOVr), DestReg)
+ .addReg(SrcReg)));
+ } else if (DestRC == ARM::SPRRegisterClass)
+ AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::FCPYS), DestReg)
+ .addReg(SrcReg));
+ else if (DestRC == ARM::DPRRegisterClass)
+ AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::FCPYD), DestReg)
+ .addReg(SrcReg));
+ else
+ return false;
+
+ return true;
+}
+
+static const MachineInstrBuilder &ARMInstrAddOperand(MachineInstrBuilder &MIB,
+ MachineOperand &MO) {
+ if (MO.isReg())
+ MIB = MIB.addReg(MO.getReg(), MO.isDef(), MO.isImplicit());
+ else if (MO.isImm())
+ MIB = MIB.addImm(MO.getImm());
+ else if (MO.isFI())
+ MIB = MIB.addFrameIndex(MO.getIndex());
+ else
+ assert(0 && "Unknown operand for ARMInstrAddOperand!");
+
+ return MIB;
+}
+
+void ARMInstrInfo::
+storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
+ unsigned SrcReg, bool isKill, int FI,
+ const TargetRegisterClass *RC) const {
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ if (I != MBB.end()) DL = I->getDebugLoc();
+
+ if (RC == ARM::GPRRegisterClass) {
+ MachineFunction &MF = *MBB.getParent();
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ if (AFI->isThumbFunction())
+ BuildMI(MBB, I, DL, get(ARM::tSpill))
+ .addReg(SrcReg, false, false, isKill)
+ .addFrameIndex(FI).addImm(0);
+ else
+ AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::STR))
+ .addReg(SrcReg, false, false, isKill)
+ .addFrameIndex(FI).addReg(0).addImm(0));
+ } else if (RC == ARM::DPRRegisterClass) {
+ AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::FSTD))
+ .addReg(SrcReg, false, false, isKill)
+ .addFrameIndex(FI).addImm(0));
+ } else {
+ assert(RC == ARM::SPRRegisterClass && "Unknown regclass!");
+ AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::FSTS))
+ .addReg(SrcReg, false, false, isKill)
+ .addFrameIndex(FI).addImm(0));
+ }
+}
+
+void ARMInstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg,
+ bool isKill,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const{
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ unsigned Opc = 0;
+ if (RC == ARM::GPRRegisterClass) {
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ if (AFI->isThumbFunction()) {
+ Opc = Addr[0].isFI() ? ARM::tSpill : ARM::tSTR;
+ MachineInstrBuilder MIB =
+ BuildMI(MF, DL, get(Opc)).addReg(SrcReg, false, false, isKill);
+ for (unsigned i = 0, e = Addr.size(); i != e; ++i)
+ MIB = ARMInstrAddOperand(MIB, Addr[i]);
+ NewMIs.push_back(MIB);
+ return;
+ }
+ Opc = ARM::STR;
+ } else if (RC == ARM::DPRRegisterClass) {
+ Opc = ARM::FSTD;
+ } else {
+ assert(RC == ARM::SPRRegisterClass && "Unknown regclass!");
+ Opc = ARM::FSTS;
+ }
+
+ MachineInstrBuilder MIB =
+ BuildMI(MF, DL, get(Opc)).addReg(SrcReg, false, false, isKill);
+ for (unsigned i = 0, e = Addr.size(); i != e; ++i)
+ MIB = ARMInstrAddOperand(MIB, Addr[i]);
+ AddDefaultPred(MIB);
+ NewMIs.push_back(MIB);
+ return;
+}
+
+void ARMInstrInfo::
+loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
+ unsigned DestReg, int FI,
+ const TargetRegisterClass *RC) const {
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ if (I != MBB.end()) DL = I->getDebugLoc();
+
+ if (RC == ARM::GPRRegisterClass) {
+ MachineFunction &MF = *MBB.getParent();
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ if (AFI->isThumbFunction())
+ BuildMI(MBB, I, DL, get(ARM::tRestore), DestReg)
+ .addFrameIndex(FI).addImm(0);
+ else
+ AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::LDR), DestReg)
+ .addFrameIndex(FI).addReg(0).addImm(0));
+ } else if (RC == ARM::DPRRegisterClass) {
+ AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::FLDD), DestReg)
+ .addFrameIndex(FI).addImm(0));
+ } else {
+ assert(RC == ARM::SPRRegisterClass && "Unknown regclass!");
+ AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::FLDS), DestReg)
+ .addFrameIndex(FI).addImm(0));
+ }
+}
+
+void ARMInstrInfo::loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const {
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ unsigned Opc = 0;
+ if (RC == ARM::GPRRegisterClass) {
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ if (AFI->isThumbFunction()) {
+ Opc = Addr[0].isFI() ? ARM::tRestore : ARM::tLDR;
+ MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc), DestReg);
+ for (unsigned i = 0, e = Addr.size(); i != e; ++i)
+ MIB = ARMInstrAddOperand(MIB, Addr[i]);
+ NewMIs.push_back(MIB);
+ return;
+ }
+ Opc = ARM::LDR;
+ } else if (RC == ARM::DPRRegisterClass) {
+ Opc = ARM::FLDD;
+ } else {
+ assert(RC == ARM::SPRRegisterClass && "Unknown regclass!");
+ Opc = ARM::FLDS;
+ }
+
+ MachineInstrBuilder MIB = BuildMI(MF, DL, get(Opc), DestReg);
+ for (unsigned i = 0, e = Addr.size(); i != e; ++i)
+ MIB = ARMInstrAddOperand(MIB, Addr[i]);
+ AddDefaultPred(MIB);
+ NewMIs.push_back(MIB);
+ return;
+}
+
+bool ARMInstrInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI,
+ const std::vector<CalleeSavedInfo> &CSI) const {
+ MachineFunction &MF = *MBB.getParent();
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ if (!AFI->isThumbFunction() || CSI.empty())
+ return false;
+
+ DebugLoc DL = DebugLoc::getUnknownLoc();
+ if (MI != MBB.end()) DL = MI->getDebugLoc();
+
+ MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, get(ARM::tPUSH));
+ for (unsigned i = CSI.size(); i != 0; --i) {
+ unsigned Reg = CSI[i-1].getReg();
+ // Add the callee-saved register as live-in. It's killed at the spill.
+ MBB.addLiveIn(Reg);
+ MIB.addReg(Reg, false/*isDef*/,false/*isImp*/,true/*isKill*/);
+ }
+ return true;
+}
+
+bool ARMInstrInfo::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MI,
+ const std::vector<CalleeSavedInfo> &CSI) const {
+ MachineFunction &MF = *MBB.getParent();
+ ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+ if (!AFI->isThumbFunction() || CSI.empty())
+ return false;
+
+ bool isVarArg = AFI->getVarArgsRegSaveSize() > 0;
+ MachineInstr *PopMI = MF.CreateMachineInstr(get(ARM::tPOP),MI->getDebugLoc());
+ 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->setDesc(get(ARM::tPOP_RET));
+ MBB.erase(MI);
+ }
+ PopMI->addOperand(MachineOperand::CreateReg(Reg, true));
+ }
+ return true;
+}
+
+MachineInstr *ARMInstrInfo::foldMemoryOperandImpl(MachineFunction &MF,
+ MachineInstr *MI,
+ const SmallVectorImpl<unsigned> &Ops,
+ int FI) const {
+ if (Ops.size() != 1) return NULL;
+
+ unsigned OpNum = Ops[0];
+ unsigned Opc = MI->getOpcode();
+ MachineInstr *NewMI = NULL;
+ switch (Opc) {
+ default: break;
+ case ARM::MOVr: {
+ if (MI->getOperand(4).getReg() == ARM::CPSR)
+ // If it is updating CPSR, then it cannot be foled.
+ break;
+ unsigned Pred = MI->getOperand(2).getImm();
+ unsigned PredReg = MI->getOperand(3).getReg();
+ if (OpNum == 0) { // move -> store
+ unsigned SrcReg = MI->getOperand(1).getReg();
+ bool isKill = MI->getOperand(1).isKill();
+ NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::STR))
+ .addReg(SrcReg, false, false, isKill)
+ .addFrameIndex(FI).addReg(0).addImm(0).addImm(Pred).addReg(PredReg);
+ } else { // move -> load
+ unsigned DstReg = MI->getOperand(0).getReg();
+ bool isDead = MI->getOperand(0).isDead();
+ NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::LDR))
+ .addReg(DstReg, true, false, false, isDead)
+ .addFrameIndex(FI).addReg(0).addImm(0).addImm(Pred).addReg(PredReg);
+ }
+ break;
+ }
+ case ARM::tMOVr: {
+ if (OpNum == 0) { // move -> store
+ unsigned SrcReg = MI->getOperand(1).getReg();
+ bool isKill = MI->getOperand(1).isKill();
+ if (RI.isPhysicalRegister(SrcReg) && !RI.isLowRegister(SrcReg))
+ // tSpill cannot take a high register operand.
+ break;
+ NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::tSpill))
+ .addReg(SrcReg, false, false, isKill)
+ .addFrameIndex(FI).addImm(0);
+ } else { // move -> load
+ unsigned DstReg = MI->getOperand(0).getReg();
+ if (RI.isPhysicalRegister(DstReg) && !RI.isLowRegister(DstReg))
+ // tRestore cannot target a high register operand.
+ break;
+ bool isDead = MI->getOperand(0).isDead();
+ NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::tRestore))
+ .addReg(DstReg, true, false, false, isDead)
+ .addFrameIndex(FI).addImm(0);
+ }
+ break;
+ }
+ case ARM::FCPYS: {
+ unsigned Pred = MI->getOperand(2).getImm();
+ unsigned PredReg = MI->getOperand(3).getReg();
+ if (OpNum == 0) { // move -> store
+ unsigned SrcReg = MI->getOperand(1).getReg();
+ NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::FSTS))
+ .addReg(SrcReg).addFrameIndex(FI)
+ .addImm(0).addImm(Pred).addReg(PredReg);
+ } else { // move -> load
+ unsigned DstReg = MI->getOperand(0).getReg();
+ NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::FLDS), DstReg)
+ .addFrameIndex(FI)
+ .addImm(0).addImm(Pred).addReg(PredReg);
+ }
+ break;
+ }
+ case ARM::FCPYD: {
+ unsigned Pred = MI->getOperand(2).getImm();
+ unsigned PredReg = MI->getOperand(3).getReg();
+ if (OpNum == 0) { // move -> store
+ unsigned SrcReg = MI->getOperand(1).getReg();
+ bool isKill = MI->getOperand(1).isKill();
+ NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::FSTD))
+ .addReg(SrcReg, false, false, isKill)
+ .addFrameIndex(FI).addImm(0).addImm(Pred).addReg(PredReg);
+ } else { // move -> load
+ unsigned DstReg = MI->getOperand(0).getReg();
+ bool isDead = MI->getOperand(0).isDead();
+ NewMI = BuildMI(MF, MI->getDebugLoc(), get(ARM::FLDD))
+ .addReg(DstReg, true, false, false, isDead)
+ .addFrameIndex(FI).addImm(0).addImm(Pred).addReg(PredReg);
+ }
+ break;
+ }
+ }
+
+ return NewMI;
+}
+
+bool ARMInstrInfo::canFoldMemoryOperand(const MachineInstr *MI,
+ const SmallVectorImpl<unsigned> &Ops) const {
+ if (Ops.size() != 1) return false;
+
+ unsigned OpNum = Ops[0];
+ unsigned Opc = MI->getOpcode();
+ switch (Opc) {
+ default: break;
+ case ARM::MOVr:
+ // If it is updating CPSR, then it cannot be foled.
+ return MI->getOperand(4).getReg() != ARM::CPSR;
+ case ARM::tMOVr: {
+ if (OpNum == 0) { // move -> store
+ unsigned SrcReg = MI->getOperand(1).getReg();
+ if (RI.isPhysicalRegister(SrcReg) && !RI.isLowRegister(SrcReg))
+ // tSpill cannot take a high register operand.
+ return false;
+ } else { // move -> load
+ unsigned DstReg = MI->getOperand(0).getReg();
+ if (RI.isPhysicalRegister(DstReg) && !RI.isLowRegister(DstReg))
+ // tRestore cannot target a high register operand.
+ return false;
+ }
+ return true;
+ }
+ case ARM::FCPYS:
+ case ARM::FCPYD:
+ return true;
+ }
+
+ return false;
+}
+
+bool ARMInstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const {