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 520b57cec5SDimitry Andric Thumb2ITBlock() : MachineFunctionPass(ID) {} 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 570b57cec5SDimitry Andric return MachineFunctionProperties().set( 580b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry 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 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) 1010b57cec5SDimitry Andric for (MCSubRegIterator Subreg(Reg, TRI, /*IncludeSelf=*/true); 1020b57cec5SDimitry Andric Subreg.isValid(); ++Subreg) 1030b57cec5SDimitry Andric UsesDefs.insert(*Subreg); 1040b57cec5SDimitry Andric }; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric InsertUsesDefs(LocalDefs, Defs); 1070b57cec5SDimitry Andric InsertUsesDefs(LocalUses, Uses); 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric /// Clear kill flags for any uses in the given set. This will likely 1110b57cec5SDimitry Andric /// conservatively remove more kill flags than are necessary, but removing them 1120b57cec5SDimitry Andric /// is safer than incorrect kill flags remaining on instructions. 1130b57cec5SDimitry Andric static void ClearKillFlags(MachineInstr *MI, RegisterSet &Uses) { 1140b57cec5SDimitry Andric for (MachineOperand &MO : MI->operands()) { 1150b57cec5SDimitry Andric if (!MO.isReg() || MO.isDef() || !MO.isKill()) 1160b57cec5SDimitry Andric continue; 1170b57cec5SDimitry Andric if (!Uses.count(MO.getReg())) 1180b57cec5SDimitry Andric continue; 1190b57cec5SDimitry Andric MO.setIsKill(false); 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric static bool isCopy(MachineInstr *MI) { 1240b57cec5SDimitry Andric switch (MI->getOpcode()) { 1250b57cec5SDimitry Andric default: 1260b57cec5SDimitry Andric return false; 1270b57cec5SDimitry Andric case ARM::MOVr: 1280b57cec5SDimitry Andric case ARM::MOVr_TC: 1290b57cec5SDimitry Andric case ARM::tMOVr: 1300b57cec5SDimitry Andric case ARM::t2MOVr: 1310b57cec5SDimitry Andric return true; 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric bool 1360b57cec5SDimitry Andric Thumb2ITBlock::MoveCopyOutOfITBlock(MachineInstr *MI, 1370b57cec5SDimitry Andric ARMCC::CondCodes CC, ARMCC::CondCodes OCC, 1380b57cec5SDimitry Andric RegisterSet &Defs, RegisterSet &Uses) { 1390b57cec5SDimitry Andric if (!isCopy(MI)) 1400b57cec5SDimitry Andric return false; 1410b57cec5SDimitry Andric // llvm models select's as two-address instructions. That means a copy 1420b57cec5SDimitry Andric // is inserted before a t2MOVccr, etc. If the copy is scheduled in 1430b57cec5SDimitry Andric // between selects we would end up creating multiple IT blocks. 1440b57cec5SDimitry Andric assert(MI->getOperand(0).getSubReg() == 0 && 1450b57cec5SDimitry Andric MI->getOperand(1).getSubReg() == 0 && 1460b57cec5SDimitry Andric "Sub-register indices still around?"); 1470b57cec5SDimitry Andric 1488bcb0991SDimitry Andric Register DstReg = MI->getOperand(0).getReg(); 1498bcb0991SDimitry Andric Register SrcReg = MI->getOperand(1).getReg(); 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric // First check if it's safe to move it. 1520b57cec5SDimitry Andric if (Uses.count(DstReg) || Defs.count(SrcReg)) 1530b57cec5SDimitry Andric return false; 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric // If the CPSR is defined by this copy, then we don't want to move it. E.g., 1560b57cec5SDimitry Andric // if we have: 1570b57cec5SDimitry Andric // 1580b57cec5SDimitry Andric // movs r1, r1 1590b57cec5SDimitry Andric // rsb r1, 0 1600b57cec5SDimitry Andric // movs r2, r2 1610b57cec5SDimitry Andric // rsb r2, 0 1620b57cec5SDimitry Andric // 1630b57cec5SDimitry Andric // we don't want this to be converted to: 1640b57cec5SDimitry Andric // 1650b57cec5SDimitry Andric // movs r1, r1 1660b57cec5SDimitry Andric // movs r2, r2 1670b57cec5SDimitry Andric // itt mi 1680b57cec5SDimitry Andric // rsb r1, 0 1690b57cec5SDimitry Andric // rsb r2, 0 1700b57cec5SDimitry Andric // 1710b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 1720b57cec5SDimitry Andric if (MI->hasOptionalDef() && 1730b57cec5SDimitry Andric MI->getOperand(MCID.getNumOperands() - 1).getReg() == ARM::CPSR) 1740b57cec5SDimitry Andric return false; 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric // Then peek at the next instruction to see if it's predicated on CC or OCC. 1770b57cec5SDimitry Andric // If not, then there is nothing to be gained by moving the copy. 1780b57cec5SDimitry Andric MachineBasicBlock::iterator I = MI; 1790b57cec5SDimitry Andric ++I; 1800b57cec5SDimitry Andric MachineBasicBlock::iterator E = MI->getParent()->end(); 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric while (I != E && I->isDebugInstr()) 1830b57cec5SDimitry Andric ++I; 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric if (I != E) { 1865ffd83dbSDimitry Andric Register NPredReg; 1870b57cec5SDimitry Andric ARMCC::CondCodes NCC = getITInstrPredicate(*I, NPredReg); 1880b57cec5SDimitry Andric if (NCC == CC || NCC == OCC) 1890b57cec5SDimitry Andric return true; 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric return false; 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric bool Thumb2ITBlock::InsertITInstructions(MachineBasicBlock &MBB) { 1950b57cec5SDimitry Andric bool Modified = false; 1960b57cec5SDimitry Andric RegisterSet Defs, Uses; 1970b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric while (MBBI != E) { 2000b57cec5SDimitry Andric MachineInstr *MI = &*MBBI; 2010b57cec5SDimitry Andric DebugLoc dl = MI->getDebugLoc(); 2025ffd83dbSDimitry Andric Register PredReg; 2030b57cec5SDimitry Andric ARMCC::CondCodes CC = getITInstrPredicate(*MI, PredReg); 2040b57cec5SDimitry Andric if (CC == ARMCC::AL) { 2050b57cec5SDimitry Andric ++MBBI; 2060b57cec5SDimitry Andric continue; 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric Defs.clear(); 2100b57cec5SDimitry Andric Uses.clear(); 2110b57cec5SDimitry Andric TrackDefUses(MI, Defs, Uses, TRI); 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric // Insert an IT instruction. 2140b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII->get(ARM::t2IT)) 2150b57cec5SDimitry Andric .addImm(CC); 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric // Add implicit use of ITSTATE to IT block instructions. 2180b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/, 2190b57cec5SDimitry Andric true/*isImp*/, false/*isKill*/)); 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric MachineInstr *LastITMI = MI; 2220b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPos = MIB.getInstr(); 2230b57cec5SDimitry Andric ++MBBI; 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric // Form IT block. 2260b57cec5SDimitry Andric ARMCC::CondCodes OCC = ARMCC::getOppositeCondition(CC); 2270b57cec5SDimitry Andric unsigned Mask = 0, Pos = 3; 2280b57cec5SDimitry Andric 229*81ad6265SDimitry Andric // IT blocks are limited to one conditional op if -arm-restrict-it 2300b57cec5SDimitry Andric // is set: skip the loop 2310b57cec5SDimitry Andric if (!restrictIT) { 232*81ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Allowing complex IT block\n";); 2330b57cec5SDimitry Andric // Branches, including tricky ones like LDM_RET, need to end an IT 2340b57cec5SDimitry Andric // block so check the instruction we just put in the block. 2350b57cec5SDimitry Andric for (; MBBI != E && Pos && 2360b57cec5SDimitry Andric (!MI->isBranch() && !MI->isReturn()) ; ++MBBI) { 2370b57cec5SDimitry Andric if (MBBI->isDebugInstr()) 2380b57cec5SDimitry Andric continue; 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric MachineInstr *NMI = &*MBBI; 2410b57cec5SDimitry Andric MI = NMI; 2420b57cec5SDimitry Andric 2435ffd83dbSDimitry Andric Register NPredReg; 2440b57cec5SDimitry Andric ARMCC::CondCodes NCC = getITInstrPredicate(*NMI, NPredReg); 2450b57cec5SDimitry Andric if (NCC == CC || NCC == OCC) { 2460b57cec5SDimitry Andric Mask |= ((NCC ^ CC) & 1) << Pos; 2470b57cec5SDimitry Andric // Add implicit use of ITSTATE. 2480b57cec5SDimitry Andric NMI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/, 2490b57cec5SDimitry Andric true/*isImp*/, false/*isKill*/)); 2500b57cec5SDimitry Andric LastITMI = NMI; 2510b57cec5SDimitry Andric } else { 2520b57cec5SDimitry Andric if (NCC == ARMCC::AL && 2530b57cec5SDimitry Andric MoveCopyOutOfITBlock(NMI, CC, OCC, Defs, Uses)) { 2540b57cec5SDimitry Andric --MBBI; 2550b57cec5SDimitry Andric MBB.remove(NMI); 2560b57cec5SDimitry Andric MBB.insert(InsertPos, NMI); 2570b57cec5SDimitry Andric ClearKillFlags(MI, Uses); 2580b57cec5SDimitry Andric ++NumMovedInsts; 2590b57cec5SDimitry Andric continue; 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric break; 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric TrackDefUses(NMI, Defs, Uses, TRI); 2640b57cec5SDimitry Andric --Pos; 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric 2680b57cec5SDimitry Andric // Finalize IT mask. 2690b57cec5SDimitry Andric Mask |= (1 << Pos); 2700b57cec5SDimitry Andric MIB.addImm(Mask); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric // Last instruction in IT block kills ITSTATE. 2730b57cec5SDimitry Andric LastITMI->findRegisterUseOperand(ARM::ITSTATE)->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 2860b57cec5SDimitry Andric bool Thumb2ITBlock::runOnMachineFunction(MachineFunction &Fn) { 287*81ad6265SDimitry 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. 3100b57cec5SDimitry Andric FunctionPass *llvm::createThumb2ITBlockPass() { return new Thumb2ITBlock(); } 311