1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
//===-- HexagonHazardRecognizer.cpp - Hexagon Post RA Hazard Recognizer ---===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the hazard recognizer for scheduling on Hexagon.
// Use a DFA based hazard recognizer.
//
//===----------------------------------------------------------------------===//
#include "HexagonHazardRecognizer.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/ScheduleDAG.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
using namespace llvm;
#define DEBUG_TYPE "post-RA-sched"
void HexagonHazardRecognizer::Reset() {
DEBUG(dbgs() << "Reset hazard recognizer\n");
Resources->clearResources();
PacketNum = 0;
UsesDotCur = nullptr;
DotCurPNum = -1;
RegDefs.clear();
}
ScheduleHazardRecognizer::HazardType
HexagonHazardRecognizer::getHazardType(SUnit *SU, int stalls) {
MachineInstr *MI = SU->getInstr();
if (!MI || TII->isZeroCost(MI->getOpcode()))
return NoHazard;
if (!Resources->canReserveResources(*MI)) {
DEBUG(dbgs() << "*** Hazard in cycle " << PacketNum << ", " << *MI);
HazardType RetVal = Hazard;
if (TII->mayBeNewStore(*MI)) {
// Make sure the register to be stored is defined by an instruction in the
// packet.
MachineOperand &MO = MI->getOperand(MI->getNumOperands() - 1);
if (!MO.isReg() || RegDefs.count(MO.getReg()) == 0)
return Hazard;
// The .new store version uses different resources so check if it
// causes a hazard.
MachineFunction *MF = MI->getParent()->getParent();
MachineInstr *NewMI =
MF->CreateMachineInstr(TII->get(TII->getDotNewOp(*MI)),
MI->getDebugLoc());
if (Resources->canReserveResources(*NewMI))
RetVal = NoHazard;
DEBUG(dbgs() << "*** Try .new version? " << (RetVal == NoHazard) << "\n");
MF->DeleteMachineInstr(NewMI);
}
return RetVal;
}
if (SU == UsesDotCur && DotCurPNum != (int)PacketNum) {
DEBUG(dbgs() << "*** .cur Hazard in cycle " << PacketNum << ", " << *MI);
return Hazard;
}
return NoHazard;
}
void HexagonHazardRecognizer::AdvanceCycle() {
DEBUG(dbgs() << "Advance cycle, clear state\n");
Resources->clearResources();
if (DotCurPNum != -1 && DotCurPNum != (int)PacketNum) {
UsesDotCur = nullptr;
DotCurPNum = -1;
}
PacketNum++;
RegDefs.clear();
}
/// If a packet contains a dot cur instruction, then we may prefer the
/// instruction that can use the dot cur result. Or, if the use
/// isn't scheduled in the same packet, then prefer other instructions
/// in the subsequent packet.
bool HexagonHazardRecognizer::ShouldPreferAnother(SUnit *SU) {
return UsesDotCur && ((SU == UsesDotCur) ^ (DotCurPNum == (int)PacketNum));
}
void HexagonHazardRecognizer::EmitInstruction(SUnit *SU) {
MachineInstr *MI = SU->getInstr();
if (!MI)
return;
// Keep the set of definitions for each packet, which is used to determine
// if a .new can be used.
for (const MachineOperand &MO : MI->operands())
if (MO.isReg() && MO.isDef() && !MO.isImplicit())
RegDefs.insert(MO.getReg());
if (TII->isZeroCost(MI->getOpcode()))
return;
if (!Resources->canReserveResources(*MI)) {
// It must be a .new store since other instructions must be able to be
// reserved at this point.
assert(TII->mayBeNewStore(*MI) && "Expecting .new store");
MachineFunction *MF = MI->getParent()->getParent();
MachineInstr *NewMI =
MF->CreateMachineInstr(TII->get(TII->getDotNewOp(*MI)),
MI->getDebugLoc());
assert(Resources->canReserveResources(*NewMI));
Resources->reserveResources(*NewMI);
MF->DeleteMachineInstr(NewMI);
}
else
Resources->reserveResources(*MI);
DEBUG(dbgs() << " Add instruction " << *MI);
// When scheduling a dot cur instruction, check if there is an instruction
// that can use the dot cur in the same packet. If so, we'll attempt to
// schedule it before other instructions. We only do this if the use has
// the same height as the dot cur. Otherwise, we may miss scheduling an
// instruction with a greater height, which is more important.
if (TII->mayBeCurLoad(*MI))
for (auto &S : SU->Succs)
if (S.isAssignedRegDep() && S.getLatency() == 0 &&
SU->getHeight() == S.getSUnit()->getHeight()) {
UsesDotCur = S.getSUnit();
DotCurPNum = PacketNum;
break;
}
if (SU == UsesDotCur) {
UsesDotCur = nullptr;
DotCurPNum = -1;
}
}
|