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