Home | History | Annotate | Download | only in Mips
      1 //===-- MipsHazardSchedule.cpp - Workaround pipeline hazards --------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 /// \file
     10 /// This pass is used to workaround certain pipeline hazards. For now, this covers
     11 /// compact branch hazards. In future this pass can be extended to other pipeline
     12 /// hazards, such as various MIPS1 hazards, processor errata that require
     13 /// instruction reorganization, etc.
     14 ///
     15 /// This pass has to run after the delay slot filler as that pass can introduce
     16 /// pipeline hazards, hence the existing hazard recognizer is not suitable.
     17 ///
     18 /// Hazards handled: forbidden slots for MIPSR6.
     19 ///
     20 /// A forbidden slot hazard occurs when a compact branch instruction is executed
     21 /// and the adjacent instruction in memory is a control transfer instruction such
     22 /// as a branch or jump, ERET, ERETNC, DERET, WAIT and PAUSE.
     23 ///
     24 /// For example:
     25 ///
     26 /// 0x8004      bnec    a1,v0,<P+0x18>
     27 /// 0x8008      beqc    a1,a2,<P+0x54>
     28 ///
     29 /// In such cases, the processor is required to signal a Reserved Instruction
     30 /// exception.
     31 ///
     32 /// Here, if the instruction at 0x8004 is executed, the processor will raise an
     33 /// exception as there is a control transfer instruction at 0x8008.
     34 ///
     35 /// There are two sources of forbidden slot hazards:
     36 ///
     37 /// A) A previous pass has created a compact branch directly.
     38 /// B) Transforming a delay slot branch into compact branch. This case can be
     39 ///    difficult to process as lookahead for hazards is insufficent, as
     40 ///    backwards delay slot fillling can also produce hazards in previously
     41 ///    processed instuctions.
     42 ///
     43 //===----------------------------------------------------------------------===//
     44 
     45 #include "Mips.h"
     46 #include "MipsInstrInfo.h"
     47 #include "MipsSEInstrInfo.h"
     48 #include "MipsTargetMachine.h"
     49 #include "llvm/ADT/Statistic.h"
     50 #include "llvm/CodeGen/MachineFunctionPass.h"
     51 #include "llvm/CodeGen/MachineInstrBuilder.h"
     52 #include "llvm/IR/Function.h"
     53 #include "llvm/Target/TargetInstrInfo.h"
     54 #include "llvm/Target/TargetMachine.h"
     55 #include "llvm/Target/TargetRegisterInfo.h"
     56 
     57 using namespace llvm;
     58 
     59 #define DEBUG_TYPE "mips-hazard-schedule"
     60 
     61 STATISTIC(NumInsertedNops, "Number of nops inserted");
     62 
     63 namespace {
     64 
     65 typedef MachineBasicBlock::iterator Iter;
     66 typedef MachineBasicBlock::reverse_iterator ReverseIter;
     67 
     68 class MipsHazardSchedule : public MachineFunctionPass {
     69 
     70 public:
     71   MipsHazardSchedule() : MachineFunctionPass(ID) {}
     72 
     73   const char *getPassName() const override { return "Mips Hazard Schedule"; }
     74 
     75   bool runOnMachineFunction(MachineFunction &F) override;
     76 
     77   MachineFunctionProperties getRequiredProperties() const override {
     78     return MachineFunctionProperties().set(
     79         MachineFunctionProperties::Property::AllVRegsAllocated);
     80   }
     81 
     82 private:
     83   static char ID;
     84 };
     85 
     86 char MipsHazardSchedule::ID = 0;
     87 } // end of anonymous namespace
     88 
     89 /// Returns a pass that clears pipeline hazards.
     90 FunctionPass *llvm::createMipsHazardSchedule() {
     91   return new MipsHazardSchedule();
     92 }
     93 
     94 // Find the next real instruction from the current position.
     95 static Iter getNextMachineInstr(Iter Position) {
     96   Iter I = Position, E = Position->getParent()->end();
     97   I = std::find_if_not(I, E, [](const Iter &Insn) { return Insn->isTransient(); });
     98   assert(I != E);
     99   return I;
    100 }
    101 
    102 bool MipsHazardSchedule::runOnMachineFunction(MachineFunction &MF) {
    103 
    104   const MipsSubtarget *STI =
    105       &static_cast<const MipsSubtarget &>(MF.getSubtarget());
    106 
    107   // Forbidden slot hazards are only defined for MIPSR6.
    108   if (!STI->hasMips32r6() || STI->inMicroMipsMode())
    109     return false;
    110 
    111   bool Changed = false;
    112   const MipsInstrInfo *TII = STI->getInstrInfo();
    113 
    114   for (MachineFunction::iterator FI = MF.begin(); FI != MF.end(); ++FI) {
    115     for (Iter I = FI->begin(); I != FI->end(); ++I) {
    116 
    117       // Forbidden slot hazard handling. Use lookahead over state.
    118       if (!TII->HasForbiddenSlot(*I))
    119         continue;
    120 
    121       bool InsertNop = false;
    122       // Next instruction in the basic block.
    123       if (std::next(I) != FI->end() &&
    124           !TII->SafeInForbiddenSlot(*getNextMachineInstr(std::next(I)))) {
    125         InsertNop = true;
    126       } else {
    127         // Next instruction in the physical successor basic block.
    128         for (auto *Succ : FI->successors()) {
    129           if (FI->isLayoutSuccessor(Succ) &&
    130               getNextMachineInstr(Succ->begin()) != Succ->end() &&
    131               !TII->SafeInForbiddenSlot(*getNextMachineInstr(Succ->begin()))) {
    132             InsertNop = true;
    133             break;
    134           }
    135         }
    136       }
    137 
    138       if (InsertNop) {
    139         Changed = true;
    140         MIBundleBuilder(&*I).append(
    141             BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP)));
    142         NumInsertedNops++;
    143       }
    144     }
    145   }
    146   return Changed;
    147 }
    148