1*0b57cec5SDimitry Andric //===----- PostRAHazardRecognizer.cpp - hazard recognizer -----------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric /// \file 10*0b57cec5SDimitry Andric /// This runs the hazard recognizer and emits noops when necessary. This 11*0b57cec5SDimitry Andric /// gives targets a way to run the hazard recognizer without running one of 12*0b57cec5SDimitry Andric /// the schedulers. Example use cases for this pass would be: 13*0b57cec5SDimitry Andric /// 14*0b57cec5SDimitry Andric /// - Targets that need the hazard recognizer to be run at -O0. 15*0b57cec5SDimitry Andric /// - Targets that want to guarantee that hazards at the beginning of 16*0b57cec5SDimitry Andric /// scheduling regions are handled correctly. The post-RA scheduler is 17*0b57cec5SDimitry Andric /// a top-down scheduler, but when there are multiple scheduling regions 18*0b57cec5SDimitry Andric /// in a basic block, it visits the regions in bottom-up order. This 19*0b57cec5SDimitry Andric /// makes it impossible for the scheduler to gauranttee it can correctly 20*0b57cec5SDimitry Andric /// handle hazards at the beginning of scheduling regions. 21*0b57cec5SDimitry Andric /// 22*0b57cec5SDimitry Andric /// This pass traverses all the instructions in a program in top-down order. 23*0b57cec5SDimitry Andric /// In contrast to the instruction scheduling passes, this pass never resets 24*0b57cec5SDimitry Andric /// the hazard recognizer to ensure it can correctly handles noop hazards at 25*0b57cec5SDimitry Andric /// the beginning of blocks. 26*0b57cec5SDimitry Andric // 27*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 30*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 31*0b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 32*0b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleHazardRecognizer.h" 33*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 34*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 35*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 36*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 37*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 38*0b57cec5SDimitry Andric using namespace llvm; 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric #define DEBUG_TYPE "post-RA-hazard-rec" 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric STATISTIC(NumNoops, "Number of noops inserted"); 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric namespace { 45*0b57cec5SDimitry Andric class PostRAHazardRecognizer : public MachineFunctionPass { 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric public: 48*0b57cec5SDimitry Andric static char ID; 49*0b57cec5SDimitry Andric PostRAHazardRecognizer() : MachineFunctionPass(ID) {} 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 52*0b57cec5SDimitry Andric AU.setPreservesCFG(); 53*0b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 54*0b57cec5SDimitry Andric } 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric }; 59*0b57cec5SDimitry Andric char PostRAHazardRecognizer::ID = 0; 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric } 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric char &llvm::PostRAHazardRecognizerID = PostRAHazardRecognizer::ID; 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric INITIALIZE_PASS(PostRAHazardRecognizer, DEBUG_TYPE, 66*0b57cec5SDimitry Andric "Post RA hazard recognizer", false, false) 67*0b57cec5SDimitry Andric 68*0b57cec5SDimitry Andric bool PostRAHazardRecognizer::runOnMachineFunction(MachineFunction &Fn) { 69*0b57cec5SDimitry Andric const TargetInstrInfo *TII = Fn.getSubtarget().getInstrInfo(); 70*0b57cec5SDimitry Andric std::unique_ptr<ScheduleHazardRecognizer> HazardRec( 71*0b57cec5SDimitry Andric TII->CreateTargetPostRAHazardRecognizer(Fn)); 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric // Return if the target has not implemented a hazard recognizer. 74*0b57cec5SDimitry Andric if (!HazardRec.get()) 75*0b57cec5SDimitry Andric return false; 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric // Loop over all of the basic blocks 78*0b57cec5SDimitry Andric for (auto &MBB : Fn) { 79*0b57cec5SDimitry Andric // We do not call HazardRec->reset() here to make sure we are handling noop 80*0b57cec5SDimitry Andric // hazards at the start of basic blocks. 81*0b57cec5SDimitry Andric for (MachineInstr &MI : MBB) { 82*0b57cec5SDimitry Andric // If we need to emit noops prior to this instruction, then do so. 83*0b57cec5SDimitry Andric unsigned NumPreNoops = HazardRec->PreEmitNoops(&MI); 84*0b57cec5SDimitry Andric for (unsigned i = 0; i != NumPreNoops; ++i) { 85*0b57cec5SDimitry Andric HazardRec->EmitNoop(); 86*0b57cec5SDimitry Andric TII->insertNoop(MBB, MachineBasicBlock::iterator(MI)); 87*0b57cec5SDimitry Andric ++NumNoops; 88*0b57cec5SDimitry Andric } 89*0b57cec5SDimitry Andric 90*0b57cec5SDimitry Andric HazardRec->EmitInstruction(&MI); 91*0b57cec5SDimitry Andric if (HazardRec->atIssueLimit()) { 92*0b57cec5SDimitry Andric HazardRec->AdvanceCycle(); 93*0b57cec5SDimitry Andric } 94*0b57cec5SDimitry Andric } 95*0b57cec5SDimitry Andric } 96*0b57cec5SDimitry Andric return true; 97*0b57cec5SDimitry Andric } 98