LLVM 24.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"
67#include "llvm/ADT/StringRef.h"
73#include "llvm/CodeGen/Passes.h"
74#include "llvm/Pass.h"
76#include "llvm/Support/Debug.h"
78#include <map>
79
80#define DEBUG_TYPE "hexagon-qfp-optimizer"
81
82using namespace llvm;
83
85 DisableQFOptimizer("disable-qfp-opt", cl::init(false),
86 cl::desc("Disable optimization of Qfloat operations."));
88 "disable-qfp-opt-mul", cl::init(true),
89 cl::desc("Disable optimization of Qfloat operations for multiply."));
90
91namespace {
92const std::map<unsigned short, unsigned short> QFPInstMap{
93 {Hexagon::V6_vadd_hf, Hexagon::V6_vadd_qf16_mix},
94 {Hexagon::V6_vadd_qf16_mix, Hexagon::V6_vadd_qf16},
95 {Hexagon::V6_vadd_sf, Hexagon::V6_vadd_qf32_mix},
96 {Hexagon::V6_vadd_qf32_mix, Hexagon::V6_vadd_qf32},
97 {Hexagon::V6_vsub_hf, Hexagon::V6_vsub_qf16_mix},
98 {Hexagon::V6_vsub_qf16_mix, Hexagon::V6_vsub_qf16},
99 {Hexagon::V6_vsub_sf, Hexagon::V6_vsub_qf32_mix},
100 {Hexagon::V6_vsub_qf32_mix, Hexagon::V6_vsub_qf32},
101 {Hexagon::V6_vmpy_qf16_hf, Hexagon::V6_vmpy_qf16_mix_hf},
102 {Hexagon::V6_vmpy_qf16_mix_hf, Hexagon::V6_vmpy_qf16},
103 {Hexagon::V6_vmpy_qf32_hf, Hexagon::V6_vmpy_qf32_mix_hf},
104 {Hexagon::V6_vmpy_qf32_mix_hf, Hexagon::V6_vmpy_qf32_qf16},
105 {Hexagon::V6_vmpy_qf32_sf, Hexagon::V6_vmpy_qf32},
106 {Hexagon::V6_vilog2_sf, Hexagon::V6_vilog2_qf32},
107 {Hexagon::V6_vilog2_hf, Hexagon::V6_vilog2_qf16},
108 {Hexagon::V6_vabs_qf32_sf, Hexagon::V6_vabs_qf32_qf32},
109 {Hexagon::V6_vabs_qf16_hf, Hexagon::V6_vabs_qf16_qf16},
110 {Hexagon::V6_vneg_qf32_sf, Hexagon::V6_vneg_qf32_qf32},
111 {Hexagon::V6_vneg_qf16_hf, Hexagon::V6_vneg_qf16_qf16}};
112} // namespace
113
114namespace {
115struct HexagonQFPOptimizer : public MachineFunctionPass {
116public:
117 static char ID;
118
119 HexagonQFPOptimizer() : MachineFunctionPass(ID) {}
120
121 bool runOnMachineFunction(MachineFunction &MF) override;
122
123 bool optimizeQfp(MachineInstr *MI, MachineBasicBlock *MBB);
124
125 bool optimizeQfpTwoOp(MachineInstr *MI, MachineBasicBlock *MBB);
126
127 bool optimizeQfpOneOp(MachineInstr *MI, MachineBasicBlock *MBB);
128
129 StringRef getPassName() const override { return HEXAGON_QFP_OPTIMIZER; }
130
131 void getAnalysisUsage(AnalysisUsage &AU) const override {
132 AU.setPreservesCFG();
134 }
135
136private:
137 const HexagonSubtarget *HST = nullptr;
138 const HexagonInstrInfo *HII = nullptr;
139 const MachineRegisterInfo *MRI = nullptr;
140};
141
142char HexagonQFPOptimizer::ID = 0;
143} // namespace
144
145INITIALIZE_PASS(HexagonQFPOptimizer, "hexagon-qfp-optimizer",
146 HEXAGON_QFP_OPTIMIZER, false, false)
147
149 return new HexagonQFPOptimizer();
150}
151
152bool HexagonQFPOptimizer::optimizeQfp(MachineInstr *MI,
154
155 if (MI->getNumOperands() == 2)
156 return optimizeQfpOneOp(MI, MBB);
157 else if (MI->getNumOperands() == 3)
158 return optimizeQfpTwoOp(MI, MBB);
159 else
160 return false;
161}
162
163bool HexagonQFPOptimizer::optimizeQfpOneOp(MachineInstr *MI,
164 MachineBasicBlock *MBB) {
165
166 RegState Op0F = {};
167 auto It = QFPInstMap.find(MI->getOpcode());
168 if (It == QFPInstMap.end())
169 return false;
170
171 unsigned short InstTy = It->second;
172 // Get the reachind defs of MI
173 MachineInstr *DefMI = MRI->getVRegDef(MI->getOperand(1).getReg());
174 MachineOperand &Res = MI->getOperand(0);
175 if (!Res.isReg())
176 return false;
177
178 LLVM_DEBUG(dbgs() << "\n[Reaching Defs of operands]: "; DefMI->dump());
179 MachineInstr *ReachDefDef = nullptr;
180
181 // Get the reaching def of the reaching def to check for W reg def
182 if (DefMI->getNumOperands() > 1 && DefMI->getOperand(1).isReg() &&
184 ReachDefDef = MRI->getVRegDef(DefMI->getOperand(1).getReg());
185 unsigned ReachDefOp = DefMI->getOpcode();
186 MachineInstrBuilder MIB;
187
188 // Check if the reaching def is a conversion
189 if (ReachDefOp == Hexagon::V6_vconv_sf_qf32 ||
190 ReachDefOp == Hexagon::V6_vconv_hf_qf16) {
191
192 // Return if the reaching def of reaching def is W type
193 if (ReachDefDef && MRI->getRegClass(ReachDefDef->getOperand(0).getReg()) ==
194 &Hexagon::HvxWRRegClass)
195 return false;
196
197 // Analyze the use operands of the conversion to get their KILL status
198 MachineOperand &SrcOp = DefMI->getOperand(1);
199 Op0F = getKillRegState(SrcOp.isKill());
200 SrcOp.setIsKill(false);
201 MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())
202 .addReg(SrcOp.getReg(), Op0F, SrcOp.getSubReg());
203 LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());
204 return true;
205 }
206 return false;
207}
208
209bool HexagonQFPOptimizer::optimizeQfpTwoOp(MachineInstr *MI,
210 MachineBasicBlock *MBB) {
211
212 RegState Op0F = {};
213 RegState Op1F = {};
214 auto It = QFPInstMap.find(MI->getOpcode());
215 if (It == QFPInstMap.end())
216 return false;
217 unsigned short InstTy = It->second;
218 // Get the reaching defs of MI, DefMI1 and DefMI2
219 MachineInstr *DefMI1 = nullptr;
220 MachineInstr *DefMI2 = nullptr;
221
222 if (MI->getOperand(1).isReg())
223 DefMI1 = MRI->getVRegDef(MI->getOperand(1).getReg());
224 if (MI->getOperand(2).isReg())
225 DefMI2 = MRI->getVRegDef(MI->getOperand(2).getReg());
226 if (!DefMI1 || !DefMI2)
227 return false;
228
229 MachineOperand &Res = MI->getOperand(0);
230 if (!Res.isReg())
231 return false;
232
233 MachineInstr *Inst1 = nullptr;
234 MachineInstr *Inst2 = nullptr;
235 LLVM_DEBUG(dbgs() << "\n[Reaching Defs of operands]: "; DefMI1->dump();
236 DefMI2->dump());
237
238 // Get the reaching defs of DefMI
239 if (DefMI1->getNumOperands() > 1 && DefMI1->getOperand(1).isReg() &&
240 DefMI1->getOperand(1).getReg().isVirtual())
241 Inst1 = MRI->getVRegDef(DefMI1->getOperand(1).getReg());
242
243 if (DefMI2->getNumOperands() > 1 && DefMI2->getOperand(1).isReg() &&
244 DefMI2->getOperand(1).getReg().isVirtual())
245 Inst2 = MRI->getVRegDef(DefMI2->getOperand(1).getReg());
246
247 unsigned Def1OP = DefMI1->getOpcode();
248 unsigned Def2OP = DefMI2->getOpcode();
249
250 MachineInstrBuilder MIB;
251
252 // Check if the both the reaching defs of MI are qf to sf/hf conversions
253 if ((Def1OP == Hexagon::V6_vconv_sf_qf32 &&
254 Def2OP == Hexagon::V6_vconv_sf_qf32) ||
255 (Def1OP == Hexagon::V6_vconv_hf_qf16 &&
256 Def2OP == Hexagon::V6_vconv_hf_qf16)) {
257
258 // If the reaching defs of DefMI are W register type, we return
259 if ((Inst1 && Inst1->getNumOperands() > 0 && Inst1->getOperand(0).isReg() &&
260 MRI->getRegClass(Inst1->getOperand(0).getReg()) ==
261 &Hexagon::HvxWRRegClass) ||
262 (Inst2 && Inst2->getNumOperands() > 0 && Inst2->getOperand(0).isReg() &&
263 MRI->getRegClass(Inst2->getOperand(0).getReg()) ==
264 &Hexagon::HvxWRRegClass))
265 return false;
266
267 // Analyze the use operands of the conversion to get their KILL status
268 MachineOperand &Src1 = DefMI1->getOperand(1);
269 MachineOperand &Src2 = DefMI2->getOperand(1);
270
271 Op0F = getKillRegState(Src1.isKill());
272 Src1.setIsKill(false);
273
274 Op1F = getKillRegState(Src2.isKill());
275 Src2.setIsKill(false);
276
277 if (MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf) {
278 auto OuterIt = QFPInstMap.find(MI->getOpcode());
279 if (OuterIt == QFPInstMap.end())
280 return false;
281 auto InnerIt = QFPInstMap.find(OuterIt->second);
282 if (InnerIt == QFPInstMap.end())
283 return false;
284 InstTy = InnerIt->second;
285 }
286
287 MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())
288 .addReg(Src1.getReg(), Op0F, Src1.getSubReg())
289 .addReg(Src2.getReg(), Op1F, Src2.getSubReg());
290 LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());
291 return true;
292
293 // Check if left operand's reaching def is a conversion to sf/hf
294 } else if (((Def1OP == Hexagon::V6_vconv_sf_qf32 &&
295 Def2OP != Hexagon::V6_vconv_sf_qf32) ||
296 (Def1OP == Hexagon::V6_vconv_hf_qf16 &&
297 Def2OP != Hexagon::V6_vconv_hf_qf16)) &&
298 !DefMI2->isPHI() &&
299 (MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf)) {
300
301 if (Inst1 && MRI->getRegClass(Inst1->getOperand(0).getReg()) ==
302 &Hexagon::HvxWRRegClass)
303 return false;
304
305 MachineOperand &Src1 = DefMI1->getOperand(1);
306 MachineOperand &Src2 = MI->getOperand(2);
307
308 Op0F = getKillRegState(Src1.isKill());
309 Src1.setIsKill(false);
310 Op1F = getKillRegState(Src2.isKill());
311 MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())
312 .addReg(Src1.getReg(), Op0F, Src1.getSubReg())
313 .addReg(Src2.getReg(), Op1F, Src2.getSubReg());
314 LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());
315 return true;
316
317 // Check if right operand's reaching def is a conversion to sf/hf
318 } else if (((Def1OP != Hexagon::V6_vconv_sf_qf32 &&
319 Def2OP == Hexagon::V6_vconv_sf_qf32) ||
320 (Def1OP != Hexagon::V6_vconv_hf_qf16 &&
321 Def2OP == Hexagon::V6_vconv_hf_qf16)) &&
322 !DefMI1->isPHI() &&
323 (MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf)) {
324 // The second operand of original instruction is converted.
325 if (Inst2 && MRI->getRegClass(Inst2->getOperand(0).getReg()) ==
326 &Hexagon::HvxWRRegClass)
327 return false;
328
329 MachineOperand &Src1 = MI->getOperand(1);
330 MachineOperand &Src2 = DefMI2->getOperand(1);
331
332 Op1F = getKillRegState(Src2.isKill());
333 Src2.setIsKill(false);
334 Op0F = getKillRegState(Src1.isKill());
335 if (InstTy == Hexagon::V6_vsub_qf16_mix ||
336 InstTy == Hexagon::V6_vsub_qf32_mix) {
337 if (!HST->useHVXV81Ops())
338 // vsub_(hf|sf)_mix insts are only avlbl on hvx81+
339 return false;
340 // vsub is not commutative w.r.t. operands -> treat it as a special case
341 // to choose the correct mix instruction.
342 if (Def2OP == Hexagon::V6_vconv_sf_qf32)
343 InstTy = Hexagon::V6_vsub_sf_mix;
344 else if (Def2OP == Hexagon::V6_vconv_hf_qf16)
345 InstTy = Hexagon::V6_vsub_hf_mix;
346 MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())
347 .addReg(Src1.getReg(), Op0F, Src1.getSubReg())
348 .addReg(Src2.getReg(), Op1F, Src2.getSubReg());
349 } else {
350 MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), HII->get(InstTy), Res.getReg())
351 .addReg(Src2.getReg(), Op1F,
352 Src2.getSubReg()) // Notice the operands are flipped.
353 .addReg(Src1.getReg(), Op0F, Src1.getSubReg());
354 }
355 LLVM_DEBUG(dbgs() << "\n[Inserting]: "; MIB.getInstr()->dump());
356 return true;
357 }
358
359 return false;
360}
361
362bool HexagonQFPOptimizer::runOnMachineFunction(MachineFunction &MF) {
363
364 bool Changed = false;
365
367 return Changed;
368
369 HST = &MF.getSubtarget<HexagonSubtarget>();
370 if (!HST->useHVXV68Ops() || !HST->usePackets() ||
371 skipFunction(MF.getFunction()))
372 return false;
373 HII = HST->getInstrInfo();
374 MRI = &MF.getRegInfo();
375
377 LLVM_DEBUG(dbgs() << "\n=== Running QFPOptimzer Pass for : " << MF.getName()
378 << " Optimize intermediate conversions ===\n");
379 while (MBBI != MF.end()) {
380 MachineBasicBlock *MBB = &*MBBI;
382 while (MII != MBBI->instr_end()) {
383 MachineInstr *MI = &*MII;
384 ++MII; // As MI might be removed.
385 if (QFPInstMap.count(MI->getOpcode())) {
386 auto OpC = MI->getOpcode();
387 if (DisableQFOptForMul && HII->isQFPMul(MI))
388 continue;
389 if (OpC != Hexagon::V6_vconv_sf_qf32 &&
390 OpC != Hexagon::V6_vconv_hf_qf16) {
391 LLVM_DEBUG(dbgs() << "\n###Analyzing for removal: "; MI->dump());
392 if (optimizeQfp(MI, MBB)) {
393 MI->eraseFromParent();
394 LLVM_DEBUG(dbgs() << "\t....Removing....");
395 Changed = true;
396 }
397 }
398 }
399 }
400 ++MBBI;
401 }
402 return Changed;
403}
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
#define LLVM_DEBUG(...)
Definition Debug.h:119
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:275
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, RegState Flags={}, 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.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
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.
RegState
Flags to represent properties of register accesses.
constexpr RegState getKillRegState(bool B)
FunctionPass * createHexagonQFPOptimizer()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209