109467b48Spatrick //===- Thumb2InstrInfo.cpp - Thumb-2 Instruction Information --------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file contains the Thumb-2 implementation of the TargetInstrInfo class.
1009467b48Spatrick //
1109467b48Spatrick //===----------------------------------------------------------------------===//
1209467b48Spatrick
1309467b48Spatrick #include "Thumb2InstrInfo.h"
1409467b48Spatrick #include "ARMMachineFunctionInfo.h"
1573471bf0Spatrick #include "ARMSubtarget.h"
1609467b48Spatrick #include "MCTargetDesc/ARMAddressingModes.h"
1709467b48Spatrick #include "llvm/CodeGen/MachineBasicBlock.h"
1809467b48Spatrick #include "llvm/CodeGen/MachineFrameInfo.h"
1909467b48Spatrick #include "llvm/CodeGen/MachineFunction.h"
2009467b48Spatrick #include "llvm/CodeGen/MachineInstr.h"
2109467b48Spatrick #include "llvm/CodeGen/MachineInstrBuilder.h"
2209467b48Spatrick #include "llvm/CodeGen/MachineMemOperand.h"
2309467b48Spatrick #include "llvm/CodeGen/MachineOperand.h"
2409467b48Spatrick #include "llvm/CodeGen/MachineRegisterInfo.h"
2509467b48Spatrick #include "llvm/CodeGen/TargetRegisterInfo.h"
2609467b48Spatrick #include "llvm/IR/DebugLoc.h"
2709467b48Spatrick #include "llvm/MC/MCInst.h"
2873471bf0Spatrick #include "llvm/MC/MCInstBuilder.h"
2909467b48Spatrick #include "llvm/MC/MCInstrDesc.h"
3009467b48Spatrick #include "llvm/Support/CommandLine.h"
3109467b48Spatrick #include "llvm/Support/ErrorHandling.h"
3209467b48Spatrick #include "llvm/Support/MathExtras.h"
3309467b48Spatrick #include "llvm/Target/TargetMachine.h"
3409467b48Spatrick #include <cassert>
3509467b48Spatrick
3609467b48Spatrick using namespace llvm;
3709467b48Spatrick
3809467b48Spatrick static cl::opt<bool>
3909467b48Spatrick OldT2IfCvt("old-thumb2-ifcvt", cl::Hidden,
4009467b48Spatrick cl::desc("Use old-style Thumb2 if-conversion heuristics"),
4109467b48Spatrick cl::init(false));
4209467b48Spatrick
4373471bf0Spatrick static cl::opt<bool>
4473471bf0Spatrick PreferNoCSEL("prefer-no-csel", cl::Hidden,
4573471bf0Spatrick cl::desc("Prefer predicated Move to CSEL"),
4673471bf0Spatrick cl::init(false));
4773471bf0Spatrick
Thumb2InstrInfo(const ARMSubtarget & STI)4809467b48Spatrick Thumb2InstrInfo::Thumb2InstrInfo(const ARMSubtarget &STI)
4909467b48Spatrick : ARMBaseInstrInfo(STI) {}
5009467b48Spatrick
5109467b48Spatrick /// Return the noop instruction to use for a noop.
getNop() const5273471bf0Spatrick MCInst Thumb2InstrInfo::getNop() const {
5373471bf0Spatrick return MCInstBuilder(ARM::tHINT).addImm(0).addImm(ARMCC::AL).addReg(0);
5409467b48Spatrick }
5509467b48Spatrick
getUnindexedOpcode(unsigned Opc) const5609467b48Spatrick unsigned Thumb2InstrInfo::getUnindexedOpcode(unsigned Opc) const {
5709467b48Spatrick // FIXME
5809467b48Spatrick return 0;
5909467b48Spatrick }
6009467b48Spatrick
6109467b48Spatrick void
ReplaceTailWithBranchTo(MachineBasicBlock::iterator Tail,MachineBasicBlock * NewDest) const6209467b48Spatrick Thumb2InstrInfo::ReplaceTailWithBranchTo(MachineBasicBlock::iterator Tail,
6309467b48Spatrick MachineBasicBlock *NewDest) const {
6409467b48Spatrick MachineBasicBlock *MBB = Tail->getParent();
6509467b48Spatrick ARMFunctionInfo *AFI = MBB->getParent()->getInfo<ARMFunctionInfo>();
6609467b48Spatrick if (!AFI->hasITBlocks() || Tail->isBranch()) {
6709467b48Spatrick TargetInstrInfo::ReplaceTailWithBranchTo(Tail, NewDest);
6809467b48Spatrick return;
6909467b48Spatrick }
7009467b48Spatrick
7109467b48Spatrick // If the first instruction of Tail is predicated, we may have to update
7209467b48Spatrick // the IT instruction.
73097a140dSpatrick Register PredReg;
7409467b48Spatrick ARMCC::CondCodes CC = getInstrPredicate(*Tail, PredReg);
7509467b48Spatrick MachineBasicBlock::iterator MBBI = Tail;
7609467b48Spatrick if (CC != ARMCC::AL)
7709467b48Spatrick // Expecting at least the t2IT instruction before it.
7809467b48Spatrick --MBBI;
7909467b48Spatrick
8009467b48Spatrick // Actually replace the tail.
8109467b48Spatrick TargetInstrInfo::ReplaceTailWithBranchTo(Tail, NewDest);
8209467b48Spatrick
8309467b48Spatrick // Fix up IT.
8409467b48Spatrick if (CC != ARMCC::AL) {
8509467b48Spatrick MachineBasicBlock::iterator E = MBB->begin();
8609467b48Spatrick unsigned Count = 4; // At most 4 instructions in an IT block.
8709467b48Spatrick while (Count && MBBI != E) {
8809467b48Spatrick if (MBBI->isDebugInstr()) {
8909467b48Spatrick --MBBI;
9009467b48Spatrick continue;
9109467b48Spatrick }
9209467b48Spatrick if (MBBI->getOpcode() == ARM::t2IT) {
9309467b48Spatrick unsigned Mask = MBBI->getOperand(1).getImm();
9409467b48Spatrick if (Count == 4)
9509467b48Spatrick MBBI->eraseFromParent();
9609467b48Spatrick else {
9709467b48Spatrick unsigned MaskOn = 1 << Count;
9809467b48Spatrick unsigned MaskOff = ~(MaskOn - 1);
9909467b48Spatrick MBBI->getOperand(1).setImm((Mask & MaskOff) | MaskOn);
10009467b48Spatrick }
10109467b48Spatrick return;
10209467b48Spatrick }
10309467b48Spatrick --MBBI;
10409467b48Spatrick --Count;
10509467b48Spatrick }
10609467b48Spatrick
10709467b48Spatrick // Ctrl flow can reach here if branch folding is run before IT block
10809467b48Spatrick // formation pass.
10909467b48Spatrick }
11009467b48Spatrick }
11109467b48Spatrick
11209467b48Spatrick bool
isLegalToSplitMBBAt(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI) const11309467b48Spatrick Thumb2InstrInfo::isLegalToSplitMBBAt(MachineBasicBlock &MBB,
11409467b48Spatrick MachineBasicBlock::iterator MBBI) const {
11509467b48Spatrick while (MBBI->isDebugInstr()) {
11609467b48Spatrick ++MBBI;
11709467b48Spatrick if (MBBI == MBB.end())
11809467b48Spatrick return false;
11909467b48Spatrick }
12009467b48Spatrick
121097a140dSpatrick Register PredReg;
12209467b48Spatrick return getITInstrPredicate(*MBBI, PredReg) == ARMCC::AL;
12309467b48Spatrick }
12409467b48Spatrick
12573471bf0Spatrick MachineInstr *
optimizeSelect(MachineInstr & MI,SmallPtrSetImpl<MachineInstr * > & SeenMIs,bool PreferFalse) const12673471bf0Spatrick Thumb2InstrInfo::optimizeSelect(MachineInstr &MI,
12773471bf0Spatrick SmallPtrSetImpl<MachineInstr *> &SeenMIs,
12873471bf0Spatrick bool PreferFalse) const {
12973471bf0Spatrick // Try to use the base optimizeSelect, which uses canFoldIntoMOVCC to fold the
13073471bf0Spatrick // MOVCC into another instruction. If that fails on 8.1-M fall back to using a
13173471bf0Spatrick // CSEL.
13273471bf0Spatrick MachineInstr *RV = ARMBaseInstrInfo::optimizeSelect(MI, SeenMIs, PreferFalse);
13373471bf0Spatrick if (!RV && getSubtarget().hasV8_1MMainlineOps() && !PreferNoCSEL) {
13473471bf0Spatrick Register DestReg = MI.getOperand(0).getReg();
13573471bf0Spatrick
13673471bf0Spatrick if (!DestReg.isVirtual())
13773471bf0Spatrick return nullptr;
13873471bf0Spatrick
13973471bf0Spatrick MachineInstrBuilder NewMI = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(),
14073471bf0Spatrick get(ARM::t2CSEL), DestReg)
14173471bf0Spatrick .add(MI.getOperand(2))
14273471bf0Spatrick .add(MI.getOperand(1))
14373471bf0Spatrick .add(MI.getOperand(3));
14473471bf0Spatrick SeenMIs.insert(NewMI);
14573471bf0Spatrick return NewMI;
14673471bf0Spatrick }
14773471bf0Spatrick return RV;
14873471bf0Spatrick }
14973471bf0Spatrick
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,const DebugLoc & DL,MCRegister DestReg,MCRegister SrcReg,bool KillSrc) const15009467b48Spatrick void Thumb2InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
15109467b48Spatrick MachineBasicBlock::iterator I,
15209467b48Spatrick const DebugLoc &DL, MCRegister DestReg,
15309467b48Spatrick MCRegister SrcReg, bool KillSrc) const {
15409467b48Spatrick // Handle SPR, DPR, and QPR copies.
15509467b48Spatrick if (!ARM::GPRRegClass.contains(DestReg, SrcReg))
15609467b48Spatrick return ARMBaseInstrInfo::copyPhysReg(MBB, I, DL, DestReg, SrcReg, KillSrc);
15709467b48Spatrick
15809467b48Spatrick BuildMI(MBB, I, DL, get(ARM::tMOVr), DestReg)
15909467b48Spatrick .addReg(SrcReg, getKillRegState(KillSrc))
16009467b48Spatrick .add(predOps(ARMCC::AL));
16109467b48Spatrick }
16209467b48Spatrick
storeRegToStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register SrcReg,bool isKill,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const163*d415bd75Srobert void Thumb2InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
164*d415bd75Srobert MachineBasicBlock::iterator I,
165097a140dSpatrick Register SrcReg, bool isKill, int FI,
16609467b48Spatrick const TargetRegisterClass *RC,
167*d415bd75Srobert const TargetRegisterInfo *TRI,
168*d415bd75Srobert Register VReg) const {
16909467b48Spatrick DebugLoc DL;
17009467b48Spatrick if (I != MBB.end()) DL = I->getDebugLoc();
17109467b48Spatrick
17209467b48Spatrick MachineFunction &MF = *MBB.getParent();
17309467b48Spatrick MachineFrameInfo &MFI = MF.getFrameInfo();
17409467b48Spatrick MachineMemOperand *MMO = MF.getMachineMemOperand(
17509467b48Spatrick MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOStore,
176097a140dSpatrick MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
17709467b48Spatrick
17809467b48Spatrick if (ARM::GPRRegClass.hasSubClassEq(RC)) {
17909467b48Spatrick BuildMI(MBB, I, DL, get(ARM::t2STRi12))
18009467b48Spatrick .addReg(SrcReg, getKillRegState(isKill))
18109467b48Spatrick .addFrameIndex(FI)
18209467b48Spatrick .addImm(0)
18309467b48Spatrick .addMemOperand(MMO)
18409467b48Spatrick .add(predOps(ARMCC::AL));
18509467b48Spatrick return;
18609467b48Spatrick }
18709467b48Spatrick
18809467b48Spatrick if (ARM::GPRPairRegClass.hasSubClassEq(RC)) {
18909467b48Spatrick // Thumb2 STRD expects its dest-registers to be in rGPR. Not a problem for
19009467b48Spatrick // gsub_0, but needs an extra constraint for gsub_1 (which could be sp
19109467b48Spatrick // otherwise).
192*d415bd75Srobert if (SrcReg.isVirtual()) {
19309467b48Spatrick MachineRegisterInfo *MRI = &MF.getRegInfo();
19409467b48Spatrick MRI->constrainRegClass(SrcReg, &ARM::GPRPairnospRegClass);
19509467b48Spatrick }
19609467b48Spatrick
19709467b48Spatrick MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(ARM::t2STRDi8));
19809467b48Spatrick AddDReg(MIB, SrcReg, ARM::gsub_0, getKillRegState(isKill), TRI);
19909467b48Spatrick AddDReg(MIB, SrcReg, ARM::gsub_1, 0, TRI);
20009467b48Spatrick MIB.addFrameIndex(FI).addImm(0).addMemOperand(MMO).add(predOps(ARMCC::AL));
20109467b48Spatrick return;
20209467b48Spatrick }
20309467b48Spatrick
204*d415bd75Srobert ARMBaseInstrInfo::storeRegToStackSlot(MBB, I, SrcReg, isKill, FI, RC, TRI,
205*d415bd75Srobert Register());
20609467b48Spatrick }
20709467b48Spatrick
loadRegFromStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register DestReg,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const208*d415bd75Srobert void Thumb2InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
209*d415bd75Srobert MachineBasicBlock::iterator I,
210097a140dSpatrick Register DestReg, int FI,
21109467b48Spatrick const TargetRegisterClass *RC,
212*d415bd75Srobert const TargetRegisterInfo *TRI,
213*d415bd75Srobert Register VReg) const {
21409467b48Spatrick MachineFunction &MF = *MBB.getParent();
21509467b48Spatrick MachineFrameInfo &MFI = MF.getFrameInfo();
21609467b48Spatrick MachineMemOperand *MMO = MF.getMachineMemOperand(
21709467b48Spatrick MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad,
218097a140dSpatrick MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
21909467b48Spatrick DebugLoc DL;
22009467b48Spatrick if (I != MBB.end()) DL = I->getDebugLoc();
22109467b48Spatrick
22209467b48Spatrick if (ARM::GPRRegClass.hasSubClassEq(RC)) {
22309467b48Spatrick BuildMI(MBB, I, DL, get(ARM::t2LDRi12), DestReg)
22409467b48Spatrick .addFrameIndex(FI)
22509467b48Spatrick .addImm(0)
22609467b48Spatrick .addMemOperand(MMO)
22709467b48Spatrick .add(predOps(ARMCC::AL));
22809467b48Spatrick return;
22909467b48Spatrick }
23009467b48Spatrick
23109467b48Spatrick if (ARM::GPRPairRegClass.hasSubClassEq(RC)) {
23209467b48Spatrick // Thumb2 LDRD expects its dest-registers to be in rGPR. Not a problem for
23309467b48Spatrick // gsub_0, but needs an extra constraint for gsub_1 (which could be sp
23409467b48Spatrick // otherwise).
235*d415bd75Srobert if (DestReg.isVirtual()) {
23609467b48Spatrick MachineRegisterInfo *MRI = &MF.getRegInfo();
23709467b48Spatrick MRI->constrainRegClass(DestReg, &ARM::GPRPairnospRegClass);
23809467b48Spatrick }
23909467b48Spatrick
24009467b48Spatrick MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(ARM::t2LDRDi8));
24109467b48Spatrick AddDReg(MIB, DestReg, ARM::gsub_0, RegState::DefineNoRead, TRI);
24209467b48Spatrick AddDReg(MIB, DestReg, ARM::gsub_1, RegState::DefineNoRead, TRI);
24309467b48Spatrick MIB.addFrameIndex(FI).addImm(0).addMemOperand(MMO).add(predOps(ARMCC::AL));
24409467b48Spatrick
245*d415bd75Srobert if (DestReg.isPhysical())
24609467b48Spatrick MIB.addReg(DestReg, RegState::ImplicitDefine);
24709467b48Spatrick return;
24809467b48Spatrick }
24909467b48Spatrick
250*d415bd75Srobert ARMBaseInstrInfo::loadRegFromStackSlot(MBB, I, DestReg, FI, RC, TRI,
251*d415bd75Srobert Register());
25209467b48Spatrick }
25309467b48Spatrick
expandLoadStackGuard(MachineBasicBlock::iterator MI) const25409467b48Spatrick void Thumb2InstrInfo::expandLoadStackGuard(
25509467b48Spatrick MachineBasicBlock::iterator MI) const {
25609467b48Spatrick MachineFunction &MF = *MI->getParent()->getParent();
257*d415bd75Srobert Module &M = *MF.getFunction().getParent();
258*d415bd75Srobert
259*d415bd75Srobert if (M.getStackProtectorGuard() == "tls") {
260*d415bd75Srobert expandLoadStackGuardBase(MI, ARM::t2MRC, ARM::t2LDRi12);
261*d415bd75Srobert return;
262*d415bd75Srobert }
263*d415bd75Srobert
264*d415bd75Srobert const GlobalValue *GV =
265*d415bd75Srobert cast<GlobalValue>((*MI->memoperands_begin())->getValue());
266*d415bd75Srobert
267*d415bd75Srobert if (MF.getSubtarget<ARMSubtarget>().isGVInGOT(GV))
268*d415bd75Srobert expandLoadStackGuardBase(MI, ARM::t2LDRLIT_ga_pcrel, ARM::t2LDRi12);
269*d415bd75Srobert else if (MF.getTarget().isPositionIndependent())
27009467b48Spatrick expandLoadStackGuardBase(MI, ARM::t2MOV_ga_pcrel, ARM::t2LDRi12);
27109467b48Spatrick else
27209467b48Spatrick expandLoadStackGuardBase(MI, ARM::t2MOVi32imm, ARM::t2LDRi12);
27309467b48Spatrick }
27409467b48Spatrick
commuteInstructionImpl(MachineInstr & MI,bool NewMI,unsigned OpIdx1,unsigned OpIdx2) const27573471bf0Spatrick MachineInstr *Thumb2InstrInfo::commuteInstructionImpl(MachineInstr &MI,
27673471bf0Spatrick bool NewMI,
27773471bf0Spatrick unsigned OpIdx1,
27873471bf0Spatrick unsigned OpIdx2) const {
27973471bf0Spatrick switch (MI.getOpcode()) {
28073471bf0Spatrick case ARM::MVE_VMAXNMAf16:
28173471bf0Spatrick case ARM::MVE_VMAXNMAf32:
28273471bf0Spatrick case ARM::MVE_VMINNMAf16:
28373471bf0Spatrick case ARM::MVE_VMINNMAf32:
28473471bf0Spatrick // Don't allow predicated instructions to be commuted.
28573471bf0Spatrick if (getVPTInstrPredicate(MI) != ARMVCC::None)
28673471bf0Spatrick return nullptr;
28773471bf0Spatrick }
28873471bf0Spatrick return ARMBaseInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
28973471bf0Spatrick }
29073471bf0Spatrick
emitT2RegPlusImmediate(MachineBasicBlock & MBB,MachineBasicBlock::iterator & MBBI,const DebugLoc & dl,Register DestReg,Register BaseReg,int NumBytes,ARMCC::CondCodes Pred,Register PredReg,const ARMBaseInstrInfo & TII,unsigned MIFlags)29109467b48Spatrick void llvm::emitT2RegPlusImmediate(MachineBasicBlock &MBB,
29209467b48Spatrick MachineBasicBlock::iterator &MBBI,
293097a140dSpatrick const DebugLoc &dl, Register DestReg,
294097a140dSpatrick Register BaseReg, int NumBytes,
295097a140dSpatrick ARMCC::CondCodes Pred, Register PredReg,
29609467b48Spatrick const ARMBaseInstrInfo &TII,
29709467b48Spatrick unsigned MIFlags) {
29809467b48Spatrick if (NumBytes == 0 && DestReg != BaseReg) {
29909467b48Spatrick BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), DestReg)
30009467b48Spatrick .addReg(BaseReg, RegState::Kill)
30109467b48Spatrick .addImm((unsigned)Pred).addReg(PredReg).setMIFlags(MIFlags);
30209467b48Spatrick return;
30309467b48Spatrick }
30409467b48Spatrick
30509467b48Spatrick bool isSub = NumBytes < 0;
30609467b48Spatrick if (isSub) NumBytes = -NumBytes;
30709467b48Spatrick
30809467b48Spatrick // If profitable, use a movw or movt to materialize the offset.
30909467b48Spatrick // FIXME: Use the scavenger to grab a scratch register.
31009467b48Spatrick if (DestReg != ARM::SP && DestReg != BaseReg &&
31109467b48Spatrick NumBytes >= 4096 &&
31209467b48Spatrick ARM_AM::getT2SOImmVal(NumBytes) == -1) {
31309467b48Spatrick bool Fits = false;
31409467b48Spatrick if (NumBytes < 65536) {
31509467b48Spatrick // Use a movw to materialize the 16-bit constant.
31609467b48Spatrick BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVi16), DestReg)
31709467b48Spatrick .addImm(NumBytes)
31809467b48Spatrick .addImm((unsigned)Pred).addReg(PredReg).setMIFlags(MIFlags);
31909467b48Spatrick Fits = true;
32009467b48Spatrick } else if ((NumBytes & 0xffff) == 0) {
32109467b48Spatrick // Use a movt to materialize the 32-bit constant.
32209467b48Spatrick BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVTi16), DestReg)
32309467b48Spatrick .addReg(DestReg)
32409467b48Spatrick .addImm(NumBytes >> 16)
32509467b48Spatrick .addImm((unsigned)Pred).addReg(PredReg).setMIFlags(MIFlags);
32609467b48Spatrick Fits = true;
32709467b48Spatrick }
32809467b48Spatrick
32909467b48Spatrick if (Fits) {
33009467b48Spatrick if (isSub) {
33109467b48Spatrick BuildMI(MBB, MBBI, dl, TII.get(ARM::t2SUBrr), DestReg)
33209467b48Spatrick .addReg(BaseReg)
33309467b48Spatrick .addReg(DestReg, RegState::Kill)
33409467b48Spatrick .add(predOps(Pred, PredReg))
33509467b48Spatrick .add(condCodeOp())
33609467b48Spatrick .setMIFlags(MIFlags);
33709467b48Spatrick } else {
33809467b48Spatrick // Here we know that DestReg is not SP but we do not
33909467b48Spatrick // know anything about BaseReg. t2ADDrr is an invalid
34009467b48Spatrick // instruction is SP is used as the second argument, but
34109467b48Spatrick // is fine if SP is the first argument. To be sure we
34209467b48Spatrick // do not generate invalid encoding, put BaseReg first.
34309467b48Spatrick BuildMI(MBB, MBBI, dl, TII.get(ARM::t2ADDrr), DestReg)
34409467b48Spatrick .addReg(BaseReg)
34509467b48Spatrick .addReg(DestReg, RegState::Kill)
34609467b48Spatrick .add(predOps(Pred, PredReg))
34709467b48Spatrick .add(condCodeOp())
34809467b48Spatrick .setMIFlags(MIFlags);
34909467b48Spatrick }
35009467b48Spatrick return;
35109467b48Spatrick }
35209467b48Spatrick }
35309467b48Spatrick
35409467b48Spatrick while (NumBytes) {
35509467b48Spatrick unsigned ThisVal = NumBytes;
35609467b48Spatrick unsigned Opc = 0;
35709467b48Spatrick if (DestReg == ARM::SP && BaseReg != ARM::SP) {
35809467b48Spatrick // mov sp, rn. Note t2MOVr cannot be used.
35909467b48Spatrick BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), DestReg)
36009467b48Spatrick .addReg(BaseReg)
36109467b48Spatrick .setMIFlags(MIFlags)
36209467b48Spatrick .add(predOps(ARMCC::AL));
36309467b48Spatrick BaseReg = ARM::SP;
36409467b48Spatrick continue;
36509467b48Spatrick }
36609467b48Spatrick
36709467b48Spatrick assert((DestReg != ARM::SP || BaseReg == ARM::SP) &&
36809467b48Spatrick "Writing to SP, from other register.");
36909467b48Spatrick
37009467b48Spatrick // Try to use T1, as it smaller
37109467b48Spatrick if ((DestReg == ARM::SP) && (ThisVal < ((1 << 7) - 1) * 4)) {
37209467b48Spatrick assert((ThisVal & 3) == 0 && "Stack update is not multiple of 4?");
37309467b48Spatrick Opc = isSub ? ARM::tSUBspi : ARM::tADDspi;
37409467b48Spatrick BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
37509467b48Spatrick .addReg(BaseReg)
37609467b48Spatrick .addImm(ThisVal / 4)
37709467b48Spatrick .setMIFlags(MIFlags)
37809467b48Spatrick .add(predOps(ARMCC::AL));
37909467b48Spatrick break;
38009467b48Spatrick }
38109467b48Spatrick bool HasCCOut = true;
38209467b48Spatrick int ImmIsT2SO = ARM_AM::getT2SOImmVal(ThisVal);
38309467b48Spatrick bool ToSP = DestReg == ARM::SP;
38409467b48Spatrick unsigned t2SUB = ToSP ? ARM::t2SUBspImm : ARM::t2SUBri;
38509467b48Spatrick unsigned t2ADD = ToSP ? ARM::t2ADDspImm : ARM::t2ADDri;
38609467b48Spatrick unsigned t2SUBi12 = ToSP ? ARM::t2SUBspImm12 : ARM::t2SUBri12;
38709467b48Spatrick unsigned t2ADDi12 = ToSP ? ARM::t2ADDspImm12 : ARM::t2ADDri12;
38809467b48Spatrick Opc = isSub ? t2SUB : t2ADD;
38909467b48Spatrick // Prefer T2: sub rd, rn, so_imm | sub sp, sp, so_imm
39009467b48Spatrick if (ImmIsT2SO != -1) {
39109467b48Spatrick NumBytes = 0;
39209467b48Spatrick } else if (ThisVal < 4096) {
39309467b48Spatrick // Prefer T3 if can make it in a single go: subw rd, rn, imm12 | subw sp,
39409467b48Spatrick // sp, imm12
39509467b48Spatrick Opc = isSub ? t2SUBi12 : t2ADDi12;
39609467b48Spatrick HasCCOut = false;
39709467b48Spatrick NumBytes = 0;
39809467b48Spatrick } else {
39909467b48Spatrick // Use one T2 instruction to reduce NumBytes
40009467b48Spatrick // FIXME: Move this to ARMAddressingModes.h?
40109467b48Spatrick unsigned RotAmt = countLeadingZeros(ThisVal);
40209467b48Spatrick ThisVal = ThisVal & ARM_AM::rotr32(0xff000000U, RotAmt);
40309467b48Spatrick NumBytes &= ~ThisVal;
40409467b48Spatrick assert(ARM_AM::getT2SOImmVal(ThisVal) != -1 &&
40509467b48Spatrick "Bit extraction didn't work?");
40609467b48Spatrick }
40709467b48Spatrick
40809467b48Spatrick // Build the new ADD / SUB.
40909467b48Spatrick MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
41009467b48Spatrick .addReg(BaseReg, RegState::Kill)
41109467b48Spatrick .addImm(ThisVal)
41209467b48Spatrick .add(predOps(ARMCC::AL))
41309467b48Spatrick .setMIFlags(MIFlags);
41409467b48Spatrick if (HasCCOut)
41509467b48Spatrick MIB.add(condCodeOp());
41609467b48Spatrick
41709467b48Spatrick BaseReg = DestReg;
41809467b48Spatrick }
41909467b48Spatrick }
42009467b48Spatrick
42109467b48Spatrick static unsigned
negativeOffsetOpcode(unsigned opcode)42209467b48Spatrick negativeOffsetOpcode(unsigned opcode)
42309467b48Spatrick {
42409467b48Spatrick switch (opcode) {
42509467b48Spatrick case ARM::t2LDRi12: return ARM::t2LDRi8;
42609467b48Spatrick case ARM::t2LDRHi12: return ARM::t2LDRHi8;
42709467b48Spatrick case ARM::t2LDRBi12: return ARM::t2LDRBi8;
42809467b48Spatrick case ARM::t2LDRSHi12: return ARM::t2LDRSHi8;
42909467b48Spatrick case ARM::t2LDRSBi12: return ARM::t2LDRSBi8;
43009467b48Spatrick case ARM::t2STRi12: return ARM::t2STRi8;
43109467b48Spatrick case ARM::t2STRBi12: return ARM::t2STRBi8;
43209467b48Spatrick case ARM::t2STRHi12: return ARM::t2STRHi8;
43309467b48Spatrick case ARM::t2PLDi12: return ARM::t2PLDi8;
43409467b48Spatrick case ARM::t2PLDWi12: return ARM::t2PLDWi8;
43509467b48Spatrick case ARM::t2PLIi12: return ARM::t2PLIi8;
43609467b48Spatrick
43709467b48Spatrick case ARM::t2LDRi8:
43809467b48Spatrick case ARM::t2LDRHi8:
43909467b48Spatrick case ARM::t2LDRBi8:
44009467b48Spatrick case ARM::t2LDRSHi8:
44109467b48Spatrick case ARM::t2LDRSBi8:
44209467b48Spatrick case ARM::t2STRi8:
44309467b48Spatrick case ARM::t2STRBi8:
44409467b48Spatrick case ARM::t2STRHi8:
44509467b48Spatrick case ARM::t2PLDi8:
44609467b48Spatrick case ARM::t2PLDWi8:
44709467b48Spatrick case ARM::t2PLIi8:
44809467b48Spatrick return opcode;
44909467b48Spatrick
45009467b48Spatrick default:
45109467b48Spatrick llvm_unreachable("unknown thumb2 opcode.");
45209467b48Spatrick }
45309467b48Spatrick }
45409467b48Spatrick
45509467b48Spatrick static unsigned
positiveOffsetOpcode(unsigned opcode)45609467b48Spatrick positiveOffsetOpcode(unsigned opcode)
45709467b48Spatrick {
45809467b48Spatrick switch (opcode) {
45909467b48Spatrick case ARM::t2LDRi8: return ARM::t2LDRi12;
46009467b48Spatrick case ARM::t2LDRHi8: return ARM::t2LDRHi12;
46109467b48Spatrick case ARM::t2LDRBi8: return ARM::t2LDRBi12;
46209467b48Spatrick case ARM::t2LDRSHi8: return ARM::t2LDRSHi12;
46309467b48Spatrick case ARM::t2LDRSBi8: return ARM::t2LDRSBi12;
46409467b48Spatrick case ARM::t2STRi8: return ARM::t2STRi12;
46509467b48Spatrick case ARM::t2STRBi8: return ARM::t2STRBi12;
46609467b48Spatrick case ARM::t2STRHi8: return ARM::t2STRHi12;
46709467b48Spatrick case ARM::t2PLDi8: return ARM::t2PLDi12;
46809467b48Spatrick case ARM::t2PLDWi8: return ARM::t2PLDWi12;
46909467b48Spatrick case ARM::t2PLIi8: return ARM::t2PLIi12;
47009467b48Spatrick
47109467b48Spatrick case ARM::t2LDRi12:
47209467b48Spatrick case ARM::t2LDRHi12:
47309467b48Spatrick case ARM::t2LDRBi12:
47409467b48Spatrick case ARM::t2LDRSHi12:
47509467b48Spatrick case ARM::t2LDRSBi12:
47609467b48Spatrick case ARM::t2STRi12:
47709467b48Spatrick case ARM::t2STRBi12:
47809467b48Spatrick case ARM::t2STRHi12:
47909467b48Spatrick case ARM::t2PLDi12:
48009467b48Spatrick case ARM::t2PLDWi12:
48109467b48Spatrick case ARM::t2PLIi12:
48209467b48Spatrick return opcode;
48309467b48Spatrick
48409467b48Spatrick default:
48509467b48Spatrick llvm_unreachable("unknown thumb2 opcode.");
48609467b48Spatrick }
48709467b48Spatrick }
48809467b48Spatrick
48909467b48Spatrick static unsigned
immediateOffsetOpcode(unsigned opcode)49009467b48Spatrick immediateOffsetOpcode(unsigned opcode)
49109467b48Spatrick {
49209467b48Spatrick switch (opcode) {
49309467b48Spatrick case ARM::t2LDRs: return ARM::t2LDRi12;
49409467b48Spatrick case ARM::t2LDRHs: return ARM::t2LDRHi12;
49509467b48Spatrick case ARM::t2LDRBs: return ARM::t2LDRBi12;
49609467b48Spatrick case ARM::t2LDRSHs: return ARM::t2LDRSHi12;
49709467b48Spatrick case ARM::t2LDRSBs: return ARM::t2LDRSBi12;
49809467b48Spatrick case ARM::t2STRs: return ARM::t2STRi12;
49909467b48Spatrick case ARM::t2STRBs: return ARM::t2STRBi12;
50009467b48Spatrick case ARM::t2STRHs: return ARM::t2STRHi12;
50109467b48Spatrick case ARM::t2PLDs: return ARM::t2PLDi12;
50209467b48Spatrick case ARM::t2PLDWs: return ARM::t2PLDWi12;
50309467b48Spatrick case ARM::t2PLIs: return ARM::t2PLIi12;
50409467b48Spatrick
50509467b48Spatrick case ARM::t2LDRi12:
50609467b48Spatrick case ARM::t2LDRHi12:
50709467b48Spatrick case ARM::t2LDRBi12:
50809467b48Spatrick case ARM::t2LDRSHi12:
50909467b48Spatrick case ARM::t2LDRSBi12:
51009467b48Spatrick case ARM::t2STRi12:
51109467b48Spatrick case ARM::t2STRBi12:
51209467b48Spatrick case ARM::t2STRHi12:
51309467b48Spatrick case ARM::t2PLDi12:
51409467b48Spatrick case ARM::t2PLDWi12:
51509467b48Spatrick case ARM::t2PLIi12:
51609467b48Spatrick case ARM::t2LDRi8:
51709467b48Spatrick case ARM::t2LDRHi8:
51809467b48Spatrick case ARM::t2LDRBi8:
51909467b48Spatrick case ARM::t2LDRSHi8:
52009467b48Spatrick case ARM::t2LDRSBi8:
52109467b48Spatrick case ARM::t2STRi8:
52209467b48Spatrick case ARM::t2STRBi8:
52309467b48Spatrick case ARM::t2STRHi8:
52409467b48Spatrick case ARM::t2PLDi8:
52509467b48Spatrick case ARM::t2PLDWi8:
52609467b48Spatrick case ARM::t2PLIi8:
52709467b48Spatrick return opcode;
52809467b48Spatrick
52909467b48Spatrick default:
53009467b48Spatrick llvm_unreachable("unknown thumb2 opcode.");
53109467b48Spatrick }
53209467b48Spatrick }
53309467b48Spatrick
rewriteT2FrameIndex(MachineInstr & MI,unsigned FrameRegIdx,Register FrameReg,int & Offset,const ARMBaseInstrInfo & TII,const TargetRegisterInfo * TRI)53409467b48Spatrick bool llvm::rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
535097a140dSpatrick Register FrameReg, int &Offset,
53609467b48Spatrick const ARMBaseInstrInfo &TII,
53709467b48Spatrick const TargetRegisterInfo *TRI) {
53809467b48Spatrick unsigned Opcode = MI.getOpcode();
53909467b48Spatrick const MCInstrDesc &Desc = MI.getDesc();
54009467b48Spatrick unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
54109467b48Spatrick bool isSub = false;
54209467b48Spatrick
54309467b48Spatrick MachineFunction &MF = *MI.getParent()->getParent();
54409467b48Spatrick const TargetRegisterClass *RegClass =
54509467b48Spatrick TII.getRegClass(Desc, FrameRegIdx, TRI, MF);
54609467b48Spatrick
54709467b48Spatrick // Memory operands in inline assembly always use AddrModeT2_i12.
54809467b48Spatrick if (Opcode == ARM::INLINEASM || Opcode == ARM::INLINEASM_BR)
54909467b48Spatrick AddrMode = ARMII::AddrModeT2_i12; // FIXME. mode for thumb2?
55009467b48Spatrick
55109467b48Spatrick const bool IsSP = Opcode == ARM::t2ADDspImm12 || Opcode == ARM::t2ADDspImm;
55209467b48Spatrick if (IsSP || Opcode == ARM::t2ADDri || Opcode == ARM::t2ADDri12) {
55309467b48Spatrick Offset += MI.getOperand(FrameRegIdx+1).getImm();
55409467b48Spatrick
555097a140dSpatrick Register PredReg;
55609467b48Spatrick if (Offset == 0 && getInstrPredicate(MI, PredReg) == ARMCC::AL &&
55709467b48Spatrick !MI.definesRegister(ARM::CPSR)) {
55809467b48Spatrick // Turn it into a move.
55909467b48Spatrick MI.setDesc(TII.get(ARM::tMOVr));
56009467b48Spatrick MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
56109467b48Spatrick // Remove offset and remaining explicit predicate operands.
562*d415bd75Srobert do MI.removeOperand(FrameRegIdx+1);
56309467b48Spatrick while (MI.getNumOperands() > FrameRegIdx+1);
56409467b48Spatrick MachineInstrBuilder MIB(*MI.getParent()->getParent(), &MI);
56509467b48Spatrick MIB.add(predOps(ARMCC::AL));
56609467b48Spatrick return true;
56709467b48Spatrick }
56809467b48Spatrick
56909467b48Spatrick bool HasCCOut = (Opcode != ARM::t2ADDspImm12 && Opcode != ARM::t2ADDri12);
57009467b48Spatrick
57109467b48Spatrick if (Offset < 0) {
57209467b48Spatrick Offset = -Offset;
57309467b48Spatrick isSub = true;
57409467b48Spatrick MI.setDesc(IsSP ? TII.get(ARM::t2SUBspImm) : TII.get(ARM::t2SUBri));
57509467b48Spatrick } else {
57609467b48Spatrick MI.setDesc(IsSP ? TII.get(ARM::t2ADDspImm) : TII.get(ARM::t2ADDri));
57709467b48Spatrick }
57809467b48Spatrick
57909467b48Spatrick // Common case: small offset, fits into instruction.
58009467b48Spatrick if (ARM_AM::getT2SOImmVal(Offset) != -1) {
58109467b48Spatrick MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
58209467b48Spatrick MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset);
58309467b48Spatrick // Add cc_out operand if the original instruction did not have one.
58409467b48Spatrick if (!HasCCOut)
58509467b48Spatrick MI.addOperand(MachineOperand::CreateReg(0, false));
58609467b48Spatrick Offset = 0;
58709467b48Spatrick return true;
58809467b48Spatrick }
58909467b48Spatrick // Another common case: imm12.
59009467b48Spatrick if (Offset < 4096 &&
59109467b48Spatrick (!HasCCOut || MI.getOperand(MI.getNumOperands()-1).getReg() == 0)) {
59209467b48Spatrick unsigned NewOpc = isSub ? IsSP ? ARM::t2SUBspImm12 : ARM::t2SUBri12
59309467b48Spatrick : IsSP ? ARM::t2ADDspImm12 : ARM::t2ADDri12;
59409467b48Spatrick MI.setDesc(TII.get(NewOpc));
59509467b48Spatrick MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
59609467b48Spatrick MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset);
59709467b48Spatrick // Remove the cc_out operand.
59809467b48Spatrick if (HasCCOut)
599*d415bd75Srobert MI.removeOperand(MI.getNumOperands()-1);
60009467b48Spatrick Offset = 0;
60109467b48Spatrick return true;
60209467b48Spatrick }
60309467b48Spatrick
60409467b48Spatrick // Otherwise, extract 8 adjacent bits from the immediate into this
60509467b48Spatrick // t2ADDri/t2SUBri.
60609467b48Spatrick unsigned RotAmt = countLeadingZeros<unsigned>(Offset);
60709467b48Spatrick unsigned ThisImmVal = Offset & ARM_AM::rotr32(0xff000000U, RotAmt);
60809467b48Spatrick
60909467b48Spatrick // We will handle these bits from offset, clear them.
61009467b48Spatrick Offset &= ~ThisImmVal;
61109467b48Spatrick
61209467b48Spatrick assert(ARM_AM::getT2SOImmVal(ThisImmVal) != -1 &&
61309467b48Spatrick "Bit extraction didn't work?");
61409467b48Spatrick MI.getOperand(FrameRegIdx+1).ChangeToImmediate(ThisImmVal);
61509467b48Spatrick // Add cc_out operand if the original instruction did not have one.
61609467b48Spatrick if (!HasCCOut)
61709467b48Spatrick MI.addOperand(MachineOperand::CreateReg(0, false));
61809467b48Spatrick } else {
61909467b48Spatrick // AddrMode4 and AddrMode6 cannot handle any offset.
62009467b48Spatrick if (AddrMode == ARMII::AddrMode4 || AddrMode == ARMII::AddrMode6)
62109467b48Spatrick return false;
62209467b48Spatrick
62309467b48Spatrick // AddrModeT2_so cannot handle any offset. If there is no offset
62409467b48Spatrick // register then we change to an immediate version.
62509467b48Spatrick unsigned NewOpc = Opcode;
62609467b48Spatrick if (AddrMode == ARMII::AddrModeT2_so) {
62709467b48Spatrick Register OffsetReg = MI.getOperand(FrameRegIdx + 1).getReg();
62809467b48Spatrick if (OffsetReg != 0) {
62909467b48Spatrick MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
63009467b48Spatrick return Offset == 0;
63109467b48Spatrick }
63209467b48Spatrick
633*d415bd75Srobert MI.removeOperand(FrameRegIdx+1);
63409467b48Spatrick MI.getOperand(FrameRegIdx+1).ChangeToImmediate(0);
63509467b48Spatrick NewOpc = immediateOffsetOpcode(Opcode);
63609467b48Spatrick AddrMode = ARMII::AddrModeT2_i12;
63709467b48Spatrick }
63809467b48Spatrick
63909467b48Spatrick unsigned NumBits = 0;
64009467b48Spatrick unsigned Scale = 1;
641*d415bd75Srobert if (AddrMode == ARMII::AddrModeT2_i8neg ||
642*d415bd75Srobert AddrMode == ARMII::AddrModeT2_i12) {
64309467b48Spatrick // i8 supports only negative, and i12 supports only positive, so
64409467b48Spatrick // based on Offset sign convert Opcode to the appropriate
64509467b48Spatrick // instruction
64609467b48Spatrick Offset += MI.getOperand(FrameRegIdx+1).getImm();
64709467b48Spatrick if (Offset < 0) {
64809467b48Spatrick NewOpc = negativeOffsetOpcode(Opcode);
64909467b48Spatrick NumBits = 8;
65009467b48Spatrick isSub = true;
65109467b48Spatrick Offset = -Offset;
65209467b48Spatrick } else {
65309467b48Spatrick NewOpc = positiveOffsetOpcode(Opcode);
65409467b48Spatrick NumBits = 12;
65509467b48Spatrick }
65609467b48Spatrick } else if (AddrMode == ARMII::AddrMode5) {
65709467b48Spatrick // VFP address mode.
65809467b48Spatrick const MachineOperand &OffOp = MI.getOperand(FrameRegIdx+1);
65909467b48Spatrick int InstrOffs = ARM_AM::getAM5Offset(OffOp.getImm());
66009467b48Spatrick if (ARM_AM::getAM5Op(OffOp.getImm()) == ARM_AM::sub)
66109467b48Spatrick InstrOffs *= -1;
66209467b48Spatrick NumBits = 8;
66309467b48Spatrick Scale = 4;
66409467b48Spatrick Offset += InstrOffs * 4;
66509467b48Spatrick assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
66609467b48Spatrick if (Offset < 0) {
66709467b48Spatrick Offset = -Offset;
66809467b48Spatrick isSub = true;
66909467b48Spatrick }
67009467b48Spatrick } else if (AddrMode == ARMII::AddrMode5FP16) {
67109467b48Spatrick // VFP address mode.
67209467b48Spatrick const MachineOperand &OffOp = MI.getOperand(FrameRegIdx+1);
67309467b48Spatrick int InstrOffs = ARM_AM::getAM5FP16Offset(OffOp.getImm());
67409467b48Spatrick if (ARM_AM::getAM5FP16Op(OffOp.getImm()) == ARM_AM::sub)
67509467b48Spatrick InstrOffs *= -1;
67609467b48Spatrick NumBits = 8;
67709467b48Spatrick Scale = 2;
67809467b48Spatrick Offset += InstrOffs * 2;
67909467b48Spatrick assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
68009467b48Spatrick if (Offset < 0) {
68109467b48Spatrick Offset = -Offset;
68209467b48Spatrick isSub = true;
68309467b48Spatrick }
68409467b48Spatrick } else if (AddrMode == ARMII::AddrModeT2_i7s4 ||
68509467b48Spatrick AddrMode == ARMII::AddrModeT2_i7s2 ||
68609467b48Spatrick AddrMode == ARMII::AddrModeT2_i7) {
68709467b48Spatrick Offset += MI.getOperand(FrameRegIdx + 1).getImm();
68809467b48Spatrick unsigned OffsetMask;
68909467b48Spatrick switch (AddrMode) {
69009467b48Spatrick case ARMII::AddrModeT2_i7s4: NumBits = 9; OffsetMask = 0x3; break;
69109467b48Spatrick case ARMII::AddrModeT2_i7s2: NumBits = 8; OffsetMask = 0x1; break;
69209467b48Spatrick default: NumBits = 7; OffsetMask = 0x0; break;
69309467b48Spatrick }
69409467b48Spatrick // MCInst operand expects already scaled value.
69509467b48Spatrick Scale = 1;
69609467b48Spatrick assert((Offset & OffsetMask) == 0 && "Can't encode this offset!");
69709467b48Spatrick (void)OffsetMask; // squash unused-variable warning at -NDEBUG
69809467b48Spatrick } else if (AddrMode == ARMII::AddrModeT2_i8s4) {
699097a140dSpatrick Offset += MI.getOperand(FrameRegIdx + 1).getImm();
70009467b48Spatrick NumBits = 8 + 2;
70109467b48Spatrick // MCInst operand expects already scaled value.
70209467b48Spatrick Scale = 1;
70309467b48Spatrick assert((Offset & 3) == 0 && "Can't encode this offset!");
70409467b48Spatrick } else if (AddrMode == ARMII::AddrModeT2_ldrex) {
70509467b48Spatrick Offset += MI.getOperand(FrameRegIdx + 1).getImm() * 4;
70609467b48Spatrick NumBits = 8; // 8 bits scaled by 4
70709467b48Spatrick Scale = 4;
70809467b48Spatrick assert((Offset & 3) == 0 && "Can't encode this offset!");
70909467b48Spatrick } else {
71009467b48Spatrick llvm_unreachable("Unsupported addressing mode!");
71109467b48Spatrick }
71209467b48Spatrick
71309467b48Spatrick if (NewOpc != Opcode)
71409467b48Spatrick MI.setDesc(TII.get(NewOpc));
71509467b48Spatrick
71609467b48Spatrick MachineOperand &ImmOp = MI.getOperand(FrameRegIdx+1);
71709467b48Spatrick
71809467b48Spatrick // Attempt to fold address computation
71909467b48Spatrick // Common case: small offset, fits into instruction. We need to make sure
72009467b48Spatrick // the register class is correct too, for instructions like the MVE
72109467b48Spatrick // VLDRH.32, which only accepts low tGPR registers.
72209467b48Spatrick int ImmedOffset = Offset / Scale;
72309467b48Spatrick unsigned Mask = (1 << NumBits) - 1;
72409467b48Spatrick if ((unsigned)Offset <= Mask * Scale &&
725*d415bd75Srobert (FrameReg.isVirtual() || RegClass->contains(FrameReg))) {
726*d415bd75Srobert if (FrameReg.isVirtual()) {
72709467b48Spatrick // Make sure the register class for the virtual register is correct
72809467b48Spatrick MachineRegisterInfo *MRI = &MF.getRegInfo();
72909467b48Spatrick if (!MRI->constrainRegClass(FrameReg, RegClass))
73009467b48Spatrick llvm_unreachable("Unable to constrain virtual register class.");
73109467b48Spatrick }
73209467b48Spatrick
73309467b48Spatrick // Replace the FrameIndex with fp/sp
73409467b48Spatrick MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
73509467b48Spatrick if (isSub) {
73609467b48Spatrick if (AddrMode == ARMII::AddrMode5 || AddrMode == ARMII::AddrMode5FP16)
73709467b48Spatrick // FIXME: Not consistent.
73809467b48Spatrick ImmedOffset |= 1 << NumBits;
73909467b48Spatrick else
74009467b48Spatrick ImmedOffset = -ImmedOffset;
74109467b48Spatrick }
74209467b48Spatrick ImmOp.ChangeToImmediate(ImmedOffset);
74309467b48Spatrick Offset = 0;
74409467b48Spatrick return true;
74509467b48Spatrick }
74609467b48Spatrick
74709467b48Spatrick // Otherwise, offset doesn't fit. Pull in what we can to simplify
74809467b48Spatrick ImmedOffset = ImmedOffset & Mask;
74909467b48Spatrick if (isSub) {
75009467b48Spatrick if (AddrMode == ARMII::AddrMode5 || AddrMode == ARMII::AddrMode5FP16)
75109467b48Spatrick // FIXME: Not consistent.
75209467b48Spatrick ImmedOffset |= 1 << NumBits;
75309467b48Spatrick else {
75409467b48Spatrick ImmedOffset = -ImmedOffset;
75509467b48Spatrick if (ImmedOffset == 0)
75609467b48Spatrick // Change the opcode back if the encoded offset is zero.
75709467b48Spatrick MI.setDesc(TII.get(positiveOffsetOpcode(NewOpc)));
75809467b48Spatrick }
75909467b48Spatrick }
76009467b48Spatrick ImmOp.ChangeToImmediate(ImmedOffset);
76109467b48Spatrick Offset &= ~(Mask*Scale);
76209467b48Spatrick }
76309467b48Spatrick
76409467b48Spatrick Offset = (isSub) ? -Offset : Offset;
765*d415bd75Srobert return Offset == 0 && (FrameReg.isVirtual() || RegClass->contains(FrameReg));
76609467b48Spatrick }
76709467b48Spatrick
getITInstrPredicate(const MachineInstr & MI,Register & PredReg)76809467b48Spatrick ARMCC::CondCodes llvm::getITInstrPredicate(const MachineInstr &MI,
769097a140dSpatrick Register &PredReg) {
77009467b48Spatrick unsigned Opc = MI.getOpcode();
77109467b48Spatrick if (Opc == ARM::tBcc || Opc == ARM::t2Bcc)
77209467b48Spatrick return ARMCC::AL;
77309467b48Spatrick return getInstrPredicate(MI, PredReg);
77409467b48Spatrick }
77509467b48Spatrick
findFirstVPTPredOperandIdx(const MachineInstr & MI)77609467b48Spatrick int llvm::findFirstVPTPredOperandIdx(const MachineInstr &MI) {
77709467b48Spatrick const MCInstrDesc &MCID = MI.getDesc();
77809467b48Spatrick
77909467b48Spatrick for (unsigned i = 0, e = MCID.getNumOperands(); i != e; ++i)
780*d415bd75Srobert if (ARM::isVpred(MCID.operands()[i].OperandType))
78109467b48Spatrick return i;
78209467b48Spatrick
78309467b48Spatrick return -1;
78409467b48Spatrick }
78509467b48Spatrick
getVPTInstrPredicate(const MachineInstr & MI,Register & PredReg)78609467b48Spatrick ARMVCC::VPTCodes llvm::getVPTInstrPredicate(const MachineInstr &MI,
787097a140dSpatrick Register &PredReg) {
78809467b48Spatrick int PIdx = findFirstVPTPredOperandIdx(MI);
78909467b48Spatrick if (PIdx == -1) {
79009467b48Spatrick PredReg = 0;
79109467b48Spatrick return ARMVCC::None;
79209467b48Spatrick }
79309467b48Spatrick
79409467b48Spatrick PredReg = MI.getOperand(PIdx+1).getReg();
79509467b48Spatrick return (ARMVCC::VPTCodes)MI.getOperand(PIdx).getImm();
79609467b48Spatrick }
797097a140dSpatrick
recomputeVPTBlockMask(MachineInstr & Instr)798097a140dSpatrick void llvm::recomputeVPTBlockMask(MachineInstr &Instr) {
799097a140dSpatrick assert(isVPTOpcode(Instr.getOpcode()) && "Not a VPST or VPT Instruction!");
800097a140dSpatrick
801097a140dSpatrick MachineOperand &MaskOp = Instr.getOperand(0);
802097a140dSpatrick assert(MaskOp.isImm() && "Operand 0 is not the block mask of the VPT/VPST?!");
803097a140dSpatrick
804097a140dSpatrick MachineBasicBlock::iterator Iter = ++Instr.getIterator(),
805097a140dSpatrick End = Instr.getParent()->end();
806097a140dSpatrick
807*d415bd75Srobert while (Iter != End && Iter->isDebugInstr())
808*d415bd75Srobert ++Iter;
809*d415bd75Srobert
810097a140dSpatrick // Verify that the instruction after the VPT/VPST is predicated (it should
811097a140dSpatrick // be), and skip it.
812*d415bd75Srobert assert(Iter != End && "Expected some instructions in any VPT block");
813097a140dSpatrick assert(
814097a140dSpatrick getVPTInstrPredicate(*Iter) == ARMVCC::Then &&
815097a140dSpatrick "VPT/VPST should be followed by an instruction with a 'then' predicate!");
816097a140dSpatrick ++Iter;
817097a140dSpatrick
818097a140dSpatrick // Iterate over the predicated instructions, updating the BlockMask as we go.
819097a140dSpatrick ARM::PredBlockMask BlockMask = ARM::PredBlockMask::T;
820097a140dSpatrick while (Iter != End) {
821*d415bd75Srobert if (Iter->isDebugInstr()) {
822*d415bd75Srobert ++Iter;
823*d415bd75Srobert continue;
824*d415bd75Srobert }
825097a140dSpatrick ARMVCC::VPTCodes Pred = getVPTInstrPredicate(*Iter);
826097a140dSpatrick if (Pred == ARMVCC::None)
827097a140dSpatrick break;
828097a140dSpatrick BlockMask = expandPredBlockMask(BlockMask, Pred);
829097a140dSpatrick ++Iter;
830097a140dSpatrick }
831097a140dSpatrick
832097a140dSpatrick // Rewrite the BlockMask.
833097a140dSpatrick MaskOp.setImm((int64_t)(BlockMask));
834097a140dSpatrick }
835