summaryrefslogtreecommitdiff
path: root/include/llvm/MC/MCInstrItineraries.h
blob: e6178a2d6120a753da81a66b83f43e305d1bdafc (plain)
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
//===-- llvm/MC/MCInstrItineraries.h - Scheduling ---------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the structures used for instruction
// itineraries, stages, and operand reads/writes.  This is used by
// schedulers to determine instruction stages and latencies.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_MC_MCINSTRITINERARIES_H
#define LLVM_MC_MCINSTRITINERARIES_H

#include <algorithm>

namespace llvm {

//===----------------------------------------------------------------------===//
/// Instruction stage - These values represent a non-pipelined step in
/// the execution of an instruction.  Cycles represents the number of
/// discrete time slots needed to complete the stage.  Units represent
/// the choice of functional units that can be used to complete the
/// stage.  Eg. IntUnit1, IntUnit2. NextCycles indicates how many
/// cycles should elapse from the start of this stage to the start of
/// the next stage in the itinerary. A value of -1 indicates that the
/// next stage should start immediately after the current one.
/// For example:
///
///   { 1, x, -1 }
///      indicates that the stage occupies FU x for 1 cycle and that
///      the next stage starts immediately after this one.
///
///   { 2, x|y, 1 }
///      indicates that the stage occupies either FU x or FU y for 2
///      consecuative cycles and that the next stage starts one cycle
///      after this stage starts. That is, the stage requirements
///      overlap in time.
///
///   { 1, x, 0 }
///      indicates that the stage occupies FU x for 1 cycle and that
///      the next stage starts in this same cycle. This can be used to
///      indicate that the instruction requires multiple stages at the
///      same time.
///
/// FU reservation can be of two different kinds:
///  - FUs which instruction actually requires
///  - FUs which instruction just reserves. Reserved unit is not available for
///    execution of other instruction. However, several instructions can reserve
///    the same unit several times.
/// Such two types of units reservation is used to model instruction domain
/// change stalls, FUs using the same resource (e.g. same register file), etc.

struct InstrStage {
  enum ReservationKinds {
    Required = 0,
    Reserved = 1
  };

  unsigned Cycles_;  ///< Length of stage in machine cycles
  uint64_t Units_;   ///< Choice of functional units
  int NextCycles_;   ///< Number of machine cycles to next stage
  ReservationKinds Kind_; ///< Kind of the FU reservation

  /// getCycles - returns the number of cycles the stage is occupied
  unsigned getCycles() const {
    return Cycles_;
  }

  /// getUnits - returns the choice of FUs
  uint64_t getUnits() const {
    return Units_;
  }

  ReservationKinds getReservationKind() const {
    return Kind_;
  }

  /// getNextCycles - returns the number of cycles from the start of
  /// this stage to the start of the next stage in the itinerary
  unsigned getNextCycles() const {
    return (NextCycles_ >= 0) ? (unsigned)NextCycles_ : Cycles_;
  }
};


//===----------------------------------------------------------------------===//
/// Instruction itinerary - An itinerary represents the scheduling
/// information for an instruction. This includes a set of stages
/// occupies by the instruction, and the pipeline cycle in which
/// operands are read and written.
///
struct InstrItinerary {
  unsigned NumMicroOps;        ///< # of micro-ops, 0 means it's variable
  unsigned FirstStage;         ///< Index of first stage in itinerary
  unsigned LastStage;          ///< Index of last + 1 stage in itinerary
  unsigned FirstOperandCycle;  ///< Index of first operand rd/wr
  unsigned LastOperandCycle;   ///< Index of last + 1 operand rd/wr
};


//===----------------------------------------------------------------------===//
/// Instruction itinerary properties - These properties provide general
/// information about the microarchitecture to the scheduler.
///
struct InstrItineraryProps {
  // IssueWidth is the maximum number of instructions that may be scheduled in
  // the same per-cycle group.
  unsigned IssueWidth;
  static const unsigned DefaultIssueWidth = 1;

  // MinLatency is the minimum latency between a register write
  // followed by a data dependent read. This determines which
  // instructions may be scheduled in the same per-cycle group. This
  // is distinct from *expected* latency, which determines the likely
  // critical path but does not guarantee a pipeline
  // hazard. MinLatency can always be overridden by the number of
  // InstrStage cycles.
  //
  // (-1) Standard in-order processor.
  //      Use InstrItinerary OperandCycles as MinLatency.
  //      If no OperandCycles exist, then use the cycle of the last InstrStage.
  //
  //  (0) Out-of-order processor, or in-order with bundled dependencies.
  //      RAW dependencies may be dispatched in the same cycle.
  //      Optional InstrItinerary OperandCycles provides expected latency.
  //
  // (>0) In-order processor with variable latencies.
  //      Use the greater of this value or the cycle of the last InstrStage.
  //      Optional InstrItinerary OperandCycles provides expected latency.
  //      TODO: can't yet specify both min and expected latency per operand.
  int MinLatency;
  static const unsigned DefaultMinLatency = -1;

  // LoadLatency is the expected latency of load instructions.
  //
  // If MinLatency >= 0, this may be overriden for individual load opcodes by
  // InstrItinerary OperandCycles.
  unsigned LoadLatency;
  static const unsigned DefaultLoadLatency = 4;

  // HighLatency is the expected latency of "very high latency" operations.
  // See TargetInstrInfo::isHighLatencyDef().
  // By default, this is set to an arbitrarily high number of cycles
  // likely to have some impact on scheduling heuristics.
  // If MinLatency >= 0, this may be overriden by InstrItinData OperandCycles.
  unsigned HighLatency;
  static const unsigned DefaultHighLatency = 10;

  // Default's must be specified as static const literals so that tablegenerated
  // target code can use it in static initializers. The defaults need to be
  // initialized in this default ctor because some clients directly instantiate
  // InstrItineraryData instead of using a generated itinerary.
  InstrItineraryProps(): IssueWidth(DefaultMinLatency),
                         MinLatency(DefaultMinLatency),
                         LoadLatency(DefaultLoadLatency),
                         HighLatency(DefaultHighLatency) {}

  InstrItineraryProps(unsigned iw, int ml, unsigned ll, unsigned hl):
    IssueWidth(iw), MinLatency(ml), LoadLatency(ll), HighLatency(hl) {}
};

//===----------------------------------------------------------------------===//
/// Encapsulate all subtarget specific information for scheduling for use with
/// SubtargetInfoKV.
struct InstrItinerarySubtargetValue {
  const InstrItineraryProps *Props;
  const InstrItinerary *Itineraries;
};

//===----------------------------------------------------------------------===//
/// Instruction itinerary Data - Itinerary data supplied by a subtarget to be
/// used by a target.
///
class InstrItineraryData {
public:
  InstrItineraryProps Props;
  const InstrStage     *Stages;         ///< Array of stages selected
  const unsigned       *OperandCycles;  ///< Array of operand cycles selected
  const unsigned       *Forwardings;    ///< Array of pipeline forwarding pathes
  const InstrItinerary *Itineraries;    ///< Array of itineraries selected

  /// Ctors.
  ///
  InstrItineraryData() : Stages(0), OperandCycles(0), Forwardings(0),
                         Itineraries(0) {}

  InstrItineraryData(const InstrItineraryProps *P, const InstrStage *S,
                     const unsigned *OS, const unsigned *F,
                     const InstrItinerary *I)
    : Props(*P), Stages(S), OperandCycles(OS), Forwardings(F), Itineraries(I) {}

  /// isEmpty - Returns true if there are no itineraries.
  ///
  bool isEmpty() const { return Itineraries == 0; }

  /// isEndMarker - Returns true if the index is for the end marker
  /// itinerary.
  ///
  bool isEndMarker(unsigned ItinClassIndx) const {
    return ((Itineraries[ItinClassIndx].FirstStage == ~0U) &&
            (Itineraries[ItinClassIndx].LastStage == ~0U));
  }

  /// beginStage - Return the first stage of the itinerary.
  ///
  const InstrStage *beginStage(unsigned ItinClassIndx) const {
    unsigned StageIdx = Itineraries[ItinClassIndx].FirstStage;
    return Stages + StageIdx;
  }

  /// endStage - Return the last+1 stage of the itinerary.
  ///
  const InstrStage *endStage(unsigned ItinClassIndx) const {
    unsigned StageIdx = Itineraries[ItinClassIndx].LastStage;
    return Stages + StageIdx;
  }

  /// getStageLatency - Return the total stage latency of the given
  /// class.  The latency is the maximum completion time for any stage
  /// in the itinerary.
  ///
  /// InstrStages override the itinerary's MinLatency property. In fact, if the
  /// stage latencies, which may be zero, are less than MinLatency,
  /// getStageLatency returns a value less than MinLatency.
  ///
  /// If no stages exist, MinLatency is used. If MinLatency is invalid (<0),
  /// then it defaults to one cycle.
  unsigned getStageLatency(unsigned ItinClassIndx) const {
    // If the target doesn't provide itinerary information, use a simple
    // non-zero default value for all instructions.  Some target's provide a
    // dummy (Generic) itinerary which should be handled as if it's itinerary is
    // empty. We identify this by looking for a reference to stage zero (invalid
    // stage). This is different from beginStage == endStage != 0, which could
    // be used for zero-latency pseudo ops.
    if (isEmpty() || Itineraries[ItinClassIndx].FirstStage == 0)
      return (Props.MinLatency < 0) ? 1 : Props.MinLatency;

    // Calculate the maximum completion time for any stage.
    unsigned Latency = 0, StartCycle = 0;
    for (const InstrStage *IS = beginStage(ItinClassIndx),
           *E = endStage(ItinClassIndx); IS != E; ++IS) {
      Latency = std::max(Latency, StartCycle + IS->getCycles());
      StartCycle += IS->getNextCycles();
    }

    return Latency;
  }

  /// getOperandCycle - Return the cycle for the given class and
  /// operand. Return -1 if no cycle is specified for the operand.
  ///
  int getOperandCycle(unsigned ItinClassIndx, unsigned OperandIdx) const {
    if (isEmpty())
      return -1;

    unsigned FirstIdx = Itineraries[ItinClassIndx].FirstOperandCycle;
    unsigned LastIdx = Itineraries[ItinClassIndx].LastOperandCycle;
    if ((FirstIdx + OperandIdx) >= LastIdx)
      return -1;

    return (int)OperandCycles[FirstIdx + OperandIdx];
  }

  /// hasPipelineForwarding - Return true if there is a pipeline forwarding
  /// between instructions of itinerary classes DefClass and UseClasses so that
  /// value produced by an instruction of itinerary class DefClass, operand
  /// index DefIdx can be bypassed when it's read by an instruction of
  /// itinerary class UseClass, operand index UseIdx.
  bool hasPipelineForwarding(unsigned DefClass, unsigned DefIdx,
                             unsigned UseClass, unsigned UseIdx) const {
    unsigned FirstDefIdx = Itineraries[DefClass].FirstOperandCycle;
    unsigned LastDefIdx = Itineraries[DefClass].LastOperandCycle;
    if ((FirstDefIdx + DefIdx) >= LastDefIdx)
      return false;
    if (Forwardings[FirstDefIdx + DefIdx] == 0)
      return false;

    unsigned FirstUseIdx = Itineraries[UseClass].FirstOperandCycle;
    unsigned LastUseIdx = Itineraries[UseClass].LastOperandCycle;
    if ((FirstUseIdx + UseIdx) >= LastUseIdx)
      return false;

    return Forwardings[FirstDefIdx + DefIdx] ==
      Forwardings[FirstUseIdx + UseIdx];
  }

  /// getOperandLatency - Compute and return the use operand latency of a given
  /// itinerary class and operand index if the value is produced by an
  /// instruction of the specified itinerary class and def operand index.
  int getOperandLatency(unsigned DefClass, unsigned DefIdx,
                        unsigned UseClass, unsigned UseIdx) const {
    if (isEmpty())
      return -1;

    int DefCycle = getOperandCycle(DefClass, DefIdx);
    if (DefCycle == -1)
      return -1;

    int UseCycle = getOperandCycle(UseClass, UseIdx);
    if (UseCycle == -1)
      return -1;

    UseCycle = DefCycle - UseCycle + 1;
    if (UseCycle > 0 &&
        hasPipelineForwarding(DefClass, DefIdx, UseClass, UseIdx))
      // FIXME: This assumes one cycle benefit for every pipeline forwarding.
      --UseCycle;
    return UseCycle;
  }

  /// isMicroCoded - Return true if the instructions in the given class decode
  /// to more than one micro-ops.
  bool isMicroCoded(unsigned ItinClassIndx) const {
    if (isEmpty())
      return false;
    return Itineraries[ItinClassIndx].NumMicroOps != 1;
  }
};


} // End llvm namespace

#endif