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