LLVM 24.0.0git
HexagonPeephole.cpp
Go to the documentation of this file.
1//===-- HexagonPeephole.cpp - Hexagon Peephole Optimizations --------------===//
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// This peephole pass optimizes in the following cases.
8// 1. Optimizes redundant sign extends for the following case
9// Transform the following pattern
10// %170 = SXTW %166
11// ...
12// %176 = COPY %170:isub_lo
13//
14// Into
15// %176 = COPY %166
16//
17// 2. Optimizes redundant negation of predicates.
18// %15 = CMPGTrr %6, %2
19// ...
20// %16 = NOT_p killed %15
21// ...
22// JMP_c killed %16, <%bb.1>, implicit dead %pc
23//
24// Into
25// %15 = CMPGTrr %6, %2;
26// ...
27// JMP_cNot killed %15, <%bb.1>, implicit dead %pc;
28//
29// 3. Fuse the A2_vminub/C2_cmpgtup intrinsic pair, which share inputs, into the
30// dual-output A6_vminub_RdP hardware instruction.
31// %1 = A2_vminub %a, %b
32// %2 = C2_cmpgtup %a, %b
33// turning it into
34// %3, %4 = A6_vminub_RdP %a, %b
35// (Hexagon has no multi-output intrinsics, so the two results are produced by
36// separate intrinsics that this pass recombines.)
37//
38// Note: The first two transformations make instructions like
39// %170 = SXTW %166 or %16 = NOT_p killed %15
40// redundant. A dead-instruction removal pass, such as DCE or DIE, eliminates
41// them.
42
43//===----------------------------------------------------------------------===//
44
45#include "Hexagon.h"
47#include "llvm/ADT/ArrayRef.h"
48#include "llvm/ADT/DenseMap.h"
51#include "llvm/ADT/Statistic.h"
56#include "llvm/CodeGen/Passes.h"
59#include "llvm/Pass.h"
62
63using namespace llvm;
64
65#define DEBUG_TYPE "hexagon-peephole"
66
67static cl::opt<bool>
68 DisableHexagonPeephole("disable-hexagon-peephole", cl::Hidden,
69 cl::desc("Disable Peephole Optimization"));
70
71static cl::opt<bool> DisablePNotP("disable-hexagon-pnotp", cl::Hidden,
72 cl::desc("Disable Optimization of PNotP"));
73
74static cl::opt<bool>
75 DisableOptSZExt("disable-hexagon-optszext", cl::Hidden, cl::init(true),
76 cl::desc("Disable Optimization of Sign/Zero Extends"));
77
78static cl::opt<bool>
79 DisableOptExtTo64("disable-hexagon-opt-ext-to-64", cl::Hidden,
80 cl::init(true),
81 cl::desc("Disable Optimization of extensions to i64."));
82
83static cl::opt<bool>
84 FuseIntrinsicVMinUB("hexagon-fuse-intrinsic-vminub", cl::Hidden,
85 cl::init(true),
86 cl::desc("Fuse A2_vminub/C2_cmpgtup into "
87 "A6_vminub_RdP."));
88
89namespace {
90 struct HexagonPeephole : public MachineFunctionPass {
91 const HexagonInstrInfo *QII;
93
94 public:
95 static char ID;
96 HexagonPeephole() : MachineFunctionPass(ID) {}
97
98 bool runOnMachineFunction(MachineFunction &MF) override;
99 bool fuseIntrinsicVMinUB(MachineFunction &MF);
100
101 StringRef getPassName() const override {
102 return "Hexagon optimize redundant zero and size extends";
103 }
104
105 void getAnalysisUsage(AnalysisUsage &AU) const override {
107 }
108 };
109}
110
111char HexagonPeephole::ID = 0;
112
113INITIALIZE_PASS(HexagonPeephole, "hexagon-peephole", "Hexagon Peephole",
114 false, false)
115
116bool HexagonPeephole::runOnMachineFunction(MachineFunction &MF) {
117 if (skipFunction(MF.getFunction()))
118 return false;
119
120 bool Changed = false;
121
122 QII = static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo());
123 MRI = &MF.getRegInfo();
124
126 DenseMap<unsigned, std::pair<unsigned, unsigned> > PeepholeDoubleRegsMap;
127
128 if (DisableHexagonPeephole) return false;
129
130 // Loop over all of the basic blocks.
131 for (MachineBasicBlock &MBB : MF) {
132 PeepholeMap.clear();
133 PeepholeDoubleRegsMap.clear();
134
135 // Traverse the basic block.
137 // Look for sign extends:
138 // %170 = SXTW %166
139 if (!DisableOptSZExt && MI.getOpcode() == Hexagon::A2_sxtw) {
140 assert(MI.getNumOperands() == 2);
141 MachineOperand &Dst = MI.getOperand(0);
142 MachineOperand &Src = MI.getOperand(1);
143 Register DstReg = Dst.getReg();
144 Register SrcReg = Src.getReg();
145 // Just handle virtual registers.
146 if (DstReg.isVirtual() && SrcReg.isVirtual()) {
147 // Map the following:
148 // %170 = SXTW %166
149 // PeepholeMap[170] = %166
150 PeepholeMap[DstReg] = SrcReg;
151 }
152 }
153
154 // Look for %170 = COMBINE_ir_V4 (0, %169)
155 // %170:DoublRegs, %169:IntRegs
156 if (!DisableOptExtTo64 && MI.getOpcode() == Hexagon::A4_combineir) {
157 assert(MI.getNumOperands() == 3);
158 MachineOperand &Dst = MI.getOperand(0);
159 MachineOperand &Src1 = MI.getOperand(1);
160 MachineOperand &Src2 = MI.getOperand(2);
161 if (Src1.getImm() != 0)
162 continue;
163 Register DstReg = Dst.getReg();
164 Register SrcReg = Src2.getReg();
165 PeepholeMap[DstReg] = SrcReg;
166 }
167
168 // Look for this sequence below
169 // %DoubleReg1 = LSRd_ri %DoubleReg0, 32
170 // %IntReg = COPY %DoubleReg1:isub_lo.
171 // and convert into
172 // %IntReg = COPY %DoubleReg0:isub_hi.
173 if (MI.getOpcode() == Hexagon::S2_lsr_i_p) {
174 assert(MI.getNumOperands() == 3);
175 MachineOperand &Dst = MI.getOperand(0);
176 MachineOperand &Src1 = MI.getOperand(1);
177 MachineOperand &Src2 = MI.getOperand(2);
178 if (Src2.getImm() != 32)
179 continue;
180 Register DstReg = Dst.getReg();
181 Register SrcReg = Src1.getReg();
182 PeepholeDoubleRegsMap[DstReg] =
183 std::make_pair(*&SrcReg, Hexagon::isub_hi);
184 }
185
186 // Look for P=NOT(P).
187 if (!DisablePNotP && MI.getOpcode() == Hexagon::C2_not) {
188 assert(MI.getNumOperands() == 2);
189 MachineOperand &Dst = MI.getOperand(0);
190 MachineOperand &Src = MI.getOperand(1);
191 Register DstReg = Dst.getReg();
192 Register SrcReg = Src.getReg();
193 // Just handle virtual registers.
194 if (DstReg.isVirtual() && SrcReg.isVirtual()) {
195 // Map the following:
196 // %170 = NOT_xx %166
197 // PeepholeMap[170] = %166
198 PeepholeMap[DstReg] = SrcReg;
199 }
200 }
201
202 // Look for copy:
203 // %176 = COPY %170:isub_lo
204 if (!DisableOptSZExt && MI.isCopy()) {
205 assert(MI.getNumOperands() == 2);
206 MachineOperand &Dst = MI.getOperand(0);
207 MachineOperand &Src = MI.getOperand(1);
208
209 // Make sure we are copying the lower 32 bits.
210 if (Src.getSubReg() != Hexagon::isub_lo)
211 continue;
212
213 Register DstReg = Dst.getReg();
214 Register SrcReg = Src.getReg();
215 if (DstReg.isVirtual() && SrcReg.isVirtual()) {
216 // Try to find in the map.
217 if (unsigned PeepholeSrc = PeepholeMap.lookup(SrcReg)) {
218 // Change the 1st operand.
219 MI.removeOperand(1);
220 MI.addOperand(MachineOperand::CreateReg(PeepholeSrc, false));
221 Changed = true;
222 } else {
224 PeepholeDoubleRegsMap.find(SrcReg);
225 if (DI != PeepholeDoubleRegsMap.end()) {
226 std::pair<unsigned,unsigned> PeepholeSrc = DI->second;
227 MI.removeOperand(1);
228 MI.addOperand(MachineOperand::CreateReg(
229 PeepholeSrc.first, false /*isDef*/, false /*isImp*/,
230 false /*isKill*/, false /*isDead*/, false /*isUndef*/,
231 false /*isEarlyClobber*/, PeepholeSrc.second));
232 Changed = true;
233 }
234 }
235 }
236 }
237
238 // Look for Predicated instructions.
239 if (!DisablePNotP) {
240 bool Done = false;
241 if (QII->isPredicated(MI)) {
242 MachineOperand &Op0 = MI.getOperand(0);
243 Register Reg0 = Op0.getReg();
244 const TargetRegisterClass *RC0 = MRI->getRegClass(Reg0);
245 if (RC0->getID() == Hexagon::PredRegsRegClassID) {
246 // Handle instructions that have a prediate register in op0
247 // (most cases of predicable instructions).
248 if (Reg0.isVirtual()) {
249 // Try to find in the map.
250 if (unsigned PeepholeSrc = PeepholeMap.lookup(Reg0)) {
251 // Change the 1st operand and, flip the opcode.
252 MI.getOperand(0).setReg(PeepholeSrc);
253 MRI->clearKillFlags(PeepholeSrc);
254 int NewOp = QII->getInvertedPredicatedOpcode(MI.getOpcode());
255 MI.setDesc(QII->get(NewOp));
256 Changed = true;
257 Done = true;
258 }
259 }
260 }
261 }
262
263 if (!Done) {
264 // Handle special instructions.
265 unsigned Op = MI.getOpcode();
266 unsigned NewOp = 0;
267 unsigned PR = 1, S1 = 2, S2 = 3; // Operand indices.
268
269 switch (Op) {
270 case Hexagon::C2_mux:
271 case Hexagon::C2_muxii:
272 NewOp = Op;
273 break;
274 case Hexagon::C2_muxri:
275 NewOp = Hexagon::C2_muxir;
276 break;
277 case Hexagon::C2_muxir:
278 NewOp = Hexagon::C2_muxri;
279 break;
280 }
281 if (NewOp) {
282 Register PSrc = MI.getOperand(PR).getReg();
283 if (unsigned POrig = PeepholeMap.lookup(PSrc)) {
284 BuildMI(MBB, MI.getIterator(), MI.getDebugLoc(), QII->get(NewOp),
285 MI.getOperand(0).getReg())
286 .addReg(POrig)
287 .add(MI.getOperand(S2))
288 .add(MI.getOperand(S1));
289 MRI->clearKillFlags(POrig);
290 MI.eraseFromParent();
291 Changed = true;
292 }
293 } // if (NewOp)
294 } // if (!Done)
295
296 } // if (!DisablePNotP)
297
298 } // Instruction
299 } // Basic Block
300
302 Changed |= fuseIntrinsicVMinUB(MF);
303
304 return Changed;
305}
306
307// Return true if both instructions have identical input operands in order.
308static bool hasCommonInputOps(const MachineInstr &I1, const MachineInstr &I2) {
309 auto I1Uses = I1.explicit_uses();
310 auto I2Uses = I2.explicit_uses();
311 unsigned I1NumUses = I1.getNumExplicitOperands() - I1.getNumExplicitDefs();
312 unsigned I2NumUses = I2.getNumExplicitOperands() - I2.getNumExplicitDefs();
313 if (!I1NumUses || I1NumUses != I2NumUses)
314 return false;
315
316 auto I2Use = I2Uses.begin();
317 for (const MachineOperand &I1Use : I1Uses)
318 if (!I1Use.isIdenticalTo(*I2Use++))
319 return false;
320 return true;
321}
322
324 const MachineInstr &Between,
325 const TargetRegisterInfo *TRI) {
326 for (Register Input : Inputs)
327 if (Between.modifiesRegister(Input, TRI))
328 return true;
329 return false;
330}
331
332bool HexagonPeephole::fuseIntrinsicVMinUB(MachineFunction &MF) {
333 bool Changed = false;
334 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
335
336 for (MachineBasicBlock &MBB : MF) {
337 SmallPtrSet<MachineInstr *, 8> DeadMIs;
338
339 for (MachineInstr &MI : MBB) {
340 unsigned Opc = MI.getOpcode();
341 if ((Opc != Hexagon::A2_vminub && Opc != Hexagon::C2_cmpgtup) ||
342 DeadMIs.count(&MI))
343 continue;
344
345 unsigned SiblingOpc =
346 Opc == Hexagon::A2_vminub ? Hexagon::C2_cmpgtup : Hexagon::A2_vminub;
347 SmallVector<Register, 2> PhysicalInputs;
348 for (const MachineOperand &MO : MI.operands())
349 if (MO.isReg() && !MO.isDef() && MO.getReg().isPhysical())
350 PhysicalInputs.push_back(MO.getReg());
351 MachineInstr *Sibling = nullptr;
352 auto It = MI.getIterator();
353 for (++It; It != MBB.end(); ++It) {
354 if (!DeadMIs.count(&*It) && It->getOpcode() == SiblingOpc &&
355 hasCommonInputOps(MI, *It)) {
356 Sibling = &*It;
357 break;
358 }
359 if (modifiesPhysicalInput(PhysicalInputs, *It, TRI))
360 break;
361 }
362 if (!Sibling)
363 continue;
364
365 MachineInstr *VMin = Opc == Hexagon::A2_vminub ? &MI : Sibling;
366 MachineInstr *Cmp = Opc == Hexagon::A2_vminub ? Sibling : &MI;
367 Register VMinReg =
368 MRI->createVirtualRegister(&Hexagon::DoubleRegsRegClass);
369 Register CmpReg = MRI->createVirtualRegister(&Hexagon::PredRegsRegClass);
370
371 BuildMI(MBB, MI.getIterator(), MI.getDebugLoc(),
372 QII->get(Hexagon::A6_vminub_RdP), VMinReg)
373 .addReg(CmpReg, RegState::Define)
374 .add(VMin->getOperand(1))
375 .add(VMin->getOperand(2));
376
377 Register VMinDef = VMin->getOperand(0).getReg();
378 Register CmpDef = Cmp->getOperand(0).getReg();
379 assert(VMinDef.isVirtual() && CmpDef.isVirtual() &&
380 "vminub fusion requires virtual result registers");
381 MRI->replaceRegWith(VMinDef, VMinReg);
382 VMin->getOperand(0).setReg(VMinDef);
383 MRI->replaceRegWith(CmpDef, CmpReg);
384 Cmp->getOperand(0).setReg(CmpDef);
385
386 DeadMIs.insert(&MI);
387 DeadMIs.insert(Sibling);
388 Changed = true;
389 }
390
391 for (MachineInstr *MI : DeadMIs)
392 MI->eraseFromParent();
393 }
394
395 return Changed;
396}
397
399 return new HexagonPeephole();
400}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
constexpr LLT S1
MachineBasicBlock & MBB
This file defines the DenseMap class.
static bool modifiesPhysicalInput(ArrayRef< Register > Inputs, const MachineInstr &Between, const TargetRegisterInfo *TRI)
static cl::opt< bool > FuseIntrinsicVMinUB("hexagon-fuse-intrinsic-vminub", cl::Hidden, cl::init(true), cl::desc("Fuse A2_vminub/C2_cmpgtup into " "A6_vminub_RdP."))
static cl::opt< bool > DisableOptExtTo64("disable-hexagon-opt-ext-to-64", cl::Hidden, cl::init(true), cl::desc("Disable Optimization of extensions to i64."))
static cl::opt< bool > DisableHexagonPeephole("disable-hexagon-peephole", cl::Hidden, cl::desc("Disable Peephole Optimization"))
static cl::opt< bool > DisablePNotP("disable-hexagon-pnotp", cl::Hidden, cl::desc("Disable Optimization of PNotP"))
static cl::opt< bool > DisableOptSZExt("disable-hexagon-optszext", cl::Hidden, cl::init(true), cl::desc("Disable Optimization of Sign/Zero Extends"))
static bool hasCommonInputOps(const MachineInstr &I1, const MachineInstr &I2)
IRTranslator LLVM IR MI
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
if(PassOpts->AAPipeline)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
The Input class is used to parse a yaml document into in-memory structs and vectors.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
iterator end()
Definition DenseMap.h:686
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
unsigned getID() const
getID() - Return the register class ID number.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
bool modifiesRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr modifies (fully define or partially define) the specified register.
mop_range explicit_uses()
LLVM_ABI unsigned getNumExplicitDefs() const
Returns the number of non-implicit definitions.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
void push_back(const T &Elt)
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
self_iterator getIterator()
Definition ilist_node.h:123
Changed
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
@ Done
Definition Threading.h:60
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:649
FunctionPass * createHexagonPeephole()
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
DWARFExpression::Operation Op
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58