10b57cec5SDimitry Andric //===-- Thumb2ITBlockPass.cpp - Insert Thumb-2 IT blocks ------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "ARM.h"
100b57cec5SDimitry Andric #include "ARMMachineFunctionInfo.h"
110b57cec5SDimitry Andric #include "ARMSubtarget.h"
120b57cec5SDimitry Andric #include "MCTargetDesc/ARMBaseInfo.h"
130b57cec5SDimitry Andric #include "Thumb2InstrInfo.h"
140b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
150b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
160b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
170b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBundle.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
250b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
260b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
270b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
280b57cec5SDimitry Andric #include <cassert>
290b57cec5SDimitry Andric #include <new>
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric using namespace llvm;
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric #define DEBUG_TYPE "thumb2-it"
340b57cec5SDimitry Andric #define PASS_NAME "Thumb IT blocks insertion pass"
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric STATISTIC(NumITs, "Number of IT blocks inserted");
370b57cec5SDimitry Andric STATISTIC(NumMovedInsts, "Number of predicated instructions moved");
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric using RegisterSet = SmallSet<unsigned, 4>;
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric namespace {
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric class Thumb2ITBlock : public MachineFunctionPass {
440b57cec5SDimitry Andric public:
450b57cec5SDimitry Andric static char ID;
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric bool restrictIT;
480b57cec5SDimitry Andric const Thumb2InstrInfo *TII;
490b57cec5SDimitry Andric const TargetRegisterInfo *TRI;
500b57cec5SDimitry Andric ARMFunctionInfo *AFI;
510b57cec5SDimitry Andric
Thumb2ITBlock()520b57cec5SDimitry Andric Thumb2ITBlock() : MachineFunctionPass(ID) {}
530b57cec5SDimitry Andric
540b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override;
550b57cec5SDimitry Andric
getRequiredProperties() const560b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override {
570b57cec5SDimitry Andric return MachineFunctionProperties().set(
580b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs);
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric
getPassName() const610b57cec5SDimitry Andric StringRef getPassName() const override {
620b57cec5SDimitry Andric return PASS_NAME;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
650b57cec5SDimitry Andric private:
660b57cec5SDimitry Andric bool MoveCopyOutOfITBlock(MachineInstr *MI,
670b57cec5SDimitry Andric ARMCC::CondCodes CC, ARMCC::CondCodes OCC,
680b57cec5SDimitry Andric RegisterSet &Defs, RegisterSet &Uses);
690b57cec5SDimitry Andric bool InsertITInstructions(MachineBasicBlock &Block);
700b57cec5SDimitry Andric };
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric char Thumb2ITBlock::ID = 0;
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric } // end anonymous namespace
750b57cec5SDimitry Andric
INITIALIZE_PASS(Thumb2ITBlock,DEBUG_TYPE,PASS_NAME,false,false)760b57cec5SDimitry Andric INITIALIZE_PASS(Thumb2ITBlock, DEBUG_TYPE, PASS_NAME, false, false)
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric /// TrackDefUses - Tracking what registers are being defined and used by
790b57cec5SDimitry Andric /// instructions in the IT block. This also tracks "dependencies", i.e. uses
800b57cec5SDimitry Andric /// in the IT block that are defined before the IT instruction.
810b57cec5SDimitry Andric static void TrackDefUses(MachineInstr *MI, RegisterSet &Defs, RegisterSet &Uses,
820b57cec5SDimitry Andric const TargetRegisterInfo *TRI) {
830b57cec5SDimitry Andric using RegList = SmallVector<unsigned, 4>;
840b57cec5SDimitry Andric RegList LocalDefs;
850b57cec5SDimitry Andric RegList LocalUses;
860b57cec5SDimitry Andric
870b57cec5SDimitry Andric for (auto &MO : MI->operands()) {
880b57cec5SDimitry Andric if (!MO.isReg())
890b57cec5SDimitry Andric continue;
908bcb0991SDimitry Andric Register Reg = MO.getReg();
910b57cec5SDimitry Andric if (!Reg || Reg == ARM::ITSTATE || Reg == ARM::SP)
920b57cec5SDimitry Andric continue;
930b57cec5SDimitry Andric if (MO.isUse())
940b57cec5SDimitry Andric LocalUses.push_back(Reg);
950b57cec5SDimitry Andric else
960b57cec5SDimitry Andric LocalDefs.push_back(Reg);
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric
990b57cec5SDimitry Andric auto InsertUsesDefs = [&](RegList &Regs, RegisterSet &UsesDefs) {
1000b57cec5SDimitry Andric for (unsigned Reg : Regs)
10106c3fb27SDimitry Andric for (MCPhysReg Subreg : TRI->subregs_inclusive(Reg))
10206c3fb27SDimitry Andric UsesDefs.insert(Subreg);
1030b57cec5SDimitry Andric };
1040b57cec5SDimitry Andric
1050b57cec5SDimitry Andric InsertUsesDefs(LocalDefs, Defs);
1060b57cec5SDimitry Andric InsertUsesDefs(LocalUses, Uses);
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andric /// Clear kill flags for any uses in the given set. This will likely
1100b57cec5SDimitry Andric /// conservatively remove more kill flags than are necessary, but removing them
1110b57cec5SDimitry Andric /// is safer than incorrect kill flags remaining on instructions.
ClearKillFlags(MachineInstr * MI,RegisterSet & Uses)1120b57cec5SDimitry Andric static void ClearKillFlags(MachineInstr *MI, RegisterSet &Uses) {
1130b57cec5SDimitry Andric for (MachineOperand &MO : MI->operands()) {
1140b57cec5SDimitry Andric if (!MO.isReg() || MO.isDef() || !MO.isKill())
1150b57cec5SDimitry Andric continue;
1160b57cec5SDimitry Andric if (!Uses.count(MO.getReg()))
1170b57cec5SDimitry Andric continue;
1180b57cec5SDimitry Andric MO.setIsKill(false);
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric
isCopy(MachineInstr * MI)1220b57cec5SDimitry Andric static bool isCopy(MachineInstr *MI) {
1230b57cec5SDimitry Andric switch (MI->getOpcode()) {
1240b57cec5SDimitry Andric default:
1250b57cec5SDimitry Andric return false;
1260b57cec5SDimitry Andric case ARM::MOVr:
1270b57cec5SDimitry Andric case ARM::MOVr_TC:
1280b57cec5SDimitry Andric case ARM::tMOVr:
1290b57cec5SDimitry Andric case ARM::t2MOVr:
1300b57cec5SDimitry Andric return true;
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric bool
MoveCopyOutOfITBlock(MachineInstr * MI,ARMCC::CondCodes CC,ARMCC::CondCodes OCC,RegisterSet & Defs,RegisterSet & Uses)1350b57cec5SDimitry Andric Thumb2ITBlock::MoveCopyOutOfITBlock(MachineInstr *MI,
1360b57cec5SDimitry Andric ARMCC::CondCodes CC, ARMCC::CondCodes OCC,
1370b57cec5SDimitry Andric RegisterSet &Defs, RegisterSet &Uses) {
1380b57cec5SDimitry Andric if (!isCopy(MI))
1390b57cec5SDimitry Andric return false;
1400b57cec5SDimitry Andric // llvm models select's as two-address instructions. That means a copy
1410b57cec5SDimitry Andric // is inserted before a t2MOVccr, etc. If the copy is scheduled in
1420b57cec5SDimitry Andric // between selects we would end up creating multiple IT blocks.
1430b57cec5SDimitry Andric assert(MI->getOperand(0).getSubReg() == 0 &&
1440b57cec5SDimitry Andric MI->getOperand(1).getSubReg() == 0 &&
1450b57cec5SDimitry Andric "Sub-register indices still around?");
1460b57cec5SDimitry Andric
1478bcb0991SDimitry Andric Register DstReg = MI->getOperand(0).getReg();
1488bcb0991SDimitry Andric Register SrcReg = MI->getOperand(1).getReg();
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric // First check if it's safe to move it.
1510b57cec5SDimitry Andric if (Uses.count(DstReg) || Defs.count(SrcReg))
1520b57cec5SDimitry Andric return false;
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric // If the CPSR is defined by this copy, then we don't want to move it. E.g.,
1550b57cec5SDimitry Andric // if we have:
1560b57cec5SDimitry Andric //
1570b57cec5SDimitry Andric // movs r1, r1
1580b57cec5SDimitry Andric // rsb r1, 0
1590b57cec5SDimitry Andric // movs r2, r2
1600b57cec5SDimitry Andric // rsb r2, 0
1610b57cec5SDimitry Andric //
1620b57cec5SDimitry Andric // we don't want this to be converted to:
1630b57cec5SDimitry Andric //
1640b57cec5SDimitry Andric // movs r1, r1
1650b57cec5SDimitry Andric // movs r2, r2
1660b57cec5SDimitry Andric // itt mi
1670b57cec5SDimitry Andric // rsb r1, 0
1680b57cec5SDimitry Andric // rsb r2, 0
1690b57cec5SDimitry Andric //
1700b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc();
1710b57cec5SDimitry Andric if (MI->hasOptionalDef() &&
1720b57cec5SDimitry Andric MI->getOperand(MCID.getNumOperands() - 1).getReg() == ARM::CPSR)
1730b57cec5SDimitry Andric return false;
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric // Then peek at the next instruction to see if it's predicated on CC or OCC.
1760b57cec5SDimitry Andric // If not, then there is nothing to be gained by moving the copy.
1770b57cec5SDimitry Andric MachineBasicBlock::iterator I = MI;
1780b57cec5SDimitry Andric ++I;
1790b57cec5SDimitry Andric MachineBasicBlock::iterator E = MI->getParent()->end();
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric while (I != E && I->isDebugInstr())
1820b57cec5SDimitry Andric ++I;
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric if (I != E) {
1855ffd83dbSDimitry Andric Register NPredReg;
1860b57cec5SDimitry Andric ARMCC::CondCodes NCC = getITInstrPredicate(*I, NPredReg);
1870b57cec5SDimitry Andric if (NCC == CC || NCC == OCC)
1880b57cec5SDimitry Andric return true;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric return false;
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric
InsertITInstructions(MachineBasicBlock & MBB)1930b57cec5SDimitry Andric bool Thumb2ITBlock::InsertITInstructions(MachineBasicBlock &MBB) {
1940b57cec5SDimitry Andric bool Modified = false;
1950b57cec5SDimitry Andric RegisterSet Defs, Uses;
1960b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric while (MBBI != E) {
1990b57cec5SDimitry Andric MachineInstr *MI = &*MBBI;
2000b57cec5SDimitry Andric DebugLoc dl = MI->getDebugLoc();
2015ffd83dbSDimitry Andric Register PredReg;
2020b57cec5SDimitry Andric ARMCC::CondCodes CC = getITInstrPredicate(*MI, PredReg);
2030b57cec5SDimitry Andric if (CC == ARMCC::AL) {
2040b57cec5SDimitry Andric ++MBBI;
2050b57cec5SDimitry Andric continue;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric
2080b57cec5SDimitry Andric Defs.clear();
2090b57cec5SDimitry Andric Uses.clear();
2100b57cec5SDimitry Andric TrackDefUses(MI, Defs, Uses, TRI);
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andric // Insert an IT instruction.
2130b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII->get(ARM::t2IT))
2140b57cec5SDimitry Andric .addImm(CC);
2150b57cec5SDimitry Andric
2160b57cec5SDimitry Andric // Add implicit use of ITSTATE to IT block instructions.
2170b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/,
2180b57cec5SDimitry Andric true/*isImp*/, false/*isKill*/));
2190b57cec5SDimitry Andric
2200b57cec5SDimitry Andric MachineInstr *LastITMI = MI;
2210b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPos = MIB.getInstr();
2220b57cec5SDimitry Andric ++MBBI;
2230b57cec5SDimitry Andric
2240b57cec5SDimitry Andric // Form IT block.
2250b57cec5SDimitry Andric ARMCC::CondCodes OCC = ARMCC::getOppositeCondition(CC);
2260b57cec5SDimitry Andric unsigned Mask = 0, Pos = 3;
2270b57cec5SDimitry Andric
22881ad6265SDimitry Andric // IT blocks are limited to one conditional op if -arm-restrict-it
2290b57cec5SDimitry Andric // is set: skip the loop
2300b57cec5SDimitry Andric if (!restrictIT) {
23181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Allowing complex IT block\n";);
2320b57cec5SDimitry Andric // Branches, including tricky ones like LDM_RET, need to end an IT
2330b57cec5SDimitry Andric // block so check the instruction we just put in the block.
2340b57cec5SDimitry Andric for (; MBBI != E && Pos &&
2350b57cec5SDimitry Andric (!MI->isBranch() && !MI->isReturn()) ; ++MBBI) {
2360b57cec5SDimitry Andric if (MBBI->isDebugInstr())
2370b57cec5SDimitry Andric continue;
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric MachineInstr *NMI = &*MBBI;
2400b57cec5SDimitry Andric MI = NMI;
2410b57cec5SDimitry Andric
2425ffd83dbSDimitry Andric Register NPredReg;
2430b57cec5SDimitry Andric ARMCC::CondCodes NCC = getITInstrPredicate(*NMI, NPredReg);
2440b57cec5SDimitry Andric if (NCC == CC || NCC == OCC) {
2450b57cec5SDimitry Andric Mask |= ((NCC ^ CC) & 1) << Pos;
2460b57cec5SDimitry Andric // Add implicit use of ITSTATE.
2470b57cec5SDimitry Andric NMI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/,
2480b57cec5SDimitry Andric true/*isImp*/, false/*isKill*/));
2490b57cec5SDimitry Andric LastITMI = NMI;
2500b57cec5SDimitry Andric } else {
2510b57cec5SDimitry Andric if (NCC == ARMCC::AL &&
2520b57cec5SDimitry Andric MoveCopyOutOfITBlock(NMI, CC, OCC, Defs, Uses)) {
2530b57cec5SDimitry Andric --MBBI;
2540b57cec5SDimitry Andric MBB.remove(NMI);
2550b57cec5SDimitry Andric MBB.insert(InsertPos, NMI);
2560b57cec5SDimitry Andric ClearKillFlags(MI, Uses);
2570b57cec5SDimitry Andric ++NumMovedInsts;
2580b57cec5SDimitry Andric continue;
2590b57cec5SDimitry Andric }
2600b57cec5SDimitry Andric break;
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric TrackDefUses(NMI, Defs, Uses, TRI);
2630b57cec5SDimitry Andric --Pos;
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric
2670b57cec5SDimitry Andric // Finalize IT mask.
2680b57cec5SDimitry Andric Mask |= (1 << Pos);
2690b57cec5SDimitry Andric MIB.addImm(Mask);
2700b57cec5SDimitry Andric
2710b57cec5SDimitry Andric // Last instruction in IT block kills ITSTATE.
272*0fca6ea1SDimitry Andric LastITMI->findRegisterUseOperand(ARM::ITSTATE, /*TRI=*/nullptr)
273*0fca6ea1SDimitry Andric ->setIsKill();
2740b57cec5SDimitry Andric
2750b57cec5SDimitry Andric // Finalize the bundle.
2760b57cec5SDimitry Andric finalizeBundle(MBB, InsertPos.getInstrIterator(),
2770b57cec5SDimitry Andric ++LastITMI->getIterator());
2780b57cec5SDimitry Andric
2790b57cec5SDimitry Andric Modified = true;
2800b57cec5SDimitry Andric ++NumITs;
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric return Modified;
2840b57cec5SDimitry Andric }
2850b57cec5SDimitry Andric
runOnMachineFunction(MachineFunction & Fn)2860b57cec5SDimitry Andric bool Thumb2ITBlock::runOnMachineFunction(MachineFunction &Fn) {
28781ad6265SDimitry Andric const ARMSubtarget &STI = Fn.getSubtarget<ARMSubtarget>();
2880b57cec5SDimitry Andric if (!STI.isThumb2())
2890b57cec5SDimitry Andric return false;
2900b57cec5SDimitry Andric AFI = Fn.getInfo<ARMFunctionInfo>();
2910b57cec5SDimitry Andric TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo());
2920b57cec5SDimitry Andric TRI = STI.getRegisterInfo();
2930b57cec5SDimitry Andric restrictIT = STI.restrictIT();
2940b57cec5SDimitry Andric
2950b57cec5SDimitry Andric if (!AFI->isThumbFunction())
2960b57cec5SDimitry Andric return false;
2970b57cec5SDimitry Andric
2980b57cec5SDimitry Andric bool Modified = false;
2990b57cec5SDimitry Andric for (auto &MBB : Fn )
3000b57cec5SDimitry Andric Modified |= InsertITInstructions(MBB);
3010b57cec5SDimitry Andric
3020b57cec5SDimitry Andric if (Modified)
3030b57cec5SDimitry Andric AFI->setHasITBlocks(true);
3040b57cec5SDimitry Andric
3050b57cec5SDimitry Andric return Modified;
3060b57cec5SDimitry Andric }
3070b57cec5SDimitry Andric
3080b57cec5SDimitry Andric /// createThumb2ITBlockPass - Returns an instance of the Thumb2 IT blocks
3090b57cec5SDimitry Andric /// insertion pass.
createThumb2ITBlockPass()3100b57cec5SDimitry Andric FunctionPass *llvm::createThumb2ITBlockPass() { return new Thumb2ITBlock(); }
311