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) 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. 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 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 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 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 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. 3100b57cec5SDimitry Andric FunctionPass *llvm::createThumb2ITBlockPass() { return new Thumb2ITBlock(); } 311