Coverage Report

Created: 2017-10-03 07:32

/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
}