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 int NewOp = QII->getInvertedPredicatedOpcode(MI.getOpcode());
254 MI.setDesc(QII->get(NewOp));
255 Changed = true;
256 Done = true;
257 }
258 }
259 }
260 }
261
262 if (!Done) {
263 // Handle special instructions.
264 unsigned Op = MI.getOpcode();
265 unsigned NewOp = 0;
266 unsigned PR = 1, S1 = 2, S2 = 3; // Operand indices.
267
268 switch (Op) {
269 case Hexagon::C2_mux:
270 case Hexagon::C2_muxii:
271 NewOp = Op;
272 break;
273 case Hexagon::C2_muxri:
274 NewOp = Hexagon::C2_muxir;
275 break;
276 case Hexagon::C2_muxir:
277 NewOp = Hexagon::C2_muxri;
278 break;
279 }
280 if (NewOp) {
281 Register PSrc = MI.getOperand(PR).getReg();
282 if (unsigned POrig = PeepholeMap.lookup(PSrc)) {
283 BuildMI(MBB, MI.getIterator(), MI.getDebugLoc(), QII->get(NewOp),
284 MI.getOperand(0).getReg())
285 .addReg(POrig)
286 .add(MI.getOperand(S2))
287 .add(MI.getOperand(S1));
288 MI.eraseFromParent();
289 Changed = true;
290 }
291 } // if (NewOp)
292 } // if (!Done)
293
294 } // if (!DisablePNotP)
295
296 } // Instruction
297 } // Basic Block
298
300 Changed |= fuseIntrinsicVMinUB(MF);
301
302 return Changed;
303}
304
305// Return true if both instructions have identical input operands in order.
306static bool hasCommonInputOps(const MachineInstr &I1, const MachineInstr &I2) {
307 auto I1Uses = I1.explicit_uses();
308 auto I2Uses = I2.explicit_uses();
309 unsigned I1NumUses = I1.getNumExplicitOperands() - I1.getNumExplicitDefs();
310 unsigned I2NumUses = I2.getNumExplicitOperands() - I2.getNumExplicitDefs();
311 if (!I1NumUses || I1NumUses != I2NumUses)
312 return false;
313
314 auto I2Use = I2Uses.begin();
315 for (const MachineOperand &I1Use : I1Uses)
316 if (!I1Use.isIdenticalTo(*I2Use++))
317 return false;
318 return true;
319}
320
322 const MachineInstr &Between,
323 const TargetRegisterInfo *TRI) {
324 for (Register Input : Inputs)
325 if (Between.modifiesRegister(Input, TRI))
326 return true;
327 return false;
328}
329
330bool HexagonPeephole::fuseIntrinsicVMinUB(MachineFunction &MF) {
331 bool Changed = false;
332 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
333
334 for (MachineBasicBlock &MBB : MF) {
335 SmallPtrSet<MachineInstr *, 8> DeadMIs;
336
337 for (MachineInstr &MI : MBB) {
338 unsigned Opc = MI.getOpcode();
339 if ((Opc != Hexagon::A2_vminub && Opc != Hexagon::C2_cmpgtup) ||
340 DeadMIs.count(&MI))
341 continue;
342
343 unsigned SiblingOpc =
344 Opc == Hexagon::A2_vminub ? Hexagon::C2_cmpgtup : Hexagon::A2_vminub;
345 SmallVector<Register, 2> PhysicalInputs;
346 for (const MachineOperand &MO : MI.operands())
347 if (MO.isReg() && !MO.isDef() && MO.getReg().isPhysical())
348 PhysicalInputs.push_back(MO.getReg());
349 MachineInstr *Sibling = nullptr;
350 auto It = MI.getIterator();
351 for (++It; It != MBB.end(); ++It) {
352 if (!DeadMIs.count(&*It) && It->getOpcode() == SiblingOpc &&
353 hasCommonInputOps(MI, *It)) {
354 Sibling = &*It;
355 break;
356 }
357 if (modifiesPhysicalInput(PhysicalInputs, *It, TRI))
358 break;
359 }
360 if (!Sibling)
361 continue;
362
363 MachineInstr *VMin = Opc == Hexagon::A2_vminub ? &MI : Sibling;
364 MachineInstr *Cmp = Opc == Hexagon::A2_vminub ? Sibling : &MI;
365 Register VMinReg =
366 MRI->createVirtualRegister(&Hexagon::DoubleRegsRegClass);
367 Register CmpReg = MRI->createVirtualRegister(&Hexagon::PredRegsRegClass);
368
369 BuildMI(MBB, MI.getIterator(), MI.getDebugLoc(),
370 QII->get(Hexagon::A6_vminub_RdP), VMinReg)
371 .addReg(CmpReg, RegState::Define)
372 .add(VMin->getOperand(1))
373 .add(VMin->getOperand(2));
374
375 Register VMinDef = VMin->getOperand(0).getReg();
376 Register CmpDef = Cmp->getOperand(0).getReg();
377 assert(VMinDef.isVirtual() && CmpDef.isVirtual() &&
378 "vminub fusion requires virtual result registers");
379 MRI->replaceRegWith(VMinDef, VMinReg);
380 VMin->getOperand(0).setReg(VMinDef);
381 MRI->replaceRegWith(CmpDef, CmpReg);
382 Cmp->getOperand(0).setReg(CmpDef);
383
384 DeadMIs.insert(&MI);
385 DeadMIs.insert(Sibling);
386 Changed = true;
387 }
388
389 for (MachineInstr *MI : DeadMIs)
390 MI->eraseFromParent();
391 }
392
393 return Changed;
394}
395
397 return new HexagonPeephole();
398}
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
MachineRegisterInfo & MRI
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
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