-//===-- Thumb2ITBlockPass.cpp - Insert Thumb IT blocks ----------*- C++ -*-===//
+//===-- Thumb2ITBlockPass.cpp - Insert Thumb-2 IT blocks ------------------===//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "thumb2-it"
#include "ARM.h"
#include "ARMMachineFunctionInfo.h"
#include "Thumb2InstrInfo.h"
-#include "llvm/CodeGen/MachineInstr.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineInstrBundle.h"
using namespace llvm;
+#define DEBUG_TYPE "thumb2-it"
+
STATISTIC(NumITs, "Number of IT blocks inserted");
STATISTIC(NumMovedInsts, "Number of predicated instructions moved");
namespace {
class Thumb2ITBlockPass : public MachineFunctionPass {
- bool PreRegAlloc;
-
public:
static char ID;
- Thumb2ITBlockPass(bool PreRA) :
- MachineFunctionPass(&ID), PreRegAlloc(PreRA) {}
+ Thumb2ITBlockPass() : MachineFunctionPass(ID) {}
+ bool restrictIT;
const Thumb2InstrInfo *TII;
const TargetRegisterInfo *TRI;
ARMFunctionInfo *AFI;
- virtual bool runOnMachineFunction(MachineFunction &Fn);
+ bool runOnMachineFunction(MachineFunction &Fn) override;
- virtual const char *getPassName() const {
+ const char *getPassName() const override {
return "Thumb IT blocks insertion pass";
}
private:
- bool MoveCPSRUseUp(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI,
- MachineBasicBlock::iterator E,
- unsigned PredReg,
- ARMCC::CondCodes CC, ARMCC::CondCodes OCC,
- bool &Done);
-
- void FindITBlockRanges(MachineBasicBlock &MBB,
- SmallVector<MachineInstr*,4> &FirstUses,
- SmallVector<MachineInstr*,4> &LastUses);
- bool InsertITBlock(MachineInstr *First, MachineInstr *Last);
- bool InsertITBlocks(MachineBasicBlock &MBB);
bool MoveCopyOutOfITBlock(MachineInstr *MI,
ARMCC::CondCodes CC, ARMCC::CondCodes OCC,
SmallSet<unsigned, 4> &Defs,
char Thumb2ITBlockPass::ID = 0;
}
-bool
-Thumb2ITBlockPass::MoveCPSRUseUp(MachineBasicBlock &MBB,
- MachineBasicBlock::iterator MBBI,
- MachineBasicBlock::iterator E,
- unsigned PredReg,
- ARMCC::CondCodes CC, ARMCC::CondCodes OCC,
- bool &Done) {
- SmallSet<unsigned, 4> Defs, Uses;
- MachineBasicBlock::iterator I = MBBI;
- // Look for next CPSR use by scanning up to 4 instructions.
- for (unsigned i = 0; i < 4; ++i) {
- MachineInstr *MI = &*I;
- unsigned MPredReg = 0;
- ARMCC::CondCodes MCC = llvm::getITInstrPredicate(MI, MPredReg);
- if (MCC != ARMCC::AL) {
- if (MPredReg != PredReg || (MCC != CC && MCC != OCC))
- return false;
-
- // Check if the instruction is using any register that's defined
- // below the previous predicated instruction. Also return false if
- // it defines any register which is used in between.
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
- const MachineOperand &MO = MI->getOperand(i);
- if (!MO.isReg())
- continue;
- unsigned Reg = MO.getReg();
- if (!Reg)
- continue;
- if (MO.isDef()) {
- if (Reg == PredReg || Uses.count(Reg))
- return false;
- } else {
- if (Defs.count(Reg))
- return false;
- }
- }
-
- Done = (I == E);
- MBB.remove(MI);
- MBB.insert(MBBI, MI);
- ++NumMovedInsts;
- return true;
- }
-
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
- const MachineOperand &MO = MI->getOperand(i);
- if (!MO.isReg())
- continue;
- unsigned Reg = MO.getReg();
- if (!Reg)
- continue;
- if (MO.isDef()) {
- if (Reg == PredReg)
- return false;
- Defs.insert(Reg);
- } else
- Uses.insert(Reg);
- }
-
- if (I == E)
- break;
- ++I;
- }
- return false;
-}
-
-static bool isCPSRLiveout(MachineBasicBlock &MBB) {
- for (MachineBasicBlock::succ_iterator I = MBB.succ_begin(),
- E = MBB.succ_end(); I != E; ++I) {
- if ((*I)->isLiveIn(ARM::CPSR))
- return true;
- }
- return false;
-}
-
-void Thumb2ITBlockPass::FindITBlockRanges(MachineBasicBlock &MBB,
- SmallVector<MachineInstr*,4> &FirstUses,
- SmallVector<MachineInstr*,4> &LastUses) {
- bool SeenUse = false;
- MachineOperand *LastDef = 0;
- MachineOperand *LastUse = 0;
- MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
- while (MBBI != E) {
- MachineInstr *MI = &*MBBI;
- ++MBBI;
-
- MachineOperand *Def = 0;
- MachineOperand *Use = 0;
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
- MachineOperand &MO = MI->getOperand(i);
- if (!MO.isReg() || MO.getReg() != ARM::CPSR)
- continue;
- if (MO.isDef()) {
- assert(Def == 0 && "Multiple defs of CPSR?");
- Def = &MO;
- } else {
- assert(Use == 0 && "Multiple uses of CPSR?");
- Use = &MO;
- }
- }
-
- if (Use) {
- LastUse = Use;
- if (!SeenUse) {
- FirstUses.push_back(MI);
- SeenUse = true;
- }
- }
- if (Def) {
- if (LastUse) {
- LastUses.push_back(LastUse->getParent());
- LastUse = 0;
- }
- LastDef = Def;
- SeenUse = false;
- }
- }
-
- if (LastUse) {
- // Is the last use a kill?
- if (isCPSRLiveout(MBB))
- LastUses.push_back(0);
- else
- LastUses.push_back(LastUse->getParent());
- }
-}
-
-bool Thumb2ITBlockPass::InsertITBlock(MachineInstr *First, MachineInstr *Last) {
- if (First == Last)
- return false;
-
- bool Modified = false;
- MachineBasicBlock *MBB = First->getParent();
- MachineBasicBlock::iterator MBBI = First;
- MachineBasicBlock::iterator E = Last;
-
- if (First->getDesc().isBranch() || First->getDesc().isReturn())
- return false;
-
- unsigned PredReg = 0;
- ARMCC::CondCodes CC = llvm::getITInstrPredicate(First, PredReg);
- if (CC == ARMCC::AL)
- return Modified;
-
- // Move uses of the CPSR together if possible.
- ARMCC::CondCodes OCC = ARMCC::getOppositeCondition(CC);
-
- do {
- ++MBBI;
- if (MBBI->getDesc().isBranch() || MBBI->getDesc().isReturn())
- return Modified;
- MachineInstr *NMI = &*MBBI;
- unsigned NPredReg = 0;
- ARMCC::CondCodes NCC = llvm::getITInstrPredicate(NMI, NPredReg);
- if (NCC != CC && NCC != OCC) {
- if (NCC != ARMCC::AL)
- return Modified;
- assert(MBBI != E);
- bool Done = false;
- if (!MoveCPSRUseUp(*MBB, MBBI, E, PredReg, CC, OCC, Done))
- return Modified;
- Modified = true;
- if (Done)
- MBBI = E;
- }
- } while (MBBI != E);
- return true;
-}
-
-bool Thumb2ITBlockPass::InsertITBlocks(MachineBasicBlock &MBB) {
- SmallVector<MachineInstr*, 4> FirstUses;
- SmallVector<MachineInstr*, 4> LastUses;
- FindITBlockRanges(MBB, FirstUses, LastUses);
- assert(FirstUses.size() == LastUses.size() && "Incorrect range information!");
-
- bool Modified = false;
- for (unsigned i = 0, e = FirstUses.size(); i != e; ++i) {
- if (LastUses[i] == 0)
- // Must be the last pair where CPSR is live out of the block.
- return Modified;
- Modified |= InsertITBlock(FirstUses[i], LastUses[i]);
- }
- return Modified;
-}
-
/// TrackDefUses - Tracking what registers are being defined and used by
/// instructions in the IT block. This also tracks "dependencies", i.e. uses
/// in the IT block that are defined before the IT instruction.
for (unsigned i = 0, e = LocalUses.size(); i != e; ++i) {
unsigned Reg = LocalUses[i];
- Uses.insert(Reg);
- for (const unsigned *Subreg = TRI->getSubRegisters(Reg);
- *Subreg; ++Subreg)
+ for (MCSubRegIterator Subreg(Reg, TRI, /*IncludeSelf=*/true);
+ Subreg.isValid(); ++Subreg)
Uses.insert(*Subreg);
}
for (unsigned i = 0, e = LocalDefs.size(); i != e; ++i) {
unsigned Reg = LocalDefs[i];
- Defs.insert(Reg);
- for (const unsigned *Subreg = TRI->getSubRegisters(Reg);
- *Subreg; ++Subreg)
+ for (MCSubRegIterator Subreg(Reg, TRI, /*IncludeSelf=*/true);
+ Subreg.isValid(); ++Subreg)
Defs.insert(*Subreg);
if (Reg == ARM::CPSR)
continue;
}
}
+/// Clear kill flags for any uses in the given set. This will likely
+/// conservatively remove more kill flags than are necessary, but removing them
+/// is safer than incorrect kill flags remaining on instructions.
+static void ClearKillFlags(MachineInstr *MI, SmallSet<unsigned, 4> &Uses) {
+ for (MachineOperand &MO : MI->operands()) {
+ if (!MO.isReg() || MO.isDef() || !MO.isKill())
+ continue;
+ if (!Uses.count(MO.getReg()))
+ continue;
+ MO.setIsKill(false);
+ }
+}
+
+static bool isCopy(MachineInstr *MI) {
+ switch (MI->getOpcode()) {
+ default:
+ return false;
+ case ARM::MOVr:
+ case ARM::MOVr_TC:
+ case ARM::tMOVr:
+ case ARM::t2MOVr:
+ return true;
+ }
+}
+
bool
Thumb2ITBlockPass::MoveCopyOutOfITBlock(MachineInstr *MI,
ARMCC::CondCodes CC, ARMCC::CondCodes OCC,
SmallSet<unsigned, 4> &Defs,
SmallSet<unsigned, 4> &Uses) {
- unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx;
- if (TII->isMoveInstr(*MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx)) {
- assert(SrcSubIdx == 0 && DstSubIdx == 0 &&
- "Sub-register indices still around?");
- // llvm models select's as two-address instructions. That means a copy
- // is inserted before a t2MOVccr, etc. If the copy is scheduled in
- // between selects we would end up creating multiple IT blocks.
-
- // First check if it's safe to move it.
- if (Uses.count(DstReg) || Defs.count(SrcReg))
- return false;
-
- // Then peek at the next instruction to see if it's predicated on CC or OCC.
- // If not, then there is nothing to be gained by moving the copy.
- MachineBasicBlock::iterator I = MI; ++I;
- MachineBasicBlock::iterator E = MI->getParent()->end();
- while (I != E && I->isDebugValue())
- ++I;
- if (I != E) {
- unsigned NPredReg = 0;
- ARMCC::CondCodes NCC = llvm::getITInstrPredicate(I, NPredReg);
- if (NCC == CC || NCC == OCC)
- return true;
- }
+ if (!isCopy(MI))
+ return false;
+ // llvm models select's as two-address instructions. That means a copy
+ // is inserted before a t2MOVccr, etc. If the copy is scheduled in
+ // between selects we would end up creating multiple IT blocks.
+ assert(MI->getOperand(0).getSubReg() == 0 &&
+ MI->getOperand(1).getSubReg() == 0 &&
+ "Sub-register indices still around?");
+
+ unsigned DstReg = MI->getOperand(0).getReg();
+ unsigned SrcReg = MI->getOperand(1).getReg();
+
+ // First check if it's safe to move it.
+ if (Uses.count(DstReg) || Defs.count(SrcReg))
+ return false;
+
+ // If the CPSR is defined by this copy, then we don't want to move it. E.g.,
+ // if we have:
+ //
+ // movs r1, r1
+ // rsb r1, 0
+ // movs r2, r2
+ // rsb r2, 0
+ //
+ // we don't want this to be converted to:
+ //
+ // movs r1, r1
+ // movs r2, r2
+ // itt mi
+ // rsb r1, 0
+ // rsb r2, 0
+ //
+ const MCInstrDesc &MCID = MI->getDesc();
+ if (MI->hasOptionalDef() &&
+ MI->getOperand(MCID.getNumOperands() - 1).getReg() == ARM::CPSR)
+ return false;
+
+ // Then peek at the next instruction to see if it's predicated on CC or OCC.
+ // If not, then there is nothing to be gained by moving the copy.
+ MachineBasicBlock::iterator I = MI; ++I;
+ MachineBasicBlock::iterator E = MI->getParent()->end();
+ while (I != E && I->isDebugValue())
+ ++I;
+ if (I != E) {
+ unsigned NPredReg = 0;
+ ARMCC::CondCodes NCC = getITInstrPredicate(I, NPredReg);
+ if (NCC == CC || NCC == OCC)
+ return true;
}
return false;
}
MachineInstr *MI = &*MBBI;
DebugLoc dl = MI->getDebugLoc();
unsigned PredReg = 0;
- ARMCC::CondCodes CC = llvm::getITInstrPredicate(MI, PredReg);
+ ARMCC::CondCodes CC = getITInstrPredicate(MI, PredReg);
if (CC == ARMCC::AL) {
++MBBI;
continue;
true/*isImp*/, false/*isKill*/));
MachineInstr *LastITMI = MI;
- MachineBasicBlock::iterator InsertPos = MIB;
+ MachineBasicBlock::iterator InsertPos = MIB.getInstr();
++MBBI;
// Form IT block.
ARMCC::CondCodes OCC = ARMCC::getOppositeCondition(CC);
unsigned Mask = 0, Pos = 3;
- // Branches, including tricky ones like LDM_RET, need to end an IT
- // block so check the instruction we just put in the block.
- for (; MBBI != E && Pos &&
- (!MI->getDesc().isBranch() && !MI->getDesc().isReturn()) ; ++MBBI) {
- if (MBBI->isDebugValue())
- continue;
-
- MachineInstr *NMI = &*MBBI;
- MI = NMI;
-
- unsigned NPredReg = 0;
- ARMCC::CondCodes NCC = llvm::getITInstrPredicate(NMI, NPredReg);
- if (NCC == CC || NCC == OCC) {
- Mask |= (NCC & 1) << Pos;
- // Add implicit use of ITSTATE.
- NMI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/,
- true/*isImp*/, false/*isKill*/));
- LastITMI = NMI;
- } else {
- if (NCC == ARMCC::AL &&
- MoveCopyOutOfITBlock(NMI, CC, OCC, Defs, Uses)) {
- --MBBI;
- MBB.remove(NMI);
- MBB.insert(InsertPos, NMI);
- ++NumMovedInsts;
+
+ // v8 IT blocks are limited to one conditional op unless -arm-no-restrict-it
+ // is set: skip the loop
+ if (!restrictIT) {
+ // Branches, including tricky ones like LDM_RET, need to end an IT
+ // block so check the instruction we just put in the block.
+ for (; MBBI != E && Pos &&
+ (!MI->isBranch() && !MI->isReturn()) ; ++MBBI) {
+ if (MBBI->isDebugValue())
continue;
+
+ MachineInstr *NMI = &*MBBI;
+ MI = NMI;
+
+ unsigned NPredReg = 0;
+ ARMCC::CondCodes NCC = getITInstrPredicate(NMI, NPredReg);
+ if (NCC == CC || NCC == OCC) {
+ Mask |= (NCC & 1) << Pos;
+ // Add implicit use of ITSTATE.
+ NMI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/,
+ true/*isImp*/, false/*isKill*/));
+ LastITMI = NMI;
+ } else {
+ if (NCC == ARMCC::AL &&
+ MoveCopyOutOfITBlock(NMI, CC, OCC, Defs, Uses)) {
+ --MBBI;
+ MBB.remove(NMI);
+ MBB.insert(InsertPos, NMI);
+ ClearKillFlags(MI, Uses);
+ ++NumMovedInsts;
+ continue;
+ }
+ break;
}
- break;
+ TrackDefUses(NMI, Defs, Uses, TRI);
+ --Pos;
}
- TrackDefUses(NMI, Defs, Uses, TRI);
- --Pos;
}
// Finalize IT mask.
// Last instruction in IT block kills ITSTATE.
LastITMI->findRegisterUseOperand(ARM::ITSTATE)->setIsKill();
+ // Finalize the bundle.
+ MachineBasicBlock::instr_iterator LI = LastITMI;
+ finalizeBundle(MBB, InsertPos.getInstrIterator(), std::next(LI));
+
Modified = true;
++NumITs;
}
}
bool Thumb2ITBlockPass::runOnMachineFunction(MachineFunction &Fn) {
- const TargetMachine &TM = Fn.getTarget();
+ const ARMSubtarget &STI =
+ static_cast<const ARMSubtarget &>(Fn.getSubtarget());
+ if (!STI.isThumb2())
+ return false;
AFI = Fn.getInfo<ARMFunctionInfo>();
- TII = static_cast<const Thumb2InstrInfo*>(TM.getInstrInfo());
- TRI = TM.getRegisterInfo();
+ TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo());
+ TRI = STI.getRegisterInfo();
+ restrictIT = STI.restrictIT();
if (!AFI->isThumbFunction())
return false;
for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; ) {
MachineBasicBlock &MBB = *MFI;
++MFI;
- if (PreRegAlloc)
- Modified |= InsertITBlocks(MBB);
- else
- Modified |= InsertITInstructions(MBB);
+ Modified |= InsertITInstructions(MBB);
}
- if (Modified && !PreRegAlloc)
+ if (Modified)
AFI->setHasITBlocks(true);
return Modified;
/// createThumb2ITBlockPass - Returns an instance of the Thumb2 IT blocks
/// insertion pass.
-FunctionPass *llvm::createThumb2ITBlockPass(bool PreAlloc) {
- return new Thumb2ITBlockPass(PreAlloc);
+FunctionPass *llvm::createThumb2ITBlockPass() {
+ return new Thumb2ITBlockPass();
}