Path: blob/main/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonHazardRecognizer.cpp
35294 views
//===-- HexagonHazardRecognizer.cpp - Hexagon Post RA Hazard Recognizer ---===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the hazard recognizer for scheduling on Hexagon.9// Use a DFA based hazard recognizer.10//11//===----------------------------------------------------------------------===//1213#include "HexagonHazardRecognizer.h"14#include "llvm/CodeGen/MachineFunction.h"15#include "llvm/CodeGen/MachineInstr.h"16#include "llvm/CodeGen/MachineOperand.h"17#include "llvm/CodeGen/ScheduleDAG.h"18#include "llvm/Support/Debug.h"19#include "llvm/Support/raw_ostream.h"20#include <cassert>2122using namespace llvm;2324#define DEBUG_TYPE "post-RA-sched"2526void HexagonHazardRecognizer::Reset() {27LLVM_DEBUG(dbgs() << "Reset hazard recognizer\n");28Resources->clearResources();29PacketNum = 0;30UsesDotCur = nullptr;31DotCurPNum = -1;32UsesLoad = false;33PrefVectorStoreNew = nullptr;34RegDefs.clear();35}3637ScheduleHazardRecognizer::HazardType38HexagonHazardRecognizer::getHazardType(SUnit *SU, int stalls) {39MachineInstr *MI = SU->getInstr();40if (!MI || TII->isZeroCost(MI->getOpcode()))41return NoHazard;4243if (!Resources->canReserveResources(*MI)) {44LLVM_DEBUG(dbgs() << "*** Hazard in cycle " << PacketNum << ", " << *MI);45HazardType RetVal = Hazard;46if (isNewStore(*MI)) {47// The .new store version uses different resources so check if it48// causes a hazard.49MachineFunction *MF = MI->getParent()->getParent();50MachineInstr *NewMI =51MF->CreateMachineInstr(TII->get(TII->getDotNewOp(*MI)),52MI->getDebugLoc());53if (Resources->canReserveResources(*NewMI))54RetVal = NoHazard;55LLVM_DEBUG(dbgs() << "*** Try .new version? " << (RetVal == NoHazard)56<< "\n");57MF->deleteMachineInstr(NewMI);58}59return RetVal;60}6162if (SU == UsesDotCur && DotCurPNum != (int)PacketNum) {63LLVM_DEBUG(dbgs() << "*** .cur Hazard in cycle " << PacketNum << ", "64<< *MI);65return Hazard;66}6768return NoHazard;69}7071void HexagonHazardRecognizer::AdvanceCycle() {72LLVM_DEBUG(dbgs() << "Advance cycle, clear state\n");73Resources->clearResources();74if (DotCurPNum != -1 && DotCurPNum != (int)PacketNum) {75UsesDotCur = nullptr;76DotCurPNum = -1;77}78UsesLoad = false;79PrefVectorStoreNew = nullptr;80PacketNum++;81RegDefs.clear();82}8384/// Handle the cases when we prefer one instruction over another. Case 1 - we85/// prefer not to generate multiple loads in the packet to avoid a potential86/// bank conflict. Case 2 - if a packet contains a dot cur instruction, then we87/// prefer the instruction that can use the dot cur result. However, if the use88/// is not scheduled in the same packet, then prefer other instructions in the89/// subsequent packet. Case 3 - we prefer a vector store that can be converted90/// to a .new store. The packetizer will not generate the .new store if the91/// store doesn't have resources to fit in the packet (but the .new store may92/// have resources). We attempt to schedule the store as soon as possible to93/// help packetize the two instructions together.94bool HexagonHazardRecognizer::ShouldPreferAnother(SUnit *SU) {95if (PrefVectorStoreNew != nullptr && PrefVectorStoreNew != SU)96return true;97if (UsesLoad && SU->isInstr() && SU->getInstr()->mayLoad())98return true;99return UsesDotCur && ((SU == UsesDotCur) ^ (DotCurPNum == (int)PacketNum));100}101102/// Return true if the instruction would be converted to a new value store when103/// packetized.104bool HexagonHazardRecognizer::isNewStore(MachineInstr &MI) {105if (!TII->mayBeNewStore(MI))106return false;107MachineOperand &MO = MI.getOperand(MI.getNumOperands() - 1);108return MO.isReg() && RegDefs.contains(MO.getReg());109}110111void HexagonHazardRecognizer::EmitInstruction(SUnit *SU) {112MachineInstr *MI = SU->getInstr();113if (!MI)114return;115116// Keep the set of definitions for each packet, which is used to determine117// if a .new can be used.118for (const MachineOperand &MO : MI->operands())119if (MO.isReg() && MO.isDef() && !MO.isImplicit())120RegDefs.insert(MO.getReg());121122if (TII->isZeroCost(MI->getOpcode()))123return;124125if (!Resources->canReserveResources(*MI) || isNewStore(*MI)) {126// It must be a .new store since other instructions must be able to be127// reserved at this point.128assert(TII->mayBeNewStore(*MI) && "Expecting .new store");129MachineFunction *MF = MI->getParent()->getParent();130MachineInstr *NewMI =131MF->CreateMachineInstr(TII->get(TII->getDotNewOp(*MI)),132MI->getDebugLoc());133if (Resources->canReserveResources(*NewMI))134Resources->reserveResources(*NewMI);135else136Resources->reserveResources(*MI);137MF->deleteMachineInstr(NewMI);138} else139Resources->reserveResources(*MI);140LLVM_DEBUG(dbgs() << " Add instruction " << *MI);141142// When scheduling a dot cur instruction, check if there is an instruction143// that can use the dot cur in the same packet. If so, we'll attempt to144// schedule it before other instructions. We only do this if the load has a145// single zero-latency use.146if (TII->mayBeCurLoad(*MI))147for (auto &S : SU->Succs)148if (S.isAssignedRegDep() && S.getLatency() == 0 &&149S.getSUnit()->NumPredsLeft == 1) {150UsesDotCur = S.getSUnit();151DotCurPNum = PacketNum;152break;153}154if (SU == UsesDotCur) {155UsesDotCur = nullptr;156DotCurPNum = -1;157}158159UsesLoad = MI->mayLoad();160161if (TII->isHVXVec(*MI) && !MI->mayLoad() && !MI->mayStore())162for (auto &S : SU->Succs)163if (S.isAssignedRegDep() && S.getLatency() == 0 &&164TII->mayBeNewStore(*S.getSUnit()->getInstr()) &&165Resources->canReserveResources(*S.getSUnit()->getInstr())) {166PrefVectorStoreNew = S.getSUnit();167break;168}169}170171172