1 | //===-- HexagonPeephole.cpp - Hexagon Peephole Optimiztions ---------------===// |
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 | // Note: The peephole pass makes the instrucstions like |
30 | // %170 = SXTW %166 or %16 = NOT_p killed %15 |
31 | // redundant and relies on some form of dead removal instructions, like |
32 | // DCE or DIE to actually eliminate them. |
33 | |
34 | //===----------------------------------------------------------------------===// |
35 | |
36 | #include "Hexagon.h" |
37 | #include "HexagonTargetMachine.h" |
38 | #include "llvm/ADT/DenseMap.h" |
39 | #include "llvm/ADT/Statistic.h" |
40 | #include "llvm/CodeGen/MachineFunction.h" |
41 | #include "llvm/CodeGen/MachineFunctionPass.h" |
42 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
43 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
44 | #include "llvm/CodeGen/Passes.h" |
45 | #include "llvm/CodeGen/TargetInstrInfo.h" |
46 | #include "llvm/CodeGen/TargetRegisterInfo.h" |
47 | #include "llvm/IR/Constants.h" |
48 | #include "llvm/Pass.h" |
49 | #include "llvm/Support/CommandLine.h" |
50 | #include "llvm/Support/Debug.h" |
51 | #include "llvm/Support/raw_ostream.h" |
52 | #include "llvm/Target/TargetMachine.h" |
53 | #include <algorithm> |
54 | |
55 | using namespace llvm; |
56 | |
57 | #define DEBUG_TYPE "hexagon-peephole" |
58 | |
59 | static cl::opt<bool> |
60 | DisableHexagonPeephole("disable-hexagon-peephole" , cl::Hidden, |
61 | cl::desc("Disable Peephole Optimization" )); |
62 | |
63 | static cl::opt<bool> DisablePNotP("disable-hexagon-pnotp" , cl::Hidden, |
64 | cl::desc("Disable Optimization of PNotP" )); |
65 | |
66 | static cl::opt<bool> |
67 | DisableOptSZExt("disable-hexagon-optszext" , cl::Hidden, cl::init(Val: true), |
68 | cl::desc("Disable Optimization of Sign/Zero Extends" )); |
69 | |
70 | static cl::opt<bool> |
71 | DisableOptExtTo64("disable-hexagon-opt-ext-to-64" , cl::Hidden, |
72 | cl::init(Val: true), |
73 | cl::desc("Disable Optimization of extensions to i64." )); |
74 | |
75 | namespace llvm { |
76 | FunctionPass *createHexagonPeephole(); |
77 | void initializeHexagonPeepholePass(PassRegistry&); |
78 | } |
79 | |
80 | namespace { |
81 | struct HexagonPeephole : public MachineFunctionPass { |
82 | const HexagonInstrInfo *QII; |
83 | const HexagonRegisterInfo *QRI; |
84 | const MachineRegisterInfo *MRI; |
85 | |
86 | public: |
87 | static char ID; |
88 | HexagonPeephole() : MachineFunctionPass(ID) { |
89 | initializeHexagonPeepholePass(*PassRegistry::getPassRegistry()); |
90 | } |
91 | |
92 | bool runOnMachineFunction(MachineFunction &MF) override; |
93 | |
94 | StringRef getPassName() const override { |
95 | return "Hexagon optimize redundant zero and size extends" ; |
96 | } |
97 | |
98 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
99 | MachineFunctionPass::getAnalysisUsage(AU); |
100 | } |
101 | }; |
102 | } |
103 | |
104 | char HexagonPeephole::ID = 0; |
105 | |
106 | INITIALIZE_PASS(HexagonPeephole, "hexagon-peephole" , "Hexagon Peephole" , |
107 | false, false) |
108 | |
109 | bool HexagonPeephole::runOnMachineFunction(MachineFunction &MF) { |
110 | if (skipFunction(F: MF.getFunction())) |
111 | return false; |
112 | |
113 | QII = static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo()); |
114 | QRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); |
115 | MRI = &MF.getRegInfo(); |
116 | |
117 | DenseMap<unsigned, unsigned> PeepholeMap; |
118 | DenseMap<unsigned, std::pair<unsigned, unsigned> > PeepholeDoubleRegsMap; |
119 | |
120 | if (DisableHexagonPeephole) return false; |
121 | |
122 | // Loop over all of the basic blocks. |
123 | for (MachineBasicBlock &MBB : MF) { |
124 | PeepholeMap.clear(); |
125 | PeepholeDoubleRegsMap.clear(); |
126 | |
127 | // Traverse the basic block. |
128 | for (MachineInstr &MI : llvm::make_early_inc_range(Range&: MBB)) { |
129 | // Look for sign extends: |
130 | // %170 = SXTW %166 |
131 | if (!DisableOptSZExt && MI.getOpcode() == Hexagon::A2_sxtw) { |
132 | assert(MI.getNumOperands() == 2); |
133 | MachineOperand &Dst = MI.getOperand(i: 0); |
134 | MachineOperand &Src = MI.getOperand(i: 1); |
135 | Register DstReg = Dst.getReg(); |
136 | Register SrcReg = Src.getReg(); |
137 | // Just handle virtual registers. |
138 | if (DstReg.isVirtual() && SrcReg.isVirtual()) { |
139 | // Map the following: |
140 | // %170 = SXTW %166 |
141 | // PeepholeMap[170] = %166 |
142 | PeepholeMap[DstReg] = SrcReg; |
143 | } |
144 | } |
145 | |
146 | // Look for %170 = COMBINE_ir_V4 (0, %169) |
147 | // %170:DoublRegs, %169:IntRegs |
148 | if (!DisableOptExtTo64 && MI.getOpcode() == Hexagon::A4_combineir) { |
149 | assert(MI.getNumOperands() == 3); |
150 | MachineOperand &Dst = MI.getOperand(i: 0); |
151 | MachineOperand &Src1 = MI.getOperand(i: 1); |
152 | MachineOperand &Src2 = MI.getOperand(i: 2); |
153 | if (Src1.getImm() != 0) |
154 | continue; |
155 | Register DstReg = Dst.getReg(); |
156 | Register SrcReg = Src2.getReg(); |
157 | PeepholeMap[DstReg] = SrcReg; |
158 | } |
159 | |
160 | // Look for this sequence below |
161 | // %DoubleReg1 = LSRd_ri %DoubleReg0, 32 |
162 | // %IntReg = COPY %DoubleReg1:isub_lo. |
163 | // and convert into |
164 | // %IntReg = COPY %DoubleReg0:isub_hi. |
165 | if (MI.getOpcode() == Hexagon::S2_lsr_i_p) { |
166 | assert(MI.getNumOperands() == 3); |
167 | MachineOperand &Dst = MI.getOperand(i: 0); |
168 | MachineOperand &Src1 = MI.getOperand(i: 1); |
169 | MachineOperand &Src2 = MI.getOperand(i: 2); |
170 | if (Src2.getImm() != 32) |
171 | continue; |
172 | Register DstReg = Dst.getReg(); |
173 | Register SrcReg = Src1.getReg(); |
174 | PeepholeDoubleRegsMap[DstReg] = |
175 | std::make_pair(x&: *&SrcReg, y: Hexagon::isub_hi); |
176 | } |
177 | |
178 | // Look for P=NOT(P). |
179 | if (!DisablePNotP && MI.getOpcode() == Hexagon::C2_not) { |
180 | assert(MI.getNumOperands() == 2); |
181 | MachineOperand &Dst = MI.getOperand(i: 0); |
182 | MachineOperand &Src = MI.getOperand(i: 1); |
183 | Register DstReg = Dst.getReg(); |
184 | Register SrcReg = Src.getReg(); |
185 | // Just handle virtual registers. |
186 | if (DstReg.isVirtual() && SrcReg.isVirtual()) { |
187 | // Map the following: |
188 | // %170 = NOT_xx %166 |
189 | // PeepholeMap[170] = %166 |
190 | PeepholeMap[DstReg] = SrcReg; |
191 | } |
192 | } |
193 | |
194 | // Look for copy: |
195 | // %176 = COPY %170:isub_lo |
196 | if (!DisableOptSZExt && MI.isCopy()) { |
197 | assert(MI.getNumOperands() == 2); |
198 | MachineOperand &Dst = MI.getOperand(i: 0); |
199 | MachineOperand &Src = MI.getOperand(i: 1); |
200 | |
201 | // Make sure we are copying the lower 32 bits. |
202 | if (Src.getSubReg() != Hexagon::isub_lo) |
203 | continue; |
204 | |
205 | Register DstReg = Dst.getReg(); |
206 | Register SrcReg = Src.getReg(); |
207 | if (DstReg.isVirtual() && SrcReg.isVirtual()) { |
208 | // Try to find in the map. |
209 | if (unsigned PeepholeSrc = PeepholeMap.lookup(Val: SrcReg)) { |
210 | // Change the 1st operand. |
211 | MI.removeOperand(OpNo: 1); |
212 | MI.addOperand(Op: MachineOperand::CreateReg(Reg: PeepholeSrc, isDef: false)); |
213 | } else { |
214 | DenseMap<unsigned, std::pair<unsigned, unsigned> >::iterator DI = |
215 | PeepholeDoubleRegsMap.find(Val: SrcReg); |
216 | if (DI != PeepholeDoubleRegsMap.end()) { |
217 | std::pair<unsigned,unsigned> PeepholeSrc = DI->second; |
218 | MI.removeOperand(OpNo: 1); |
219 | MI.addOperand(Op: MachineOperand::CreateReg( |
220 | Reg: PeepholeSrc.first, isDef: false /*isDef*/, isImp: false /*isImp*/, |
221 | isKill: false /*isKill*/, isDead: false /*isDead*/, isUndef: false /*isUndef*/, |
222 | isEarlyClobber: false /*isEarlyClobber*/, SubReg: PeepholeSrc.second)); |
223 | } |
224 | } |
225 | } |
226 | } |
227 | |
228 | // Look for Predicated instructions. |
229 | if (!DisablePNotP) { |
230 | bool Done = false; |
231 | if (QII->isPredicated(MI)) { |
232 | MachineOperand &Op0 = MI.getOperand(i: 0); |
233 | Register Reg0 = Op0.getReg(); |
234 | const TargetRegisterClass *RC0 = MRI->getRegClass(Reg: Reg0); |
235 | if (RC0->getID() == Hexagon::PredRegsRegClassID) { |
236 | // Handle instructions that have a prediate register in op0 |
237 | // (most cases of predicable instructions). |
238 | if (Reg0.isVirtual()) { |
239 | // Try to find in the map. |
240 | if (unsigned PeepholeSrc = PeepholeMap.lookup(Val: Reg0)) { |
241 | // Change the 1st operand and, flip the opcode. |
242 | MI.getOperand(i: 0).setReg(PeepholeSrc); |
243 | MRI->clearKillFlags(Reg: PeepholeSrc); |
244 | int NewOp = QII->getInvertedPredicatedOpcode(Opc: MI.getOpcode()); |
245 | MI.setDesc(QII->get(Opcode: NewOp)); |
246 | Done = true; |
247 | } |
248 | } |
249 | } |
250 | } |
251 | |
252 | if (!Done) { |
253 | // Handle special instructions. |
254 | unsigned Op = MI.getOpcode(); |
255 | unsigned NewOp = 0; |
256 | unsigned PR = 1, S1 = 2, S2 = 3; // Operand indices. |
257 | |
258 | switch (Op) { |
259 | case Hexagon::C2_mux: |
260 | case Hexagon::C2_muxii: |
261 | NewOp = Op; |
262 | break; |
263 | case Hexagon::C2_muxri: |
264 | NewOp = Hexagon::C2_muxir; |
265 | break; |
266 | case Hexagon::C2_muxir: |
267 | NewOp = Hexagon::C2_muxri; |
268 | break; |
269 | } |
270 | if (NewOp) { |
271 | Register PSrc = MI.getOperand(i: PR).getReg(); |
272 | if (unsigned POrig = PeepholeMap.lookup(Val: PSrc)) { |
273 | BuildMI(BB&: MBB, I: MI.getIterator(), MIMD: MI.getDebugLoc(), MCID: QII->get(Opcode: NewOp), |
274 | DestReg: MI.getOperand(i: 0).getReg()) |
275 | .addReg(RegNo: POrig) |
276 | .add(MO: MI.getOperand(i: S2)) |
277 | .add(MO: MI.getOperand(i: S1)); |
278 | MRI->clearKillFlags(Reg: POrig); |
279 | MI.eraseFromParent(); |
280 | } |
281 | } // if (NewOp) |
282 | } // if (!Done) |
283 | |
284 | } // if (!DisablePNotP) |
285 | |
286 | } // Instruction |
287 | } // Basic Block |
288 | return true; |
289 | } |
290 | |
291 | FunctionPass *llvm::createHexagonPeephole() { |
292 | return new HexagonPeephole(); |
293 | } |
294 | |