1*0b57cec5SDimitry Andric //===-- Thumb2ITBlockPass.cpp - Insert Thumb-2 IT blocks ------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "ARM.h" 10*0b57cec5SDimitry Andric #include "ARMMachineFunctionInfo.h" 11*0b57cec5SDimitry Andric #include "ARMSubtarget.h" 12*0b57cec5SDimitry Andric #include "MCTargetDesc/ARMBaseInfo.h" 13*0b57cec5SDimitry Andric #include "Thumb2InstrInfo.h" 14*0b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h" 15*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 16*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 17*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 18*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 19*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 20*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 23*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBundle.h" 24*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 25*0b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h" 26*0b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 27*0b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 28*0b57cec5SDimitry Andric #include <cassert> 29*0b57cec5SDimitry Andric #include <new> 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric using namespace llvm; 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric #define DEBUG_TYPE "thumb2-it" 34*0b57cec5SDimitry Andric #define PASS_NAME "Thumb IT blocks insertion pass" 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric STATISTIC(NumITs, "Number of IT blocks inserted"); 37*0b57cec5SDimitry Andric STATISTIC(NumMovedInsts, "Number of predicated instructions moved"); 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric using RegisterSet = SmallSet<unsigned, 4>; 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric namespace { 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric class Thumb2ITBlock : public MachineFunctionPass { 44*0b57cec5SDimitry Andric public: 45*0b57cec5SDimitry Andric static char ID; 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric bool restrictIT; 48*0b57cec5SDimitry Andric const Thumb2InstrInfo *TII; 49*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI; 50*0b57cec5SDimitry Andric ARMFunctionInfo *AFI; 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric Thumb2ITBlock() : MachineFunctionPass(ID) {} 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 57*0b57cec5SDimitry Andric return MachineFunctionProperties().set( 58*0b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 59*0b57cec5SDimitry Andric } 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric StringRef getPassName() const override { 62*0b57cec5SDimitry Andric return PASS_NAME; 63*0b57cec5SDimitry Andric } 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric private: 66*0b57cec5SDimitry Andric bool MoveCopyOutOfITBlock(MachineInstr *MI, 67*0b57cec5SDimitry Andric ARMCC::CondCodes CC, ARMCC::CondCodes OCC, 68*0b57cec5SDimitry Andric RegisterSet &Defs, RegisterSet &Uses); 69*0b57cec5SDimitry Andric bool InsertITInstructions(MachineBasicBlock &Block); 70*0b57cec5SDimitry Andric }; 71*0b57cec5SDimitry Andric 72*0b57cec5SDimitry Andric char Thumb2ITBlock::ID = 0; 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric } // end anonymous namespace 75*0b57cec5SDimitry Andric 76*0b57cec5SDimitry Andric INITIALIZE_PASS(Thumb2ITBlock, DEBUG_TYPE, PASS_NAME, false, false) 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric /// TrackDefUses - Tracking what registers are being defined and used by 79*0b57cec5SDimitry Andric /// instructions in the IT block. This also tracks "dependencies", i.e. uses 80*0b57cec5SDimitry Andric /// in the IT block that are defined before the IT instruction. 81*0b57cec5SDimitry Andric static void TrackDefUses(MachineInstr *MI, RegisterSet &Defs, RegisterSet &Uses, 82*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 83*0b57cec5SDimitry Andric using RegList = SmallVector<unsigned, 4>; 84*0b57cec5SDimitry Andric RegList LocalDefs; 85*0b57cec5SDimitry Andric RegList LocalUses; 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric for (auto &MO : MI->operands()) { 88*0b57cec5SDimitry Andric if (!MO.isReg()) 89*0b57cec5SDimitry Andric continue; 90*0b57cec5SDimitry Andric unsigned Reg = MO.getReg(); 91*0b57cec5SDimitry Andric if (!Reg || Reg == ARM::ITSTATE || Reg == ARM::SP) 92*0b57cec5SDimitry Andric continue; 93*0b57cec5SDimitry Andric if (MO.isUse()) 94*0b57cec5SDimitry Andric LocalUses.push_back(Reg); 95*0b57cec5SDimitry Andric else 96*0b57cec5SDimitry Andric LocalDefs.push_back(Reg); 97*0b57cec5SDimitry Andric } 98*0b57cec5SDimitry Andric 99*0b57cec5SDimitry Andric auto InsertUsesDefs = [&](RegList &Regs, RegisterSet &UsesDefs) { 100*0b57cec5SDimitry Andric for (unsigned Reg : Regs) 101*0b57cec5SDimitry Andric for (MCSubRegIterator Subreg(Reg, TRI, /*IncludeSelf=*/true); 102*0b57cec5SDimitry Andric Subreg.isValid(); ++Subreg) 103*0b57cec5SDimitry Andric UsesDefs.insert(*Subreg); 104*0b57cec5SDimitry Andric }; 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric InsertUsesDefs(LocalDefs, Defs); 107*0b57cec5SDimitry Andric InsertUsesDefs(LocalUses, Uses); 108*0b57cec5SDimitry Andric } 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric /// Clear kill flags for any uses in the given set. This will likely 111*0b57cec5SDimitry Andric /// conservatively remove more kill flags than are necessary, but removing them 112*0b57cec5SDimitry Andric /// is safer than incorrect kill flags remaining on instructions. 113*0b57cec5SDimitry Andric static void ClearKillFlags(MachineInstr *MI, RegisterSet &Uses) { 114*0b57cec5SDimitry Andric for (MachineOperand &MO : MI->operands()) { 115*0b57cec5SDimitry Andric if (!MO.isReg() || MO.isDef() || !MO.isKill()) 116*0b57cec5SDimitry Andric continue; 117*0b57cec5SDimitry Andric if (!Uses.count(MO.getReg())) 118*0b57cec5SDimitry Andric continue; 119*0b57cec5SDimitry Andric MO.setIsKill(false); 120*0b57cec5SDimitry Andric } 121*0b57cec5SDimitry Andric } 122*0b57cec5SDimitry Andric 123*0b57cec5SDimitry Andric static bool isCopy(MachineInstr *MI) { 124*0b57cec5SDimitry Andric switch (MI->getOpcode()) { 125*0b57cec5SDimitry Andric default: 126*0b57cec5SDimitry Andric return false; 127*0b57cec5SDimitry Andric case ARM::MOVr: 128*0b57cec5SDimitry Andric case ARM::MOVr_TC: 129*0b57cec5SDimitry Andric case ARM::tMOVr: 130*0b57cec5SDimitry Andric case ARM::t2MOVr: 131*0b57cec5SDimitry Andric return true; 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric } 134*0b57cec5SDimitry Andric 135*0b57cec5SDimitry Andric bool 136*0b57cec5SDimitry Andric Thumb2ITBlock::MoveCopyOutOfITBlock(MachineInstr *MI, 137*0b57cec5SDimitry Andric ARMCC::CondCodes CC, ARMCC::CondCodes OCC, 138*0b57cec5SDimitry Andric RegisterSet &Defs, RegisterSet &Uses) { 139*0b57cec5SDimitry Andric if (!isCopy(MI)) 140*0b57cec5SDimitry Andric return false; 141*0b57cec5SDimitry Andric // llvm models select's as two-address instructions. That means a copy 142*0b57cec5SDimitry Andric // is inserted before a t2MOVccr, etc. If the copy is scheduled in 143*0b57cec5SDimitry Andric // between selects we would end up creating multiple IT blocks. 144*0b57cec5SDimitry Andric assert(MI->getOperand(0).getSubReg() == 0 && 145*0b57cec5SDimitry Andric MI->getOperand(1).getSubReg() == 0 && 146*0b57cec5SDimitry Andric "Sub-register indices still around?"); 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric unsigned DstReg = MI->getOperand(0).getReg(); 149*0b57cec5SDimitry Andric unsigned SrcReg = MI->getOperand(1).getReg(); 150*0b57cec5SDimitry Andric 151*0b57cec5SDimitry Andric // First check if it's safe to move it. 152*0b57cec5SDimitry Andric if (Uses.count(DstReg) || Defs.count(SrcReg)) 153*0b57cec5SDimitry Andric return false; 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric // If the CPSR is defined by this copy, then we don't want to move it. E.g., 156*0b57cec5SDimitry Andric // if we have: 157*0b57cec5SDimitry Andric // 158*0b57cec5SDimitry Andric // movs r1, r1 159*0b57cec5SDimitry Andric // rsb r1, 0 160*0b57cec5SDimitry Andric // movs r2, r2 161*0b57cec5SDimitry Andric // rsb r2, 0 162*0b57cec5SDimitry Andric // 163*0b57cec5SDimitry Andric // we don't want this to be converted to: 164*0b57cec5SDimitry Andric // 165*0b57cec5SDimitry Andric // movs r1, r1 166*0b57cec5SDimitry Andric // movs r2, r2 167*0b57cec5SDimitry Andric // itt mi 168*0b57cec5SDimitry Andric // rsb r1, 0 169*0b57cec5SDimitry Andric // rsb r2, 0 170*0b57cec5SDimitry Andric // 171*0b57cec5SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 172*0b57cec5SDimitry Andric if (MI->hasOptionalDef() && 173*0b57cec5SDimitry Andric MI->getOperand(MCID.getNumOperands() - 1).getReg() == ARM::CPSR) 174*0b57cec5SDimitry Andric return false; 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric // Then peek at the next instruction to see if it's predicated on CC or OCC. 177*0b57cec5SDimitry Andric // If not, then there is nothing to be gained by moving the copy. 178*0b57cec5SDimitry Andric MachineBasicBlock::iterator I = MI; 179*0b57cec5SDimitry Andric ++I; 180*0b57cec5SDimitry Andric MachineBasicBlock::iterator E = MI->getParent()->end(); 181*0b57cec5SDimitry Andric 182*0b57cec5SDimitry Andric while (I != E && I->isDebugInstr()) 183*0b57cec5SDimitry Andric ++I; 184*0b57cec5SDimitry Andric 185*0b57cec5SDimitry Andric if (I != E) { 186*0b57cec5SDimitry Andric unsigned NPredReg = 0; 187*0b57cec5SDimitry Andric ARMCC::CondCodes NCC = getITInstrPredicate(*I, NPredReg); 188*0b57cec5SDimitry Andric if (NCC == CC || NCC == OCC) 189*0b57cec5SDimitry Andric return true; 190*0b57cec5SDimitry Andric } 191*0b57cec5SDimitry Andric return false; 192*0b57cec5SDimitry Andric } 193*0b57cec5SDimitry Andric 194*0b57cec5SDimitry Andric bool Thumb2ITBlock::InsertITInstructions(MachineBasicBlock &MBB) { 195*0b57cec5SDimitry Andric bool Modified = false; 196*0b57cec5SDimitry Andric RegisterSet Defs, Uses; 197*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 198*0b57cec5SDimitry Andric 199*0b57cec5SDimitry Andric while (MBBI != E) { 200*0b57cec5SDimitry Andric MachineInstr *MI = &*MBBI; 201*0b57cec5SDimitry Andric DebugLoc dl = MI->getDebugLoc(); 202*0b57cec5SDimitry Andric unsigned PredReg = 0; 203*0b57cec5SDimitry Andric ARMCC::CondCodes CC = getITInstrPredicate(*MI, PredReg); 204*0b57cec5SDimitry Andric if (CC == ARMCC::AL) { 205*0b57cec5SDimitry Andric ++MBBI; 206*0b57cec5SDimitry Andric continue; 207*0b57cec5SDimitry Andric } 208*0b57cec5SDimitry Andric 209*0b57cec5SDimitry Andric Defs.clear(); 210*0b57cec5SDimitry Andric Uses.clear(); 211*0b57cec5SDimitry Andric TrackDefUses(MI, Defs, Uses, TRI); 212*0b57cec5SDimitry Andric 213*0b57cec5SDimitry Andric // Insert an IT instruction. 214*0b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII->get(ARM::t2IT)) 215*0b57cec5SDimitry Andric .addImm(CC); 216*0b57cec5SDimitry Andric 217*0b57cec5SDimitry Andric // Add implicit use of ITSTATE to IT block instructions. 218*0b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/, 219*0b57cec5SDimitry Andric true/*isImp*/, false/*isKill*/)); 220*0b57cec5SDimitry Andric 221*0b57cec5SDimitry Andric MachineInstr *LastITMI = MI; 222*0b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPos = MIB.getInstr(); 223*0b57cec5SDimitry Andric ++MBBI; 224*0b57cec5SDimitry Andric 225*0b57cec5SDimitry Andric // Form IT block. 226*0b57cec5SDimitry Andric ARMCC::CondCodes OCC = ARMCC::getOppositeCondition(CC); 227*0b57cec5SDimitry Andric unsigned Mask = 0, Pos = 3; 228*0b57cec5SDimitry Andric 229*0b57cec5SDimitry Andric // v8 IT blocks are limited to one conditional op unless -arm-no-restrict-it 230*0b57cec5SDimitry Andric // is set: skip the loop 231*0b57cec5SDimitry Andric if (!restrictIT) { 232*0b57cec5SDimitry Andric // Branches, including tricky ones like LDM_RET, need to end an IT 233*0b57cec5SDimitry Andric // block so check the instruction we just put in the block. 234*0b57cec5SDimitry Andric for (; MBBI != E && Pos && 235*0b57cec5SDimitry Andric (!MI->isBranch() && !MI->isReturn()) ; ++MBBI) { 236*0b57cec5SDimitry Andric if (MBBI->isDebugInstr()) 237*0b57cec5SDimitry Andric continue; 238*0b57cec5SDimitry Andric 239*0b57cec5SDimitry Andric MachineInstr *NMI = &*MBBI; 240*0b57cec5SDimitry Andric MI = NMI; 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric unsigned NPredReg = 0; 243*0b57cec5SDimitry Andric ARMCC::CondCodes NCC = getITInstrPredicate(*NMI, NPredReg); 244*0b57cec5SDimitry Andric if (NCC == CC || NCC == OCC) { 245*0b57cec5SDimitry Andric Mask |= ((NCC ^ CC) & 1) << Pos; 246*0b57cec5SDimitry Andric // Add implicit use of ITSTATE. 247*0b57cec5SDimitry Andric NMI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/, 248*0b57cec5SDimitry Andric true/*isImp*/, false/*isKill*/)); 249*0b57cec5SDimitry Andric LastITMI = NMI; 250*0b57cec5SDimitry Andric } else { 251*0b57cec5SDimitry Andric if (NCC == ARMCC::AL && 252*0b57cec5SDimitry Andric MoveCopyOutOfITBlock(NMI, CC, OCC, Defs, Uses)) { 253*0b57cec5SDimitry Andric --MBBI; 254*0b57cec5SDimitry Andric MBB.remove(NMI); 255*0b57cec5SDimitry Andric MBB.insert(InsertPos, NMI); 256*0b57cec5SDimitry Andric ClearKillFlags(MI, Uses); 257*0b57cec5SDimitry Andric ++NumMovedInsts; 258*0b57cec5SDimitry Andric continue; 259*0b57cec5SDimitry Andric } 260*0b57cec5SDimitry Andric break; 261*0b57cec5SDimitry Andric } 262*0b57cec5SDimitry Andric TrackDefUses(NMI, Defs, Uses, TRI); 263*0b57cec5SDimitry Andric --Pos; 264*0b57cec5SDimitry Andric } 265*0b57cec5SDimitry Andric } 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric // Finalize IT mask. 268*0b57cec5SDimitry Andric Mask |= (1 << Pos); 269*0b57cec5SDimitry Andric MIB.addImm(Mask); 270*0b57cec5SDimitry Andric 271*0b57cec5SDimitry Andric // Last instruction in IT block kills ITSTATE. 272*0b57cec5SDimitry Andric LastITMI->findRegisterUseOperand(ARM::ITSTATE)->setIsKill(); 273*0b57cec5SDimitry Andric 274*0b57cec5SDimitry Andric // Finalize the bundle. 275*0b57cec5SDimitry Andric finalizeBundle(MBB, InsertPos.getInstrIterator(), 276*0b57cec5SDimitry Andric ++LastITMI->getIterator()); 277*0b57cec5SDimitry Andric 278*0b57cec5SDimitry Andric Modified = true; 279*0b57cec5SDimitry Andric ++NumITs; 280*0b57cec5SDimitry Andric } 281*0b57cec5SDimitry Andric 282*0b57cec5SDimitry Andric return Modified; 283*0b57cec5SDimitry Andric } 284*0b57cec5SDimitry Andric 285*0b57cec5SDimitry Andric bool Thumb2ITBlock::runOnMachineFunction(MachineFunction &Fn) { 286*0b57cec5SDimitry Andric const ARMSubtarget &STI = 287*0b57cec5SDimitry Andric static_cast<const ARMSubtarget &>(Fn.getSubtarget()); 288*0b57cec5SDimitry Andric if (!STI.isThumb2()) 289*0b57cec5SDimitry Andric return false; 290*0b57cec5SDimitry Andric AFI = Fn.getInfo<ARMFunctionInfo>(); 291*0b57cec5SDimitry Andric TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo()); 292*0b57cec5SDimitry Andric TRI = STI.getRegisterInfo(); 293*0b57cec5SDimitry Andric restrictIT = STI.restrictIT(); 294*0b57cec5SDimitry Andric 295*0b57cec5SDimitry Andric if (!AFI->isThumbFunction()) 296*0b57cec5SDimitry Andric return false; 297*0b57cec5SDimitry Andric 298*0b57cec5SDimitry Andric bool Modified = false; 299*0b57cec5SDimitry Andric for (auto &MBB : Fn ) 300*0b57cec5SDimitry Andric Modified |= InsertITInstructions(MBB); 301*0b57cec5SDimitry Andric 302*0b57cec5SDimitry Andric if (Modified) 303*0b57cec5SDimitry Andric AFI->setHasITBlocks(true); 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric return Modified; 306*0b57cec5SDimitry Andric } 307*0b57cec5SDimitry Andric 308*0b57cec5SDimitry Andric /// createThumb2ITBlockPass - Returns an instance of the Thumb2 IT blocks 309*0b57cec5SDimitry Andric /// insertion pass. 310*0b57cec5SDimitry Andric FunctionPass *llvm::createThumb2ITBlockPass() { return new Thumb2ITBlock(); } 311*0b57cec5SDimitry Andric 312*0b57cec5SDimitry Andric #undef DEBUG_TYPE 313*0b57cec5SDimitry Andric #define DEBUG_TYPE "arm-mve-vpt" 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric namespace { 316*0b57cec5SDimitry Andric class MVEVPTBlock : public MachineFunctionPass { 317*0b57cec5SDimitry Andric public: 318*0b57cec5SDimitry Andric static char ID; 319*0b57cec5SDimitry Andric const Thumb2InstrInfo *TII; 320*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI; 321*0b57cec5SDimitry Andric 322*0b57cec5SDimitry Andric MVEVPTBlock() : MachineFunctionPass(ID) {} 323*0b57cec5SDimitry Andric 324*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 325*0b57cec5SDimitry Andric 326*0b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 327*0b57cec5SDimitry Andric return MachineFunctionProperties().set( 328*0b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 329*0b57cec5SDimitry Andric } 330*0b57cec5SDimitry Andric 331*0b57cec5SDimitry Andric StringRef getPassName() const override { 332*0b57cec5SDimitry Andric return "MVE VPT block insertion pass"; 333*0b57cec5SDimitry Andric } 334*0b57cec5SDimitry Andric 335*0b57cec5SDimitry Andric private: 336*0b57cec5SDimitry Andric bool InsertVPTBlocks(MachineBasicBlock &MBB); 337*0b57cec5SDimitry Andric }; 338*0b57cec5SDimitry Andric 339*0b57cec5SDimitry Andric char MVEVPTBlock::ID = 0; 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric } // end anonymous namespace 342*0b57cec5SDimitry Andric 343*0b57cec5SDimitry Andric INITIALIZE_PASS(MVEVPTBlock, DEBUG_TYPE, "ARM MVE VPT block pass", false, false) 344*0b57cec5SDimitry Andric 345*0b57cec5SDimitry Andric enum VPTMaskValue { 346*0b57cec5SDimitry Andric T = 8, // 0b1000 347*0b57cec5SDimitry Andric TT = 4, // 0b0100 348*0b57cec5SDimitry Andric TE = 12, // 0b1100 349*0b57cec5SDimitry Andric TTT = 2, // 0b0010 350*0b57cec5SDimitry Andric TTE = 6, // 0b0110 351*0b57cec5SDimitry Andric TEE = 10, // 0b1010 352*0b57cec5SDimitry Andric TET = 14, // 0b1110 353*0b57cec5SDimitry Andric TTTT = 1, // 0b0001 354*0b57cec5SDimitry Andric TTTE = 3, // 0b0011 355*0b57cec5SDimitry Andric TTEE = 5, // 0b0101 356*0b57cec5SDimitry Andric TTET = 7, // 0b0111 357*0b57cec5SDimitry Andric TEEE = 9, // 0b1001 358*0b57cec5SDimitry Andric TEET = 11, // 0b1011 359*0b57cec5SDimitry Andric TETT = 13, // 0b1101 360*0b57cec5SDimitry Andric TETE = 15 // 0b1111 361*0b57cec5SDimitry Andric }; 362*0b57cec5SDimitry Andric 363*0b57cec5SDimitry Andric bool MVEVPTBlock::InsertVPTBlocks(MachineBasicBlock &Block) { 364*0b57cec5SDimitry Andric bool Modified = false; 365*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBIter = Block.begin(); 366*0b57cec5SDimitry Andric MachineBasicBlock::iterator EndIter = Block.end(); 367*0b57cec5SDimitry Andric 368*0b57cec5SDimitry Andric while (MBIter != EndIter) { 369*0b57cec5SDimitry Andric MachineInstr *MI = &*MBIter; 370*0b57cec5SDimitry Andric unsigned PredReg = 0; 371*0b57cec5SDimitry Andric DebugLoc dl = MI->getDebugLoc(); 372*0b57cec5SDimitry Andric 373*0b57cec5SDimitry Andric ARMVCC::VPTCodes Pred = getVPTInstrPredicate(*MI, PredReg); 374*0b57cec5SDimitry Andric 375*0b57cec5SDimitry Andric // The idea of the predicate is that None, Then and Else are for use when 376*0b57cec5SDimitry Andric // handling assembly language: they correspond to the three possible 377*0b57cec5SDimitry Andric // suffixes "", "t" and "e" on the mnemonic. So when instructions are read 378*0b57cec5SDimitry Andric // from assembly source or disassembled from object code, you expect to see 379*0b57cec5SDimitry Andric // a mixture whenever there's a long VPT block. But in code generation, we 380*0b57cec5SDimitry Andric // hope we'll never generate an Else as input to this pass. 381*0b57cec5SDimitry Andric 382*0b57cec5SDimitry Andric assert(Pred != ARMVCC::Else && "VPT block pass does not expect Else preds"); 383*0b57cec5SDimitry Andric 384*0b57cec5SDimitry Andric if (Pred == ARMVCC::None) { 385*0b57cec5SDimitry Andric ++MBIter; 386*0b57cec5SDimitry Andric continue; 387*0b57cec5SDimitry Andric } 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric MachineInstrBuilder MIBuilder = 390*0b57cec5SDimitry Andric BuildMI(Block, MBIter, dl, TII->get(ARM::MVE_VPST)); 391*0b57cec5SDimitry Andric // The mask value for the VPST instruction is T = 0b1000 = 8 392*0b57cec5SDimitry Andric MIBuilder.addImm(VPTMaskValue::T); 393*0b57cec5SDimitry Andric 394*0b57cec5SDimitry Andric MachineBasicBlock::iterator VPSTInsertPos = MIBuilder.getInstr(); 395*0b57cec5SDimitry Andric int VPTInstCnt = 1; 396*0b57cec5SDimitry Andric ARMVCC::VPTCodes NextPred; 397*0b57cec5SDimitry Andric 398*0b57cec5SDimitry Andric do { 399*0b57cec5SDimitry Andric ++MBIter; 400*0b57cec5SDimitry Andric NextPred = getVPTInstrPredicate(*MBIter, PredReg); 401*0b57cec5SDimitry Andric } while (NextPred != ARMVCC::None && NextPred == Pred && ++VPTInstCnt < 4); 402*0b57cec5SDimitry Andric 403*0b57cec5SDimitry Andric MachineInstr *LastMI = &*MBIter; 404*0b57cec5SDimitry Andric finalizeBundle(Block, VPSTInsertPos.getInstrIterator(), 405*0b57cec5SDimitry Andric ++LastMI->getIterator()); 406*0b57cec5SDimitry Andric 407*0b57cec5SDimitry Andric Modified = true; 408*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "VPT block created for: "; MI->dump();); 409*0b57cec5SDimitry Andric 410*0b57cec5SDimitry Andric ++MBIter; 411*0b57cec5SDimitry Andric } 412*0b57cec5SDimitry Andric return Modified; 413*0b57cec5SDimitry Andric } 414*0b57cec5SDimitry Andric 415*0b57cec5SDimitry Andric bool MVEVPTBlock::runOnMachineFunction(MachineFunction &Fn) { 416*0b57cec5SDimitry Andric const ARMSubtarget &STI = 417*0b57cec5SDimitry Andric static_cast<const ARMSubtarget &>(Fn.getSubtarget()); 418*0b57cec5SDimitry Andric 419*0b57cec5SDimitry Andric if (!STI.isThumb2() || !STI.hasMVEIntegerOps()) 420*0b57cec5SDimitry Andric return false; 421*0b57cec5SDimitry Andric 422*0b57cec5SDimitry Andric TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo()); 423*0b57cec5SDimitry Andric TRI = STI.getRegisterInfo(); 424*0b57cec5SDimitry Andric 425*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** ARM MVE VPT BLOCKS **********\n" 426*0b57cec5SDimitry Andric << "********** Function: " << Fn.getName() << '\n'); 427*0b57cec5SDimitry Andric 428*0b57cec5SDimitry Andric bool Modified = false; 429*0b57cec5SDimitry Andric for (MachineBasicBlock &MBB : Fn) 430*0b57cec5SDimitry Andric Modified |= InsertVPTBlocks(MBB); 431*0b57cec5SDimitry Andric 432*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "**************************************\n"); 433*0b57cec5SDimitry Andric return Modified; 434*0b57cec5SDimitry Andric } 435*0b57cec5SDimitry Andric 436*0b57cec5SDimitry Andric /// createMVEVPTBlock - Returns an instance of the MVE VPT block 437*0b57cec5SDimitry Andric /// insertion pass. 438*0b57cec5SDimitry Andric FunctionPass *llvm::createMVEVPTBlockPass() { return new MVEVPTBlock(); } 439