LLVM 24.0.0git
HexagonPostRAHandleQFP.cpp
Go to the documentation of this file.
1//===--------------------- HexagonPostRAHandleQFP.cpp --------------------------
2//===//
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// For v79 and above, we generate qf operations for HVX which includes vadd,
10// vsub and vmpy instructions. These qf operations with qf operands are fast,
11// maintain similar accuracy as IEEE and saves power.
12//
13// However, these qf operands should always be converted back to IEEE format
14// when used in non-HVX instructions. This is because of how the qf values
15// are stored in memory. qf operands have 4 extra bits. If used in non-HVX
16// operations, these bits get dropped resulting in incorrect value being
17// used. So, before use in any non-HVX operation we need to convert these
18// qf values to IEEE format.
19//
20// During register allocation, when no more physical registers are available
21// the qf operands may be spilled to memory. This instantly causes loss of
22// accuracy. This pass prevents that by:
23// 1. Inserting qf type to IEEE type conversion instructions before the spill.
24// 2. Iterating over the uses of qf def (created before the spill) and
25// changing their opcodes to handle IEEE type operands for saturating
26// instructions. This is because, the refills will use IEEE type operands, but
27// the instructions will still assume qf operands. For non-saturating
28// instructions which uses qf, we incorporate a conversion to IEEE before that.
29// 3. Iterating over the uses of qf def created by the spill and replacing
30// them with appropiate opcode (which uses IEEE operands) for saturating
31// instructions. For non-saturating instructions which uses qf,
32// we incorporate a conversion to IEEE before that.
33// 4. Iterating over the copy instructions and checking their uses,
34// inserting conversions from qf to IEEE whenever required. The conversions
35// are inserted after their reaching def since there can be multiple defs
36// for use in non-SSA form.
37//
38// To get the use-def chains, we make use of Register DataFlow Graph (RDF),
39// since after register allocation SSA form is lost. This can be done during
40// spills and fills during Frame Lowering for register allocation. However,
41// that was abandoned due to the intermediate state of the code.
42// Liveness is preserved in this pass.
43//
44// NOTE:
45// Saturating instructions: Instructions for which transformation involves
46// only changing the opcode. Eg. vmpy(qf32, sf) saturates to vmpy(sf, sf) when
47// we see that the first operand is now a sf type.
48// Non-Saturating instructions: Instructions for which conversion(s) have
49// to be inserted. Eg. Vd.f8=Vu.qf16. If the use operand is now hf type,
50// we have to insert a conversion qf16 = hf before this instruction.
51//
52// FIXME tags have been added for potential errors, along with the underlying
53// assumption.
54// FIXME Implement v81 specific optimizations as below. At the moment, we add
55// converts.
56// Vd.qf16=Vu.hf
57// Vd.qf16=Vu.qf16
58// Vd.qf32=Vu.qf32
59// Vd.qf32=Vu.sf
60//===---------------------------------------------------------------------===//
61
71#include "llvm/CodeGen/Passes.h"
79#include "llvm/Support/Debug.h"
82
83#define DEBUG_TYPE "handle-qfp"
84
85using namespace llvm;
86using namespace rdf;
87
89
91 "disable-handle-qfp", cl::init(false),
92 cl::desc("Disable handling of Qfloat spills/refills after register "
93 "allocation."));
94
96 "enable-postra-xqf-check", cl::init(false),
97 cl::desc("Enable ABI compliance for xqf operands post regalloc."));
98
99namespace llvm {
102} // namespace llvm
103
104// QF Instructions list which need to be analyzed.
105// The value of the key denotes a pair
106// pair.first|pair.second = True if IEEE type, false otherwise.
107// We only need to change the opcode to handling qf/sf
108// misuses for these, or these instructions can be 'saturated'.
110 {Hexagon::V6_vadd_qf16_mix, {false, true}},
111 {Hexagon::V6_vadd_qf16, {false, false}},
112 {Hexagon::V6_vadd_qf32_mix, {false, true}},
113 {Hexagon::V6_vadd_qf32, {false, false}},
114 {Hexagon::V6_vsub_qf16_mix, {false, true}},
115 {Hexagon::V6_vsub_hf_mix, {true, false}},
116 {Hexagon::V6_vsub_qf16, {false, false}},
117 {Hexagon::V6_vsub_qf32_mix, {false, true}},
118 {Hexagon::V6_vsub_sf_mix, {true, false}},
119 {Hexagon::V6_vsub_qf32, {false, false}},
120 {Hexagon::V6_vmpy_qf16_mix_hf, {false, true}},
121 {Hexagon::V6_vmpy_qf16, {false, false}},
122 {Hexagon::V6_vmpy_qf32_mix_hf, {false, true}},
123 {Hexagon::V6_vmpy_qf32_qf16, {false, false}},
124 {Hexagon::V6_vmpy_qf32, {false, false}},
125 {Hexagon::V6_vmpy_rt_qf16, {false, true}},
126 // These opcodes take a single operand only.
127 // Second placeholder op is true always.
128 {Hexagon::V6_vabs_qf32_qf32, {false, true}},
129 {Hexagon::V6_vabs_qf16_qf16, {false, true}},
130 {Hexagon::V6_vneg_qf32_qf32, {false, true}},
131 {Hexagon::V6_vneg_qf16_qf16, {false, true}},
132 {Hexagon::V6_vilog2_qf32, {false, true}},
133 {Hexagon::V6_vilog2_qf16, {false, true}},
134 {Hexagon::V6_vconv_qf32_qf32, {false, true}},
135 {Hexagon::V6_vconv_qf16_qf16, {false, true}},
136};
137
138// This holds the instruction opcodes for which there are
139// no 'saturating' opcodes. The only way is to insert
140// convert instructions before them.
142 Hexagon::V6_vconv_hf_qf16, Hexagon::V6_vconv_hf_qf32,
143 Hexagon::V6_vconv_sf_qf32,
144 // v81 instructions
145 Hexagon::V6_vconv_bf_qf32, Hexagon::V6_vconv_f8_qf16};
146
147namespace {
148class HexagonPostRAHandleQFP : public MachineFunctionPass {
149public:
150 static char ID;
151 HexagonPostRAHandleQFP() : MachineFunctionPass(ID) {
152 PassRegistry &R = *PassRegistry::getPassRegistry();
154 }
155 StringRef getPassName() const override {
156 return "Hexagon handle QFloat spills and refills post RA.";
157 }
158 void getAnalysisUsage(AnalysisUsage &AU) const override {
160 AU.addRequired<MachineDominatorTreeWrapperPass>();
161 AU.addRequired<MachineDominanceFrontierWrapperPass>();
162 AU.setPreservesCFG();
163 }
164 bool runOnMachineFunction(MachineFunction &MF) override;
165
166private:
167 // QFUses collects the instructions which uses QF operands.
168 // These have to be deleted and transformed to opcodes
169 // to denote usage of IEEE operands.
170 // It might involve changing the order of the Register operands.
171 using QFUses = std::map<MachineInstr *, std::pair<bool, bool>>;
172 QFUses QFUsesMap;
173
174 // Holds the Register Dataglow Graph.
175 DataFlowGraph *DFG = nullptr;
176
177 // Stores spill nodes and their reaching definition instructions
178 // which generates the qf operand to be stored.
179 std::vector<std::pair<MachineInstr *, NodeAddr<DefNode *>>> SpillMIs;
180 // Stores the refill nodes consisting of load instructions.
181 std::vector<NodeAddr<DefNode *>> RefillMIs;
182
183 // Stores the type of op.
184 enum ConvOperand {
185 Undefined = 0x0,
186 Lo = 0x1,
187 Hi = 0x2,
188 HiLo = 0x3,
189 };
190 // Stores the convert instructions which take qf operands.
191 MapVector<MachineInstr *, unsigned> QFNonSatMIs;
192
193 // Stores the qf-generating vmul/vadd/etc. nodes with mutiple reaching defs
194 std::set<NodeAddr<StmtNode *>> PossibleMultiReachDefs;
195 // Qf generating instructions to ignore. Do not insert conversion instruction
196 // to sf/hf from qf, if the instr is present in this list; since that means
197 // a conversion has already been inserted after the instruction.
198 SmallPtrSet<MachineInstr *, 4> IgnoreInsertConvList;
199
200 // Register type
201 enum class RegType { qf32, qf16, qf32_double, qf16_double, ieee, undefined };
202 // Stores the copy instructions which their reaching def, along with the op
203 // type
204 std::map<std::pair<NodeAddr<DefNode *>, NodeAddr<DefNode *>>, RegType>
205 QFCopys;
206
207 // Stores the reaching defs of copies whose result has to be converted to IEEE
208 DenseMap<MachineInstr *, RegType> ReachDefOfCopies;
209
210 // Stores copies which need to be converted back to qf. The uses of these
211 // copies feed to qf type instructions and hence can be converted back to qf
212 // type.
213 DenseMap<MachineInstr *, std::pair<NodeAddr<DefNode *>, RegType>>
214 ConvertToQfCopies;
215
216 // Subregister kill set for a doubletype use. The pair of bool,bool
217 // represents the hi and lo subregisters of the double register.
218 DenseMap<MachineInstr *, std::pair<bool, bool>> SubRegKillSet;
219
220 const HexagonInstrInfo *HII = nullptr;
221 const HexagonRegisterInfo *HRI = nullptr;
222 MachineRegisterInfo *MRI = nullptr;
223 Liveness *LV = nullptr;
224 const HexagonSubtarget *HST = nullptr;
225
226 void collectQFPStackSpill(NodeAddr<StmtNode *> *);
227 void collectQFPStackRefill(NodeAddr<StmtNode *> *);
228 void collectCopies(NodeAddr<StmtNode *> *);
229 bool HandleRefills();
230 bool HandleSpills();
231 bool HandleCopies();
232 bool HandleNonSatInstr();
233 bool HandleMultiReachingDefs();
234 bool HandleReachDefOfCopies();
235 bool HandleConvertToQfCopies();
236 RegType HasQfUses(NodeAddr<DefNode *>, MachineInstr *);
237 void collectConvQFInstr(NodeAddr<DefNode *> &);
238 void collectQFUses(NodeAddr<DefNode *>, MachineInstr *DefMI);
239 void conditionallyInsert(MachineInstr &, Register &);
240
241 // Helper functions
242 unsigned short getreplacedQFOpcode(unsigned, bool, bool);
243 MCPhysReg findAllocatableReg(MachineInstr *MI) const;
244 void insertIEEEToQF(MachineInstr *, Register, MachineOperand, bool is32bit);
245 void collectLivenessForSubregs(NodeAddr<UseNode *> &);
246 void insertInstr(MachineInstr *, unsigned, unsigned, unsigned, RegState);
247};
248} // namespace
249
250// This class handles spurious vector instrutions which do not
251// follow the ABI. For eg, vcombine(qf,qf) takes qf operands
252// instead of IEEE type. This diagnostic pass can be used
253// as a final verifier for XQF implementation. Turned off by
254// default
256public:
258 : G(&G), L(&L), HII(HII) {}
259 // Deleting default constructor to handle misconstruction
261
262 void runCompliance() const;
263 void print_warning(Twine &, MachineInstr *, MachineInstr *) const;
264
265private:
266 DataFlowGraph *G = nullptr;
267 Liveness *L = nullptr;
268 const HexagonInstrInfo *HII = nullptr;
269};
270
272 MachineInstr *UseMI) const {
273#ifndef NDEBUG
274 dbgs() << wstr;
275 dbgs() << "\n\tDef:";
276 DefMI->dump();
277 // dbgs() << "\t" << DefMI->getParent()->getName();
278 dbgs() << "\tUse:";
279 UseMI->dump();
280 // dbgs() << "\t" << UseMI->getParent()->getName();
281#endif // NDEBUG
282}
283
284// This static function gets all reached uses of a def.
285// When it encounters a phi node, it goes over the
286// reached uses of the phi node too.
289 bool comprehensive = false) {
290 RegisterRef DR = DA.Addr->getRegRef(*G);
291 NodeAddr<StmtNode *> DefStmt = DA.Addr->getOwner(*G);
292 MachineInstr *Instr = DefStmt.Addr->getCode();
293 auto UseSet = L->getAllReachedUses(DR, DA);
294
295 for (auto UI : UseSet) {
296 NodeAddr<UseNode *> UA = G->addr<UseNode *>(UI);
297
298 MachineFunction *MF = Instr->getMF();
299 const auto &HRI = MF->getSubtarget<HexagonSubtarget>().getRegisterInfo();
300 Register RR = UA.Addr->getRegRef(*G).Id;
301 if (HRI->isFakeReg(RR))
302 continue;
303
304 if (UA.Addr->getFlags() & NodeAttrs::PhiRef) {
305 NodeAddr<PhiNode *> PA = UA.Addr->getOwner(*G);
306 NodeId id = PA.Id;
307 const Liveness::RefMap &phiUse = L->getRealUses(id);
308 for (auto I : phiUse) {
309 if (!G->getPRI().alias(RegisterRef(I.first), DR))
310 continue;
311 auto phiUseSet = I.second;
312 for (auto phiUI : phiUseSet) {
313 NodeAddr<UseNode *> phiUA = G->addr<UseNode *>(phiUI.first);
314 UNodeSet.insert(phiUA.Id);
315 }
316 }
317 } else {
318 // FIXME Due to bug in RDF, check if the reaching def of the use
319 // reaches this instruction
320 if (comprehensive) {
321 UNodeSet.insert(UA.Id);
322 continue;
323 }
324 NodeAddr<StmtNode *> UseStmt = UA.Addr->getOwner(*G);
325 for (NodeAddr<UseNode *> UA : UseStmt.Addr->members_if(G->IsUse, *G)) {
326 NodeId QFPDefNode = UA.Addr->getReachingDef();
327 NodeAddr<DefNode *> RegDef = G->addr<DefNode *>(QFPDefNode);
328 // FIXME Reaching def computation error
329 if (QFPDefNode == 0)
330 continue;
331 NodeAddr<StmtNode *> RegStmt = RegDef.Addr->getOwner(*G);
332 MachineInstr *ReachDefInstr = RegStmt.Addr->getCode();
333 if (ReachDefInstr && ReachDefInstr == Instr)
334 UNodeSet.insert(UA.Id);
335 }
336 }
337 }
338}
339
341 NodeAddr<FuncNode *> FA = G->getFunc();
342 for (NodeAddr<BlockNode *> BA : FA.Addr->members(*G)) {
343 for (auto IA : BA.Addr->members(*G)) {
344 if (!G->IsCode<NodeAttrs::Stmt>(IA))
345 continue;
346 NodeAddr<StmtNode *> SA = IA;
347 MachineInstr *DefMI = SA.Addr->getCode();
348 if (DefMI->isDebugInstr() || DefMI->isInlineAsm())
349 continue;
350 auto NodeBase = SA.Addr->members_if(G->IsDef, *G);
351 if (NodeBase.empty())
352 continue;
353 NodeAddr<DefNode *> DfNode = NodeBase.front();
354
355 NodeSet UseSet;
356 getAllRealUses(DfNode, UseSet, L, G, true);
357 for (auto UI : UseSet) {
358 NodeAddr<UseNode *> UA = G->addr<UseNode *>(UI);
359 if (UA.Addr->getFlags() & NodeAttrs::PhiRef)
360 continue;
361 NodeAddr<StmtNode *> UseStmt = UA.Addr->getOwner(*G);
362 MachineInstr *UseMI = UseStmt.Addr->getCode();
363 if (UseMI->isDebugInstr() || UseMI->isInlineAsm())
364 continue;
365 unsigned OpNo = UA.Addr->getOp().getOperandNo();
366 if (HII->usesQF32Operand(UseMI, OpNo) && !HII->isQFP32Instr(DefMI)) {
367 Twine wstr(Twine("Mismatch: sf type used as qf32 at operand ")
368 .concat(Twine(OpNo)));
369 print_warning(wstr, DefMI, UseMI);
370 } else if (!HII->usesQF32Operand(UseMI, OpNo) &&
371 HII->isQFP32Instr(DefMI)) {
372 Twine wstr(Twine("Mismatch: qf32 type used as sf at operand ")
373 .concat(Twine(OpNo)));
374 print_warning(wstr, DefMI, UseMI);
375 } else if (HII->usesQF16Operand(UseMI, OpNo) &&
376 !HII->isQFP16Instr(DefMI)) {
377 Twine wstr(Twine("Mismatch: hf type used as qf16 at operand ")
378 .concat(Twine(OpNo)));
379 print_warning(wstr, DefMI, UseMI);
380 } else if (!HII->usesQF16Operand(UseMI, OpNo) &&
381 HII->isQFP16Instr(DefMI)) {
382 Twine wstr(Twine("Mismatch: qf16 type used as hf at operand ")
383 .concat(Twine(OpNo)));
384 print_warning(wstr, DefMI, UseMI);
385 }
386 }
387 }
388 }
389}
390
391char HexagonPostRAHandleQFP::ID = 0;
392
393namespace llvm {
394char &HexagonPostRAHandleQFPID = HexagonPostRAHandleQFP::ID;
395}
396
397// Check whether the instruction is added already, if not add it
398// along with the Register values and qf type.
399// If already added, then check the register values and edit them.
400void HexagonPostRAHandleQFP::conditionallyInsert(MachineInstr &MI,
401 Register &DefReg) {
402 LLVM_DEBUG(dbgs() << "\nCollecting instruction using QF: "; MI.dump());
403 // check if the key exists.
404 Register Reg1 = MI.getOperand(1).getReg();
405
406 // If the use is a unary operation, make second register point to Defreg
407 // This ensures that secondOp is always true
408 Register Reg2 = MI.getNumOperands() == 2 ? DefReg : MI.getOperand(2).getReg();
409
410 if (QFUsesMap.find(&MI) != QFUsesMap.end()) {
411 auto Entry = QFUsesMap[&MI];
412 bool firstOp = ((Reg1 == DefReg) ? true : false) | Entry.first;
413 bool secondOp = ((Reg2 == DefReg) ? true : false) | Entry.second;
414 QFUsesMap[&MI] = std::make_pair(firstOp, secondOp);
415
416 } else { // encountered first time.
417 // Get the default type of the operand:
418 // True : IEEE type
419 // False : QF type
420 auto defaultPair = QFPSatInstsMap[MI.getOpcode()];
421 bool firstOp = (Reg1 == DefReg) ? true : defaultPair.first;
422 bool secondOp = (Reg2 == DefReg) ? true : defaultPair.second;
423 QFUsesMap[&MI] = std::make_pair(firstOp, secondOp);
424 }
425}
426
427unsigned short HexagonPostRAHandleQFP::getreplacedQFOpcode(unsigned srcOpcode,
428 bool firstOp,
429 bool secondOp) {
430 if (firstOp && secondOp) {
431 switch (srcOpcode) {
432 case Hexagon::V6_vadd_qf32:
433 case Hexagon::V6_vadd_qf32_mix:
434 return Hexagon::V6_vadd_sf;
435 case Hexagon::V6_vadd_qf16:
436 case Hexagon::V6_vadd_qf16_mix:
437 return Hexagon::V6_vadd_hf;
438
439 case Hexagon::V6_vsub_qf32:
440 case Hexagon::V6_vsub_qf32_mix:
441 case Hexagon::V6_vsub_sf_mix:
442 return Hexagon::V6_vsub_sf;
443 case Hexagon::V6_vsub_qf16:
444 case Hexagon::V6_vsub_qf16_mix:
445 case Hexagon::V6_vsub_hf_mix:
446 return Hexagon::V6_vsub_hf;
447
448 case Hexagon::V6_vmpy_qf32:
449 return Hexagon::V6_vmpy_qf32_sf;
450 case Hexagon::V6_vmpy_qf16:
451 case Hexagon::V6_vmpy_qf16_mix_hf:
452 return Hexagon::V6_vmpy_qf16_hf;
453 case Hexagon::V6_vmpy_qf32_qf16:
454 case Hexagon::V6_vmpy_qf32_mix_hf:
455 return Hexagon::V6_vmpy_qf32_hf;
456
457 case Hexagon::V6_vmpy_rt_qf16:
458 return Hexagon::V6_vmpy_rt_hf;
459 // v81 opcodes start
460 case Hexagon::V6_vabs_qf32_qf32:
461 return Hexagon::V6_vabs_qf32_sf;
462 case Hexagon::V6_vabs_qf16_qf16:
463 return Hexagon::V6_vabs_qf16_hf;
464 case Hexagon::V6_vneg_qf32_qf32:
465 return Hexagon::V6_vneg_qf32_sf;
466 case Hexagon::V6_vneg_qf16_qf16:
467 return Hexagon::V6_vneg_qf16_hf;
468 case Hexagon::V6_vilog2_qf32:
469 return Hexagon::V6_vilog2_sf;
470 case Hexagon::V6_vilog2_qf16:
471 return Hexagon::V6_vilog2_hf;
472 case Hexagon::V6_vconv_qf32_qf32:
473 return Hexagon::V6_vconv_qf32_sf;
474 case Hexagon::V6_vconv_qf16_qf16:
475 return Hexagon::V6_vconv_qf16_hf;
476 // v81 opcodes end
477
478 default:
479 llvm_unreachable("Invalid qf opcode in this scenario!");
480 }
481 } else if (firstOp) {
482 switch (srcOpcode) {
483 case Hexagon::V6_vadd_qf32:
484 return Hexagon::V6_vadd_qf32_mix; // interchange reqd
485 case Hexagon::V6_vadd_qf16:
486 return Hexagon::V6_vadd_qf16_mix; // interchange reqd
487
488 case Hexagon::V6_vsub_qf32:
489 if (HST->useHVXV81Ops())
490 return Hexagon::V6_vsub_sf_mix;
491 else if (HST->useHVXV79Ops())
492 return Hexagon::V6_vsub_sf; // conv reqd
493 else
494 llvm_unreachable("Invalid Hexagon Arch for this scenario!");
495 case Hexagon::V6_vsub_qf16:
496 if (HST->useHVXV81Ops())
497 return Hexagon::V6_vsub_hf_mix;
498 else if (HST->useHVXV79Ops())
499 return Hexagon::V6_vsub_hf; // conv reqd
500 else
501 llvm_unreachable("Invalid Hexagon Arch for this scenario!");
502 case Hexagon::V6_vsub_qf32_mix:
503 return Hexagon::V6_vsub_sf;
504 case Hexagon::V6_vsub_qf16_mix:
505 return Hexagon::V6_vsub_hf;
506
507 // This opcode does not have a mixed type. Hence if one
508 // of op1 or op2 is IEEE type and another qf type,
509 // send the opcode which takes in both as IEEE type.
510 case Hexagon::V6_vmpy_qf32:
511 return Hexagon::V6_vmpy_qf32_sf; // conv reqd
512 case Hexagon::V6_vmpy_qf16:
513 return Hexagon::V6_vmpy_qf16_mix_hf; // interchange reqd
514 case Hexagon::V6_vmpy_qf32_qf16:
515 return Hexagon::V6_vmpy_qf32_mix_hf; // interchange reqd
516
517 default:
518 return srcOpcode;
519 }
520 } else if (secondOp) {
521 switch (srcOpcode) {
522 case Hexagon::V6_vadd_qf32:
523 return Hexagon::V6_vadd_qf32_mix;
524 case Hexagon::V6_vadd_qf16:
525 return Hexagon::V6_vadd_qf16_mix;
526
527 case Hexagon::V6_vsub_qf32:
528 return Hexagon::V6_vsub_qf32_mix;
529 case Hexagon::V6_vsub_qf16:
530 return Hexagon::V6_vsub_qf16_mix;
531 case Hexagon::V6_vsub_sf_mix:
532 return Hexagon::V6_vsub_sf;
533 case Hexagon::V6_vsub_hf_mix:
534 return Hexagon::V6_vsub_hf;
535
536 case Hexagon::V6_vmpy_qf32:
537 return Hexagon::V6_vmpy_qf32_sf; // conv reqd
538
539 case Hexagon::V6_vmpy_qf16:
540 return Hexagon::V6_vmpy_qf16_mix_hf;
541 case Hexagon::V6_vmpy_qf32_qf16:
542 return Hexagon::V6_vmpy_qf32_mix_hf;
543
544 default:
545 return srcOpcode;
546 }
547 } else
548 return srcOpcode;
549}
550
551// Insert IEEE to Qf conversion instructions
552// is32bit: If true, SrcReg holds sf type, else a hf type
553void HexagonPostRAHandleQFP::insertIEEEToQF(MachineInstr *MI, Register SrcReg,
554 MachineOperand SrcOp,
555 bool is32bit = false) {
556
557 auto MBB = MI->getParent();
558 MachineInstrBuilder MIB;
559 const DebugLoc &DL = MI->getDebugLoc();
560
561 if (HST->useHVXV81Ops()) {
562 auto Op = is32bit ? Hexagon::V6_vconv_qf32_sf : Hexagon::V6_vconv_qf16_hf;
563 MIB = BuildMI(*MBB, *MI, DL, HII->get(Op), SrcReg)
564 .addReg(SrcReg, RegState::Renamable | RegState::Kill);
565 LLVM_DEBUG(dbgs() << "\nInserting new instruction: ";
566 MIB.getInstr()->dump());
567
568 } else if (HST->useHVXV79Ops()) {
569 // Get an available register
570 auto V0_Reg = findAllocatableReg(MI);
571
572 MIB = BuildMI(*MBB, *MI, DL, HII->get(Hexagon::V6_vd0), V0_Reg);
573 LLVM_DEBUG(dbgs() << "\nInserting new instruction: ";
574 MIB.getInstr()->dump());
575 auto Op = is32bit ? Hexagon::V6_vadd_sf : Hexagon::V6_vadd_hf;
576 MIB = BuildMI(*MBB, *MI, DL, HII->get(Op), SrcReg)
577 .addReg(SrcReg, RegState::Renamable | RegState::Kill)
578 .addReg(V0_Reg, RegState::Kill);
579 LLVM_DEBUG(dbgs() << "Inserting new instruction: "; MIB.getInstr()->dump());
580 } else
581 llvm_unreachable("Not possible to insert qf = hf/sf for this unknown\
582 subtarget!");
583}
584
585// Create a new instruction which handle sf/hf types to replace
586// qf type handling instructions.
587bool HexagonPostRAHandleQFP::HandleRefills() {
588
589 bool Changed = false;
590 LLVM_DEBUG(dbgs() << "HandleRefills: ");
591 std::vector<MachineInstr *> eraseList;
592
593 for (auto It : QFUsesMap) {
594
595 // Separately handle unary qf opcodes
596 MachineInstr *MI = It.first;
597 auto SrcOpcode = MI->getOpcode();
598 auto Pair = It.second;
599 auto SrcOp1 = MI->getOperand(1);
600 Register DestReg = MI->getOperand(0).getReg();
601 auto MBB = MI->getParent();
602 MachineInstrBuilder MIB;
603 LLVM_DEBUG(dbgs() << "\nProcessing: "; MI->dump());
604 const DebugLoc &DL = MI->getDebugLoc();
605
606 // lambda to handle unary qf operations
607 // ieee: True if the 1st operand is sf/hf type, false if qf type
608 auto HandleUnaryRefill = [&](MachineInstr *MI, bool isIeee) -> bool {
609 if (isIeee) {
610 auto finalOpcode = getreplacedQFOpcode(SrcOpcode, true, true);
611 MIB = BuildMI(*MBB, *MI, DL, HII->get(finalOpcode), DestReg)
612 .addReg(SrcOp1.getReg(), getRegState(SrcOp1));
613 Changed |= true;
614 LLVM_DEBUG(dbgs() << "\nInserting new instruction: ";
615 MIB.getInstr()->dump());
616 } else
617 eraseList.push_back(MI);
618 return Changed;
619 };
620
621 if (MI->getNumOperands() == 2) {
622 Changed |= HandleUnaryRefill(It.first, It.second.first);
623 continue;
624 }
625 auto SrcOp2 = MI->getOperand(2);
626
627 // lambda to handle mixed type vsub instructions for v79
628 auto HandleSub = [&](auto srcOpcode) -> bool {
629 auto ConvOp = (srcOpcode == Hexagon::V6_vsub_qf32)
630 ? Hexagon::V6_vconv_sf_qf32
631 : Hexagon::V6_vconv_hf_qf16;
632 auto SubOp = (ConvOp == Hexagon::V6_vconv_sf_qf32) ? Hexagon::V6_vsub_sf
633 : Hexagon::V6_vsub_hf;
634
635 Register SrcOp2Reg = SrcOp2.getReg();
636 MIB = BuildMI(*MBB, *MI, DL, HII->get(ConvOp), SrcOp2Reg)
637 .addReg(SrcOp2Reg, getRegState(SrcOp2) | RegState::Kill);
638 LLVM_DEBUG(dbgs() << "\nInserting new instruction: ";
639 MIB.getInstr()->dump());
640 MIB = BuildMI(*MBB, *MI, DL, HII->get(SubOp), DestReg)
641 .addReg(SrcOp1.getReg(), getRegState(SrcOp1))
642 .addReg(SrcOp2Reg, getRegState(SrcOp2));
643 // If Op2 is not killed, it is used after this instruction.
644 // convert it back to original qf form.
645 if (!SrcOp2.isKill())
646 insertIEEEToQF(&*(++MI->getIterator()), SrcOp2.getReg(), SrcOp2);
647 return true;
648 };
649
650 // If both operands are sf type, we only need to replace the opcode.
651 if (Pair.first == true && Pair.second == true) {
652 auto finalOpcode = getreplacedQFOpcode(SrcOpcode, true, true);
653 MIB = BuildMI(*MBB, *MI, DL, HII->get(finalOpcode), DestReg)
654 .addReg(SrcOp1.getReg(), getRegState(SrcOp1))
655 .addReg(SrcOp2.getReg(), getRegState(SrcOp2));
656 Changed |= true;
657 LLVM_DEBUG(dbgs() << "\nInserting new instruction: ";
658 MIB.getInstr()->dump());
659
660 } else if (Pair.first == true && Pair.second == false) {
661 auto finalOpcode = getreplacedQFOpcode(SrcOpcode, true, false);
662
663 // If 2nd op is qf, first op is sf, convert the 2nd
664 // op to sf before inserting the vmpy instruction.
665 if (SrcOpcode == Hexagon::V6_vmpy_qf32) {
666 Register SrcOp2Reg = SrcOp2.getReg();
667 MIB = BuildMI(*MBB, *MI, DL, HII->get(Hexagon::V6_vconv_sf_qf32),
668 SrcOp2Reg)
669 .addReg(SrcOp2Reg, getRegState(SrcOp2) | RegState::Kill);
670 LLVM_DEBUG(dbgs() << "\nInserting new instruction before: ";
671 MIB.getInstr()->dump());
672 MIB = BuildMI(*MBB, *MI, DL, HII->get(finalOpcode), DestReg)
673 .addReg(SrcOp1.getReg(), getRegState(SrcOp1))
674 .addReg(SrcOp2Reg, getRegState(SrcOp2));
675 // If Op2 is not killed convert back to qf, since there
676 // are uses for this qf op.
677 if (!SrcOp2.isKill())
678 insertIEEEToQF(&*(++MI->getIterator()), SrcOp2.getReg(), SrcOp2,
679 true /* sf type reg */);
680
681 // if the opcode is mixed type, we use Op2 as first operand
682 // since that takes in qf type. Op1 is taken as second op.
683 } else if (finalOpcode == Hexagon::V6_vadd_qf16_mix ||
684 finalOpcode == Hexagon::V6_vadd_qf32_mix ||
685 finalOpcode == Hexagon::V6_vmpy_qf16_mix_hf ||
686 finalOpcode == Hexagon::V6_vmpy_qf32_mix_hf) {
687 MIB = BuildMI(*MBB, *MI, DL, HII->get(finalOpcode), DestReg)
688 .addReg(SrcOp2.getReg(), getRegState(SrcOp2))
689 .addReg(SrcOp1.getReg(), getRegState(SrcOp1));
690
691 // Subtracting is not associative, so if Op1 is sf/hf type and
692 // Op2 is qf type, we cannot interchange the operands.
693 // For v79, we convert Op2 to IEEE and use the non-mix type
694 // instruction for the subtraction.
695 // For v81, we have an appropiate opcode with vsub(sf/hf, qf) type
696 } else if ((SrcOpcode == Hexagon::V6_vsub_qf32 ||
697 SrcOpcode == Hexagon::V6_vsub_qf16) &&
698 HST->useHVXV79Ops()) {
699 Changed |= HandleSub(SrcOpcode);
700
701 } else {
702 MIB = BuildMI(*MBB, *MI, DL, HII->get(finalOpcode), DestReg)
703 .addReg(SrcOp1.getReg(), getRegState(SrcOp1))
704 .addReg(SrcOp2.getReg(), getRegState(SrcOp2));
705 }
706 LLVM_DEBUG(dbgs() << "\nInserting new instruction: ";
707 MIB.getInstr()->dump());
708 Changed |= true;
709 } else if (Pair.first == false && Pair.second == true) {
710
711 auto finalOpcode = getreplacedQFOpcode(SrcOpcode, false, true);
712 // If 2nd op is sf, first op is qf, convert the 1st
713 // op to sf before inserting the vmpy instruction.
714 if (SrcOpcode == Hexagon::V6_vmpy_qf32) {
715 Register SrcOp1Reg = SrcOp1.getReg();
716 MIB = BuildMI(*MBB, *MI, DL, HII->get(Hexagon::V6_vconv_sf_qf32),
717 SrcOp1Reg)
718 .addReg(SrcOp1Reg, getRegState(SrcOp1) | RegState::Kill);
719 LLVM_DEBUG(dbgs() << "\nInserting new instruction before: ";
720 MIB.getInstr()->dump());
721 MIB = BuildMI(*MBB, *MI, DL, HII->get(finalOpcode), DestReg)
722 .addReg(SrcOp1Reg, getRegState(SrcOp1))
723 .addReg(SrcOp2.getReg(), getRegState(SrcOp2));
724 LLVM_DEBUG(dbgs() << "\nInserting new instruction: ";
725 MIB.getInstr()->dump());
726 // If Op1 is not killed convert back to qf, since there
727 // are uses for this qf op.
728 if (!SrcOp1.isKill())
729 insertIEEEToQF(&*(++MI->getIterator()), SrcOp1.getReg(), SrcOp1,
730 true /*sf type reg*/);
731 } else {
732
733 MIB = BuildMI(*MBB, *MI, DL, HII->get(finalOpcode), DestReg)
734 .addReg(SrcOp1.getReg(), getRegState(SrcOp1))
735 .addReg(SrcOp2.getReg(), getRegState(SrcOp2));
736 LLVM_DEBUG(dbgs() << "\nInserting new instruction: ";
737 MIB.getInstr()->dump());
738 }
739 Changed |= true;
740 } else {
741 // Both the operands of this instructions are valid, so no use of
742 // this instruction is to be modified. We need to remove this
743 // instruction from the action map QFUsesMap.
744 eraseList.push_back(MI);
745 }
746 }
747
748 for (MachineInstr *delMI : eraseList)
749 QFUsesMap.erase(delMI);
750
751 return Changed;
752}
753
754// Insert a new instruction.
755void HexagonPostRAHandleQFP::insertInstr(MachineInstr *MI, unsigned MIOpcode,
756 unsigned SrcReg, unsigned DstReg,
757 RegState Flags) {
758
759 MachineInstrBuilder MIB;
760 MachineBasicBlock *MBB = MI->getParent();
761 DebugLoc DL = MI->getDebugLoc();
763 auto MINext = ++MI->getIterator();
764 if (++MIt == MBB->end())
765 MIB = BuildMI(MBB, DL, HII->get(MIOpcode), DstReg).addReg(SrcReg, Flags);
766 else
767 MIB = BuildMI(*MBB, MINext, DL, HII->get(MIOpcode), DstReg)
768 .addReg(SrcReg, Flags);
769 LLVM_DEBUG(dbgs() << "\t\tInserting after conv: "; MIB.getInstr()->dump());
770}
771
772// Find an available vector register to store 0x0. We have reserved vector
773// register v30 to be exempted from being used during register allocation
774// for this purpose.
775MCPhysReg HexagonPostRAHandleQFP::findAllocatableReg(MachineInstr *MI) const {
776 LLVM_DEBUG(dbgs() << "\tUsing V30 register to store a vector of zeroes!");
777 return Hexagon::V30;
778}
779
780// Insert qf = sf/hf conversions before non-saturating instructions
781bool HexagonPostRAHandleQFP::HandleNonSatInstr() {
782
783 for (auto It : QFNonSatMIs) {
784 MachineInstr *MI = It.first;
785 auto MIOpcode = MI->getOpcode();
786 auto Op = MI->getOperand(1);
787 Register DefReg = Op.getReg();
788 LLVM_DEBUG(dbgs() << "Analyzing convert instruction: "; MI->dump());
789 // Handle hf = qf16.
790 // Handle f8 = qf16
791 if (MIOpcode == Hexagon::V6_vconv_hf_qf16 ||
792 MIOpcode == Hexagon::V6_vconv_f8_qf16) {
793
794 insertIEEEToQF(MI, DefReg, Op);
795 // TODO Check if there are any reaching def which is qf generating type.
796 // That op should be converted to sf/hf
797 if (!Op.isKill())
798 insertInstr(MI, Hexagon::V6_vconv_hf_qf16, DefReg, DefReg,
799 getRegState(Op) | RegState::Kill);
800
801 // Handle hf = qf.qf.
802 // Handle bf = qf.qf
803 } else if (MIOpcode == Hexagon::V6_vconv_hf_qf32 ||
804 MIOpcode == Hexagon::V6_vconv_bf_qf32) {
805 Register DefLo = HRI->getSubReg(DefReg, Hexagon::vsub_lo);
806 Register DefHi = HRI->getSubReg(DefReg, Hexagon::vsub_hi);
807
808 if (It.second == ConvOperand::HiLo) {
809 insertIEEEToQF(MI, DefLo, Op, true /* sf type */);
810 insertIEEEToQF(MI, DefHi, Op, true /* sf type */);
811
812 // Check which subregister is live and convert it
813 // and according insert conversion for that subreg
814 auto KillState = SubRegKillSet[MI];
815 if (!KillState.first)
816 insertInstr(MI, Hexagon::V6_vconv_sf_qf32, DefHi, DefHi,
817 getRegState(Op) | RegState::Kill);
818
819 if (!KillState.second)
820 insertInstr(MI, Hexagon::V6_vconv_sf_qf32, DefLo, DefLo,
821 getRegState(Op) | RegState::Kill);
822
823 } else if (It.second == ConvOperand::Hi) {
824 insertIEEEToQF(MI, DefHi, Op, true /* sf type */);
825 if (!Op.isKill())
826 insertInstr(MI, Hexagon::V6_vconv_sf_qf32, DefHi, DefHi,
827 getRegState(Op) | RegState::Kill);
828
829 } else { // It.second == ConvOperand::Lo
830 insertIEEEToQF(MI, DefLo, Op, true /* sf type */);
831 if (!Op.isKill())
832 insertInstr(MI, Hexagon::V6_vconv_sf_qf32, DefLo, DefLo,
833 getRegState(Op) | RegState::Kill);
834 }
835 // Handle sf = qf32.
836 } else if (MIOpcode == Hexagon::V6_vconv_sf_qf32) {
837 insertIEEEToQF(MI, DefReg, Op, true /* sf type */);
838 if (!Op.isKill())
839 insertInstr(MI, Hexagon::V6_vconv_sf_qf32, DefReg, DefReg,
840 getRegState(Op) | RegState::Kill);
841
842 } else {
843 llvm_unreachable("Unhandled non-saturating instruction!");
844 }
845 }
846
847 if (QFNonSatMIs.empty())
848 return false;
849 return true;
850}
851
852// Calculates the liveness of subregisters (whether killed or not)
853// when double register is used. This is necessary because RDF
854// carries liveness of the superreg and not the subregisters individually
855void HexagonPostRAHandleQFP::collectLivenessForSubregs(
856 NodeAddr<UseNode *> &UsedNode) {
857 RegisterRef UR = UsedNode.Addr->getRegRef(*DFG);
858 NodeAddr<StmtNode *> UseStmt = UsedNode.Addr->getOwner(*DFG);
859 MachineInstr *UseInstr = UseStmt.Addr->getCode();
860 auto UseOp = UseInstr->getOperand(1);
861 Register UseDefLo = HRI->getSubReg(UseOp.getReg(), Hexagon::vsub_lo);
862 Register UseDefHi = HRI->getSubReg(UseOp.getReg(), Hexagon::vsub_hi);
863
864 NodeSet Visited, Defs;
865 bool isHiSubRegKilled = true, isLoSubRegKilled = true;
866 const auto &P = LV->getAllReachingDefsRec(UR, UsedNode, Visited, Defs);
867
868 if (!P.second)
869 return;
870
871 for (auto RD : P.first) {
872 NodeAddr<DefNode *> RegDef = DFG->addr<DefNode *>(RD);
873 Register RR = RegDef.Addr->getRegRef(*DFG).Id;
874 if (HRI->isFakeReg(RR))
875 continue;
876 NodeAddr<StmtNode *> RegStmt = RegDef.Addr->getOwner(*DFG);
877 MachineInstr *ReachDefInstr = RegStmt.Addr->getCode();
878 if (ReachDefInstr == nullptr)
879 continue;
880
881 // If the reaching def is WReg, then the kill flag in the use is correct
882 // since there is no subreg
883 Register DefReg = ReachDefInstr->getOperand(0).getReg();
884 if (Hexagon::HvxWRRegClass.contains(DefReg)) {
885 if (!UseOp.isKill())
886 isHiSubRegKilled = isLoSubRegKilled = false;
887
888 // If the reaching ref is VReg, the liveness might be different between
889 // each of the subreg. Handle them individually.
890 // Find the other uses after this use for the reaching def. If it exists,
891 // the subregister is live after the use.
892 // NOTE: Assumption: The uses are in order in RDF.
893 } else {
894 NodeSet UseSet;
895 getAllRealUses(RegDef, UseSet, LV, DFG);
896 for (auto UIntr : UseSet) {
897 NodeAddr<UseNode *> UA = DFG->addr<UseNode *>(UIntr);
898 NodeAddr<StmtNode *> UseStmt = UA.Addr->getOwner(*DFG);
899 MachineInstr *UseMI = UseStmt.Addr->getCode();
900 if (UseMI == nullptr)
901 continue;
902 // When we reach the use set a flag to see if there are other uses
903 // after this. If yes, then the register is not killed.
904 if (UseMI == UseInstr)
905 continue;
906 if (HII->isMIBefore(UseInstr, UseMI) && DefReg == UseDefLo) {
907 isLoSubRegKilled = false;
908 break;
909 }
910 if (HII->isMIBefore(UseInstr, UseMI) && DefReg == UseDefHi) {
911 isHiSubRegKilled = false;
912 break;
913 }
914 }
915 }
916 }
917 SubRegKillSet[UseInstr] = std::make_pair(isHiSubRegKilled, isLoSubRegKilled);
918}
919
920// Store all refill instructions.
921void HexagonPostRAHandleQFP::collectQFPStackRefill(
922 NodeAddr<StmtNode *> *StNode) {
923 NodeAddr<DefNode *> DfNode =
924 StNode->Addr->members_if(DFG->IsDef, *DFG).front();
925 MachineInstr *MI = StNode->Addr->getCode();
926 // Check if operand to this instruction is a frame index.
927 const MachineOperand &OpFI = MI->getOperand(1);
928 if (!OpFI.isFI())
929 return;
930
931 // LLVM_DEBUG(dbgs() << "\n[Stack Refill]: Collecting: "; MI->dump());
932 RefillMIs.push_back(DfNode);
933}
934
935// Iterate over the uses of the qf generating instruction in RDG graph
936// If we get a qf to IEEE convert instruction, add it to a list.
937void HexagonPostRAHandleQFP::collectConvQFInstr(NodeAddr<DefNode *> &RegDef) {
938
939 NodeSet UseSet;
940 NodeAddr<StmtNode *> DefStmt = RegDef.Addr->getOwner(*DFG);
941 MachineInstr *DefInstr = DefStmt.Addr->getCode();
942 getAllRealUses(RegDef, UseSet, LV, DFG);
943 for (auto UI : UseSet) {
944 NodeAddr<UseNode *> UA = DFG->addr<UseNode *>(UI);
945 if (UA.Addr->getFlags() & NodeAttrs::PhiRef)
946 continue;
947 NodeAddr<StmtNode *> UseStmt = UA.Addr->getOwner(*DFG);
948 MachineInstr *QFConvInstr = UseStmt.Addr->getCode();
949 if (std::find(QFNonSatInstr.begin(), QFNonSatInstr.end(),
950 QFConvInstr->getOpcode()) != QFNonSatInstr.end()) {
951
952 // The use is a double register type. But the def can be hi/lo or double
953 // type. So conversion needs to be inserted only for the type
954 // which is in IEEE form.
955 auto UseReg = QFConvInstr->getOperand(1).getReg();
956 auto DefReg = DefInstr->getOperand(0).getReg();
957 if (Hexagon::HvxWRRegClass.contains(UseReg)) {
958
959 collectLivenessForSubregs(UA);
960 unsigned Op = ConvOperand::Undefined;
961 if (QFNonSatMIs.contains(QFConvInstr))
962 Op = QFNonSatMIs[QFConvInstr];
963
964 // Def is double type
965 if (Hexagon::HvxWRRegClass.contains(DefReg))
966 Op = ConvOperand::HiLo;
967 // Def is lo of double type
968 else if (DefReg == HRI->getSubReg(UseReg, Hexagon::vsub_lo))
969 Op |= ConvOperand::Lo;
970 // Def is hi of double type
971 else
972 Op |= ConvOperand::Hi;
973 QFNonSatMIs[QFConvInstr] = Op;
974 } else // for other def-use, BothOp is used as default
975 QFNonSatMIs[QFConvInstr] = ConvOperand::HiLo;
976
977 IgnoreInsertConvList.insert(DefInstr);
978 LLVM_DEBUG(std::string OpType = ""; switch (QFNonSatMIs[QFConvInstr]) {
979 case ConvOperand::HiLo:
980 OpType = "HiLo Op";
981 break;
982 case ConvOperand::Lo:
983 OpType = "Lo Op";
984 break;
985 case ConvOperand::Hi:
986 OpType = "Hi Op";
987 break;
988 default:
989 OpType = "Undefined";
990 } dbgs() << "Collecting convert instruction with type "
991 << OpType << " : ";
992 QFConvInstr->dump());
993 }
994 }
995}
996
997// Check if the COPY statements use came from a def which generates
998// a qf type. If yes, collect it in a vector. Also, collect copies
999// with reaching def other copies (nested copies).
1000void HexagonPostRAHandleQFP::collectCopies(NodeAddr<StmtNode *> *StNode) {
1001
1002 NodeAddr<DefNode *> CopyDef =
1003 StNode->Addr->members_if(DFG->IsDef, *DFG).front();
1004 MachineInstr *CopyInstr = StNode->Addr->getCode();
1005 LLVM_DEBUG(dbgs() << "\nAnalyzing copy: "; StNode->Addr->getCode()->dump());
1006
1007 for (NodeAddr<UseNode *> UA : StNode->Addr->members_if(DFG->IsUse, *DFG)) {
1008 RegisterRef UR = UA.Addr->getRegRef(*DFG);
1009 NodeSet Visited, Defs;
1010 const auto &P = LV->getAllReachingDefsRec(UR, UA, Visited, Defs);
1011 if (!P.second) {
1012 LLVM_DEBUG({
1013 dbgs() << "*** Unable to collect all reaching defs for use ***\n"
1014 << PrintNode<UseNode *>(UA, *DFG) << '\n';
1015 });
1016 continue;
1017 }
1018
1019 // Note: there can be multiple reaching defs of the copy
1020 for (auto RD : P.first) {
1021 NodeAddr<DefNode *> RegDef = DFG->addr<DefNode *>(RD);
1022 Register RR = RegDef.Addr->getRegRef(*DFG).Id;
1023 if (HRI->isFakeReg(RR))
1024 continue;
1025 NodeAddr<StmtNode *> RegStmt = RegDef.Addr->getOwner(*DFG);
1026 MachineInstr *ReachDefInstr = RegStmt.Addr->getCode();
1027 if (ReachDefInstr == nullptr)
1028 continue;
1029 LLVM_DEBUG(dbgs() << "\t[Reaching Def]: "; ReachDefInstr->dump());
1030
1031 // If the reaching def is a COPY,collect it with reg type ieee
1032 if (ReachDefInstr->getOpcode() == TargetOpcode::COPY) {
1033 auto pairKey = std::make_pair(CopyDef, RegDef);
1034 QFCopys[pairKey] = RegType::ieee;
1035 continue;
1036 }
1037
1038 // If the reaching def is a qf instr, collect the copy.
1039 // reg type is selected based on the op
1040 auto RegT = RegType::undefined;
1041 if (HII->isQFPInstr(ReachDefInstr)) {
1042 if (HII->isQFP32Instr(ReachDefInstr)) {
1043 // check whether the copies register is hvxWR or hvxVR type
1044 // NOTE: Assumption: A copy's reaching def shall not be 2,
1045 // i.e., for each of the subregister.
1046 if (Hexagon::HvxWRRegClass.contains(
1047 ReachDefInstr->getOperand(0).getReg()))
1048 RegT = RegType::qf32_double;
1049 else
1050 RegT = RegType::qf32;
1051 } else if (HII->isQFP16Instr(ReachDefInstr)) {
1052 // Check if qf16 instruction outputs double-wide register
1053 if (Hexagon::HvxWRRegClass.contains(
1054 ReachDefInstr->getOperand(0).getReg())) {
1055 RegT = RegType::qf16_double;
1056 } else {
1057 RegT = RegType::qf16;
1058 }
1059 }
1060 } else {
1061 // if the copy involves non-qf vector registers collect it too
1062 Register CopyReg = CopyInstr->getOperand(1).getReg();
1063 if (Hexagon::HvxWRRegClass.contains(CopyReg) ||
1064 Hexagon::HvxVRRegClass.contains(CopyReg))
1065 RegT = RegType::ieee;
1066 else
1067 continue;
1068 }
1069 auto pairKey = std::make_pair(CopyDef, RegDef);
1070 QFCopys[pairKey] = RegT;
1071 }
1072 }
1073}
1074
1075// Inserts an qf instruction to a list. These instruction
1076// values are spilled to the stack.
1077void HexagonPostRAHandleQFP::collectQFPStackSpill(
1078 NodeAddr<StmtNode *> *StNode) {
1079
1080 MachineInstr *MI = StNode->Addr->getCode();
1081 LLVM_DEBUG(dbgs() << "\n[Stack Spill]: Analyzing: "; MI->dump());
1082 // Check if operand to this instruction is a frame index.
1083 const MachineOperand &OpFI = MI->getOperand(0);
1084 if (!OpFI.isFI())
1085 return;
1086
1087 // Pre-RegAlloc
1088 //%46:hvxwr = V6_vmpy_qf32_hf %7:hvxvr, %10:hvxvr
1089 // PS_vstorerw_ai %stack.3, 0, %46:hvxwr :: (store (s2048) into %stack.3,
1090 // align 128)
1091 // Post-RegAlloc
1092 // renamable $w4 = V6_vmpy_qf32_hf killed renamable $v1, renamable $v0
1093 // PS_vstorerw_ai %stack.3, 0, renamable $w4 :: (store (s2048) into %stack.3,
1094 // align 128)
1095
1096 if (!MI->getOperand(2).isReg())
1097 return;
1098
1099 // Iterate over the operands of the store instruction to get their reaching
1100 // defs
1101 NodeId QFPDefNode = 0;
1102 for (NodeAddr<UseNode *> UA : StNode->Addr->members_if(DFG->IsUse, *DFG)) {
1103 QFPDefNode = UA.Addr->getReachingDef();
1104
1105 // Get the defining instruction node(s)
1106 NodeAddr<DefNode *> RegDef = DFG->addr<DefNode *>(QFPDefNode);
1107 assert(QFPDefNode != 0 && "Reaching def computation error");
1108 NodeAddr<StmtNode *> RegStmt = RegDef.Addr->getOwner(*DFG);
1109 MachineInstr *ReachDefInstr = RegStmt.Addr->getCode();
1110 if (ReachDefInstr == nullptr)
1111 continue;
1112 LLVM_DEBUG(dbgs() << "[Stack Spill]:\tReaching Def of operand:";
1113 ReachDefInstr->dump());
1114 // Reaching Def cannot be a phi instruction.
1115 if (RegDef.Addr->getFlags() & NodeAttrs::PhiRef)
1116 continue;
1117
1118 if (!HII->isQFPInstr(ReachDefInstr))
1119 continue;
1120
1121 auto RR = RegDef.Addr->getRegRef(*DFG).Id;
1122 if (HRI->isFakeReg(RR))
1123 continue;
1124
1125 LLVM_DEBUG(dbgs() << "Found a QFPStackSpill via \n"; MI->dump();
1126 dbgs() << "The corresponding XQF instruction is:\n";
1127 ReachDefInstr->dump());
1128
1129 // Collect the spills.
1130 SpillMIs.push_back(std::make_pair(MI, RegDef));
1131 }
1132}
1133
1134// Find the uses of qf generating instructions and conditionally add them
1135// to a list.
1136void HexagonPostRAHandleQFP::collectQFUses(NodeAddr<DefNode *> RegDef,
1137 MachineInstr *DefMI) {
1138
1139 NodeSet UseSet;
1140 LLVM_DEBUG(dbgs() << " Finding uses of: "; DefMI->dump(););
1141 getAllRealUses(RegDef, UseSet, LV, DFG);
1142
1143 for (auto UI : UseSet) {
1144 NodeAddr<UseNode *> UA = DFG->addr<UseNode *>(UI);
1145 if (UA.Addr->getFlags() & NodeAttrs::PhiRef)
1146 continue;
1147 NodeAddr<StmtNode *> UseStmt = UA.Addr->getOwner(*DFG);
1148 MachineInstr *UseMI = UseStmt.Addr->getCode();
1149 LLVM_DEBUG(dbgs() << "\t\t\t[Reached Use of QF operand]: "; UseMI->dump());
1150
1151 Register UsedReg = UA.Addr->getRegRef(*DFG).Id;
1152 if (QFPSatInstsMap.find(UseMI->getOpcode()) != QFPSatInstsMap.end()) {
1153 if (PossibleMultiReachDefs.count(UseStmt) == 0) {
1154 PossibleMultiReachDefs.insert(UseStmt);
1155 LLVM_DEBUG(dbgs() << "\n[Collect instr with possible multidef]:";
1156 UseMI->dump());
1157 }
1158 conditionallyInsert(*UseMI, UsedReg);
1159 }
1160 }
1161}
1162
1163// Process the list which can have multiple definitions. A possible case
1164// can be reaching defs to be a copy and a qf-generating instr respectively.
1165// Only handle the qf-generating instruction by inserting convert to sf/hf
1166// after it. Additionally, then handle the reached uses of this reaching
1167// def since the type has changed to sf/hf from qf after the conversion.
1168bool HexagonPostRAHandleQFP::HandleMultiReachingDefs() {
1169
1170 bool Changed = false;
1171 // Note: It may seem this loop can further add to PossibleMultiReachDefs.
1172 // But it is not expected to since if any instruction has multiple
1173 // definitions it should already be present in it.
1174 for (auto It : PossibleMultiReachDefs) {
1175 MachineInstr *Instr = It.Addr->getCode();
1176 // get the op type for the original instruction.
1177 // True is sf/hf, false is qf
1178 auto Pair = QFUsesMap[Instr];
1179
1180 unsigned short UseNo = 1;
1181 // Iterate over the operands
1182 for (NodeAddr<UseNode *> UA : It.Addr->members_if(DFG->IsUse, *DFG)) {
1183
1184 // If the type is qf for the operand,
1185 // we skip since there is no scope for mismatch
1186 if ((UseNo == 1 && Pair.first == false) ||
1187 (UseNo == 2 && Pair.second == false)) {
1188 ++UseNo;
1189 continue;
1190 }
1191
1192 RegisterRef UR = UA.Addr->getRegRef(*DFG);
1193 NodeSet Visited, Defs;
1194 const auto &P = LV->getAllReachingDefsRec(UR, UA, Visited, Defs);
1195 if (!P.second) {
1196 LLVM_DEBUG({
1197 dbgs() << "*** Unable to collect all reaching defs for use ***\n"
1198 << PrintNode<UseNode *>(UA, *DFG) << '\n';
1199 });
1200 continue;
1201 }
1202
1203 // Iterate over the reaching defs and process the ones which
1204 // generate qf. Ignore the ones which have already been handled
1205 for (auto RD : P.first) {
1206 NodeAddr<DefNode *> RegDef = DFG->addr<DefNode *>(RD);
1207
1208 // Ignore fake reaches
1209 auto RR = RegDef.Addr->getRegRef(*DFG).Id;
1210 if (HRI->isFakeReg(RR))
1211 continue;
1212
1213 NodeAddr<StmtNode *> RegStmt = RegDef.Addr->getOwner(*DFG);
1214 MachineInstr *ReachDefInstr = RegStmt.Addr->getCode();
1215
1216 if (ReachDefInstr == nullptr)
1217 continue;
1218
1219 if (!HII->isQFPInstr(ReachDefInstr))
1220 continue;
1221 if (IgnoreInsertConvList.find(ReachDefInstr) !=
1222 IgnoreInsertConvList.end())
1223 continue;
1224 LLVM_DEBUG(dbgs() << "[Multidef] Handling reaching def:";
1225 ReachDefInstr->dump());
1226
1227 auto *MBB = ReachDefInstr->getParent();
1228 auto &dl = ReachDefInstr->getDebugLoc();
1229 auto NextReachMI = ++ReachDefInstr->getIterator();
1230 auto DefOp = ReachDefInstr->getOperand(0);
1231 Register OpReg = DefOp.getReg();
1232 MachineInstrBuilder MIB;
1233
1234 // For double vector regs, two conversions are inserted. Single
1235 // conversion for qf32 type
1236 if (HII->isQFP32Instr(ReachDefInstr)) {
1237 // if the reaching def is a qf double type
1238 if (Hexagon::HvxWRRegClass.contains(
1239 ReachDefInstr->getOperand(0).getReg())) {
1240 Register RegLo = HRI->getSubReg(OpReg, Hexagon::vsub_lo);
1241 Register RegHi = HRI->getSubReg(OpReg, Hexagon::vsub_hi);
1242 MIB = BuildMI(*MBB, NextReachMI, dl,
1243 HII->get(Hexagon::V6_vconv_sf_qf32), RegLo)
1244 .addReg(RegLo, RegState::Renamable | RegState::Kill);
1245 LLVM_DEBUG(dbgs() << "[MultiDef] Inserting convert instruction: ";
1246 MIB.getInstr()->dump());
1247 MIB = BuildMI(*MBB, NextReachMI, dl,
1248 HII->get(Hexagon::V6_vconv_sf_qf32), RegHi)
1249 .addReg(RegHi, RegState::Renamable | RegState::Kill);
1250 } else { // If the reaching def is a qf type
1251 MIB = BuildMI(*MBB, NextReachMI, dl,
1252 HII->get(Hexagon::V6_vconv_sf_qf32), OpReg)
1253 .addReg(OpReg, RegState::Renamable | RegState::Kill);
1254 }
1255 }
1256 if (HII->isQFP16Instr(ReachDefInstr)) {
1257 MIB = BuildMI(*MBB, NextReachMI, dl,
1258 HII->get(Hexagon::V6_vconv_hf_qf16), OpReg)
1259 .addReg(OpReg, RegState::Renamable | RegState::Kill);
1260 }
1261 LLVM_DEBUG(dbgs() << "[MultiDef] Inserting convert instruction: ";
1262 MIB.getInstr()->dump(); dbgs() << "\tafter instruction: ";
1263 ReachDefInstr->dump());
1264
1265 // find the uses of the newly transformed to sf/hf and handle
1266 // accordingly. Uses can be vmul/vadd/etc. types or converts which take
1267 // in qf types.
1268 collectQFUses(RegDef, ReachDefInstr);
1269 collectConvQFInstr(RegDef);
1270 IgnoreInsertConvList.insert(ReachDefInstr);
1271 Changed = true;
1272 }
1273 UseNo++;
1274 }
1275 }
1276 return Changed;
1277}
1278
1279bool HexagonPostRAHandleQFP::HandleConvertToQfCopies() {
1280 if (ConvertToQfCopies.empty())
1281 return false;
1282
1283 LLVM_DEBUG(
1284 dbgs() << "\n*** Inserting convert to qf for selected copies ***\n");
1285
1286 // Any reached use of the copy should not already be collected to be
1287 // converted to IEEE. If present, it means that the reached use has
1288 // other reaching def with type IEEE, other than this copy.
1289 auto CanTransform = [&](MachineInstr *MI, unsigned OpNo) -> bool {
1290 if (QFUsesMap.find(MI) != QFUsesMap.end()) {
1291 auto Entry = QFUsesMap[MI];
1292 if (OpNo == 1 && Entry.first == true)
1293 return false;
1294 if (OpNo == 2 && Entry.second == true)
1295 return false;
1296 }
1297 return true;
1298 };
1299
1300 for (auto It : ConvertToQfCopies) {
1301 NodeSet UseSet;
1302 getAllRealUses(It.second.first, UseSet, LV, DFG);
1303
1304 bool transform = true;
1305 for (auto UI : UseSet) {
1306 NodeAddr<UseNode *> UA = DFG->addr<UseNode *>(UI);
1307 if (UA.Addr->getFlags() & NodeAttrs::PhiRef)
1308 continue;
1309 NodeAddr<StmtNode *> UseStmt = UA.Addr->getOwner(*DFG);
1310 MachineInstr *UseMI = UseStmt.Addr->getCode();
1311 unsigned OpNo = UA.Addr->getOp().getOperandNo();
1312
1313 if (!CanTransform(UseMI, OpNo)) {
1314 transform = false;
1315 break;
1316 }
1317 }
1318
1319 if (transform) {
1320
1321 LLVM_DEBUG(dbgs() << "\n[HandleConvertToQfCopies]\tProcessing Copy:";
1322 It.first->dump());
1323 auto CopyOp = It.first->getOperand(0);
1324 auto NextMIIter = std::next(It.first->getIterator());
1325 switch (It.second.second) {
1326 case RegType::qf32_double: {
1327 Register DefLo = HRI->getSubReg(CopyOp.getReg(), Hexagon::vsub_lo);
1328 Register DefHi = HRI->getSubReg(CopyOp.getReg(), Hexagon::vsub_hi);
1329 insertIEEEToQF(&*NextMIIter, DefLo, CopyOp, /*is32bit=*/true);
1330 insertIEEEToQF(&*NextMIIter, DefHi, CopyOp, /*is32bit=*/true);
1331 break;
1332 }
1333 case RegType::qf16_double: {
1334 Register DefLo = HRI->getSubReg(CopyOp.getReg(), Hexagon::vsub_lo);
1335 Register DefHi = HRI->getSubReg(CopyOp.getReg(), Hexagon::vsub_hi);
1336 insertIEEEToQF(&*NextMIIter, DefLo, CopyOp, /*is32bit=*/false);
1337 insertIEEEToQF(&*NextMIIter, DefHi, CopyOp, /*is32bit=*/false);
1338 break;
1339 }
1340 case RegType::qf16:
1341 insertIEEEToQF(&*NextMIIter, CopyOp.getReg(), CopyOp,
1342 /*is32bit=*/false);
1343 break;
1344 case RegType::qf32:
1345 insertIEEEToQF(&*NextMIIter, CopyOp.getReg(), CopyOp, /*is32bit=*/true);
1346 break;
1347 default:
1348 break;
1349 }
1350 } else {
1351 collectQFUses(It.second.first, It.first);
1352 collectConvQFInstr(It.second.first);
1353 }
1354 }
1355 return true;
1356}
1357
1358bool HexagonPostRAHandleQFP::HandleReachDefOfCopies() {
1359 if (ReachDefOfCopies.empty())
1360 return false;
1361
1362 MachineInstrBuilder MIB;
1363 for (auto It : ReachDefOfCopies) {
1364 auto *MBB = It.first->getParent();
1365 auto &dl = It.first->getDebugLoc();
1366 auto NextMI = ++(It.first)->getIterator();
1367 auto RegOp = It.first->getOperand(0);
1368 Register OpReg = RegOp.getReg();
1369
1370 if (It.second == RegType::qf32)
1371 MIB =
1372 BuildMI(*MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_sf_qf32), OpReg)
1373 .addReg(OpReg, RegState::Renamable | RegState::Kill);
1374 else if (It.second == RegType::qf16)
1375 MIB =
1376 BuildMI(*MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_hf_qf16), OpReg)
1377 .addReg(OpReg, RegState::Renamable | RegState::Kill);
1378 else if (It.second == RegType::qf32_double) {
1379 Register RegLo = HRI->getSubReg(OpReg, Hexagon::vsub_lo);
1380 Register RegHi = HRI->getSubReg(OpReg, Hexagon::vsub_hi);
1381 MIB =
1382 BuildMI(*MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_sf_qf32), RegLo)
1383 .addReg(RegLo, RegState::Renamable | RegState::Kill);
1384 LLVM_DEBUG(dbgs() << "Inserting convert instruction: ";
1385 MIB.getInstr()->dump());
1386 MIB =
1387 BuildMI(*MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_sf_qf32), RegHi)
1388 .addReg(RegHi, RegState::Renamable | RegState::Kill);
1389 } else if (It.second == RegType::qf16_double) {
1390 Register RegLo = HRI->getSubReg(OpReg, Hexagon::vsub_lo);
1391 Register RegHi = HRI->getSubReg(OpReg, Hexagon::vsub_hi);
1392 MIB =
1393 BuildMI(*MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_hf_qf16), RegLo)
1394 .addReg(RegLo, RegState::Renamable | RegState::Kill);
1395 LLVM_DEBUG(dbgs() << "Inserting convert instruction: ";
1396 MIB.getInstr()->dump());
1397 MIB =
1398 BuildMI(*MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_hf_qf16), RegHi)
1399 .addReg(RegHi, RegState::Renamable | RegState::Kill);
1400 }
1401 LLVM_DEBUG(dbgs() << "Inserting convert instruction: ";
1402 MIB.getInstr()->dump(); dbgs() << "\tafter instruction: ";
1403 It.first->dump());
1404 }
1405 return true;
1406}
1407
1408HexagonPostRAHandleQFP::RegType
1409HexagonPostRAHandleQFP::HasQfUses(NodeAddr<DefNode *> CopyDef,
1410 MachineInstr *CopyMI) {
1411 NodeSet UseSet;
1412 getAllRealUses(CopyDef, UseSet, LV, DFG);
1413
1414 if (UseSet.size() == 0)
1415 return RegType::undefined;
1416
1417 bool hasQf16Use = false;
1418 bool hasQf32Use = false;
1419
1420 LLVM_DEBUG(dbgs() << "[COPY]\nUses of the copy are: ");
1421 for (auto UI : UseSet) {
1422 NodeAddr<UseNode *> UA = DFG->addr<UseNode *>(UI);
1423 if (UA.Addr->getFlags() & NodeAttrs::PhiRef)
1424 continue;
1425 NodeAddr<StmtNode *> UseStmt = UA.Addr->getOwner(*DFG);
1426 MachineInstr *UseMI = UseStmt.Addr->getCode();
1427 unsigned OpNo = UA.Addr->getOp().getOperandNo();
1428
1429 LLVM_DEBUG(dbgs() << "\nCopy's use: "; UseMI->dump());
1430 // Any reached use should not be a non-qf instruction
1431 if (!HII->usesQFOperand(UseMI, OpNo))
1432 return RegType::ieee;
1433
1434 // Determine the qf type from the use
1435 if (HII->usesQF16Operand(UseMI, OpNo))
1436 hasQf16Use = true;
1437 else if (HII->usesQF32Operand(UseMI, OpNo))
1438 hasQf32Use = true;
1439
1440 // Any reached use should not already be converted to IEEE.
1441 // If present, it means that the reached use has other reaching def
1442 // other than the copy.
1443 if (QFUsesMap.find(UseMI) != QFUsesMap.end()) {
1444 auto Entry = QFUsesMap[UseMI];
1445 if (OpNo == 1 && Entry.first == true)
1446 return RegType::ieee;
1447 if (OpNo == 2 && Entry.second == true)
1448 return RegType::ieee;
1449 }
1450 }
1451
1452 // Set the output type based on uses
1453 if (hasQf16Use) {
1454 // Check if copy destination is double-wide
1455 if (Hexagon::HvxWRRegClass.contains(CopyMI->getOperand(0).getReg()))
1456 return RegType::qf16_double;
1457 else
1458 return RegType::qf16;
1459 } else if (hasQf32Use) {
1460 if (Hexagon::HvxWRRegClass.contains(CopyMI->getOperand(0).getReg()))
1461 return RegType::qf32_double;
1462 else
1463 return RegType::qf32;
1464 }
1465
1466 return RegType::undefined;
1467}
1468
1469// Go through the collected copies and insert conversion to sf/hf
1470// conditionally *after their reaching defs*. This is done because there
1471// can be mutliple reaching defs of the copies. Also, check for the uses
1472// of the reaching def and handle qf uses too by changing opcode or
1473// inserting converts.
1474// Additionally, check for the uses of the copy
1475// and handle them via changing opcode or inserting converts.
1476bool HexagonPostRAHandleQFP::HandleCopies() {
1477
1478 bool Changed = false;
1479
1480 // If a convert is inserted after a reaching def, add it to ignorelist.
1481 // This is because this reaching def can be reaching def of other copies
1482 // due to non-SSA form.
1483 for (auto It : QFCopys) {
1484
1485 // Get details of the copy node
1486 NodeAddr<DefNode *> CopyNode = It.first.first;
1487 NodeAddr<StmtNode *> StNode = CopyNode.Addr->getOwner(*DFG);
1488 [[maybe_unused]] auto *CopyMI = StNode.Addr->getCode();
1489 LLVM_DEBUG(dbgs() << "\nHandling Reaching Defs of COPY: "; CopyMI->dump();
1490 std::string Type; switch (It.second) {
1491 case RegType::qf32_double:
1492 Type = "qf32_double";
1493 break;
1494 case RegType::qf32:
1495 Type = "qf32";
1496 break;
1497 case RegType::qf16:
1498 Type = "qf16";
1499 break;
1500 case RegType::qf16_double:
1501 Type = "qf16_double";
1502 break;
1503 default:
1504 Type = "ieee";
1505 } dbgs() << "\t Type: "
1506 << Type << "\n");
1507
1508 // insert convert to IEEE after the reaching def if it generates qf type
1509 RegType RTy = It.second;
1510 if (RTy != RegType::ieee) {
1511
1512 // get details of the reaching def node
1513 NodeAddr<DefNode *> ReachDefNode = It.first.second;
1514 NodeAddr<StmtNode *> StNode = ReachDefNode.Addr->getOwner(*DFG);
1515 auto *ReachingDef = StNode.Addr->getCode();
1516
1517 if (IgnoreInsertConvList.find(ReachingDef) != IgnoreInsertConvList.end())
1518 continue;
1519
1520 // Collect the reaching defs to be processed later.
1521 ReachDefOfCopies.insert(std::make_pair(ReachingDef, RTy));
1522
1523 // Process the reached uses of the reaching def now for
1524 // incorrect usage, since the register type has changed
1525 // following the conversion.
1526 LLVM_DEBUG(dbgs() << "\n[COPY]\tAnalyzing uses of the reaching defs \
1527 of the copy...");
1528 collectQFUses(ReachDefNode, ReachingDef);
1529 collectConvQFInstr(ReachDefNode);
1530 IgnoreInsertConvList.insert(ReachingDef);
1531 Changed = true;
1532 }
1533 }
1534
1535 // Loop through copies with qf uses
1536 for (auto It : QFCopys) {
1537
1538 // Get details of the copy node
1539 NodeAddr<DefNode *> CopyNode = It.first.first;
1540 NodeAddr<StmtNode *> StNode = CopyNode.Addr->getOwner(*DFG);
1541 auto *CopyMI = StNode.Addr->getCode();
1542 LLVM_DEBUG(dbgs() << "\nHandling COPY: "; CopyMI->dump());
1543 RegType RTy = It.second;
1544
1545 // Process the reached uses of the copy to find any incorrect
1546 // qf uses. If the copy's uses are all qf types, we need to convert
1547 // its result back to qf
1548 // FIXME: don't include the copy if its the last instruction since
1549 // it is *probably* not possible to insert via BuildMI at the end of BB
1550 RTy = HasQfUses(CopyNode, CopyMI);
1551 if (RTy != RegType::ieee && RTy != RegType::undefined &&
1552 (++CopyMI->getIterator() != CopyMI->getParent()->end())) {
1553 if (!ConvertToQfCopies.contains(CopyMI)) {
1554 ConvertToQfCopies[CopyMI] = std::make_pair(CopyNode, RTy);
1555 LLVM_DEBUG(dbgs() << "\n[ConvertToQfCopies]\tAdded copy: ";
1556 CopyMI->dump(); std::string Type; switch (RTy) {
1557 case RegType::qf32_double:
1558 Type = "qf32_double";
1559 break;
1560 case RegType::qf32:
1561 Type = "qf32";
1562 break;
1563 case RegType::qf16:
1564 Type = "qf16";
1565 break;
1566 case RegType::qf16_double:
1567 Type = "qf16_double";
1568 break;
1569 default:
1570 Type = "ieee";
1571 } dbgs() << "\t Type: "
1572 << Type << "\n");
1573 }
1574 continue;
1575 }
1576 LLVM_DEBUG(dbgs() << "\n[COPY]\tAnalyzing uses of the copy...");
1577 collectQFUses(CopyNode, CopyMI);
1578 collectConvQFInstr(CopyNode);
1579 }
1580
1581 Changed |= HandleReachDefOfCopies();
1582 Changed |= HandleMultiReachingDefs();
1583 Changed |= HandleConvertToQfCopies();
1584
1585 return Changed;
1586}
1587
1588// Inserts conversion instruction sf/hf = qf before spilling
1589// Uses the same physical register for conversion.
1590// Additinally checks for the uses of the register; and
1591// conditionally store them to handle later.
1592bool HexagonPostRAHandleQFP::HandleSpills() {
1593
1594 LLVM_DEBUG(dbgs() << "\n[Handling Spill]\n");
1595 bool Changed = false;
1596 for (auto It : SpillMIs) {
1597
1598 MachineInstr *MI = It.first;
1599 auto OpC = MI->getOpcode();
1600
1601 auto NodeDef = It.second;
1602 NodeAddr<StmtNode *> Stmt = NodeDef.Addr->getOwner(*DFG);
1603 MachineInstr *DefMI = Stmt.Addr->getCode();
1604 auto RegOp = MI->getOperand(2);
1605 Register DefR = RegOp.getReg();
1606
1607 // handles widened qf16/qf32 instructions.
1608 if (OpC == Hexagon::PS_vstorerw_ai) {
1609 if (!Hexagon::HvxWRRegClass.contains(DefR))
1610 assert(false && " Unhandled Vector Register class passed\n");
1611 // Walk through the uses of DefLo and DefHi and if there is QFP
1612 // instructions, the instruction needs to be updated to use sf operands
1613 // instead of qf operands.
1614 collectQFUses(NodeDef, DefMI);
1615
1616 if (IgnoreInsertConvList.find(DefMI) != IgnoreInsertConvList.end())
1617 continue;
1618
1619 // Collect the reached uses of ReachDefInstr
1620 // which are sf/hf = qf conversion instructions.
1621 collectConvQFInstr(NodeDef);
1622 Register DefLo = HRI->getSubReg(DefR, Hexagon::vsub_lo);
1623 Register DefHi = HRI->getSubReg(DefR, Hexagon::vsub_hi);
1624
1625 // Create two copy instructions, one each for Hi and Lo conditionally.
1626 // Liveness is the same is for the store instruction for the register.
1627 // If both are double registers, two insertions are done.
1628 // If one of the subregs are reaching to the store, conversion is done
1629 // for that subreg.
1631 if (HII->isQFP16Instr(DefMI)) {
1632 if (DefLo == DReg || Hexagon::HvxWRRegClass.contains(DReg))
1633 insertInstr(DefMI, Hexagon::V6_vconv_hf_qf16, DefLo, DefLo,
1634 getRegState(RegOp) | RegState::Kill);
1635
1636 if (DefHi == DReg || Hexagon::HvxWRRegClass.contains(DReg))
1637 insertInstr(DefMI, Hexagon::V6_vconv_hf_qf16, DefHi, DefHi,
1638 getRegState(RegOp) | RegState::Kill);
1639 } else if (HII->isQFP32Instr(DefMI)) {
1640 if (DefLo == DReg || Hexagon::HvxWRRegClass.contains(DReg))
1641 insertInstr(DefMI, Hexagon::V6_vconv_sf_qf32, DefLo, DefLo,
1642 getRegState(RegOp) | RegState::Kill);
1643
1644 if (DefHi == DReg || Hexagon::HvxWRRegClass.contains(DReg))
1645 insertInstr(DefMI, Hexagon::V6_vconv_sf_qf32, DefHi, DefHi,
1646 getRegState(RegOp) | RegState::Kill);
1647 }
1648 IgnoreInsertConvList.insert(DefMI);
1649 Changed = true;
1650
1651 // Handles instructions which output qf32 type.
1652 } else if (OpC == Hexagon::PS_vstorerv_ai && HII->isQFP32Instr(DefMI)) {
1653 collectQFUses(NodeDef, DefMI);
1654 if (IgnoreInsertConvList.find(DefMI) != IgnoreInsertConvList.end())
1655 continue;
1656 collectConvQFInstr(NodeDef);
1657
1658 insertInstr(DefMI, Hexagon::V6_vconv_sf_qf32, DefR, DefR,
1659 getRegState(RegOp) | RegState::Kill);
1660
1661 IgnoreInsertConvList.insert(DefMI);
1662 Changed = true;
1663
1664 // Handles instructions which output qf16 type.
1665 } else if (OpC == Hexagon::PS_vstorerv_ai && HII->isQFP16Instr(DefMI)) {
1666 collectQFUses(NodeDef, DefMI);
1667 if (IgnoreInsertConvList.find(DefMI) != IgnoreInsertConvList.end())
1668 continue;
1669 collectConvQFInstr(NodeDef);
1670
1671 insertInstr(DefMI, Hexagon::V6_vconv_hf_qf16, DefR, DefR,
1672 getRegState(RegOp) | RegState::Kill);
1673
1674 IgnoreInsertConvList.insert(DefMI);
1675 Changed = true;
1676 } else {
1677 LLVM_DEBUG(MI->dump());
1678 llvm_unreachable("This case is not handled. Look above for MI\n");
1679 }
1680 }
1681 return Changed;
1682}
1683
1684bool HexagonPostRAHandleQFP::runOnMachineFunction(MachineFunction &MF) {
1685
1687 return false;
1688
1689 LLVM_DEBUG(
1690 dbgs() << "\n=== Entering Hexagon Fixup QF spills and refills pass ===\n"
1691 << "Mode: ";
1692 switch (QFloatModeValue) {
1693 case QFloatMode::StrictIEEE:
1694 dbgs() << "Strict IEEE";
1695 break;
1696 case QFloatMode::IEEE:
1697 dbgs() << "IEEE";
1698 break;
1699 case QFloatMode::Lossy:
1700 dbgs() << "Lossy";
1701 break;
1702 default:
1703 dbgs() << "Legacy";
1704 break;
1705 };
1706 dbgs() << "\n";);
1707 bool Changed = false;
1708
1709 auto &_HST = MF.getSubtarget<HexagonSubtarget>();
1710 if (!_HST.useHVXOps())
1711 return false;
1712
1713 HII = _HST.getInstrInfo();
1714
1715 // If the mode is legacy, the function may not contain qf instructions
1716 // check if this pass is required to run for legacy mode.
1717 if (QFloatModeValue == QFloatMode::Legacy)
1718 if (!HII->hasQFPInstrs(MF))
1719 return false;
1720
1721 HRI = _HST.getRegisterInfo();
1722 MRI = &MF.getRegInfo();
1723 const auto &MDF = getAnalysis<MachineDominanceFrontierWrapperPass>().getMDF();
1724 MachineDominatorTree *MDT =
1725 &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
1726 HST = &_HST;
1727
1728 // We need Register Dataflow Graph(RDG) to calculate reaching definitions
1729 // since the Machine code is not in SSA.
1730 // DDG holds the graph on which we iterate for the nodes.
1731 DataFlowGraph G(MF, *HII, *HRI, *MDT, MDF);
1732 G.build();
1733 DFG = &G;
1734
1735 Liveness L(*MRI, *DFG);
1736 L.computePhiInfo();
1737 LV = &L;
1738
1739 // Find and save the list of QFP stack spills.
1740 // For refills store all refill instructions to process conditionally later.
1741 NodeAddr<FuncNode *> FA = DFG->getFunc();
1742 LLVM_DEBUG(dbgs() << "==== [RefMap#]=====:\n "
1743 << Print<NodeAddr<FuncNode *>>(FA, *DFG) << "\n");
1744 for (NodeAddr<BlockNode *> BA : FA.Addr->members(*DFG)) {
1745 for (auto IA : BA.Addr->members(*DFG)) {
1746
1747 if (!DFG->IsCode<NodeAttrs::Stmt>(IA))
1748 continue;
1749
1750 // 'SA' holds the Statement node which contains the machine instruction.
1751 NodeAddr<StmtNode *> SA = IA;
1752 MachineInstr *I = SA.Addr->getCode();
1753
1754 switch (I->getOpcode()) {
1755 case Hexagon::PS_vstorerw_ai:
1756 case Hexagon::PS_vstorerv_ai:
1757 collectQFPStackSpill(&SA);
1758 break;
1759 case Hexagon::PS_vloadrw_ai:
1760 case Hexagon::PS_vloadrv_ai:
1761 collectQFPStackRefill(&SA);
1762 break;
1763 case TargetOpcode::COPY:
1764 collectCopies(&SA);
1765 break;
1766 default:
1767 break;
1768 }
1769 }
1770 }
1771
1772 // Walk through the spills and insert converts when necessary.
1773 // Additionally, walk though the uses of the converts and
1774 // store them conditionally for later processing.
1775 LLVM_DEBUG(dbgs() << "\nHandling spills....");
1776 Changed |= HandleSpills();
1777 SpillMIs.clear();
1778
1779 // Walk through the uses of the refill instructions.
1780 // Process them if they are used as qf operands.
1781 LLVM_DEBUG(dbgs() << "\nCollecting refills....\n");
1782 for (NodeAddr<DefNode *> DfNode : RefillMIs) {
1783
1784 NodeAddr<StmtNode *> Stmt = DfNode.Addr->getOwner(*DFG);
1785 MachineInstr *DefMI = Stmt.Addr->getCode();
1786 collectQFUses(DfNode, DefMI);
1787 collectConvQFInstr(DfNode);
1788 }
1789 RefillMIs.clear();
1790
1791 LLVM_DEBUG(dbgs() << "\nHandling copies....");
1792 Changed |= HandleCopies();
1793 QFCopys.clear();
1794 PossibleMultiReachDefs.clear();
1795 ReachDefOfCopies.clear();
1796 ConvertToQfCopies.clear();
1797
1798 LLVM_DEBUG(dbgs() << "\n === QF Uses map === "; for (auto It : QFUsesMap) {
1799 dbgs() << "\nInstruction: ";
1800 It.first->dump();
1801 dbgs() << "\t Property: " << It.second.first << " ," << It.second.second;
1802 });
1803
1804 // Insert new opcodes as applicable for the refill uses.
1805 // Delete the original instructions.
1806 Changed |= HandleRefills();
1807
1808 // Handle non-saturating instructions by inserting convert(s) from sf to qf.
1809 Changed |= HandleNonSatInstr();
1810 QFNonSatMIs.clear();
1811 // Cleanup
1812 for (auto It : QFUsesMap)
1813 It.first->eraseFromParent();
1814 QFUsesMap.clear();
1815 IgnoreInsertConvList.clear();
1816
1817 // Option if enabled, checks for qf use-def mismatches
1819 dbgs() << "\nChecking for ABI compliance for XQF post register \
1820allocation for function: "
1821 << MF.getName() << "\n";
1822 DataFlowGraph DFG(MF, *HII, *HRI, *MDT, MDF);
1823 DFG.build();
1824 Liveness LV(*MRI, DFG);
1825 LV.computeLiveIns();
1826 XqfPostRADiagnosis VDiag(DFG, LV, HII);
1827 VDiag.runCompliance();
1828 }
1829 return Changed;
1830}
1831
1832//===----------------------------------------------------------------------===//
1833// Public Constructor Functions
1834//===----------------------------------------------------------------------===//
1835INITIALIZE_PASS_BEGIN(HexagonPostRAHandleQFP, "handle-qfp-spills-refills",
1836 "Hexagon Post RA Handle QFloat", false, false)
1839INITIALIZE_PASS_END(HexagonPostRAHandleQFP, "handle-qfp-spills-refills",
1840 "Hexagon PostRA Handle QFloat", false, false)
1841
1843 return new HexagonPostRAHandleQFP();
1844}
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static Register UseReg(const MachineOperand &MO)
SmallVector< unsigned short, 5 > QFNonSatInstr
cl::opt< bool > DisablePostRAHandleQFloat("disable-handle-qfp", cl::init(false), cl::desc("Disable handling of Qfloat spills/refills after register " "allocation."))
DenseMap< unsigned short, std::pair< bool, bool > > QFPSatInstsMap
static cl::opt< bool > EnablePostRAXqfCompliance("enable-postra-xqf-check", cl::init(false), cl::desc("Enable ABI compliance for xqf operands post regalloc."))
cl::opt< QFloatMode > QFloatModeValue
static void getAllRealUses(NodeAddr< DefNode * > DA, NodeSet &UNodeSet, Liveness *L, DataFlowGraph *G, bool comprehensive=false)
IRTranslator LLVM IR MI
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define P(N)
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:484
#define LLVM_DEBUG(...)
Definition Debug.h:119
void print_warning(Twine &, MachineInstr *, MachineInstr *) const
XqfPostRADiagnosis(DataFlowGraph &G, Liveness &L, const HexagonInstrInfo *HII)
XqfPostRADiagnosis()=delete
AnalysisUsage & addRequired()
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 hasQFPInstrs(const MachineFunction &MF) const
bool isQFP32Instr(MachineInstr *MI) const
bool usesQF16Operand(MachineInstr *MI, unsigned Index=0) const
bool isQFP16Instr(MachineInstr *MI) const
bool usesQF32Operand(MachineInstr *MI, unsigned Index=0) const
bool isMIBefore(const MachineInstr *A, const MachineInstr *B) const
bool isQFPInstr(MachineInstr *MI) const
bool usesQFOperand(MachineInstr *MI, unsigned Index=0) const
bool isFakeReg(MCPhysReg Reg) const
Returns true if the given reserved physical register Reg is live across function calls/returns.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
Analysis pass which computes a MachineDominatorTree.
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.
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.
const MachineBasicBlock * getParent() const
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void dump() const
const MachineOperand & getOperand(unsigned i) const
Register getReg() const
getReg - Returns the register number.
bool isFI() const
isFI - Tests if this is a MO_FrameIndex operand.
A NodeSet contains a set of SUnit DAG nodes with additional information that assigns a priority to th...
unsigned size() const
bool insert(SUnit *SU)
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
void dump() const
Definition Pass.cpp:146
Wrapper class representing virtual and physical registers.
Definition Register.h:20
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
self_iterator getIterator()
Definition ilist_node.h:123
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Entry
Definition COFF.h:862
initializer< Ty > init(const Ty &Val)
NodeAddr< InstrNode * > Instr
Definition RDFGraph.h:391
Print(const T &, const DataFlowGraph &) -> Print< T >
NodeAddr< StmtNode * > Stmt
Definition RDFGraph.h:393
uint32_t NodeId
Definition RDFGraph.h:262
std::set< NodeId > NodeSet
Definition RDFGraph.h:553
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.
void initializeHexagonPostRAHandleQFPPass(PassRegistry &)
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
Definition STLExtras.h:1151
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
Definition STLExtras.h:2026
char & HexagonPostRAHandleQFPID
FunctionPass * createHexagonPostRAHandleQFP()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
RegState getRegState(const MachineOperand &RegOp)
Get all register state flags from machine operand RegOp.
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
DWARFExpression::Operation Op
T getCode() const
Definition RDFGraph.h:615
LLVM_ABI void build(const Config &config)
Definition RDFGraph.cpp:857
static bool IsDef(const Node BA)
Definition RDFGraph.h:829
static bool IsUse(const Node BA)
Definition RDFGraph.h:834
static bool IsCode(const Node BA)
Definition RDFGraph.h:825
NodeAddr< T > addr(NodeId N) const
Definition RDFGraph.h:694
LLVM_ABI Node getOwner(const DataFlowGraph &G)
Definition RDFGraph.cpp:525
DenseMap< RegisterId, NodeRefSet > RefMap
Definition RDFLiveness.h:59
LLVM_ABI std::pair< NodeSet, bool > getAllReachingDefsRec(RegisterRef RefRR, NodeAddr< RefNode * > RefA, NodeSet &Visited, const NodeSet &Defs)
LLVM_ABI void computeLiveIns()
MachineInstr * getCode() const
Definition RDFGraph.h:640