LLVM 22.0.0git
HexagonQFPOptimizer.cpp
Go to the documentation of this file.
1//===----- HexagonQFPOptimizer.cpp - Qualcomm-FP to IEEE-FP conversions
2// optimizer ------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9//
10// Basic infrastructure for optimizing intermediate conversion instructions
11// generated while performing vector floating point operations.
12// Currently run at the starting of the code generation for Hexagon, cleans
13// up redundant conversion instructions and replaces the uses of conversion
14// with appropriate machine operand. Liveness is preserved after this pass.
15//
16// @note: The redundant conversion instructions are not eliminated in this pass.
17// In this pass, we are only trying to replace the uses of conversion
18// instructions with its appropriate QFP instruction. We are leaving the job to
19// Dead instruction Elimination pass to remove redundant conversion
20// instructions.
21//
22// Brief overview of working of this QFP optimizer.
23// This version of Hexagon QFP optimizer basically iterates over each
24// instruction, checks whether if it belongs to hexagon floating point HVX
25// arithmetic instruction category(Add, Sub, Mul). And then it finds the unique
26// definition for the machine operands corresponding to the instruction.
27//
28// Example:
29// MachineInstruction *MI be the HVX vadd instruction
30// MI -> $v0 = V6_vadd_sf $v1, $v2
31// MachineOperand *DefMI1 = MRI->getVRegDef(MI->getOperand(1).getReg());
32// MachineOperand *DefMI2 = MRI->getVRegDef(MI->getOperand(2).getReg());
33//
34// In the above example, DefMI1 and DefMI2 gives the unique definitions
35// corresponding to the operands($v1 and &v2 respectively) of instruction MI.
36//
37// If both of the definitions are not conversion instructions(V6_vconv_sf_qf32,
38// V6_vconv_hf_qf16), then it will skip optimizing the current instruction and
39// iterates over next instruction.
40//
41// If one the definitions is conversion instruction then our pass will replace
42// the arithmetic instruction with its corresponding mix variant.
43// In the above example, if $v1 is conversion instruction
44// DefMI1 -> $v1 = V6_vconv_sf_qf32 $v3
45// After Transformation:
46// MI -> $v0 = V6_vadd_qf32_mix $v3, $v2 ($v1 is replaced with $v3)
47//
48// If both the definitions are conversion instructions then the instruction will
49// be replaced with its qf variant
50// In the above example, if $v1 and $v2 are conversion instructions
51// DefMI1 -> $v1 = V6_vconv_sf_qf32 $v3
52// DefMI2 -> $v2 = V6_vconv_sf_qf32 $v4
53// After Transformation:
54// MI -> $v0 = V6_vadd_qf32 $v3, $v4 ($v1 is replaced with $v3, $v2 is replaced
55// with $v4)
56//
57// Currently, in this pass, we are not handling the case when the definitions
58// are PHI inst.
59//
60//===----------------------------------------------------------------------===//
61
62#define HEXAGON_QFP_OPTIMIZER "QFP optimizer pass"
63
64#include "Hexagon.h"
65#include "HexagonInstrInfo.h"
66#include "HexagonSubtarget.h"
68#include "llvm/ADT/StringRef.h"
74#include "llvm/CodeGen/Passes.h"
75#include "llvm/Pass.h"
77#include "llvm/Support/Debug.h"
79#include <map>
80#include <vector>
81
82#define DEBUG_TYPE "hexagon-qfp-optimizer"
83
84using namespace llvm;
85
87 DisableQFOptimizer("disable-qfp-opt", cl::init(false),
88 cl::desc("Disable optimization of Qfloat operations."));
90 "disable-qfp-opt-mul", cl::init(true),
91 cl::desc("Disable optimization of Qfloat operations for multiply."));
92
93namespace {
94const std::map<unsigned short, unsigned short> QFPInstMap{
95 {Hexagon::V6_vadd_hf, Hexagon::V6_vadd_qf16_mix},
96 {Hexagon::V6_vadd_qf16_mix, Hexagon::V6_vadd_qf16},
97 {Hexagon::V6_vadd_sf, Hexagon::V6_vadd_qf32_mix},
98 {Hexagon::V6_vadd_qf32_mix, Hexagon::V6_vadd_qf32},
99 {Hexagon::V6_vsub_hf, Hexagon::V6_vsub_qf16_mix},
100 {Hexagon::V6_vsub_qf16_mix, Hexagon::V6_vsub_qf16},
101 {Hexagon::V6_vsub_sf, Hexagon::V6_vsub_qf32_mix},
102 {Hexagon::V6_vsub_qf32_mix, Hexagon::V6_vsub_qf32},
103 {Hexagon::V6_vmpy_qf16_hf, Hexagon::V6_vmpy_qf16_mix_hf},
104 {Hexagon::V6_vmpy_qf16_mix_hf, Hexagon::V6_vmpy_qf16},
105 {Hexagon::V6_vmpy_qf32_hf, Hexagon::V6_vmpy_qf32_mix_hf},
106 {Hexagon::V6_vmpy_qf32_mix_hf, Hexagon::V6_vmpy_qf32_qf16},
107 {Hexagon::V6_vmpy_qf32_sf, Hexagon::V6_vmpy_qf32},
108 {Hexagon::V6_vilog2_sf, Hexagon::V6_vilog2_qf32},
109 {Hexagon::V6_vilog2_hf, Hexagon::V6_vilog2_qf16},
110 {Hexagon::V6_vabs_qf32_sf, Hexagon::V6_vabs_qf32_qf32},
111 {Hexagon::V6_vabs_qf16_hf, Hexagon::V6_vabs_qf16_qf16},
112 {Hexagon::V6_vneg_qf32_sf, Hexagon::V6_vneg_qf32_qf32},
113 {Hexagon::V6_vneg_qf16_hf, Hexagon::V6_vneg_qf16_qf16}};
114} // namespace
115
116namespace llvm {
119} // namespace llvm
120
121namespace {
122struct HexagonQFPOptimizer : public MachineFunctionPass {
123public:
124 static char ID;
125
126 HexagonQFPOptimizer() : MachineFunctionPass(ID) {}
127
128 bool runOnMachineFunction(MachineFunction &MF) override;
129
130 bool optimizeQfp(MachineInstr *MI, MachineBasicBlock *MBB);
131
132 bool optimizeQfpTwoOp(MachineInstr *MI, MachineBasicBlock *MBB);
133
134 bool optimizeQfpOneOp(MachineInstr *MI, MachineBasicBlock *MBB);
135
136 StringRef getPassName() const override { return HEXAGON_QFP_OPTIMIZER; }
137
138 void getAnalysisUsage(AnalysisUsage &AU) const override {
139 AU.setPreservesCFG();
141 }
142
143private:
144 const HexagonSubtarget *HST = nullptr;
145 const HexagonInstrInfo *HII = nullptr;
146 const MachineRegisterInfo *MRI = nullptr;
147};
148
149char HexagonQFPOptimizer::ID = 0;
150} // namespace
151
152INITIALIZE_PASS(HexagonQFPOptimizer, "hexagon-qfp-optimizer",
153 HEXAGON_QFP_OPTIMIZER, false, false)
154
156 return new HexagonQFPOptimizer();
157}
158
159bool HexagonQFPOptimizer::optimizeQfp(MachineInstr *MI,
161
162 if (MI->getNumOperands() == 2)
163 return optimizeQfpOneOp(MI, MBB);
164 else if (MI->getNumOperands() == 3)
165 return optimizeQfpTwoOp(MI, MBB);
166 else
167 return false;
168}
169
170bool HexagonQFPOptimizer::optimizeQfpOneOp(MachineInstr *MI,
171 MachineBasicBlock *MBB) {
172
173 unsigned Op0F = 0;
174 auto It = QFPInstMap.find(MI->getOpcode());
175 if (It == QFPInstMap.end())
176 return false;
177
178 unsigned short InstTy = It->second;
179 // Get the reachind defs of MI
180 MachineInstr *DefMI = MRI->getVRegDef(MI->getOperand(1).getReg());
181 MachineOperand &Res = MI->getOperand(0);
182 if (!Res.isReg())
183 return false;
184
185 LLVM_DEBUG(dbgs() << "\n[Reaching Defs of operands]: "; DefMI->dump());
186 MachineInstr *ReachDefDef = nullptr;
187
188 // Get the reaching def of the reaching def to check for W reg def
189 if (DefMI->getNumOperands() > 1 && DefMI->getOperand(1).isReg() &&
191 ReachDefDef = MRI->getVRegDef(DefMI->getOperand(1).getReg());
192 unsigned ReachDefOp = DefMI->getOpcode();
193 MachineInstrBuilder MIB;
194
195 // Check if the reaching def is a conversion
196 if (ReachDefOp == Hexagon::V6_vconv_sf_qf32 ||
197 ReachDefOp == Hexagon::V6_vconv_hf_qf16) {
198
199 // Return if the reaching def of reaching def is W type
200 if (ReachDefDef && MRI->getRegClass(ReachDefDef->getOperand(0).getReg()) ==
201 &Hexagon::HvxWRRegClass)
202 return false;
203
204 // Analyze the use operands of the conversion to get their KILL status
205 MachineOperand &SrcOp = DefMI->getOperand(1);
206 Op0F = getKillRegState(SrcOp.isKill());
207 SrcOp.setIsKill(false);
208 MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())
209 .addReg(SrcOp.getReg(), Op0F, SrcOp.getSubReg());
210 LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());
211 return true;
212 }
213 return false;
214}
215
216bool HexagonQFPOptimizer::optimizeQfpTwoOp(MachineInstr *MI,
217 MachineBasicBlock *MBB) {
218
219 unsigned Op0F = 0;
220 unsigned Op1F = 0;
221 auto It = QFPInstMap.find(MI->getOpcode());
222 if (It == QFPInstMap.end())
223 return false;
224 unsigned short InstTy = It->second;
225 // Get the reaching defs of MI, DefMI1 and DefMI2
226 MachineInstr *DefMI1 = nullptr;
227 MachineInstr *DefMI2 = nullptr;
228
229 if (MI->getOperand(1).isReg())
230 DefMI1 = MRI->getVRegDef(MI->getOperand(1).getReg());
231 if (MI->getOperand(2).isReg())
232 DefMI2 = MRI->getVRegDef(MI->getOperand(2).getReg());
233 if (!DefMI1 || !DefMI2)
234 return false;
235
236 MachineOperand &Res = MI->getOperand(0);
237 if (!Res.isReg())
238 return false;
239
240 MachineInstr *Inst1 = nullptr;
241 MachineInstr *Inst2 = nullptr;
242 LLVM_DEBUG(dbgs() << "\n[Reaching Defs of operands]: "; DefMI1->dump();
243 DefMI2->dump());
244
245 // Get the reaching defs of DefMI
246 if (DefMI1->getNumOperands() > 1 && DefMI1->getOperand(1).isReg() &&
247 DefMI1->getOperand(1).getReg().isVirtual())
248 Inst1 = MRI->getVRegDef(DefMI1->getOperand(1).getReg());
249
250 if (DefMI2->getNumOperands() > 1 && DefMI2->getOperand(1).isReg() &&
251 DefMI2->getOperand(1).getReg().isVirtual())
252 Inst2 = MRI->getVRegDef(DefMI2->getOperand(1).getReg());
253
254 unsigned Def1OP = DefMI1->getOpcode();
255 unsigned Def2OP = DefMI2->getOpcode();
256
257 MachineInstrBuilder MIB;
258
259 // Check if the both the reaching defs of MI are qf to sf/hf conversions
260 if ((Def1OP == Hexagon::V6_vconv_sf_qf32 &&
261 Def2OP == Hexagon::V6_vconv_sf_qf32) ||
262 (Def1OP == Hexagon::V6_vconv_hf_qf16 &&
263 Def2OP == Hexagon::V6_vconv_hf_qf16)) {
264
265 // If the reaching defs of DefMI are W register type, we return
266 if ((Inst1 && Inst1->getNumOperands() > 0 && Inst1->getOperand(0).isReg() &&
267 MRI->getRegClass(Inst1->getOperand(0).getReg()) ==
268 &Hexagon::HvxWRRegClass) ||
269 (Inst2 && Inst2->getNumOperands() > 0 && Inst2->getOperand(0).isReg() &&
270 MRI->getRegClass(Inst2->getOperand(0).getReg()) ==
271 &Hexagon::HvxWRRegClass))
272 return false;
273
274 // Analyze the use operands of the conversion to get their KILL status
275 MachineOperand &Src1 = DefMI1->getOperand(1);
276 MachineOperand &Src2 = DefMI2->getOperand(1);
277
278 Op0F = getKillRegState(Src1.isKill());
279 Src1.setIsKill(false);
280
281 Op1F = getKillRegState(Src2.isKill());
282 Src2.setIsKill(false);
283
284 if (MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf) {
285 auto OuterIt = QFPInstMap.find(MI->getOpcode());
286 if (OuterIt == QFPInstMap.end())
287 return false;
288 auto InnerIt = QFPInstMap.find(OuterIt->second);
289 if (InnerIt == QFPInstMap.end())
290 return false;
291 InstTy = InnerIt->second;
292 }
293
294 MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())
295 .addReg(Src1.getReg(), Op0F, Src1.getSubReg())
296 .addReg(Src2.getReg(), Op1F, Src2.getSubReg());
297 LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());
298 return true;
299
300 // Check if left operand's reaching def is a conversion to sf/hf
301 } else if (((Def1OP == Hexagon::V6_vconv_sf_qf32 &&
302 Def2OP != Hexagon::V6_vconv_sf_qf32) ||
303 (Def1OP == Hexagon::V6_vconv_hf_qf16 &&
304 Def2OP != Hexagon::V6_vconv_hf_qf16)) &&
305 !DefMI2->isPHI() &&
306 (MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf)) {
307
308 if (Inst1 && MRI->getRegClass(Inst1->getOperand(0).getReg()) ==
309 &Hexagon::HvxWRRegClass)
310 return false;
311
312 MachineOperand &Src1 = DefMI1->getOperand(1);
313 MachineOperand &Src2 = MI->getOperand(2);
314
315 Op0F = getKillRegState(Src1.isKill());
316 Src1.setIsKill(false);
317 Op1F = getKillRegState(Src2.isKill());
318 MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())
319 .addReg(Src1.getReg(), Op0F, Src1.getSubReg())
320 .addReg(Src2.getReg(), Op1F, Src2.getSubReg());
321 LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());
322 return true;
323
324 // Check if right operand's reaching def is a conversion to sf/hf
325 } else if (((Def1OP != Hexagon::V6_vconv_sf_qf32 &&
326 Def2OP == Hexagon::V6_vconv_sf_qf32) ||
327 (Def1OP != Hexagon::V6_vconv_hf_qf16 &&
328 Def2OP == Hexagon::V6_vconv_hf_qf16)) &&
329 !DefMI1->isPHI() &&
330 (MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf)) {
331 // The second operand of original instruction is converted.
332 if (Inst2 && MRI->getRegClass(Inst2->getOperand(0).getReg()) ==
333 &Hexagon::HvxWRRegClass)
334 return false;
335
336 MachineOperand &Src1 = MI->getOperand(1);
337 MachineOperand &Src2 = DefMI2->getOperand(1);
338
339 Op1F = getKillRegState(Src2.isKill());
340 Src2.setIsKill(false);
341 Op0F = getKillRegState(Src1.isKill());
342 if (InstTy == Hexagon::V6_vsub_qf16_mix ||
343 InstTy == Hexagon::V6_vsub_qf32_mix) {
344 if (!HST->useHVXV81Ops())
345 // vsub_(hf|sf)_mix insts are only avlbl on hvx81+
346 return false;
347 // vsub is not commutative w.r.t. operands -> treat it as a special case
348 // to choose the correct mix instruction.
349 if (Def2OP == Hexagon::V6_vconv_sf_qf32)
350 InstTy = Hexagon::V6_vsub_sf_mix;
351 else if (Def2OP == Hexagon::V6_vconv_hf_qf16)
352 InstTy = Hexagon::V6_vsub_hf_mix;
353 MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())
354 .addReg(Src1.getReg(), Op0F, Src1.getSubReg())
355 .addReg(Src2.getReg(), Op1F, Src2.getSubReg());
356 } else {
357 MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())
358 .addReg(Src2.getReg(), Op1F,
359 Src2.getSubReg()) // Notice the operands are flipped.
360 .addReg(Src1.getReg(), Op0F, Src1.getSubReg());
361 }
362 LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());
363 return true;
364 }
365
366 return false;
367}
368
369bool HexagonQFPOptimizer::runOnMachineFunction(MachineFunction &MF) {
370
371 bool Changed = false;
372
374 return Changed;
375
376 HST = &MF.getSubtarget<HexagonSubtarget>();
377 if (!HST->useHVXV68Ops() || !HST->usePackets() ||
378 skipFunction(MF.getFunction()))
379 return false;
380 HII = HST->getInstrInfo();
381 MRI = &MF.getRegInfo();
382
384 LLVM_DEBUG(dbgs() << "\n=== Running QFPOptimzer Pass for : " << MF.getName()
385 << " Optimize intermediate conversions ===\n");
386 while (MBBI != MF.end()) {
387 MachineBasicBlock *MBB = &*MBBI;
389 while (MII != MBBI->instr_end()) {
390 MachineInstr *MI = &*MII;
391 ++MII; // As MI might be removed.
392 if (QFPInstMap.count(MI->getOpcode())) {
393 auto OpC = MI->getOpcode();
394 if (DisableQFOptForMul && HII->isQFPMul(MI))
395 continue;
396 if (OpC != Hexagon::V6_vconv_sf_qf32 &&
397 OpC != Hexagon::V6_vconv_hf_qf16) {
398 LLVM_DEBUG(dbgs() << "\n###Analyzing for removal: "; MI->dump());
399 if (optimizeQfp(MI, MBB)) {
400 MI->eraseFromParent();
401 LLVM_DEBUG(dbgs() << "\t....Removing....");
402 Changed = true;
403 }
404 }
405 }
406 }
407 ++MBBI;
408 }
409 return Changed;
410}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder MachineInstrBuilder & DefMI
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator MBBI
cl::opt< bool > DisableQFOptimizer("disable-qfp-opt", cl::init(false), cl::desc("Disable optimization of Qfloat operations."))
cl::opt< bool > DisableQFOptForMul("disable-qfp-opt-mul", cl::init(true), cl::desc("Disable optimization of Qfloat operations for multiply."))
#define HEXAGON_QFP_OPTIMIZER
IRTranslator LLVM IR MI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file defines the SmallVector class.
#define LLVM_DEBUG(...)
Definition Debug.h:114
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:270
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
bool isQFPMul(const MachineInstr *MF) const
const HexagonInstrInfo * getInstrInfo() const override
MachineInstrBundleIterator< MachineInstr > iterator
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.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
unsigned getNumOperands() const
Retuns the total number of operands.
LLVM_ABI void dump() const
const MachineOperand & getOperand(unsigned i) const
unsigned getSubReg() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
void dump() const
Definition Pass.cpp:146
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
Changed
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
FunctionPass * createHexagonQFPOptimizer()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
unsigned getKillRegState(bool B)
void initializeHexagonQFPOptimizerPass(PassRegistry &)