83#define DEBUG_TYPE "handle-qfp"
91 "disable-handle-qfp",
cl::init(
false),
92 cl::desc(
"Disable handling of Qfloat spills/refills after register "
100 bool comprehensive =
false) {
104 auto UseSet = L->getAllReachedUses(DR, DA);
106 for (
auto UI : UseSet) {
119 if (HRI->isFakeReg(RR))
126 for (
auto I : phiUse) {
129 auto phiUseSet =
I.second;
130 for (
auto phiUI : phiUseSet) {
144 NodeId QFPDefNode = UA.
Addr->getReachingDef();
151 if (ReachDefInstr && ReachDefInstr ==
Instr)
169 {Hexagon::V6_vadd_qf16_mix, {
false,
true}},
170 {Hexagon::V6_vadd_qf16, {
false,
false}},
171 {Hexagon::V6_vadd_qf32_mix, {
false,
true}},
172 {Hexagon::V6_vadd_qf32, {
false,
false}},
173 {Hexagon::V6_vsub_qf16_mix, {
false,
true}},
174 {Hexagon::V6_vsub_hf_mix, {
true,
false}},
175 {Hexagon::V6_vsub_qf16, {
false,
false}},
176 {Hexagon::V6_vsub_qf32_mix, {
false,
true}},
177 {Hexagon::V6_vsub_sf_mix, {
true,
false}},
178 {Hexagon::V6_vsub_qf32, {
false,
false}},
179 {Hexagon::V6_vmpy_qf16_mix_hf, {
false,
true}},
180 {Hexagon::V6_vmpy_qf16, {
false,
false}},
181 {Hexagon::V6_vmpy_qf32_mix_hf, {
false,
true}},
182 {Hexagon::V6_vmpy_qf32_qf16, {
false,
false}},
183 {Hexagon::V6_vmpy_qf32, {
false,
false}},
184 {Hexagon::V6_vmpy_rt_qf16, {
false,
true}},
187 {Hexagon::V6_vabs_qf32_qf32, {
false,
true}},
188 {Hexagon::V6_vabs_qf16_qf16, {
false,
true}},
189 {Hexagon::V6_vneg_qf32_qf32, {
false,
true}},
190 {Hexagon::V6_vneg_qf16_qf16, {
false,
true}},
191 {Hexagon::V6_vilog2_qf32, {
false,
true}},
192 {Hexagon::V6_vilog2_qf16, {
false,
true}},
193 {Hexagon::V6_vconv_qf32_qf32, {
false,
true}},
194 {Hexagon::V6_vconv_qf16_qf16, {
false,
true}},
201 Hexagon::V6_vconv_hf_qf16, Hexagon::V6_vconv_hf_qf32,
202 Hexagon::V6_vconv_sf_qf32,
204 Hexagon::V6_vconv_bf_qf32, Hexagon::V6_vconv_f8_qf16};
210 HexagonPostRAHandleQFP() : MachineFunctionPass(ID) {
214 StringRef getPassName()
const override {
215 return "Hexagon handle QFloat spills and refills post RA.";
217 void getAnalysisUsage(AnalysisUsage &AU)
const override {
220 AU.
addRequired<MachineDominanceFrontierWrapperPass>();
223 bool runOnMachineFunction(MachineFunction &MF)
override;
230 using QFUses = std::map<MachineInstr *, std::pair<bool, bool>>;
234 DataFlowGraph *DFG =
nullptr;
238 std::vector<std::pair<MachineInstr *, NodeAddr<DefNode *>>> SpillMIs;
240 std::vector<NodeAddr<DefNode *>> RefillMIs;
250 MapVector<MachineInstr *, unsigned> QFNonSatMIs;
253 std::set<NodeId> PossibleMultiReachDefs;
257 SmallPtrSet<MachineInstr *, 4> IgnoreInsertConvList;
260 enum class RegType { qf32, qf16, qf32_double, qf16_double, ieee, undefined };
263 std::map<std::pair<NodeId, NodeId>, RegType> QFCopys;
266 DenseMap<MachineInstr *, RegType> ReachDefOfCopies;
271 DenseMap<MachineInstr *, std::pair<NodeAddr<DefNode *>, RegType>>
276 DenseMap<MachineInstr *, std::pair<bool, bool>> SubRegKillSet;
278 const HexagonInstrInfo *HII =
nullptr;
279 const HexagonRegisterInfo *HRI =
nullptr;
280 MachineRegisterInfo *MRI =
nullptr;
281 Liveness *LV =
nullptr;
282 const HexagonSubtarget *HST =
nullptr;
284 void collectQFPStackSpill(NodeAddr<StmtNode *> *);
285 void collectQFPStackRefill(NodeAddr<StmtNode *> *);
286 void collectCopies(NodeAddr<StmtNode *> *);
287 bool HandleRefills();
290 bool HandleNonSatInstr();
291 bool HandleMultiReachingDefs();
292 bool HandleReachDefOfCopies();
293 bool HandleConvertToQfCopies();
294 RegType HasQfUses(NodeAddr<DefNode *>, MachineInstr *);
295 void collectConvQFInstr(NodeAddr<DefNode *> &);
296 void collectQFUses(NodeAddr<DefNode *>, MachineInstr *
DefMI);
297 void conditionallyInsert(MachineInstr &,
Register &);
300 unsigned short getreplacedQFOpcode(
unsigned,
bool,
bool);
301 MCPhysReg findAllocatableReg(MachineInstr *
MI)
const;
302 void insertIEEEToQF(MachineInstr *,
Register, MachineOperand,
bool is32bit);
303 void collectLivenessForSubregs(NodeAddr<UseNode *> &);
304 void insertInstr(MachineInstr *,
unsigned,
unsigned,
unsigned,
RegState);
313char HexagonPostRAHandleQFP::ID = 0;
330 Register Reg2 =
MI.getNumOperands() == 2 ? DefReg :
MI.getOperand(2).getReg();
332 if (QFUsesMap.find(&
MI) != QFUsesMap.end()) {
333 auto Entry = QFUsesMap[&
MI];
334 bool firstOp = ((Reg1 == DefReg) ?
true :
false) | Entry.first;
335 bool secondOp = ((Reg2 == DefReg) ?
true :
false) | Entry.second;
336 QFUsesMap[&
MI] = std::make_pair(firstOp, secondOp);
343 bool firstOp = (Reg1 == DefReg) ?
true : defaultPair.first;
344 bool secondOp = (Reg2 == DefReg) ?
true : defaultPair.second;
345 QFUsesMap[&
MI] = std::make_pair(firstOp, secondOp);
349unsigned short HexagonPostRAHandleQFP::getreplacedQFOpcode(
unsigned srcOpcode,
352 if (firstOp && secondOp) {
354 case Hexagon::V6_vadd_qf32:
355 case Hexagon::V6_vadd_qf32_mix:
356 return Hexagon::V6_vadd_sf;
357 case Hexagon::V6_vadd_qf16:
358 case Hexagon::V6_vadd_qf16_mix:
359 return Hexagon::V6_vadd_hf;
361 case Hexagon::V6_vsub_qf32:
362 case Hexagon::V6_vsub_qf32_mix:
363 case Hexagon::V6_vsub_sf_mix:
364 return Hexagon::V6_vsub_sf;
365 case Hexagon::V6_vsub_qf16:
366 case Hexagon::V6_vsub_qf16_mix:
367 case Hexagon::V6_vsub_hf_mix:
368 return Hexagon::V6_vsub_hf;
370 case Hexagon::V6_vmpy_qf32:
371 return Hexagon::V6_vmpy_qf32_sf;
372 case Hexagon::V6_vmpy_qf16:
373 case Hexagon::V6_vmpy_qf16_mix_hf:
374 return Hexagon::V6_vmpy_qf16_hf;
375 case Hexagon::V6_vmpy_qf32_qf16:
376 case Hexagon::V6_vmpy_qf32_mix_hf:
377 return Hexagon::V6_vmpy_qf32_hf;
379 case Hexagon::V6_vmpy_rt_qf16:
380 return Hexagon::V6_vmpy_rt_hf;
382 case Hexagon::V6_vabs_qf32_qf32:
383 return Hexagon::V6_vabs_qf32_sf;
384 case Hexagon::V6_vabs_qf16_qf16:
385 return Hexagon::V6_vabs_qf16_hf;
386 case Hexagon::V6_vneg_qf32_qf32:
387 return Hexagon::V6_vneg_qf32_sf;
388 case Hexagon::V6_vneg_qf16_qf16:
389 return Hexagon::V6_vneg_qf16_hf;
390 case Hexagon::V6_vilog2_qf32:
391 return Hexagon::V6_vilog2_sf;
392 case Hexagon::V6_vilog2_qf16:
393 return Hexagon::V6_vilog2_hf;
394 case Hexagon::V6_vconv_qf32_qf32:
395 return Hexagon::V6_vconv_qf32_sf;
396 case Hexagon::V6_vconv_qf16_qf16:
397 return Hexagon::V6_vconv_qf16_hf;
403 }
else if (firstOp) {
405 case Hexagon::V6_vadd_qf32:
406 return Hexagon::V6_vadd_qf32_mix;
407 case Hexagon::V6_vadd_qf16:
408 return Hexagon::V6_vadd_qf16_mix;
410 case Hexagon::V6_vsub_qf32:
412 return Hexagon::V6_vsub_sf_mix;
414 return Hexagon::V6_vsub_sf;
417 case Hexagon::V6_vsub_qf16:
419 return Hexagon::V6_vsub_hf_mix;
421 return Hexagon::V6_vsub_hf;
424 case Hexagon::V6_vsub_qf32_mix:
425 return Hexagon::V6_vsub_sf;
426 case Hexagon::V6_vsub_qf16_mix:
427 return Hexagon::V6_vsub_hf;
432 case Hexagon::V6_vmpy_qf32:
433 return Hexagon::V6_vmpy_qf32_sf;
434 case Hexagon::V6_vmpy_qf16:
435 return Hexagon::V6_vmpy_qf16_mix_hf;
436 case Hexagon::V6_vmpy_qf32_qf16:
437 return Hexagon::V6_vmpy_qf32_mix_hf;
442 }
else if (secondOp) {
444 case Hexagon::V6_vadd_qf32:
445 return Hexagon::V6_vadd_qf32_mix;
446 case Hexagon::V6_vadd_qf16:
447 return Hexagon::V6_vadd_qf16_mix;
449 case Hexagon::V6_vsub_qf32:
450 return Hexagon::V6_vsub_qf32_mix;
451 case Hexagon::V6_vsub_qf16:
452 return Hexagon::V6_vsub_qf16_mix;
453 case Hexagon::V6_vsub_sf_mix:
454 return Hexagon::V6_vsub_sf;
455 case Hexagon::V6_vsub_hf_mix:
456 return Hexagon::V6_vsub_hf;
458 case Hexagon::V6_vmpy_qf32:
459 return Hexagon::V6_vmpy_qf32_sf;
461 case Hexagon::V6_vmpy_qf16:
462 return Hexagon::V6_vmpy_qf16_mix_hf;
463 case Hexagon::V6_vmpy_qf32_qf16:
464 return Hexagon::V6_vmpy_qf32_mix_hf;
475void HexagonPostRAHandleQFP::insertIEEEToQF(MachineInstr *
MI,
Register SrcReg,
476 MachineOperand SrcOp,
477 bool is32bit =
false) {
479 auto MBB =
MI->getParent();
480 MachineInstrBuilder MIB;
484 auto Op = is32bit ? Hexagon::V6_vconv_qf32_sf : Hexagon::V6_vconv_qf16_hf;
486 .
addReg(SrcReg, RegState::Renamable | RegState::Kill);
492 auto V0_Reg = findAllocatableReg(
MI);
497 auto Op = is32bit ? Hexagon::V6_vadd_sf : Hexagon::V6_vadd_hf;
499 .
addReg(SrcReg, RegState::Renamable | RegState::Kill)
500 .
addReg(V0_Reg, RegState::Kill);
509bool HexagonPostRAHandleQFP::HandleRefills() {
513 std::vector<MachineInstr *> eraseList;
515 for (
auto It : QFUsesMap) {
518 MachineInstr *
MI = It.first;
519 auto SrcOpcode =
MI->getOpcode();
520 auto Pair = It.second;
521 auto SrcOp1 =
MI->getOperand(1);
522 Register DestReg =
MI->getOperand(0).getReg();
523 auto MBB =
MI->getParent();
524 MachineInstrBuilder MIB;
530 auto HandleUnaryRefill = [&](MachineInstr *
MI,
bool isIeee) ->
bool {
532 auto finalOpcode = getreplacedQFOpcode(SrcOpcode,
true,
true);
539 eraseList.push_back(
MI);
543 if (
MI->getNumOperands() == 2) {
544 Changed |= HandleUnaryRefill(It.first, It.second.first);
547 auto SrcOp2 =
MI->getOperand(2);
550 auto HandleSub = [&](
auto srcOpcode) ->
bool {
551 auto ConvOp = (srcOpcode == Hexagon::V6_vsub_qf32)
552 ? Hexagon::V6_vconv_sf_qf32
553 : Hexagon::V6_vconv_hf_qf16;
554 auto SubOp = (ConvOp == Hexagon::V6_vconv_sf_qf32) ? Hexagon::V6_vsub_sf
555 : Hexagon::V6_vsub_hf;
557 Register SrcOp2Reg = SrcOp2.getReg();
567 if (!SrcOp2.isKill())
568 insertIEEEToQF(&*(++
MI->getIterator()), SrcOp2.getReg(), SrcOp2);
573 if (Pair.first ==
true && Pair.second ==
true) {
574 auto finalOpcode = getreplacedQFOpcode(SrcOpcode,
true,
true);
582 }
else if (Pair.first ==
true && Pair.second ==
false) {
583 auto finalOpcode = getreplacedQFOpcode(SrcOpcode,
true,
false);
587 if (SrcOpcode == Hexagon::V6_vmpy_qf32) {
588 Register SrcOp2Reg = SrcOp2.getReg();
599 if (!SrcOp2.isKill())
600 insertIEEEToQF(&*(++
MI->getIterator()), SrcOp2.getReg(), SrcOp2,
605 }
else if (finalOpcode == Hexagon::V6_vadd_qf16_mix ||
606 finalOpcode == Hexagon::V6_vadd_qf32_mix ||
607 finalOpcode == Hexagon::V6_vmpy_qf16_mix_hf ||
608 finalOpcode == Hexagon::V6_vmpy_qf32_mix_hf) {
618 }
else if ((SrcOpcode == Hexagon::V6_vsub_qf32 ||
619 SrcOpcode == Hexagon::V6_vsub_qf16) &&
621 Changed |= HandleSub(SrcOpcode);
631 }
else if (Pair.first ==
false && Pair.second ==
true) {
633 auto finalOpcode = getreplacedQFOpcode(SrcOpcode,
false,
true);
636 if (SrcOpcode == Hexagon::V6_vmpy_qf32) {
637 Register SrcOp1Reg = SrcOp1.getReg();
650 if (!SrcOp1.isKill())
651 insertIEEEToQF(&*(++
MI->getIterator()), SrcOp1.getReg(), SrcOp1,
666 eraseList.push_back(
MI);
670 for (MachineInstr *delMI : eraseList)
671 QFUsesMap.erase(delMI);
677void HexagonPostRAHandleQFP::insertInstr(MachineInstr *
MI,
unsigned MIOpcode,
678 unsigned SrcReg,
unsigned DstReg,
681 MachineInstrBuilder MIB;
682 MachineBasicBlock *
MBB =
MI->getParent();
685 auto MINext = ++
MI->getIterator();
689 MIB =
BuildMI(*
MBB, MINext,
DL, HII->get(MIOpcode), DstReg)
697MCPhysReg HexagonPostRAHandleQFP::findAllocatableReg(MachineInstr *
MI)
const {
698 LLVM_DEBUG(
dbgs() <<
"\tUsing V30 register to store a vector of zeroes!");
703bool HexagonPostRAHandleQFP::HandleNonSatInstr() {
705 for (
auto It : QFNonSatMIs) {
706 MachineInstr *
MI = It.first;
707 auto MIOpcode =
MI->getOpcode();
708 auto Op =
MI->getOperand(1);
713 if (MIOpcode == Hexagon::V6_vconv_hf_qf16 ||
714 MIOpcode == Hexagon::V6_vconv_f8_qf16) {
716 insertIEEEToQF(
MI, DefReg,
Op);
720 insertInstr(
MI, Hexagon::V6_vconv_hf_qf16, DefReg, DefReg,
725 }
else if (MIOpcode == Hexagon::V6_vconv_hf_qf32 ||
726 MIOpcode == Hexagon::V6_vconv_bf_qf32) {
727 Register DefLo = HRI->getSubReg(DefReg, Hexagon::vsub_lo);
728 Register DefHi = HRI->getSubReg(DefReg, Hexagon::vsub_hi);
730 if (It.second == ConvOperand::HiLo) {
731 insertIEEEToQF(
MI, DefLo,
Op,
true );
732 insertIEEEToQF(
MI, DefHi,
Op,
true );
736 auto KillState = SubRegKillSet[
MI];
737 if (!KillState.first)
738 insertInstr(
MI, Hexagon::V6_vconv_sf_qf32, DefHi, DefHi,
741 if (!KillState.second)
742 insertInstr(
MI, Hexagon::V6_vconv_sf_qf32, DefLo, DefLo,
745 }
else if (It.second == ConvOperand::Hi) {
746 insertIEEEToQF(
MI, DefHi,
Op,
true );
748 insertInstr(
MI, Hexagon::V6_vconv_sf_qf32, DefHi, DefHi,
752 insertIEEEToQF(
MI, DefLo,
Op,
true );
754 insertInstr(
MI, Hexagon::V6_vconv_sf_qf32, DefLo, DefLo,
758 }
else if (MIOpcode == Hexagon::V6_vconv_sf_qf32) {
759 insertIEEEToQF(
MI, DefReg,
Op,
true );
761 insertInstr(
MI, Hexagon::V6_vconv_sf_qf32, DefReg, DefReg,
769 if (QFNonSatMIs.empty())
777void HexagonPostRAHandleQFP::collectLivenessForSubregs(
778 NodeAddr<UseNode *> &UsedNode) {
779 RegisterRef UR = UsedNode.
Addr->getRegRef(*DFG);
780 NodeAddr<StmtNode *> UseStmt = UsedNode.
Addr->getOwner(*DFG);
781 MachineInstr *UseInstr = UseStmt.
Addr->getCode();
783 Register UseDefLo = HRI->getSubReg(UseOp.getReg(), Hexagon::vsub_lo);
784 Register UseDefHi = HRI->getSubReg(UseOp.getReg(), Hexagon::vsub_hi);
787 bool isHiSubRegKilled =
true, isLoSubRegKilled =
true;
793 for (
auto RD :
P.first) {
794 NodeAddr<DefNode *> RegDef = DFG->
addr<DefNode *>(RD);
798 NodeAddr<StmtNode *> RegStmt = RegDef.Addr->getOwner(*DFG);
799 MachineInstr *ReachDefInstr = RegStmt.
Addr->getCode();
800 if (ReachDefInstr ==
nullptr)
806 if (Hexagon::HvxWRRegClass.
contains(DefReg)) {
808 isHiSubRegKilled = isLoSubRegKilled =
false;
818 for (
auto UIntr : UseSet) {
819 NodeAddr<UseNode *> UA = DFG->
addr<UseNode *>(UIntr);
820 NodeAddr<StmtNode *> UseStmt = UA.
Addr->getOwner(*DFG);
821 MachineInstr *
UseMI = UseStmt.Addr->getCode();
822 if (
UseMI ==
nullptr)
826 if (
UseMI == UseInstr)
829 isLoSubRegKilled =
false;
833 isHiSubRegKilled =
false;
839 SubRegKillSet[UseInstr] = std::make_pair(isHiSubRegKilled, isLoSubRegKilled);
843void HexagonPostRAHandleQFP::collectQFPStackRefill(
844 NodeAddr<StmtNode *> *StNode) {
845 NodeAddr<DefNode *> DfNode =
846 StNode->
Addr->members_if(DFG->
IsDef, *DFG).front();
847 MachineInstr *
MI = StNode->
Addr->getCode();
849 const MachineOperand &OpFI =
MI->getOperand(1);
854 RefillMIs.push_back(DfNode);
859void HexagonPostRAHandleQFP::collectConvQFInstr(NodeAddr<DefNode *> &RegDef) {
862 NodeAddr<StmtNode *> DefStmt = RegDef.
Addr->getOwner(*DFG);
863 MachineInstr *DefInstr = DefStmt.
Addr->getCode();
865 for (
auto UI : UseSet) {
866 NodeAddr<UseNode *> UA = DFG->
addr<UseNode *>(UI);
869 NodeAddr<StmtNode *> UseStmt = UA.
Addr->getOwner(*DFG);
870 MachineInstr *QFConvInstr = UseStmt.
Addr->getCode();
881 collectLivenessForSubregs(UA);
882 unsigned Op = ConvOperand::Undefined;
883 if (QFNonSatMIs.contains(QFConvInstr))
884 Op = QFNonSatMIs[QFConvInstr];
887 if (Hexagon::HvxWRRegClass.
contains(DefReg))
888 Op = ConvOperand::HiLo;
890 else if (DefReg == HRI->getSubReg(
UseReg, Hexagon::vsub_lo))
891 Op |= ConvOperand::Lo;
894 Op |= ConvOperand::Hi;
895 QFNonSatMIs[QFConvInstr] =
Op;
897 QFNonSatMIs[QFConvInstr] = ConvOperand::HiLo;
899 IgnoreInsertConvList.insert(DefInstr);
900 LLVM_DEBUG(std::string OpType =
"";
switch (QFNonSatMIs[QFConvInstr]) {
901 case ConvOperand::HiLo:
904 case ConvOperand::Lo:
907 case ConvOperand::Hi:
911 OpType =
"Undefined";
912 }
dbgs() <<
"Collecting convert instruction with type "
914 QFConvInstr->dump());
922void HexagonPostRAHandleQFP::collectCopies(NodeAddr<StmtNode *> *StNode) {
924 NodeAddr<DefNode *> CopyDef =
925 StNode->
Addr->members_if(DFG->
IsDef, *DFG).front();
926 MachineInstr *CopyInstr = StNode->
Addr->getCode();
929 for (NodeAddr<UseNode *> UA : StNode->
Addr->members_if(DFG->
IsUse, *DFG)) {
930 RegisterRef UR = UA.
Addr->getRegRef(*DFG);
935 dbgs() <<
"*** Unable to collect all reaching defs for use ***\n"
936 << PrintNode<UseNode *>(UA, *DFG) <<
'\n';
942 for (
auto RD :
P.first) {
943 NodeAddr<DefNode *> RegDef = DFG->
addr<DefNode *>(RD);
947 NodeAddr<StmtNode *> RegStmt = RegDef.
Addr->getOwner(*DFG);
948 MachineInstr *ReachDefInstr = RegStmt.
Addr->getCode();
949 if (ReachDefInstr ==
nullptr)
954 if (ReachDefInstr->
getOpcode() == TargetOpcode::COPY) {
955 auto pairKey = std::make_pair(CopyDef.
Id, RegDef.
Id);
956 QFCopys[pairKey] = RegType::ieee;
962 auto RegT = RegType::undefined;
968 if (Hexagon::HvxWRRegClass.
contains(
970 RegT = RegType::qf32_double;
972 RegT = RegType::qf32;
975 if (Hexagon::HvxWRRegClass.
contains(
977 RegT = RegType::qf16_double;
979 RegT = RegType::qf16;
985 if (Hexagon::HvxWRRegClass.
contains(CopyReg) ||
986 Hexagon::HvxVRRegClass.
contains(CopyReg))
987 RegT = RegType::ieee;
991 auto pairKey = std::make_pair(CopyDef.
Id, RegDef.
Id);
992 QFCopys[pairKey] = RegT;
999void HexagonPostRAHandleQFP::collectQFPStackSpill(
1000 NodeAddr<StmtNode *> *StNode) {
1002 MachineInstr *
MI = StNode->
Addr->getCode();
1005 const MachineOperand &OpFI =
MI->getOperand(0);
1018 if (!
MI->getOperand(2).isReg())
1024 for (NodeAddr<UseNode *> UA : StNode->
Addr->members_if(DFG->
IsUse, *DFG)) {
1025 QFPDefNode = UA.
Addr->getReachingDef();
1028 NodeAddr<DefNode *> RegDef = DFG->
addr<DefNode *>(QFPDefNode);
1029 assert(QFPDefNode != 0 &&
"Reaching def computation error");
1030 NodeAddr<StmtNode *> RegStmt = RegDef.
Addr->getOwner(*DFG);
1031 MachineInstr *ReachDefInstr = RegStmt.
Addr->getCode();
1032 if (ReachDefInstr ==
nullptr)
1035 ReachDefInstr->
dump());
1043 auto RR = RegDef.
Addr->getRegRef(*DFG).Id;
1048 dbgs() <<
"The corresponding XQF instruction is:\n";
1049 ReachDefInstr->
dump());
1052 SpillMIs.push_back(std::make_pair(
MI, RegDef));
1058void HexagonPostRAHandleQFP::collectQFUses(NodeAddr<DefNode *> RegDef,
1059 MachineInstr *
DefMI) {
1065 for (
auto UI : UseSet) {
1066 NodeAddr<UseNode *> UA = DFG->
addr<UseNode *>(UI);
1069 NodeAddr<StmtNode *> UseStmt = UA.
Addr->getOwner(*DFG);
1070 MachineInstr *
UseMI = UseStmt.
Addr->getCode();
1075 if (PossibleMultiReachDefs.count(UseStmt.
Id) == 0) {
1076 PossibleMultiReachDefs.insert(UseStmt.
Id);
1077 LLVM_DEBUG(
dbgs() <<
"\n[Collect instr with possible multidef]:";
1080 conditionallyInsert(*
UseMI, UsedReg);
1090bool HexagonPostRAHandleQFP::HandleMultiReachingDefs() {
1096 for (
auto It : PossibleMultiReachDefs) {
1097 NodeAddr<StmtNode *>
Stmt = DFG->
addr<StmtNode *>(It);
1101 auto Pair = QFUsesMap[
Instr];
1103 unsigned short UseNo = 1;
1109 if ((UseNo == 1 && Pair.first ==
false) ||
1110 (UseNo == 2 && Pair.second ==
false)) {
1115 RegisterRef UR = UA.
Addr->getRegRef(*DFG);
1120 dbgs() <<
"*** Unable to collect all reaching defs for use ***\n"
1121 << PrintNode<UseNode *>(UA, *DFG) <<
'\n';
1128 for (
auto RD :
P.first) {
1129 NodeAddr<DefNode *> RegDef = DFG->
addr<DefNode *>(RD);
1132 auto RR = RegDef.
Addr->getRegRef(*DFG).Id;
1136 NodeAddr<StmtNode *> RegStmt = RegDef.
Addr->getOwner(*DFG);
1137 MachineInstr *ReachDefInstr = RegStmt.
Addr->getCode();
1139 if (ReachDefInstr ==
nullptr)
1144 if (IgnoreInsertConvList.find(ReachDefInstr) !=
1145 IgnoreInsertConvList.end())
1148 ReachDefInstr->
dump());
1152 auto NextReachMI = ++ReachDefInstr->
getIterator();
1155 MachineInstrBuilder MIB;
1161 if (Hexagon::HvxWRRegClass.
contains(
1163 Register RegLo = HRI->getSubReg(OpReg, Hexagon::vsub_lo);
1164 Register RegHi = HRI->getSubReg(OpReg, Hexagon::vsub_hi);
1166 HII->get(Hexagon::V6_vconv_sf_qf32), RegLo)
1167 .
addReg(RegLo, RegState::Renamable | RegState::Kill);
1168 LLVM_DEBUG(
dbgs() <<
"[MultiDef] Inserting convert instruction: ";
1171 HII->get(Hexagon::V6_vconv_sf_qf32), RegHi)
1172 .
addReg(RegHi, RegState::Renamable | RegState::Kill);
1175 HII->get(Hexagon::V6_vconv_sf_qf32), OpReg)
1176 .
addReg(OpReg, RegState::Renamable | RegState::Kill);
1181 HII->get(Hexagon::V6_vconv_hf_qf16), OpReg)
1182 .
addReg(OpReg, RegState::Renamable | RegState::Kill);
1184 LLVM_DEBUG(
dbgs() <<
"[MultiDef] Inserting convert instruction: ";
1186 ReachDefInstr->
dump());
1191 collectQFUses(RegDef, ReachDefInstr);
1192 collectConvQFInstr(RegDef);
1193 IgnoreInsertConvList.insert(ReachDefInstr);
1202bool HexagonPostRAHandleQFP::HandleConvertToQfCopies() {
1203 if (ConvertToQfCopies.empty())
1207 dbgs() <<
"\n*** Inserting convert to qf for selected copies ***\n");
1212 auto CanTransform = [&](MachineInstr *
MI,
unsigned OpNo) ->
bool {
1213 if (QFUsesMap.find(
MI) != QFUsesMap.end()) {
1215 if (OpNo == 1 &&
Entry.first ==
true)
1217 if (OpNo == 2 &&
Entry.second ==
true)
1223 for (
auto It : ConvertToQfCopies) {
1228 for (
auto UI : UseSet) {
1229 NodeAddr<UseNode *> UA = DFG->
addr<UseNode *>(UI);
1232 NodeAddr<StmtNode *> UseStmt = UA.
Addr->getOwner(*DFG);
1233 MachineInstr *
UseMI = UseStmt.
Addr->getCode();
1234 unsigned OpNo = UA.
Addr->getOp().getOperandNo();
1236 if (!CanTransform(
UseMI, OpNo)) {
1244 LLVM_DEBUG(
dbgs() <<
"\n[HandleConvertToQfCopies]\tProcessing Copy:";
1246 auto CopyOp = It.first->getOperand(0);
1247 auto NextMIIter = std::next(It.first->getIterator());
1248 switch (It.second.second) {
1249 case RegType::qf32_double: {
1250 Register DefLo = HRI->getSubReg(CopyOp.getReg(), Hexagon::vsub_lo);
1251 Register DefHi = HRI->getSubReg(CopyOp.getReg(), Hexagon::vsub_hi);
1252 insertIEEEToQF(&*NextMIIter, DefLo, CopyOp,
true);
1253 insertIEEEToQF(&*NextMIIter, DefHi, CopyOp,
true);
1256 case RegType::qf16_double: {
1257 Register DefLo = HRI->getSubReg(CopyOp.getReg(), Hexagon::vsub_lo);
1258 Register DefHi = HRI->getSubReg(CopyOp.getReg(), Hexagon::vsub_hi);
1259 insertIEEEToQF(&*NextMIIter, DefLo, CopyOp,
false);
1260 insertIEEEToQF(&*NextMIIter, DefHi, CopyOp,
false);
1264 insertIEEEToQF(&*NextMIIter, CopyOp.getReg(), CopyOp,
1268 insertIEEEToQF(&*NextMIIter, CopyOp.getReg(), CopyOp,
true);
1274 collectQFUses(It.second.first, It.first);
1275 collectConvQFInstr(It.second.first);
1281bool HexagonPostRAHandleQFP::HandleReachDefOfCopies() {
1282 if (ReachDefOfCopies.empty())
1285 MachineInstrBuilder MIB;
1286 for (
auto It : ReachDefOfCopies) {
1288 auto &dl = It.first->getDebugLoc();
1289 auto NextMI = ++(It.first)->getIterator();
1290 auto RegOp = It.first->getOperand(0);
1293 if (It.second == RegType::qf32)
1295 BuildMI(*
MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_sf_qf32), OpReg)
1296 .
addReg(OpReg, RegState::Renamable | RegState::Kill);
1297 else if (It.second == RegType::qf16)
1299 BuildMI(*
MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_hf_qf16), OpReg)
1300 .
addReg(OpReg, RegState::Renamable | RegState::Kill);
1301 else if (It.second == RegType::qf32_double) {
1302 Register RegLo = HRI->getSubReg(OpReg, Hexagon::vsub_lo);
1303 Register RegHi = HRI->getSubReg(OpReg, Hexagon::vsub_hi);
1305 BuildMI(*
MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_sf_qf32), RegLo)
1306 .
addReg(RegLo, RegState::Renamable | RegState::Kill);
1310 BuildMI(*
MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_sf_qf32), RegHi)
1311 .
addReg(RegHi, RegState::Renamable | RegState::Kill);
1312 }
else if (It.second == RegType::qf16_double) {
1313 Register RegLo = HRI->getSubReg(OpReg, Hexagon::vsub_lo);
1314 Register RegHi = HRI->getSubReg(OpReg, Hexagon::vsub_hi);
1316 BuildMI(*
MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_hf_qf16), RegLo)
1317 .
addReg(RegLo, RegState::Renamable | RegState::Kill);
1321 BuildMI(*
MBB, NextMI, dl, HII->get(Hexagon::V6_vconv_hf_qf16), RegHi)
1322 .
addReg(RegHi, RegState::Renamable | RegState::Kill);
1331HexagonPostRAHandleQFP::RegType
1332HexagonPostRAHandleQFP::HasQfUses(NodeAddr<DefNode *> CopyDef,
1333 MachineInstr *CopyMI) {
1337 if (UseSet.
size() == 0)
1338 return RegType::undefined;
1340 bool hasQf16Use =
false;
1341 bool hasQf32Use =
false;
1344 for (
auto UI : UseSet) {
1345 NodeAddr<UseNode *> UA = DFG->
addr<UseNode *>(UI);
1348 NodeAddr<StmtNode *> UseStmt = UA.
Addr->getOwner(*DFG);
1349 MachineInstr *
UseMI = UseStmt.
Addr->getCode();
1350 unsigned OpNo = UA.
Addr->getOp().getOperandNo();
1355 return RegType::ieee;
1366 if (QFUsesMap.find(
UseMI) != QFUsesMap.end()) {
1368 if (OpNo == 1 &&
Entry.first ==
true)
1369 return RegType::ieee;
1370 if (OpNo == 2 &&
Entry.second ==
true)
1371 return RegType::ieee;
1379 return RegType::qf16_double;
1381 return RegType::qf16;
1382 }
else if (hasQf32Use) {
1384 return RegType::qf32_double;
1386 return RegType::qf32;
1389 return RegType::undefined;
1399bool HexagonPostRAHandleQFP::HandleCopies() {
1406 for (
auto It : QFCopys) {
1409 NodeAddr<DefNode *> CopyNode = DFG->
addr<DefNode *>(It.first.first);
1410 NodeAddr<StmtNode *> StNode = CopyNode.
Addr->getOwner(*DFG);
1411 [[maybe_unused]]
auto *CopyMI = StNode.Addr->getCode();
1413 std::string
Type;
switch (It.second) {
1414 case RegType::qf32_double:
1415 Type =
"qf32_double";
1423 case RegType::qf16_double:
1424 Type =
"qf16_double";
1428 }
dbgs() <<
"\t Type: "
1432 RegType RTy = It.second;
1433 if (RTy != RegType::ieee) {
1436 NodeAddr<DefNode *> ReachDefNode = DFG->
addr<DefNode *>(It.first.second);
1437 NodeAddr<StmtNode *> StNode = ReachDefNode.
Addr->getOwner(*DFG);
1438 auto *ReachingDef = StNode.Addr->getCode();
1440 if (IgnoreInsertConvList.find(ReachingDef) != IgnoreInsertConvList.end())
1444 ReachDefOfCopies.insert(std::make_pair(ReachingDef, RTy));
1449 LLVM_DEBUG(
dbgs() <<
"\n[COPY]\tAnalyzing uses of the reaching defs \
1451 collectQFUses(ReachDefNode, ReachingDef);
1452 collectConvQFInstr(ReachDefNode);
1453 IgnoreInsertConvList.insert(ReachingDef);
1459 for (
auto It : QFCopys) {
1462 NodeAddr<DefNode *> CopyNode = DFG->
addr<DefNode *>(It.first.first);
1463 NodeAddr<StmtNode *> StNode = CopyNode.
Addr->getOwner(*DFG);
1464 auto *CopyMI = StNode.Addr->getCode();
1466 RegType RTy = It.second;
1473 RTy = HasQfUses(CopyNode, CopyMI);
1474 if (RTy != RegType::ieee && RTy != RegType::undefined &&
1476 if (!ConvertToQfCopies.contains(CopyMI)) {
1477 ConvertToQfCopies[CopyMI] = std::make_pair(CopyNode, RTy);
1479 CopyMI->
dump(); std::string
Type;
switch (RTy) {
1480 case RegType::qf32_double:
1481 Type =
"qf32_double";
1489 case RegType::qf16_double:
1490 Type =
"qf16_double";
1494 }
dbgs() <<
"\t Type: "
1500 collectQFUses(CopyNode, CopyMI);
1501 collectConvQFInstr(CopyNode);
1504 Changed |= HandleReachDefOfCopies();
1505 Changed |= HandleMultiReachingDefs();
1506 Changed |= HandleConvertToQfCopies();
1515bool HexagonPostRAHandleQFP::HandleSpills() {
1519 for (
auto It : SpillMIs) {
1521 MachineInstr *
MI = It.first;
1522 auto OpC =
MI->getOpcode();
1524 auto NodeDef = It.second;
1527 auto RegOp =
MI->getOperand(2);
1531 if (OpC == Hexagon::PS_vstorerw_ai) {
1532 if (!Hexagon::HvxWRRegClass.
contains(DefR))
1533 assert(
false &&
" Unhandled Vector Register class passed\n");
1537 collectQFUses(NodeDef,
DefMI);
1539 if (IgnoreInsertConvList.find(
DefMI) != IgnoreInsertConvList.end())
1544 collectConvQFInstr(NodeDef);
1545 Register DefLo = HRI->getSubReg(DefR, Hexagon::vsub_lo);
1546 Register DefHi = HRI->getSubReg(DefR, Hexagon::vsub_hi);
1555 if (DefLo == DReg || Hexagon::HvxWRRegClass.
contains(DReg))
1556 insertInstr(
DefMI, Hexagon::V6_vconv_hf_qf16, DefLo, DefLo,
1559 if (DefHi == DReg || Hexagon::HvxWRRegClass.
contains(DReg))
1560 insertInstr(
DefMI, Hexagon::V6_vconv_hf_qf16, DefHi, DefHi,
1563 if (DefLo == DReg || Hexagon::HvxWRRegClass.
contains(DReg))
1564 insertInstr(
DefMI, Hexagon::V6_vconv_sf_qf32, DefLo, DefLo,
1567 if (DefHi == DReg || Hexagon::HvxWRRegClass.
contains(DReg))
1568 insertInstr(
DefMI, Hexagon::V6_vconv_sf_qf32, DefHi, DefHi,
1571 IgnoreInsertConvList.insert(
DefMI);
1576 collectQFUses(NodeDef,
DefMI);
1577 if (IgnoreInsertConvList.find(
DefMI) != IgnoreInsertConvList.end())
1579 collectConvQFInstr(NodeDef);
1581 insertInstr(
DefMI, Hexagon::V6_vconv_sf_qf32, DefR, DefR,
1584 IgnoreInsertConvList.insert(
DefMI);
1589 collectQFUses(NodeDef,
DefMI);
1590 if (IgnoreInsertConvList.find(
DefMI) != IgnoreInsertConvList.end())
1592 collectConvQFInstr(NodeDef);
1594 insertInstr(
DefMI, Hexagon::V6_vconv_hf_qf16, DefR, DefR,
1597 IgnoreInsertConvList.insert(
DefMI);
1607bool HexagonPostRAHandleQFP::runOnMachineFunction(MachineFunction &MF) {
1613 dbgs() <<
"\n=== Entering Hexagon Fixup QF spills and refills pass ===\n"
1616 case QFloatMode::StrictIEEE:
1617 dbgs() <<
"Strict IEEE";
1619 case QFloatMode::IEEE:
1622 case QFloatMode::Lossy:
1633 if (!_HST.useHVXOps())
1636 HII = _HST.getInstrInfo();
1644 HRI = _HST.getRegisterInfo();
1646 const auto &MDF = getAnalysis<MachineDominanceFrontierWrapperPass>().getMDF();
1647 MachineDominatorTree *MDT =
1648 &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
1654 DataFlowGraph
G(MF, *HII, *HRI, *MDT, MDF);
1658 Liveness
L(*MRI, *DFG);
1664 NodeAddr<FuncNode *> FA = DFG->
getFunc();
1666 <<
Print<NodeAddr<FuncNode *>>(FA, *DFG) <<
"\n");
1667 for (NodeAddr<BlockNode *> BA : FA.
Addr->members(*DFG)) {
1668 for (
auto IA : BA.Addr->members(*DFG)) {
1674 NodeAddr<StmtNode *> SA =
IA;
1675 MachineInstr *
I = SA.
Addr->getCode();
1677 switch (
I->getOpcode()) {
1678 case Hexagon::PS_vstorerw_ai:
1679 case Hexagon::PS_vstorerv_ai:
1680 collectQFPStackSpill(&SA);
1682 case Hexagon::PS_vloadrw_ai:
1683 case Hexagon::PS_vloadrv_ai:
1684 collectQFPStackRefill(&SA);
1686 case TargetOpcode::COPY:
1705 for (NodeAddr<DefNode *> DfNode : RefillMIs) {
1707 NodeAddr<StmtNode *>
Stmt = DfNode.
Addr->getOwner(*DFG);
1709 collectQFUses(DfNode,
DefMI);
1710 collectConvQFInstr(DfNode);
1717 PossibleMultiReachDefs.clear();
1718 ReachDefOfCopies.clear();
1719 ConvertToQfCopies.clear();
1721 LLVM_DEBUG(
dbgs() <<
"\n === QF Uses map === ";
for (
auto It : QFUsesMap) {
1722 dbgs() <<
"\nInstruction: ";
1724 dbgs() <<
"\t Property: " << It.second.first <<
" ," << It.second.second;
1732 Changed |= HandleNonSatInstr();
1733 QFNonSatMIs.clear();
1735 for (
auto It : QFUsesMap)
1736 It.first->eraseFromParent();
1738 IgnoreInsertConvList.clear();
1747 "Hexagon Post RA Handle QFloat",
false,
false)
1754 return new HexagonPostRAHandleQFP();
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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
cl::opt< QFloatMode > QFloatModeValue
static void getAllRealUses(NodeAddr< DefNode * > DA, NodeSet &UNodeSet, Liveness *L, DataFlowGraph *G, bool comprehensive=false)
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
Promote Memory to Register
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
FunctionPass class - This class is used to implement most global optimizations.
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.
bool useHVXV79Ops() const
bool useHVXV81Ops() const
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.
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...
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...
Wrapper class representing virtual and physical registers.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
initializer< Ty > init(const Ty &Val)
NodeAddr< InstrNode * > Instr
Print(const T &, const DataFlowGraph &) -> Print< T >
NodeAddr< StmtNode * > Stmt
std::set< NodeId > NodeSet
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 &)
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.
char & HexagonPostRAHandleQFPID
FunctionPass * createHexagonPostRAHandleQFP()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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...
DWARFExpression::Operation Op
NodeList members_if(Predicate P, const DataFlowGraph &G) const
static bool IsDef(const Node BA)
static bool IsUse(const Node BA)
static bool IsCode(const Node BA)
NodeAddr< T > addr(NodeId N) const
LLVM_ABI Node getOwner(const DataFlowGraph &G)
DenseMap< RegisterId, NodeRefSet > RefMap
LLVM_ABI std::pair< NodeSet, bool > getAllReachingDefsRec(RegisterRef RefRR, NodeAddr< RefNode * > RefA, NodeSet &Visited, const NodeSet &Defs)
MachineInstr * getCode() const