121
|
1 //===- llvm/Target/TargetSchedule.cpp - Sched Machine Model ---------------===//
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
2 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
3 // The LLVM Compiler Infrastructure
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
4 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
5 // This file is distributed under the University of Illinois Open Source
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
6 // License. See LICENSE.TXT for details.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
7 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
8 //===----------------------------------------------------------------------===//
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
9 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
10 // This file implements a wrapper around MCSchedModel that allows the interface
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
11 // to benefit from information currently only available in TargetInstrInfo.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
12 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
13 //===----------------------------------------------------------------------===//
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
14
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
15 #include "llvm/CodeGen/TargetSchedule.h"
|
121
|
16 #include "llvm/CodeGen/MachineFunction.h"
|
|
17 #include "llvm/CodeGen/MachineInstr.h"
|
|
18 #include "llvm/CodeGen/MachineOperand.h"
|
134
|
19 #include "llvm/CodeGen/TargetInstrInfo.h"
|
|
20 #include "llvm/CodeGen/TargetRegisterInfo.h"
|
|
21 #include "llvm/CodeGen/TargetSubtargetInfo.h"
|
121
|
22 #include "llvm/MC/MCInstrDesc.h"
|
|
23 #include "llvm/MC/MCInstrItineraries.h"
|
|
24 #include "llvm/MC/MCSchedule.h"
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
25 #include "llvm/Support/CommandLine.h"
|
121
|
26 #include "llvm/Support/ErrorHandling.h"
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
27 #include "llvm/Support/raw_ostream.h"
|
121
|
28 #include <algorithm>
|
|
29 #include <cassert>
|
|
30 #include <cstdint>
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
31
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
32 using namespace llvm;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
33
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
34 static cl::opt<bool> EnableSchedModel("schedmodel", cl::Hidden, cl::init(true),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
35 cl::desc("Use TargetSchedModel for latency lookup"));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
36
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
37 static cl::opt<bool> EnableSchedItins("scheditins", cl::Hidden, cl::init(true),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
38 cl::desc("Use InstrItineraryData for latency lookup"));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
39
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
40 bool TargetSchedModel::hasInstrSchedModel() const {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
41 return EnableSchedModel && SchedModel.hasInstrSchedModel();
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
42 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
43
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
44 bool TargetSchedModel::hasInstrItineraries() const {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
45 return EnableSchedItins && !InstrItins.isEmpty();
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
46 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
47
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
48 static unsigned gcd(unsigned Dividend, unsigned Divisor) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
49 // Dividend and Divisor will be naturally swapped as needed.
|
121
|
50 while (Divisor) {
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
51 unsigned Rem = Dividend % Divisor;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
52 Dividend = Divisor;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
53 Divisor = Rem;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
54 };
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
55 return Dividend;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
56 }
|
121
|
57
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
58 static unsigned lcm(unsigned A, unsigned B) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
59 unsigned LCM = (uint64_t(A) * B) / gcd(A, B);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
60 assert((LCM >= A && LCM >= B) && "LCM overflow");
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
61 return LCM;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
62 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
63
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
64 void TargetSchedModel::init(const MCSchedModel &sm,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
65 const TargetSubtargetInfo *sti,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
66 const TargetInstrInfo *tii) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
67 SchedModel = sm;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
68 STI = sti;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
69 TII = tii;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
70 STI->initInstrItins(InstrItins);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
71
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
72 unsigned NumRes = SchedModel.getNumProcResourceKinds();
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
73 ResourceFactors.resize(NumRes);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
74 ResourceLCM = SchedModel.IssueWidth;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
75 for (unsigned Idx = 0; Idx < NumRes; ++Idx) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
76 unsigned NumUnits = SchedModel.getProcResource(Idx)->NumUnits;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
77 if (NumUnits > 0)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
78 ResourceLCM = lcm(ResourceLCM, NumUnits);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
79 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
80 MicroOpFactor = ResourceLCM / SchedModel.IssueWidth;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
81 for (unsigned Idx = 0; Idx < NumRes; ++Idx) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
82 unsigned NumUnits = SchedModel.getProcResource(Idx)->NumUnits;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
83 ResourceFactors[Idx] = NumUnits ? (ResourceLCM / NumUnits) : 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
84 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
85 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
86
|
121
|
87 /// Returns true only if instruction is specified as single issue.
|
|
88 bool TargetSchedModel::mustBeginGroup(const MachineInstr *MI,
|
|
89 const MCSchedClassDesc *SC) const {
|
|
90 if (hasInstrSchedModel()) {
|
|
91 if (!SC)
|
|
92 SC = resolveSchedClass(MI);
|
|
93 if (SC->isValid())
|
|
94 return SC->BeginGroup;
|
|
95 }
|
|
96 return false;
|
|
97 }
|
|
98
|
|
99 bool TargetSchedModel::mustEndGroup(const MachineInstr *MI,
|
|
100 const MCSchedClassDesc *SC) const {
|
|
101 if (hasInstrSchedModel()) {
|
|
102 if (!SC)
|
|
103 SC = resolveSchedClass(MI);
|
|
104 if (SC->isValid())
|
|
105 return SC->EndGroup;
|
|
106 }
|
|
107 return false;
|
|
108 }
|
|
109
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
110 unsigned TargetSchedModel::getNumMicroOps(const MachineInstr *MI,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
111 const MCSchedClassDesc *SC) const {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
112 if (hasInstrItineraries()) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
113 int UOps = InstrItins.getNumMicroOps(MI->getDesc().getSchedClass());
|
120
|
114 return (UOps >= 0) ? UOps : TII->getNumMicroOps(&InstrItins, *MI);
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
115 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
116 if (hasInstrSchedModel()) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
117 if (!SC)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
118 SC = resolveSchedClass(MI);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
119 if (SC->isValid())
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
120 return SC->NumMicroOps;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
121 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
122 return MI->isTransient() ? 0 : 1;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
123 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
124
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
125 // The machine model may explicitly specify an invalid latency, which
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
126 // effectively means infinite latency. Since users of the TargetSchedule API
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
127 // don't know how to handle this, we convert it to a very large latency that is
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
128 // easy to distinguish when debugging the DAG but won't induce overflow.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
129 static unsigned capLatency(int Cycles) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
130 return Cycles >= 0 ? Cycles : 1000;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
131 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
132
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
133 /// Return the MCSchedClassDesc for this instruction. Some SchedClasses require
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
134 /// evaluation of predicates that depend on instruction operands or flags.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
135 const MCSchedClassDesc *TargetSchedModel::
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
136 resolveSchedClass(const MachineInstr *MI) const {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
137 // Get the definition's scheduling class descriptor from this machine model.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
138 unsigned SchedClass = MI->getDesc().getSchedClass();
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
139 const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SchedClass);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
140 if (!SCDesc->isValid())
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
141 return SCDesc;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
142
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
143 #ifndef NDEBUG
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
144 unsigned NIter = 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
145 #endif
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
146 while (SCDesc->isVariant()) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
147 assert(++NIter < 6 && "Variants are nested deeper than the magic number");
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
148
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
149 SchedClass = STI->resolveSchedClass(SchedClass, MI, this);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
150 SCDesc = SchedModel.getSchedClassDesc(SchedClass);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
151 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
152 return SCDesc;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
153 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
154
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
155 /// Find the def index of this operand. This index maps to the machine model and
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
156 /// is independent of use operands. Def operands may be reordered with uses or
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
157 /// merged with uses without affecting the def index (e.g. before/after
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
158 /// regalloc). However, an instruction's def operands must never be reordered
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
159 /// with respect to each other.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
160 static unsigned findDefIdx(const MachineInstr *MI, unsigned DefOperIdx) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
161 unsigned DefIdx = 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
162 for (unsigned i = 0; i != DefOperIdx; ++i) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
163 const MachineOperand &MO = MI->getOperand(i);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
164 if (MO.isReg() && MO.isDef())
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
165 ++DefIdx;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
166 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
167 return DefIdx;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
168 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
169
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
170 /// Find the use index of this operand. This is independent of the instruction's
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
171 /// def operands.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
172 ///
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
173 /// Note that uses are not determined by the operand's isUse property, which
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
174 /// is simply the inverse of isDef. Here we consider any readsReg operand to be
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
175 /// a "use". The machine model allows an operand to be both a Def and Use.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
176 static unsigned findUseIdx(const MachineInstr *MI, unsigned UseOperIdx) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
177 unsigned UseIdx = 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
178 for (unsigned i = 0; i != UseOperIdx; ++i) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
179 const MachineOperand &MO = MI->getOperand(i);
|
120
|
180 if (MO.isReg() && MO.readsReg() && !MO.isDef())
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
181 ++UseIdx;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
182 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
183 return UseIdx;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
184 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
185
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
186 // Top-level API for clients that know the operand indices.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
187 unsigned TargetSchedModel::computeOperandLatency(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
188 const MachineInstr *DefMI, unsigned DefOperIdx,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
189 const MachineInstr *UseMI, unsigned UseOperIdx) const {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
190
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
191 if (!hasInstrSchedModel() && !hasInstrItineraries())
|
120
|
192 return TII->defaultDefLatency(SchedModel, *DefMI);
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
193
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
194 if (hasInstrItineraries()) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
195 int OperLatency = 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
196 if (UseMI) {
|
120
|
197 OperLatency = TII->getOperandLatency(&InstrItins, *DefMI, DefOperIdx,
|
|
198 *UseMI, UseOperIdx);
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
199 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
200 else {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
201 unsigned DefClass = DefMI->getDesc().getSchedClass();
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
202 OperLatency = InstrItins.getOperandCycle(DefClass, DefOperIdx);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
203 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
204 if (OperLatency >= 0)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
205 return OperLatency;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
206
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
207 // No operand latency was found.
|
120
|
208 unsigned InstrLatency = TII->getInstrLatency(&InstrItins, *DefMI);
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
209
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
210 // Expected latency is the max of the stage latency and itinerary props.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
211 // Rather than directly querying InstrItins stage latency, we call a TII
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
212 // hook to allow subtargets to specialize latency. This hook is only
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
213 // applicable to the InstrItins model. InstrSchedModel should model all
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
214 // special cases without TII hooks.
|
120
|
215 InstrLatency =
|
|
216 std::max(InstrLatency, TII->defaultDefLatency(SchedModel, *DefMI));
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
217 return InstrLatency;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
218 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
219 // hasInstrSchedModel()
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
220 const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
221 unsigned DefIdx = findDefIdx(DefMI, DefOperIdx);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
222 if (DefIdx < SCDesc->NumWriteLatencyEntries) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
223 // Lookup the definition's write latency in SubtargetInfo.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
224 const MCWriteLatencyEntry *WLEntry =
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
225 STI->getWriteLatencyEntry(SCDesc, DefIdx);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
226 unsigned WriteID = WLEntry->WriteResourceID;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
227 unsigned Latency = capLatency(WLEntry->Cycles);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
228 if (!UseMI)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
229 return Latency;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
230
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
231 // Lookup the use's latency adjustment in SubtargetInfo.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
232 const MCSchedClassDesc *UseDesc = resolveSchedClass(UseMI);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
233 if (UseDesc->NumReadAdvanceEntries == 0)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
234 return Latency;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
235 unsigned UseIdx = findUseIdx(UseMI, UseOperIdx);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
236 int Advance = STI->getReadAdvanceCycles(UseDesc, UseIdx, WriteID);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
237 if (Advance > 0 && (unsigned)Advance > Latency) // unsigned wrap
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
238 return 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
239 return Latency - Advance;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
240 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
241 // If DefIdx does not exist in the model (e.g. implicit defs), then return
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
242 // unit latency (defaultDefLatency may be too conservative).
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
243 #ifndef NDEBUG
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
244 if (SCDesc->isValid() && !DefMI->getOperand(DefOperIdx).isImplicit()
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
245 && !DefMI->getDesc().OpInfo[DefOperIdx].isOptionalDef()
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
246 && SchedModel.isComplete()) {
|
95
|
247 errs() << "DefIdx " << DefIdx << " exceeds machine model writes for "
|
100
|
248 << *DefMI << " (Try with MCSchedModel.CompleteModel set to false)";
|
95
|
249 llvm_unreachable("incomplete machine model");
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
250 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
251 #endif
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
252 // FIXME: Automatically giving all implicit defs defaultDefLatency is
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
253 // undesirable. We should only do it for defs that are known to the MC
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
254 // desc like flags. Truly implicit defs should get 1 cycle latency.
|
120
|
255 return DefMI->isTransient() ? 0 : TII->defaultDefLatency(SchedModel, *DefMI);
|
77
|
256 }
|
|
257
|
95
|
258 unsigned
|
|
259 TargetSchedModel::computeInstrLatency(const MCSchedClassDesc &SCDesc) const {
|
|
260 unsigned Latency = 0;
|
|
261 for (unsigned DefIdx = 0, DefEnd = SCDesc.NumWriteLatencyEntries;
|
|
262 DefIdx != DefEnd; ++DefIdx) {
|
|
263 // Lookup the definition's write latency in SubtargetInfo.
|
|
264 const MCWriteLatencyEntry *WLEntry =
|
|
265 STI->getWriteLatencyEntry(&SCDesc, DefIdx);
|
|
266 Latency = std::max(Latency, capLatency(WLEntry->Cycles));
|
|
267 }
|
|
268 return Latency;
|
|
269 }
|
|
270
|
77
|
271 unsigned TargetSchedModel::computeInstrLatency(unsigned Opcode) const {
|
|
272 assert(hasInstrSchedModel() && "Only call this function with a SchedModel");
|
|
273
|
|
274 unsigned SCIdx = TII->get(Opcode).getSchedClass();
|
|
275 const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SCIdx);
|
|
276
|
95
|
277 if (SCDesc->isValid() && !SCDesc->isVariant())
|
|
278 return computeInstrLatency(*SCDesc);
|
77
|
279
|
121
|
280 if (SCDesc->isValid()) {
|
|
281 assert (!SCDesc->isVariant() && "No MI sched latency: SCDesc->isVariant()");
|
|
282 return computeInstrLatency(*SCDesc);
|
|
283 }
|
|
284 return 0;
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
285 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
286
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
287 unsigned
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
288 TargetSchedModel::computeInstrLatency(const MachineInstr *MI,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
289 bool UseDefaultDefLatency) const {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
290 // For the itinerary model, fall back to the old subtarget hook.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
291 // Allow subtargets to compute Bundle latencies outside the machine model.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
292 if (hasInstrItineraries() || MI->isBundle() ||
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
293 (!hasInstrSchedModel() && !UseDefaultDefLatency))
|
120
|
294 return TII->getInstrLatency(&InstrItins, *MI);
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
295
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
296 if (hasInstrSchedModel()) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
297 const MCSchedClassDesc *SCDesc = resolveSchedClass(MI);
|
95
|
298 if (SCDesc->isValid())
|
|
299 return computeInstrLatency(*SCDesc);
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
300 }
|
120
|
301 return TII->defaultDefLatency(SchedModel, *MI);
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
302 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
303
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
304 unsigned TargetSchedModel::
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
305 computeOutputLatency(const MachineInstr *DefMI, unsigned DefOperIdx,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
306 const MachineInstr *DepMI) const {
|
120
|
307 if (!SchedModel.isOutOfOrder())
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
308 return 1;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
309
|
120
|
310 // Out-of-order processor can dispatch WAW dependencies in the same cycle.
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
311
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
312 // Treat predication as a data dependency for out-of-order cpus. In-order
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
313 // cpus do not need to treat predicated writes specially.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
314 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
315 // TODO: The following hack exists because predication passes do not
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
316 // correctly append imp-use operands, and readsReg() strangely returns false
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
317 // for predicated defs.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
318 unsigned Reg = DefMI->getOperand(DefOperIdx).getReg();
|
121
|
319 const MachineFunction &MF = *DefMI->getMF();
|
77
|
320 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
|
120
|
321 if (!DepMI->readsRegister(Reg, TRI) && TII->isPredicated(*DepMI))
|
0
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
322 return computeInstrLatency(DefMI);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
323
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
324 // If we have a per operand scheduling model, check if this def is writing
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
325 // an unbuffered resource. If so, it treated like an in-order cpu.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
326 if (hasInstrSchedModel()) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
327 const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
328 if (SCDesc->isValid()) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
329 for (const MCWriteProcResEntry *PRI = STI->getWriteProcResBegin(SCDesc),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
330 *PRE = STI->getWriteProcResEnd(SCDesc); PRI != PRE; ++PRI) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
331 if (!SchedModel.getProcResource(PRI->ProcResourceIdx)->BufferSize)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
332 return 1;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
333 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
334 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
335 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
336 return 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
337 }
|
121
|
338
|
|
339 static Optional<double>
|
|
340 getRThroughputFromItineraries(unsigned schedClass,
|
|
341 const InstrItineraryData *IID){
|
|
342 Optional<double> Throughput;
|
|
343
|
|
344 for (const InstrStage *IS = IID->beginStage(schedClass),
|
|
345 *E = IID->endStage(schedClass);
|
|
346 IS != E; ++IS) {
|
|
347 if (IS->getCycles()) {
|
|
348 double Temp = countPopulation(IS->getUnits()) * 1.0 / IS->getCycles();
|
|
349 Throughput = Throughput.hasValue()
|
|
350 ? std::min(Throughput.getValue(), Temp)
|
|
351 : Temp;
|
|
352 }
|
|
353 }
|
|
354 if (Throughput.hasValue())
|
|
355 // We need reciprocal throughput that's why we return such value.
|
|
356 return 1 / Throughput.getValue();
|
|
357 return Throughput;
|
|
358 }
|
|
359
|
|
360 static Optional<double>
|
|
361 getRThroughputFromInstrSchedModel(const MCSchedClassDesc *SCDesc,
|
|
362 const TargetSubtargetInfo *STI,
|
|
363 const MCSchedModel &SchedModel) {
|
|
364 Optional<double> Throughput;
|
|
365
|
|
366 for (const MCWriteProcResEntry *WPR = STI->getWriteProcResBegin(SCDesc),
|
|
367 *WEnd = STI->getWriteProcResEnd(SCDesc);
|
|
368 WPR != WEnd; ++WPR) {
|
|
369 if (WPR->Cycles) {
|
|
370 unsigned NumUnits =
|
|
371 SchedModel.getProcResource(WPR->ProcResourceIdx)->NumUnits;
|
|
372 double Temp = NumUnits * 1.0 / WPR->Cycles;
|
|
373 Throughput = Throughput.hasValue()
|
|
374 ? std::min(Throughput.getValue(), Temp)
|
|
375 : Temp;
|
|
376 }
|
|
377 }
|
|
378 if (Throughput.hasValue())
|
|
379 // We need reciprocal throughput that's why we return such value.
|
|
380 return 1 / Throughput.getValue();
|
|
381 return Throughput;
|
|
382 }
|
|
383
|
|
384 Optional<double>
|
|
385 TargetSchedModel::computeInstrRThroughput(const MachineInstr *MI) const {
|
|
386 if (hasInstrItineraries())
|
|
387 return getRThroughputFromItineraries(MI->getDesc().getSchedClass(),
|
|
388 getInstrItineraries());
|
|
389 if (hasInstrSchedModel())
|
|
390 return getRThroughputFromInstrSchedModel(resolveSchedClass(MI), STI,
|
|
391 SchedModel);
|
|
392 return Optional<double>();
|
|
393 }
|
|
394
|
|
395 Optional<double>
|
|
396 TargetSchedModel::computeInstrRThroughput(unsigned Opcode) const {
|
|
397 unsigned SchedClass = TII->get(Opcode).getSchedClass();
|
|
398 if (hasInstrItineraries())
|
|
399 return getRThroughputFromItineraries(SchedClass, getInstrItineraries());
|
|
400 if (hasInstrSchedModel()) {
|
|
401 const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SchedClass);
|
|
402 if (SCDesc->isValid() && !SCDesc->isVariant())
|
|
403 return getRThroughputFromInstrSchedModel(SCDesc, STI, SchedModel);
|
|
404 }
|
|
405 return Optional<double>();
|
|
406 }
|