/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Target/Mips/MipsHazardSchedule.cpp
Line | Count | Source (jump to first uncovered line) |
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 |
11 | | /// covers compact branch hazards. In future this pass can be extended to other |
12 | | /// pipeline hazards, such as various MIPS1 hazards, processor errata that |
13 | | /// require 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 |
22 | | /// such 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 insufficient, 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 "MipsSubtarget.h" |
48 | | #include "llvm/ADT/Statistic.h" |
49 | | #include "llvm/CodeGen/MachineBasicBlock.h" |
50 | | #include "llvm/CodeGen/MachineFunction.h" |
51 | | #include "llvm/CodeGen/MachineFunctionPass.h" |
52 | | #include "llvm/CodeGen/MachineInstrBuilder.h" |
53 | | #include <algorithm> |
54 | | #include <iterator> |
55 | | #include <utility> |
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 | | using Iter = MachineBasicBlock::iterator; |
66 | | using ReverseIter = MachineBasicBlock::reverse_iterator; |
67 | | |
68 | | class MipsHazardSchedule : public MachineFunctionPass { |
69 | | public: |
70 | 1.72k | MipsHazardSchedule() : MachineFunctionPass(ID) {} |
71 | | |
72 | 1.70k | StringRef getPassName() const override { return "Mips Hazard Schedule"; } |
73 | | |
74 | | bool runOnMachineFunction(MachineFunction &F) override; |
75 | | |
76 | 1.70k | MachineFunctionProperties getRequiredProperties() const override { |
77 | 1.70k | return MachineFunctionProperties().set( |
78 | 1.70k | MachineFunctionProperties::Property::NoVRegs); |
79 | 1.70k | } |
80 | | |
81 | | private: |
82 | | static char ID; |
83 | | }; |
84 | | |
85 | | } // end of anonymous namespace |
86 | | |
87 | | char MipsHazardSchedule::ID = 0; |
88 | | |
89 | | /// Returns a pass that clears pipeline hazards. |
90 | 1.72k | FunctionPass *llvm::createMipsHazardSchedule() { |
91 | 1.72k | return new MipsHazardSchedule(); |
92 | 1.72k | } |
93 | | |
94 | | // Find the next real instruction from the current position in current basic |
95 | | // block. |
96 | 139 | static Iter getNextMachineInstrInBB(Iter Position) { |
97 | 139 | Iter I = Position, E = Position->getParent()->end(); |
98 | 139 | I = std::find_if_not(I, E, |
99 | 139 | [](const Iter &Insn) { return Insn->isTransient(); }); |
100 | 139 | |
101 | 139 | return I; |
102 | 139 | } |
103 | | |
104 | | // Find the next real instruction from the current position, looking through |
105 | | // basic block boundaries. |
106 | 139 | static std::pair<Iter, bool> getNextMachineInstr(Iter Position, MachineBasicBlock * Parent) { |
107 | 139 | if (Position == Parent->end()139 ) { |
108 | 137 | do { |
109 | 137 | MachineBasicBlock *Succ = Parent->getNextNode(); |
110 | 137 | if (Succ != nullptr && 137 Parent->isSuccessor(Succ)137 ) { |
111 | 137 | Position = Succ->begin(); |
112 | 137 | Parent = Succ; |
113 | 137 | } else { |
114 | 0 | return std::make_pair(Position, true); |
115 | 0 | } |
116 | 137 | } while (Parent->empty()); |
117 | 135 | } |
118 | 139 | |
119 | 139 | Iter Instr = getNextMachineInstrInBB(Position); |
120 | 139 | if (Instr == Parent->end()139 ) { |
121 | 1 | return getNextMachineInstr(Instr, Parent); |
122 | 1 | } |
123 | 138 | return std::make_pair(Instr, false); |
124 | 138 | } |
125 | | |
126 | 12.3k | bool MipsHazardSchedule::runOnMachineFunction(MachineFunction &MF) { |
127 | 12.3k | |
128 | 12.3k | const MipsSubtarget *STI = |
129 | 12.3k | &static_cast<const MipsSubtarget &>(MF.getSubtarget()); |
130 | 12.3k | |
131 | 12.3k | // Forbidden slot hazards are only defined for MIPSR6 but not microMIPSR6. |
132 | 12.3k | if (!STI->hasMips32r6() || 12.3k STI->inMicroMipsMode()1.87k ) |
133 | 11.0k | return false; |
134 | 1.30k | |
135 | 1.30k | bool Changed = false; |
136 | 1.30k | const MipsInstrInfo *TII = STI->getInstrInfo(); |
137 | 1.30k | |
138 | 2.94k | for (MachineFunction::iterator FI = MF.begin(); FI != MF.end()2.94k ; ++FI1.64k ) { |
139 | 12.9k | for (Iter I = FI->begin(); I != FI->end()12.9k ; ++I11.3k ) { |
140 | 11.3k | |
141 | 11.3k | // Forbidden slot hazard handling. Use lookahead over state. |
142 | 11.3k | if (!TII->HasForbiddenSlot(*I)) |
143 | 11.1k | continue; |
144 | 138 | |
145 | 138 | Iter Inst; |
146 | 138 | bool LastInstInFunction = |
147 | 134 | std::next(I) == FI->end() && std::next(FI) == MF.end(); |
148 | 138 | if (!LastInstInFunction138 ) { |
149 | 138 | std::pair<Iter, bool> Res = getNextMachineInstr(std::next(I), &*FI); |
150 | 138 | LastInstInFunction |= Res.second; |
151 | 138 | Inst = Res.first; |
152 | 138 | } |
153 | 138 | |
154 | 138 | if (LastInstInFunction || 138 !TII->SafeInForbiddenSlot(*Inst)138 ) { |
155 | 32 | Changed = true; |
156 | 32 | MIBundleBuilder(&*I) |
157 | 32 | .append(BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP))); |
158 | 32 | NumInsertedNops++; |
159 | 32 | } |
160 | 11.3k | } |
161 | 1.64k | } |
162 | 12.3k | return Changed; |
163 | 12.3k | } |