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"
68#include "llvm/CodeGen/MachineBasicBlock.h"
69#include "llvm/CodeGen/MachineFunction.h"
70#include "llvm/CodeGen/MachineFunctionPass.h"
71#include "llvm/CodeGen/MachineInstr.h"
72#include "llvm/CodeGen/MachineOperand.h"
73#include "llvm/CodeGen/Passes.h"
74#include "llvm/Pass.h"
75#include "llvm/Support/CommandLine.h"
76#include "llvm/Support/Debug.h"
77#include "llvm/Support/raw_ostream.h"
78#include <map>
79
80#define DEBUG_TYPE "hexagon-qfp-optimizer"
81
82using namespace llvm;
83
84cl::opt<bool>
85 DisableQFOptimizer("disable-qfp-opt", cl::init(Val: false),
86 cl::desc("Disable optimization of Qfloat operations."));
87cl::opt<bool> DisableQFOptForMul(
88 "disable-qfp-opt-mul", cl::init(Val: 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();
133 MachineFunctionPass::getAnalysisUsage(AU);
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
148FunctionPass *llvm::createHexagonQFPOptimizer() {
149 return new HexagonQFPOptimizer();
150}
151
152bool HexagonQFPOptimizer::optimizeQfp(MachineInstr *MI,
153 MachineBasicBlock *MBB) {
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(x: 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(Reg: MI->getOperand(i: 1).getReg());
174 MachineOperand &Res = MI->getOperand(i: 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(i: 1).isReg() &&
183 DefMI->getOperand(i: 1).getReg().isVirtual())
184 ReachDefDef = MRI->getVRegDef(Reg: DefMI->getOperand(i: 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(Reg: ReachDefDef->getOperand(i: 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(i: 1);
199 Op0F = getKillRegState(B: SrcOp.isKill());
200 SrcOp.setIsKill(false);
201 MIB = BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: HII->get(Opcode: InstTy), DestReg: Res.getReg())
202 .addReg(RegNo: SrcOp.getReg(), Flags: Op0F, SubReg: 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(x: 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(i: 1).isReg())
223 DefMI1 = MRI->getVRegDef(Reg: MI->getOperand(i: 1).getReg());
224 if (MI->getOperand(i: 2).isReg())
225 DefMI2 = MRI->getVRegDef(Reg: MI->getOperand(i: 2).getReg());
226 if (!DefMI1 || !DefMI2)
227 return false;
228
229 MachineOperand &Res = MI->getOperand(i: 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(i: 1).isReg() &&
240 DefMI1->getOperand(i: 1).getReg().isVirtual())
241 Inst1 = MRI->getVRegDef(Reg: DefMI1->getOperand(i: 1).getReg());
242
243 if (DefMI2->getNumOperands() > 1 && DefMI2->getOperand(i: 1).isReg() &&
244 DefMI2->getOperand(i: 1).getReg().isVirtual())
245 Inst2 = MRI->getVRegDef(Reg: DefMI2->getOperand(i: 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(i: 0).isReg() &&
260 MRI->getRegClass(Reg: Inst1->getOperand(i: 0).getReg()) ==
261 &Hexagon::HvxWRRegClass) ||
262 (Inst2 && Inst2->getNumOperands() > 0 && Inst2->getOperand(i: 0).isReg() &&
263 MRI->getRegClass(Reg: Inst2->getOperand(i: 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(i: 1);
269 MachineOperand &Src2 = DefMI2->getOperand(i: 1);
270
271 Op0F = getKillRegState(B: Src1.isKill());
272 Src1.setIsKill(false);
273
274 Op1F = getKillRegState(B: Src2.isKill());
275 Src2.setIsKill(false);
276
277 if (MI->getOpcode() != Hexagon::V6_vmpy_qf32_sf) {
278 auto OuterIt = QFPInstMap.find(x: MI->getOpcode());
279 if (OuterIt == QFPInstMap.end())
280 return false;
281 auto InnerIt = QFPInstMap.find(x: OuterIt->second);
282 if (InnerIt == QFPInstMap.end())
283 return false;
284 InstTy = InnerIt->second;
285 }
286
287 MIB = BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: HII->get(Opcode: InstTy), DestReg: Res.getReg())
288 .addReg(RegNo: Src1.getReg(), Flags: Op0F, SubReg: Src1.getSubReg())
289 .addReg(RegNo: Src2.getReg(), Flags: Op1F, SubReg: 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(Reg: Inst1->getOperand(i: 0).getReg()) ==
302 &Hexagon::HvxWRRegClass)
303 return false;
304
305 MachineOperand &Src1 = DefMI1->getOperand(i: 1);
306 MachineOperand &Src2 = MI->getOperand(i: 2);
307
308 Op0F = getKillRegState(B: Src1.isKill());
309 Src1.setIsKill(false);
310 Op1F = getKillRegState(B: Src2.isKill());
311 MIB = BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: HII->get(Opcode: InstTy), DestReg: Res.getReg())
312 .addReg(RegNo: Src1.getReg(), Flags: Op0F, SubReg: Src1.getSubReg())
313 .addReg(RegNo: Src2.getReg(), Flags: Op1F, SubReg: 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(Reg: Inst2->getOperand(i: 0).getReg()) ==
326 &Hexagon::HvxWRRegClass)
327 return false;
328
329 MachineOperand &Src1 = MI->getOperand(i: 1);
330 MachineOperand &Src2 = DefMI2->getOperand(i: 1);
331
332 Op1F = getKillRegState(B: Src2.isKill());
333 Src2.setIsKill(false);
334 Op0F = getKillRegState(B: 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(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: HII->get(Opcode: InstTy), DestReg: Res.getReg())
347 .addReg(RegNo: Src1.getReg(), Flags: Op0F, SubReg: Src1.getSubReg())
348 .addReg(RegNo: Src2.getReg(), Flags: Op1F, SubReg: Src2.getSubReg());
349 } else {
350 MIB = BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: HII->get(Opcode: InstTy), DestReg: Res.getReg())
351 .addReg(RegNo: Src2.getReg(), Flags: Op1F,
352 SubReg: Src2.getSubReg()) // Notice the operands are flipped.
353 .addReg(RegNo: Src1.getReg(), Flags: Op0F, SubReg: 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
366 if (DisableQFOptimizer)
367 return Changed;
368
369 HST = &MF.getSubtarget<HexagonSubtarget>();
370 if (!HST->useHVXV68Ops() || !HST->usePackets() ||
371 skipFunction(F: MF.getFunction()))
372 return false;
373 HII = HST->getInstrInfo();
374 MRI = &MF.getRegInfo();
375
376 MachineFunction::iterator MBBI = MF.begin();
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;
381 MachineBasicBlock::iterator MII = MBBI->instr_begin();
382 while (MII != MBBI->instr_end()) {
383 MachineInstr *MI = &*MII;
384 ++MII; // As MI might be removed.
385 if (QFPInstMap.count(x: MI->getOpcode())) {
386 auto OpC = MI->getOpcode();
387 if (DisableQFOptForMul && HII->isQFPMul(MF: 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}
404