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
MVEVPTBlock()41 MVEVPTBlock() : MachineFunctionPass(ID) {}
42
43 bool runOnMachineFunction(MachineFunction &Fn) override;
44
getAnalysisUsage(AnalysisUsage & AU) const45 void getAnalysisUsage(AnalysisUsage &AU) const override {
46 AU.setPreservesCFG();
47 AU.addRequired<ReachingDefAnalysis>();
48 MachineFunctionPass::getAnalysisUsage(AU);
49 }
50
getRequiredProperties() const51 MachineFunctionProperties getRequiredProperties() const override {
52 return MachineFunctionProperties().set(
53 MachineFunctionProperties::Property::NoVRegs).set(
54 MachineFunctionProperties::Property::TracksLiveness);
55 }
56
getPassName() const57 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
findVCMPToFoldIntoVPST(MachineInstr * MI,ReachingDefAnalysis * RDA,unsigned & NewOpcode)74 static MachineInstr *findVCMPToFoldIntoVPST(MachineInstr *MI,
75 ReachingDefAnalysis *RDA,
76 unsigned &NewOpcode) {
77 // First, search backwards to the instruction that defines VPR
78 auto *Def = RDA->getReachingMIDef(MI, ARM::VPR);
79 if (!Def)
80 return nullptr;
81
82 // Now check that Def is a VCMP
83 if (!(NewOpcode = VCMPOpcodeToVPT(Def->getOpcode())))
84 return nullptr;
85
86 // Check that Def's operands are not defined between the VCMP and MI, i.e.
87 // check that they have the same reaching def.
88 if (!RDA->hasSameReachingDef(Def, MI, Def->getOperand(1).getReg()) ||
89 !RDA->hasSameReachingDef(Def, MI, Def->getOperand(2).getReg()))
90 return nullptr;
91
92 return Def;
93 }
94
InsertVPTBlocks(MachineBasicBlock & Block)95 bool MVEVPTBlock::InsertVPTBlocks(MachineBasicBlock &Block) {
96 bool Modified = false;
97 MachineBasicBlock::instr_iterator MBIter = Block.instr_begin();
98 MachineBasicBlock::instr_iterator EndIter = Block.instr_end();
99 SmallSet<MachineInstr *, 4> RemovedVCMPs;
100
101 while (MBIter != EndIter) {
102 MachineInstr *MI = &*MBIter;
103 unsigned PredReg = 0;
104 DebugLoc dl = MI->getDebugLoc();
105
106 ARMVCC::VPTCodes Pred = getVPTInstrPredicate(*MI, PredReg);
107
108 // The idea of the predicate is that None, Then and Else are for use when
109 // handling assembly language: they correspond to the three possible
110 // suffixes "", "t" and "e" on the mnemonic. So when instructions are read
111 // from assembly source or disassembled from object code, you expect to see
112 // a mixture whenever there's a long VPT block. But in code generation, we
113 // hope we'll never generate an Else as input to this pass.
114 assert(Pred != ARMVCC::Else && "VPT block pass does not expect Else preds");
115
116 if (Pred == ARMVCC::None) {
117 ++MBIter;
118 continue;
119 }
120
121 LLVM_DEBUG(dbgs() << "VPT block created for: "; MI->dump());
122 int VPTInstCnt = 1;
123 ARMVCC::VPTCodes NextPred;
124
125 // Look at subsequent instructions, checking if they can be in the same VPT
126 // block.
127 ++MBIter;
128 while (MBIter != EndIter && VPTInstCnt < 4) {
129 NextPred = getVPTInstrPredicate(*MBIter, PredReg);
130 assert(NextPred != ARMVCC::Else &&
131 "VPT block pass does not expect Else preds");
132 if (NextPred != Pred)
133 break;
134 LLVM_DEBUG(dbgs() << " adding : "; MBIter->dump());
135 ++VPTInstCnt;
136 ++MBIter;
137 };
138
139 unsigned BlockMask = getARMVPTBlockMask(VPTInstCnt);
140
141 // Search back for a VCMP that can be folded to create a VPT, or else create
142 // a VPST directly
143 MachineInstrBuilder MIBuilder;
144 unsigned NewOpcode;
145 MachineInstr *VCMP = findVCMPToFoldIntoVPST(MI, RDA, NewOpcode);
146 if (VCMP) {
147 LLVM_DEBUG(dbgs() << " folding VCMP into VPST: "; VCMP->dump());
148 MIBuilder = BuildMI(Block, MI, dl, TII->get(NewOpcode));
149 MIBuilder.addImm(BlockMask);
150 MIBuilder.add(VCMP->getOperand(1));
151 MIBuilder.add(VCMP->getOperand(2));
152 MIBuilder.add(VCMP->getOperand(3));
153 // We delay removing the actual VCMP instruction by saving it to a list
154 // and deleting all instructions in this list in one go after we have
155 // created the VPT blocks. We do this in order not to invalidate the
156 // ReachingDefAnalysis that is queried by 'findVCMPToFoldIntoVPST'.
157 RemovedVCMPs.insert(VCMP);
158 } else {
159 MIBuilder = BuildMI(Block, MI, dl, TII->get(ARM::MVE_VPST));
160 MIBuilder.addImm(BlockMask);
161 }
162
163 finalizeBundle(
164 Block, MachineBasicBlock::instr_iterator(MIBuilder.getInstr()), MBIter);
165
166 Modified = true;
167 }
168
169 for (auto *I : RemovedVCMPs)
170 I->eraseFromParent();
171
172 return Modified;
173 }
174
runOnMachineFunction(MachineFunction & Fn)175 bool MVEVPTBlock::runOnMachineFunction(MachineFunction &Fn) {
176 if (skipFunction(Fn.getFunction()))
177 return false;
178
179 const ARMSubtarget &STI =
180 static_cast<const ARMSubtarget &>(Fn.getSubtarget());
181
182 if (!STI.isThumb2() || !STI.hasMVEIntegerOps())
183 return false;
184
185 TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo());
186 RDA = &getAnalysis<ReachingDefAnalysis>();
187
188 LLVM_DEBUG(dbgs() << "********** ARM MVE VPT BLOCKS **********\n"
189 << "********** Function: " << Fn.getName() << '\n');
190
191 bool Modified = false;
192 for (MachineBasicBlock &MBB : Fn)
193 Modified |= InsertVPTBlocks(MBB);
194
195 LLVM_DEBUG(dbgs() << "**************************************\n");
196 return Modified;
197 }
198
199 /// createMVEVPTBlock - Returns an instance of the MVE VPT block
200 /// insertion pass.
createMVEVPTBlockPass()201 FunctionPass *llvm::createMVEVPTBlockPass() { return new MVEVPTBlock(); }
202