xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/ARM/Thumb2ITBlockPass.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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