1 //===-- HexagonHazardRecognizer.cpp - Hexagon Post RA Hazard Recognizer ---===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the hazard recognizer for scheduling on Hexagon. 10 // Use a DFA based hazard recognizer. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "HexagonHazardRecognizer.h" 15 #include "llvm/CodeGen/MachineFunction.h" 16 #include "llvm/CodeGen/MachineInstr.h" 17 #include "llvm/CodeGen/MachineOperand.h" 18 #include "llvm/CodeGen/ScheduleDAG.h" 19 #include "llvm/Support/Debug.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <cassert> 22 23 using namespace llvm; 24 25 #define DEBUG_TYPE "post-RA-sched" 26 27 void HexagonHazardRecognizer::Reset() { 28 LLVM_DEBUG(dbgs() << "Reset hazard recognizer\n"); 29 Resources->clearResources(); 30 PacketNum = 0; 31 UsesDotCur = nullptr; 32 DotCurPNum = -1; 33 UsesLoad = false; 34 PrefVectorStoreNew = nullptr; 35 RegDefs.clear(); 36 } 37 38 ScheduleHazardRecognizer::HazardType 39 HexagonHazardRecognizer::getHazardType(SUnit *SU, int stalls) { 40 MachineInstr *MI = SU->getInstr(); 41 if (!MI || TII->isZeroCost(MI->getOpcode())) 42 return NoHazard; 43 44 if (!Resources->canReserveResources(*MI)) { 45 LLVM_DEBUG(dbgs() << "*** Hazard in cycle " << PacketNum << ", " << *MI); 46 HazardType RetVal = Hazard; 47 if (TII->mayBeNewStore(*MI)) { 48 // Make sure the register to be stored is defined by an instruction in the 49 // packet. 50 MachineOperand &MO = MI->getOperand(MI->getNumOperands() - 1); 51 if (!MO.isReg() || RegDefs.count(MO.getReg()) == 0) 52 return Hazard; 53 // The .new store version uses different resources so check if it 54 // causes a hazard. 55 MachineFunction *MF = MI->getParent()->getParent(); 56 MachineInstr *NewMI = 57 MF->CreateMachineInstr(TII->get(TII->getDotNewOp(*MI)), 58 MI->getDebugLoc()); 59 if (Resources->canReserveResources(*NewMI)) 60 RetVal = NoHazard; 61 LLVM_DEBUG(dbgs() << "*** Try .new version? " << (RetVal == NoHazard) 62 << "\n"); 63 MF->DeleteMachineInstr(NewMI); 64 } 65 return RetVal; 66 } 67 68 if (SU == UsesDotCur && DotCurPNum != (int)PacketNum) { 69 LLVM_DEBUG(dbgs() << "*** .cur Hazard in cycle " << PacketNum << ", " 70 << *MI); 71 return Hazard; 72 } 73 74 return NoHazard; 75 } 76 77 void HexagonHazardRecognizer::AdvanceCycle() { 78 LLVM_DEBUG(dbgs() << "Advance cycle, clear state\n"); 79 Resources->clearResources(); 80 if (DotCurPNum != -1 && DotCurPNum != (int)PacketNum) { 81 UsesDotCur = nullptr; 82 DotCurPNum = -1; 83 } 84 UsesLoad = false; 85 PrefVectorStoreNew = nullptr; 86 PacketNum++; 87 RegDefs.clear(); 88 } 89 90 /// Handle the cases when we prefer one instruction over another. Case 1 - we 91 /// prefer not to generate multiple loads in the packet to avoid a potential 92 /// bank conflict. Case 2 - if a packet contains a dot cur instruction, then we 93 /// prefer the instruction that can use the dot cur result. However, if the use 94 /// is not scheduled in the same packet, then prefer other instructions in the 95 /// subsequent packet. Case 3 - we prefer a vector store that can be converted 96 /// to a .new store. The packetizer will not generate the .new store if the 97 /// store doesn't have resources to fit in the packet (but the .new store may 98 /// have resources). We attempt to schedule the store as soon as possible to 99 /// help packetize the two instructions together. 100 bool HexagonHazardRecognizer::ShouldPreferAnother(SUnit *SU) { 101 if (PrefVectorStoreNew != nullptr && PrefVectorStoreNew != SU) 102 return true; 103 if (UsesLoad && SU->isInstr() && SU->getInstr()->mayLoad()) 104 return true; 105 return UsesDotCur && ((SU == UsesDotCur) ^ (DotCurPNum == (int)PacketNum)); 106 } 107 108 void HexagonHazardRecognizer::EmitInstruction(SUnit *SU) { 109 MachineInstr *MI = SU->getInstr(); 110 if (!MI) 111 return; 112 113 // Keep the set of definitions for each packet, which is used to determine 114 // if a .new can be used. 115 for (const MachineOperand &MO : MI->operands()) 116 if (MO.isReg() && MO.isDef() && !MO.isImplicit()) 117 RegDefs.insert(MO.getReg()); 118 119 if (TII->isZeroCost(MI->getOpcode())) 120 return; 121 122 if (!Resources->canReserveResources(*MI)) { 123 // It must be a .new store since other instructions must be able to be 124 // reserved at this point. 125 assert(TII->mayBeNewStore(*MI) && "Expecting .new store"); 126 MachineFunction *MF = MI->getParent()->getParent(); 127 MachineInstr *NewMI = 128 MF->CreateMachineInstr(TII->get(TII->getDotNewOp(*MI)), 129 MI->getDebugLoc()); 130 assert(Resources->canReserveResources(*NewMI)); 131 Resources->reserveResources(*NewMI); 132 MF->DeleteMachineInstr(NewMI); 133 } 134 else 135 Resources->reserveResources(*MI); 136 LLVM_DEBUG(dbgs() << " Add instruction " << *MI); 137 138 // When scheduling a dot cur instruction, check if there is an instruction 139 // that can use the dot cur in the same packet. If so, we'll attempt to 140 // schedule it before other instructions. We only do this if the load has a 141 // single zero-latency use. 142 if (TII->mayBeCurLoad(*MI)) 143 for (auto &S : SU->Succs) 144 if (S.isAssignedRegDep() && S.getLatency() == 0 && 145 S.getSUnit()->NumPredsLeft == 1) { 146 UsesDotCur = S.getSUnit(); 147 DotCurPNum = PacketNum; 148 break; 149 } 150 if (SU == UsesDotCur) { 151 UsesDotCur = nullptr; 152 DotCurPNum = -1; 153 } 154 155 UsesLoad = MI->mayLoad(); 156 157 if (TII->isHVXVec(*MI) && !MI->mayLoad() && !MI->mayStore()) 158 for (auto &S : SU->Succs) 159 if (S.isAssignedRegDep() && S.getLatency() == 0 && 160 TII->mayBeNewStore(*S.getSUnit()->getInstr()) && 161 Resources->canReserveResources(*S.getSUnit()->getInstr())) { 162 PrefVectorStoreNew = S.getSUnit(); 163 break; 164 } 165 } 166