summaryrefslogtreecommitdiffstats
path: root/include/llvm/CodeGen/ScheduleDAG.h
blob: 49acf41818c53e67fca0318308a135898ee97c87 (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
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
//===------- llvm/CodeGen/ScheduleDAG.h - Common Base Class------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Evan Cheng and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ScheduleDAG class, which is used as the common
// base class for SelectionDAG-based instruction scheduler.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CODEGEN_SCHEDULEDAG_H
#define LLVM_CODEGEN_SCHEDULEDAG_H

#include "llvm/CodeGen/SelectionDAG.h"

namespace llvm {
  struct InstrStage;
  class MachineConstantPool;
  class MachineDebugInfo;
  class MachineInstr;
  class MRegisterInfo;
  class SelectionDAG;
  class SSARegMap;
  class TargetInstrInfo;
  class TargetInstrDescriptor;
  class TargetMachine;

  class NodeInfo;
  typedef NodeInfo *NodeInfoPtr;
  typedef std::vector<NodeInfoPtr>           NIVector;
  typedef std::vector<NodeInfoPtr>::iterator NIIterator;

  // Scheduling heuristics
  enum SchedHeuristics {
    defaultScheduling,      // Let the target specify its preference.
    noScheduling,           // No scheduling, emit breadth first sequence.
    simpleScheduling,       // Two pass, min. critical path, max. utilization.
    simpleNoItinScheduling, // Same as above exact using generic latency.
    listSchedulingBURR,     // Bottom up reg reduction list scheduling.
    listSchedulingTD        // Top-down list scheduler.
  };
  
  /// HazardRecognizer - This determines whether or not an instruction can be
  /// issued this cycle, and whether or not a noop needs to be inserted to handle
  /// the hazard.
  class HazardRecognizer {
  public:
    virtual ~HazardRecognizer();
    
    enum HazardType {
      NoHazard,      // This instruction can be emitted at this cycle.
      Hazard,        // This instruction can't be emitted at this cycle.
      NoopHazard,    // This instruction can't be emitted, and needs noops.
    };
    
    /// getHazardType - Return the hazard type of emitting this node.  There are
    /// three possible results.  Either:
    ///  * NoHazard: it is legal to issue this instruction on this cycle.
    ///  * Hazard: issuing this instruction would stall the machine.  If some
    ///     other instruction is available, issue it first.
    ///  * NoopHazard: issuing this instruction would break the program.  If
    ///     some other instruction can be issued, do so, otherwise issue a noop.
    virtual HazardType getHazardType(SDNode *Node) {
      return NoHazard;
    }
    
    /// EmitInstruction - This callback is invoked when an instruction is
    /// emitted, to advance the hazard state.
    virtual void EmitInstruction(SDNode *Node) {
    }
    
    /// AdvanceCycle - This callback is invoked when no instructions can be
    /// issued on this cycle without a hazard.  This should increment the
    /// internal state of the hazard recognizer so that previously "Hazard"
    /// instructions will now not be hazards.
    virtual void AdvanceCycle() {
    }
    
    /// EmitNoop - This callback is invoked when a noop was added to the
    /// instruction stream.
    virtual void EmitNoop() {
    }
  };

  //===--------------------------------------------------------------------===//
  ///
  /// Node group -  This struct is used to manage flagged node groups.
  ///
  class NodeGroup {
  public:
    NodeGroup     *Next;
  private:
    NIVector      Members;                // Group member nodes
    NodeInfo      *Dominator;             // Node with highest latency
    unsigned      Latency;                // Total latency of the group
    int           Pending;                // Number of visits pending before
                                          // adding to order  

  public:
    // Ctor.
    NodeGroup() : Next(NULL), Dominator(NULL), Pending(0) {}
  
    // Accessors
    inline void setDominator(NodeInfo *D) { Dominator = D; }
    inline NodeInfo *getTop() { return Members.front(); }
    inline NodeInfo *getBottom() { return Members.back(); }
    inline NodeInfo *getDominator() { return Dominator; }
    inline void setLatency(unsigned L) { Latency = L; }
    inline unsigned getLatency() { return Latency; }
    inline int getPending() const { return Pending; }
    inline void setPending(int P)  { Pending = P; }
    inline int addPending(int I)  { return Pending += I; }
  
    // Pass thru
    inline bool group_empty() { return Members.empty(); }
    inline NIIterator group_begin() { return Members.begin(); }
    inline NIIterator group_end() { return Members.end(); }
    inline void group_push_back(const NodeInfoPtr &NI) {
      Members.push_back(NI);
    }
    inline NIIterator group_insert(NIIterator Pos, const NodeInfoPtr &NI) {
      return Members.insert(Pos, NI);
    }
    inline void group_insert(NIIterator Pos, NIIterator First,
                             NIIterator Last) {
      Members.insert(Pos, First, Last);
    }

    static void Add(NodeInfo *D, NodeInfo *U);
  };

  //===--------------------------------------------------------------------===//
  ///
  /// NodeInfo - This struct tracks information used to schedule the a node.
  ///
  class NodeInfo {
  private:
    int           Pending;                // Number of visits pending before
                                          // adding to order
  public:
    SDNode        *Node;                  // DAG node
    InstrStage    *StageBegin;            // First stage in itinerary
    InstrStage    *StageEnd;              // Last+1 stage in itinerary
    unsigned      Latency;                // Total cycles to complete instr
    bool          IsCall : 1;             // Is function call
    bool          IsLoad : 1;             // Is memory load
    bool          IsStore : 1;            // Is memory store
    unsigned      Slot;                   // Node's time slot
    NodeGroup     *Group;                 // Grouping information
#ifndef NDEBUG
    unsigned      Preorder;               // Index before scheduling
#endif

    // Ctor.
    NodeInfo(SDNode *N = NULL)
      : Pending(0)
      , Node(N)
      , StageBegin(NULL)
      , StageEnd(NULL)
      , Latency(0)
      , IsCall(false)
      , Slot(0)
      , Group(NULL)
#ifndef NDEBUG
      , Preorder(0)
#endif
    {}
  
    // Accessors
    inline bool isInGroup() const {
      assert(!Group || !Group->group_empty() && "Group with no members");
      return Group != NULL;
    }
    inline bool isGroupDominator() const {
      return isInGroup() && Group->getDominator() == this;
    }
    inline int getPending() const {
      return Group ? Group->getPending() : Pending;
    }
    inline void setPending(int P) {
      if (Group) Group->setPending(P);
      else       Pending = P;
    }
    inline int addPending(int I) {
      if (Group) return Group->addPending(I);
      else       return Pending += I;
    }
  };

  //===--------------------------------------------------------------------===//
  ///
  /// NodeGroupIterator - Iterates over all the nodes indicated by the node
  /// info. If the node is in a group then iterate over the members of the
  /// group, otherwise just the node info.
  ///
  class NodeGroupIterator {
  private:
    NodeInfo   *NI;                       // Node info
    NIIterator NGI;                       // Node group iterator
    NIIterator NGE;                       // Node group iterator end
  
  public:
    // Ctor.
    NodeGroupIterator(NodeInfo *N) : NI(N) {
      // If the node is in a group then set up the group iterator.  Otherwise
      // the group iterators will trip first time out.
      if (N->isInGroup()) {
        // get Group
        NodeGroup *Group = NI->Group;
        NGI = Group->group_begin();
        NGE = Group->group_end();
        // Prevent this node from being used (will be in members list
        NI = NULL;
      }
    }
  
    /// next - Return the next node info, otherwise NULL.
    ///
    NodeInfo *next() {
      // If members list
      if (NGI != NGE) return *NGI++;
      // Use node as the result (may be NULL)
      NodeInfo *Result = NI;
      // Only use once
      NI = NULL;
      // Return node or NULL
      return Result;
    }
  };
  //===--------------------------------------------------------------------===//


  //===--------------------------------------------------------------------===//
  ///
  /// NodeGroupOpIterator - Iterates over all the operands of a node.  If the
  /// node is a member of a group, this iterates over all the operands of all
  /// the members of the group.
  ///
  class NodeGroupOpIterator {
  private:
    NodeInfo            *NI;              // Node containing operands
    NodeGroupIterator   GI;               // Node group iterator
    SDNode::op_iterator OI;               // Operand iterator
    SDNode::op_iterator OE;               // Operand iterator end
  
    /// CheckNode - Test if node has more operands.  If not get the next node
    /// skipping over nodes that have no operands.
    void CheckNode() {
      // Only if operands are exhausted first
      while (OI == OE) {
        // Get next node info
        NodeInfo *NI = GI.next();
        // Exit if nodes are exhausted
        if (!NI) return;
        // Get node itself
        SDNode *Node = NI->Node;
        // Set up the operand iterators
        OI = Node->op_begin();
        OE = Node->op_end();
      }
    }
  
  public:
    // Ctor.
    NodeGroupOpIterator(NodeInfo *N)
      : NI(N), GI(N), OI(SDNode::op_iterator()), OE(SDNode::op_iterator()) {}
  
    /// isEnd - Returns true when not more operands are available.
    ///
    inline bool isEnd() { CheckNode(); return OI == OE; }
  
    /// next - Returns the next available operand.
    ///
    inline SDOperand next() {
      assert(OI != OE &&
             "Not checking for end of NodeGroupOpIterator correctly");
      return *OI++;
    }
  };

  class ScheduleDAG {
  public:
    SchedHeuristics Heuristic;            // Scheduling heuristic
    SelectionDAG &DAG;                    // DAG of the current basic block
    MachineBasicBlock *BB;                // Current basic block
    const TargetMachine &TM;              // Target processor
    const TargetInstrInfo *TII;           // Target instruction information
    const MRegisterInfo *MRI;             // Target processor register info
    SSARegMap *RegMap;                    // Virtual/real register map
    MachineConstantPool *ConstPool;       // Target constant pool
    std::map<SDNode *, NodeInfo *> Map;   // Map nodes to info
    unsigned NodeCount;                   // Number of nodes in DAG
    bool HasGroups;                       // True if there are any groups
    NodeInfo *Info;                       // Info for nodes being scheduled
    NIVector Ordering;                    // Emit ordering of nodes
    NodeGroup *HeadNG, *TailNG;           // Keep track of allocated NodeGroups

    ScheduleDAG(SchedHeuristics hstc, SelectionDAG &dag, MachineBasicBlock *bb,
                const TargetMachine &tm)
      : Heuristic(hstc), DAG(dag), BB(bb), TM(tm), NodeCount(0),
        HasGroups(false), Info(NULL), HeadNG(NULL), TailNG(NULL) {}

    virtual ~ScheduleDAG() {
      if (Info)
        delete[] Info;

      NodeGroup *NG = HeadNG;
      while (NG) {
        NodeGroup *NextSU = NG->Next;
        delete NG;
        NG = NextSU;
      }
    };

    /// Run - perform scheduling.
    ///
    MachineBasicBlock *Run();

    /// getNI - Returns the node info for the specified node.
    ///
    NodeInfo *getNI(SDNode *Node) { return Map[Node]; }
  
    /// isPassiveNode - Return true if the node is a non-scheduled leaf.
    ///
    static bool isPassiveNode(SDNode *Node) {
      if (isa<ConstantSDNode>(Node))       return true;
      if (isa<RegisterSDNode>(Node))       return true;
      if (isa<GlobalAddressSDNode>(Node))  return true;
      if (isa<BasicBlockSDNode>(Node))     return true;
      if (isa<FrameIndexSDNode>(Node))     return true;
      if (isa<ConstantPoolSDNode>(Node))   return true;
      if (isa<ExternalSymbolSDNode>(Node)) return true;
      return false;
    }

    /// EmitNode - Generate machine code for an node and needed dependencies.
    /// VRBaseMap contains, for each already emitted node, the first virtual
    /// register number for the results of the node.
    ///
    void EmitNode(SDNode *Node, std::map<SDNode*, unsigned> &VRBaseMap);
    
    /// EmitNoop - Emit a noop instruction.
    ///
    void EmitNoop();
    

    /// Schedule - Order nodes according to selected style.
    ///
    virtual void Schedule() {}

  private:
    void AddOperand(MachineInstr *MI, SDOperand Op, unsigned IIOpNum,
                    const TargetInstrDescriptor *II,
                    std::map<SDNode*, unsigned> &VRBaseMap);
  };

  /// createSimpleDAGScheduler - This creates a simple two pass instruction
  /// scheduler.
  ScheduleDAG* createSimpleDAGScheduler(SchedHeuristics Heuristic,
                                        SelectionDAG &DAG,
                                        MachineBasicBlock *BB);

  /// createBURRListDAGScheduler - This creates a bottom up register usage
  /// reduction list scheduler.
  ScheduleDAG* createBURRListDAGScheduler(SelectionDAG &DAG,
                                          MachineBasicBlock *BB);
  
  /// createTDListDAGScheduler - This creates a top-down list scheduler with
  /// the specified hazard recognizer.  This takes ownership of the hazard
  /// recognizer and deletes it when done.
  ScheduleDAG* createTDListDAGScheduler(SelectionDAG &DAG,
                                        MachineBasicBlock *BB,
                                        HazardRecognizer *HR);
}

#endif