1 //===-- MVEVPTBlockPass.cpp - Insert MVE VPT blocks -----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "ARM.h"
10 #include "ARMMachineFunctionInfo.h"
11 #include "ARMSubtarget.h"
12 #include "MCTargetDesc/ARMBaseInfo.h"
13 #include "Thumb2InstrInfo.h"
14 #include "llvm/ADT/SmallSet.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/CodeGen/MachineBasicBlock.h"
19 #include "llvm/CodeGen/MachineFunction.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/CodeGen/MachineInstrBuilder.h"
23 #include "llvm/CodeGen/MachineInstrBundle.h"
24 #include "llvm/CodeGen/MachineOperand.h"
25 #include "llvm/CodeGen/ReachingDefAnalysis.h"
26 #include "llvm/IR/DebugLoc.h"
27 #include "llvm/MC/MCInstrDesc.h"
28 #include "llvm/Support/Debug.h"
29 #include <cassert>
30 #include <new>
31 
32 using namespace llvm;
33 
34 #define DEBUG_TYPE "arm-mve-vpt"
35 
36 namespace {
37   class MVEVPTBlock : public MachineFunctionPass {
38   public:
39     static char ID;
40 
41     MVEVPTBlock() : MachineFunctionPass(ID) {}
42 
43     bool runOnMachineFunction(MachineFunction &Fn) override;
44 
45     void getAnalysisUsage(AnalysisUsage &AU) const override {
46       AU.setPreservesCFG();
47       AU.addRequired<ReachingDefAnalysis>();
48       MachineFunctionPass::getAnalysisUsage(AU);
49     }
50 
51     MachineFunctionProperties getRequiredProperties() const override {
52       return MachineFunctionProperties().set(
53           MachineFunctionProperties::Property::NoVRegs).set(
54           MachineFunctionProperties::Property::TracksLiveness);
55     }
56 
57     StringRef getPassName() const override {
58       return "MVE VPT block insertion pass";
59     }
60 
61   private:
62     bool InsertVPTBlocks(MachineBasicBlock &MBB);
63 
64     const Thumb2InstrInfo *TII = nullptr;
65     ReachingDefAnalysis *RDA = nullptr;
66   };
67 
68   char MVEVPTBlock::ID = 0;
69 
70 } // end anonymous namespace
71 
72 INITIALIZE_PASS(MVEVPTBlock, DEBUG_TYPE, "ARM MVE VPT block pass", false, false)
73 
74 enum VPTMaskValue {
75   T     =  8, // 0b1000
76   TT    =  4, // 0b0100
77   TE    = 12, // 0b1100
78   TTT   =  2, // 0b0010
79   TTE   =  6, // 0b0110
80   TEE   = 10, // 0b1010
81   TET   = 14, // 0b1110
82   TTTT  =  1, // 0b0001
83   TTTE  =  3, // 0b0011
84   TTEE  =  5, // 0b0101
85   TTET  =  7, // 0b0111
86   TEEE  =  9, // 0b1001
87   TEET  = 11, // 0b1011
88   TETT  = 13, // 0b1101
89   TETE  = 15  // 0b1111
90 };
91 
92 static unsigned VCMPOpcodeToVPT(unsigned Opcode) {
93   switch (Opcode) {
94   case ARM::MVE_VCMPf32:
95     return ARM::MVE_VPTv4f32;
96   case ARM::MVE_VCMPf16:
97     return ARM::MVE_VPTv8f16;
98   case ARM::MVE_VCMPi8:
99     return ARM::MVE_VPTv16i8;
100   case ARM::MVE_VCMPi16:
101     return ARM::MVE_VPTv8i16;
102   case ARM::MVE_VCMPi32:
103     return ARM::MVE_VPTv4i32;
104   case ARM::MVE_VCMPu8:
105     return ARM::MVE_VPTv16u8;
106   case ARM::MVE_VCMPu16:
107     return ARM::MVE_VPTv8u16;
108   case ARM::MVE_VCMPu32:
109     return ARM::MVE_VPTv4u32;
110   case ARM::MVE_VCMPs8:
111     return ARM::MVE_VPTv16s8;
112   case ARM::MVE_VCMPs16:
113     return ARM::MVE_VPTv8s16;
114   case ARM::MVE_VCMPs32:
115     return ARM::MVE_VPTv4s32;
116 
117   case ARM::MVE_VCMPf32r:
118     return ARM::MVE_VPTv4f32r;
119   case ARM::MVE_VCMPf16r:
120     return ARM::MVE_VPTv8f16r;
121   case ARM::MVE_VCMPi8r:
122     return ARM::MVE_VPTv16i8r;
123   case ARM::MVE_VCMPi16r:
124     return ARM::MVE_VPTv8i16r;
125   case ARM::MVE_VCMPi32r:
126     return ARM::MVE_VPTv4i32r;
127   case ARM::MVE_VCMPu8r:
128     return ARM::MVE_VPTv16u8r;
129   case ARM::MVE_VCMPu16r:
130     return ARM::MVE_VPTv8u16r;
131   case ARM::MVE_VCMPu32r:
132     return ARM::MVE_VPTv4u32r;
133   case ARM::MVE_VCMPs8r:
134     return ARM::MVE_VPTv16s8r;
135   case ARM::MVE_VCMPs16r:
136     return ARM::MVE_VPTv8s16r;
137   case ARM::MVE_VCMPs32r:
138     return ARM::MVE_VPTv4s32r;
139 
140   default:
141     return 0;
142   }
143 }
144 
145 static MachineInstr *findVCMPToFoldIntoVPST(MachineInstr *MI,
146                                             ReachingDefAnalysis *RDA,
147                                             unsigned &NewOpcode) {
148   // First, search backwards to the instruction that defines VPR
149   auto *Def = RDA->getReachingMIDef(MI, ARM::VPR);
150   if (!Def)
151     return nullptr;
152 
153   // Now check that Def is a VCMP
154   if (!(NewOpcode = VCMPOpcodeToVPT(Def->getOpcode())))
155     return nullptr;
156 
157   // Check that Def's operands are not defined between the VCMP and MI, i.e.
158   // check that they have the same reaching def.
159   if (!RDA->hasSameReachingDef(Def, MI, Def->getOperand(1).getReg()) ||
160       !RDA->hasSameReachingDef(Def, MI, Def->getOperand(2).getReg()))
161     return nullptr;
162 
163   return Def;
164 }
165 
166 bool MVEVPTBlock::InsertVPTBlocks(MachineBasicBlock &Block) {
167   bool Modified = false;
168   MachineBasicBlock::instr_iterator MBIter = Block.instr_begin();
169   MachineBasicBlock::instr_iterator EndIter = Block.instr_end();
170 
171   while (MBIter != EndIter) {
172     MachineInstr *MI = &*MBIter;
173     unsigned PredReg = 0;
174     DebugLoc dl = MI->getDebugLoc();
175 
176     ARMVCC::VPTCodes Pred = getVPTInstrPredicate(*MI, PredReg);
177 
178     // The idea of the predicate is that None, Then and Else are for use when
179     // handling assembly language: they correspond to the three possible
180     // suffixes "", "t" and "e" on the mnemonic. So when instructions are read
181     // from assembly source or disassembled from object code, you expect to see
182     // a mixture whenever there's a long VPT block. But in code generation, we
183     // hope we'll never generate an Else as input to this pass.
184     assert(Pred != ARMVCC::Else && "VPT block pass does not expect Else preds");
185 
186     if (Pred == ARMVCC::None) {
187       ++MBIter;
188       continue;
189     }
190 
191     LLVM_DEBUG(dbgs() << "VPT block created for: "; MI->dump());
192     int VPTInstCnt = 1;
193     ARMVCC::VPTCodes NextPred;
194 
195     // Look at subsequent instructions, checking if they can be in the same VPT
196     // block.
197     ++MBIter;
198     while (MBIter != EndIter && VPTInstCnt < 4) {
199       NextPred = getVPTInstrPredicate(*MBIter, PredReg);
200       assert(NextPred != ARMVCC::Else &&
201              "VPT block pass does not expect Else preds");
202       if (NextPred != Pred)
203         break;
204       LLVM_DEBUG(dbgs() << "  adding : "; MBIter->dump());
205       ++VPTInstCnt;
206       ++MBIter;
207     };
208 
209     unsigned BlockMask = 0;
210     switch (VPTInstCnt) {
211     case 1:
212       BlockMask = VPTMaskValue::T;
213       break;
214     case 2:
215       BlockMask = VPTMaskValue::TT;
216       break;
217     case 3:
218       BlockMask = VPTMaskValue::TTT;
219       break;
220     case 4:
221       BlockMask = VPTMaskValue::TTTT;
222       break;
223     default:
224       llvm_unreachable("Unexpected number of instruction in a VPT block");
225     };
226 
227     // Search back for a VCMP that can be folded to create a VPT, or else create
228     // a VPST directly
229     MachineInstrBuilder MIBuilder;
230     unsigned NewOpcode;
231     MachineInstr *VCMP = findVCMPToFoldIntoVPST(MI, RDA, NewOpcode);
232     if (VCMP) {
233       LLVM_DEBUG(dbgs() << "  folding VCMP into VPST: "; VCMP->dump());
234       MIBuilder = BuildMI(Block, MI, dl, TII->get(NewOpcode));
235       MIBuilder.addImm(BlockMask);
236       MIBuilder.add(VCMP->getOperand(1));
237       MIBuilder.add(VCMP->getOperand(2));
238       MIBuilder.add(VCMP->getOperand(3));
239       VCMP->eraseFromParent();
240     } else {
241       MIBuilder = BuildMI(Block, MI, dl, TII->get(ARM::MVE_VPST));
242       MIBuilder.addImm(BlockMask);
243     }
244 
245     finalizeBundle(
246         Block, MachineBasicBlock::instr_iterator(MIBuilder.getInstr()), MBIter);
247 
248     Modified = true;
249   }
250   return Modified;
251 }
252 
253 bool MVEVPTBlock::runOnMachineFunction(MachineFunction &Fn) {
254   const ARMSubtarget &STI =
255       static_cast<const ARMSubtarget &>(Fn.getSubtarget());
256 
257   if (!STI.isThumb2() || !STI.hasMVEIntegerOps())
258     return false;
259 
260   TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo());
261   RDA = &getAnalysis<ReachingDefAnalysis>();
262 
263   LLVM_DEBUG(dbgs() << "********** ARM MVE VPT BLOCKS **********\n"
264                     << "********** Function: " << Fn.getName() << '\n');
265 
266   bool Modified = false;
267   for (MachineBasicBlock &MBB : Fn)
268     Modified |= InsertVPTBlocks(MBB);
269 
270   LLVM_DEBUG(dbgs() << "**************************************\n");
271   return Modified;
272 }
273 
274 /// createMVEVPTBlock - Returns an instance of the MVE VPT block
275 /// insertion pass.
276 FunctionPass *llvm::createMVEVPTBlockPass() { return new MVEVPTBlock(); }
277