llvm.org GIT mirror llvm / ee498d3
VLIW specific scheduler framework that utilizes deterministic finite automaton (DFA). This new scheduler plugs into the existing selection DAG scheduling framework. It is a top-down critical path scheduler that tracks register pressure and uses a DFA for pipeline modeling. Patch by Sergei Larin! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@149547 91177308-0d34-0410-b5e6-96231b3b80d8 Andrew Trick 7 years ago
16 changed file(s) with 1142 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
3939
4040 llvm::linkOcamlGC();
4141 llvm::linkShadowStackGC();
42
42
4343 (void) llvm::createBURRListDAGScheduler(NULL, llvm::CodeGenOpt::Default);
4444 (void) llvm::createSourceListDAGScheduler(NULL,llvm::CodeGenOpt::Default);
4545 (void) llvm::createHybridListDAGScheduler(NULL,llvm::CodeGenOpt::Default);
4646 (void) llvm::createFastDAGScheduler(NULL, llvm::CodeGenOpt::Default);
4747 (void) llvm::createDefaultScheduler(NULL, llvm::CodeGenOpt::Default);
48 (void) llvm::createVLIWDAGScheduler(NULL, llvm::CodeGenOpt::Default);
4849
4950 }
5051 } ForceCodegenLinking; // Force link by creating a global definition.
0 //===----- ResourcePriorityQueue.h - A DFA-oriented priority queue -------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the ResourcePriorityQueue class, which is a
10 // SchedulingPriorityQueue that schedules using DFA state to
11 // reduce the length of the critical path through the basic block
12 // on VLIW platforms.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #ifndef RESOURCE_PRIORITY_QUEUE_H
17 #define RESOURCE_PRIORITY_QUEUE_H
18
19 #include "llvm/CodeGen/DFAPacketizer.h"
20 #include "llvm/CodeGen/SelectionDAGISel.h"
21 #include "llvm/CodeGen/ScheduleDAG.h"
22 #include "llvm/MC/MCInstrItineraries.h"
23 #include "llvm/Target/TargetInstrInfo.h"
24 #include "llvm/Target/TargetRegisterInfo.h"
25
26 namespace llvm {
27 class ResourcePriorityQueue;
28
29 /// Sorting functions for the Available queue.
30 struct resource_sort : public std::binary_function {
31 ResourcePriorityQueue *PQ;
32 explicit resource_sort(ResourcePriorityQueue *pq) : PQ(pq) {}
33
34 bool operator()(const SUnit* left, const SUnit* right) const;
35 };
36
37 class ResourcePriorityQueue : public SchedulingPriorityQueue {
38 /// SUnits - The SUnits for the current graph.
39 std::vector *SUnits;
40
41 /// NumNodesSolelyBlocking - This vector contains, for every node in the
42 /// Queue, the number of nodes that the node is the sole unscheduled
43 /// predecessor for. This is used as a tie-breaker heuristic for better
44 /// mobility.
45 std::vector NumNodesSolelyBlocking;
46
47 /// Queue - The queue.
48 std::vector Queue;
49
50 /// RegPressure - Tracking current reg pressure per register class.
51 ///
52 std::vector RegPressure;
53
54 /// RegLimit - Tracking the number of allocatable registers per register
55 /// class.
56 std::vector RegLimit;
57
58 resource_sort Picker;
59 const TargetRegisterInfo *TRI;
60 const TargetLowering *TLI;
61 const TargetInstrInfo *TII;
62 const InstrItineraryData* InstrItins;
63 /// ResourcesModel - Represents VLIW state.
64 /// Not limited to VLIW targets per say, but assumes
65 /// definition of DFA by a target.
66 DFAPacketizer *ResourcesModel;
67
68 /// Resource model - packet/bundle model. Purely
69 /// internal at the time.
70 std::vector Packet;
71
72 /// Heuristics for estimating register pressure.
73 unsigned ParallelLiveRanges;
74 signed HorizontalVerticalBalance;
75
76 public:
77 ResourcePriorityQueue(SelectionDAGISel *IS);
78
79 ~ResourcePriorityQueue() {
80 delete ResourcesModel;
81 }
82
83 bool isBottomUp() const { return false; }
84
85 void initNodes(std::vector &sunits);
86
87 void addNode(const SUnit *SU) {
88 NumNodesSolelyBlocking.resize(SUnits->size(), 0);
89 }
90
91 void updateNode(const SUnit *SU) {}
92
93 void releaseState() {
94 SUnits = 0;
95 }
96
97 unsigned getLatency(unsigned NodeNum) const {
98 assert(NodeNum < (*SUnits).size());
99 return (*SUnits)[NodeNum].getHeight();
100 }
101
102 unsigned getNumSolelyBlockNodes(unsigned NodeNum) const {
103 assert(NodeNum < NumNodesSolelyBlocking.size());
104 return NumNodesSolelyBlocking[NodeNum];
105 }
106
107 /// Single cost function reflecting benefit of scheduling SU
108 /// in the current cycle.
109 signed SUSchedulingCost (SUnit *SU);
110
111 /// InitNumRegDefsLeft - Determine the # of regs defined by this node.
112 ///
113 void initNumRegDefsLeft(SUnit *SU);
114 void updateNumRegDefsLeft(SUnit *SU);
115 signed regPressureDelta(SUnit *SU, bool RawPressure = false);
116 signed rawRegPressureDelta (SUnit *SU, unsigned RCId);
117
118 bool empty() const { return Queue.empty(); }
119
120 virtual void push(SUnit *U);
121
122 virtual SUnit *pop();
123
124 virtual void remove(SUnit *SU);
125
126 virtual void dump(ScheduleDAG* DAG) const;
127
128 /// ScheduledNode - Main resource tracking point.
129 void ScheduledNode(SUnit *Node);
130 bool isResourceAvailable(SUnit *SU);
131 void reserveResources(SUnit *SU);
132
133 private:
134 void adjustPriorityOfUnscheduledPreds(SUnit *SU);
135 SUnit *getSingleUnscheduledPred(SUnit *SU);
136 unsigned numberRCValPredInSU (SUnit *SU, unsigned RCId);
137 unsigned numberRCValSuccInSU (SUnit *SU, unsigned RCId);
138 };
139 }
140
141 #endif
4141 : MachinePassRegistryNode(N, D, (MachinePassCtor)C)
4242 { Registry.Add(this); }
4343 ~RegisterScheduler() { Registry.Remove(this); }
44
44
4545
4646 // Accessors.
4747 //
9191 ScheduleDAGSDNodes *createFastDAGScheduler(SelectionDAGISel *IS,
9292 CodeGenOpt::Level OptLevel);
9393
94 /// createVLIWDAGScheduler - Scheduler for VLIW targets. This creates top down
95 /// DFA driven list scheduler with clustering heuristic to control
96 /// register pressure.
97 ScheduleDAGSDNodes *createVLIWDAGScheduler(SelectionDAGISel *IS,
98 CodeGenOpt::Level OptLevel);
9499 /// createDefaultScheduler - This creates an instruction scheduler appropriate
95100 /// for the target.
96101 ScheduleDAGSDNodes *createDefaultScheduler(SelectionDAGISel *IS,
1414 #define LLVM_TARGET_TARGETINSTRINFO_H
1515
1616 #include "llvm/MC/MCInstrInfo.h"
17 #include "llvm/CodeGen/DFAPacketizer.h"
1718 #include "llvm/CodeGen/MachineFunction.h"
1819
1920 namespace llvm {
809810 virtual void
810811 breakPartialRegDependency(MachineBasicBlock::iterator MI, unsigned OpNum,
811812 const TargetRegisterInfo *TRI) const {}
813
814 /// Create machine specific model for scheduling.
815 virtual DFAPacketizer*
816 CreateTargetScheduleState(const TargetMachine*, const ScheduleDAG*) const {
817 return NULL;
818 }
812819
813820 private:
814821 int CallFrameSetupOpcode, CallFrameDestroyOpcode;
5858 Source, // Follow source order.
5959 RegPressure, // Scheduling for lowest register pressure.
6060 Hybrid, // Scheduling for both latency and register pressure.
61 ILP // Scheduling for ILP in low register pressure mode.
61 ILP, // Scheduling for ILP in low register pressure mode.
62 VLIW // Scheduling for VLIW targets.
6263 };
6364 }
6465
99 LegalizeTypesGeneric.cpp
1010 LegalizeVectorOps.cpp
1111 LegalizeVectorTypes.cpp
12 ResourcePriorityQueue.cpp
1213 ScheduleDAGFast.cpp
13 ScheduleDAGRRList.cpp
14 ScheduleDAGRRList.cpp
1415 ScheduleDAGSDNodes.cpp
1516 SelectionDAG.cpp
1617 SelectionDAGBuilder.cpp
1718 SelectionDAGISel.cpp
1819 SelectionDAGPrinter.cpp
20 SelectionDAGVLIW.cpp
1921 TargetLowering.cpp
2022 TargetSelectionDAGInfo.cpp
2123 )
0 //===- ResourcePriorityQueue.cpp - A DFA-oriented priority queue -*- C++ -*-==//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the ResourcePriorityQueue class, which is a
10 // SchedulingPriorityQueue that prioritizes instructions using DFA state to
11 // reduce the length of the critical path through the basic block
12 // on VLIW platforms.
13 // The scheduler is basically a top-down adaptable list scheduler with DFA
14 // resource tracking added to the cost function.
15 // DFA is queried as a state machine to model "packets/bundles" during
16 // schedule. Currently packets/bundles are discarded at the end of
17 // scheduling, affecting only order of instructions.
18 //
19 //===----------------------------------------------------------------------===//
20
21 #define DEBUG_TYPE "scheduler"
22 #include "llvm/CodeGen/ResourcePriorityQueue.h"
23 #include "llvm/Support/CommandLine.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include "llvm/CodeGen/MachineInstr.h"
27 #include "llvm/CodeGen/SelectionDAGNodes.h"
28 #include "llvm/Target/TargetMachine.h"
29 #include "llvm/Target/TargetLowering.h"
30
31 using namespace llvm;
32
33 static cl::opt DisableDFASched("disable-dfa-sched", cl::Hidden,
34 cl::ZeroOrMore, cl::init(false),
35 cl::desc("Disable use of DFA during scheduling"));
36
37 static cl::opt RegPressureThreshold(
38 "dfa-sched-reg-pressure-threshold", cl::Hidden, cl::ZeroOrMore, cl::init(5),
39 cl::desc("Track reg pressure and switch priority to in-depth"));
40
41
42 ResourcePriorityQueue::ResourcePriorityQueue(SelectionDAGISel *IS) :
43 Picker(this),
44 InstrItins(IS->getTargetLowering().getTargetMachine().getInstrItineraryData())
45 {
46 TII = IS->getTargetLowering().getTargetMachine().getInstrInfo();
47 TRI = IS->getTargetLowering().getTargetMachine().getRegisterInfo();
48 TLI = &IS->getTargetLowering();
49
50 const TargetMachine &tm = (*IS->MF).getTarget();
51 ResourcesModel = tm.getInstrInfo()->CreateTargetScheduleState(&tm,NULL);
52 // This hard requirment could be relaxed, but for now
53 // do not let it procede.
54 assert (ResourcesModel && "Unimplemented CreateTargetScheduleState.");
55
56 unsigned NumRC = TRI->getNumRegClasses();
57 RegLimit.resize(NumRC);
58 RegPressure.resize(NumRC);
59 std::fill(RegLimit.begin(), RegLimit.end(), 0);
60 std::fill(RegPressure.begin(), RegPressure.end(), 0);
61 for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(),
62 E = TRI->regclass_end(); I != E; ++I)
63 RegLimit[(*I)->getID()] = TRI->getRegPressureLimit(*I, *IS->MF);
64
65 ParallelLiveRanges = 0;
66 HorizontalVerticalBalance = 0;
67 }
68
69 unsigned
70 ResourcePriorityQueue::numberRCValPredInSU(SUnit *SU, unsigned RCId) {
71 unsigned NumberDeps = 0;
72 for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
73 I != E; ++I) {
74 if (I->isCtrl())
75 continue;
76
77 SUnit *PredSU = I->getSUnit();
78 const SDNode *ScegN = PredSU->getNode();
79
80 if (!ScegN)
81 continue;
82
83 // If value is passed to CopyToReg, it is probably
84 // live outside BB.
85 switch (ScegN->getOpcode()) {
86 default: break;
87 case ISD::TokenFactor: break;
88 case ISD::CopyFromReg: NumberDeps++; break;
89 case ISD::CopyToReg: break;
90 case ISD::INLINEASM: break;
91 }
92 if (!ScegN->isMachineOpcode())
93 continue;
94
95 for (unsigned i = 0, e = ScegN->getNumValues(); i != e; ++i) {
96 EVT VT = ScegN->getValueType(i);
97 if (TLI->isTypeLegal(VT)
98 && (TLI->getRegClassFor(VT)->getID() == RCId)) {
99 NumberDeps++;
100 break;
101 }
102 }
103 }
104 return NumberDeps;
105 }
106
107 unsigned ResourcePriorityQueue::numberRCValSuccInSU(SUnit *SU,
108 unsigned RCId) {
109 unsigned NumberDeps = 0;
110 for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
111 I != E; ++I) {
112 if (I->isCtrl())
113 continue;
114
115 SUnit *SuccSU = I->getSUnit();
116 const SDNode *ScegN = SuccSU->getNode();
117 if (!ScegN)
118 continue;
119
120 // If value is passed to CopyToReg, it is probably
121 // live outside BB.
122 switch (ScegN->getOpcode()) {
123 default: break;
124 case ISD::TokenFactor: break;
125 case ISD::CopyFromReg: break;
126 case ISD::CopyToReg: NumberDeps++; break;
127 case ISD::INLINEASM: break;
128 }
129 if (!ScegN->isMachineOpcode())
130 continue;
131
132 for (unsigned i = 0, e = ScegN->getNumOperands(); i != e; ++i) {
133 const SDValue &Op = ScegN->getOperand(i);
134 EVT VT = Op.getNode()->getValueType(Op.getResNo());
135 if (TLI->isTypeLegal(VT)
136 && (TLI->getRegClassFor(VT)->getID() == RCId)) {
137 NumberDeps++;
138 break;
139 }
140 }
141 }
142 return NumberDeps;
143 }
144
145 static unsigned numberCtrlDepsInSU(SUnit *SU) {
146 unsigned NumberDeps = 0;
147 for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
148 I != E; ++I)
149 if (I->isCtrl())
150 NumberDeps++;
151
152 return NumberDeps;
153 }
154
155 static unsigned numberCtrlPredInSU(SUnit *SU) {
156 unsigned NumberDeps = 0;
157 for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
158 I != E; ++I)
159 if (I->isCtrl())
160 NumberDeps++;
161
162 return NumberDeps;
163 }
164
165 ///
166 /// Initialize nodes.
167 ///
168 void ResourcePriorityQueue::initNodes(std::vector &sunits) {
169 SUnits = &sunits;
170 NumNodesSolelyBlocking.resize(SUnits->size(), 0);
171
172 for (unsigned i = 0, e = SUnits->size(); i != e; ++i) {
173 SUnit *SU = &(*SUnits)[i];
174 initNumRegDefsLeft(SU);
175 SU->NodeQueueId = 0;
176 }
177 }
178
179 /// This heuristic is used if DFA scheduling is not desired
180 /// for some VLIW platform.
181 bool resource_sort::operator()(const SUnit *LHS, const SUnit *RHS) const {
182 // The isScheduleHigh flag allows nodes with wraparound dependencies that
183 // cannot easily be modeled as edges with latencies to be scheduled as
184 // soon as possible in a top-down schedule.
185 if (LHS->isScheduleHigh && !RHS->isScheduleHigh)
186 return false;
187
188 if (!LHS->isScheduleHigh && RHS->isScheduleHigh)
189 return true;
190
191 unsigned LHSNum = LHS->NodeNum;
192 unsigned RHSNum = RHS->NodeNum;
193
194 // The most important heuristic is scheduling the critical path.
195 unsigned LHSLatency = PQ->getLatency(LHSNum);
196 unsigned RHSLatency = PQ->getLatency(RHSNum);
197 if (LHSLatency < RHSLatency) return true;
198 if (LHSLatency > RHSLatency) return false;
199
200 // After that, if two nodes have identical latencies, look to see if one will
201 // unblock more other nodes than the other.
202 unsigned LHSBlocked = PQ->getNumSolelyBlockNodes(LHSNum);
203 unsigned RHSBlocked = PQ->getNumSolelyBlockNodes(RHSNum);
204 if (LHSBlocked < RHSBlocked) return true;
205 if (LHSBlocked > RHSBlocked) return false;
206
207 // Finally, just to provide a stable ordering, use the node number as a
208 // deciding factor.
209 return LHSNum < RHSNum;
210 }
211
212
213 /// getSingleUnscheduledPred - If there is exactly one unscheduled predecessor
214 /// of SU, return it, otherwise return null.
215 SUnit *ResourcePriorityQueue::getSingleUnscheduledPred(SUnit *SU) {
216 SUnit *OnlyAvailablePred = 0;
217 for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
218 I != E; ++I) {
219 SUnit &Pred = *I->getSUnit();
220 if (!Pred.isScheduled) {
221 // We found an available, but not scheduled, predecessor. If it's the
222 // only one we have found, keep track of it... otherwise give up.
223 if (OnlyAvailablePred && OnlyAvailablePred != &Pred)
224 return 0;
225 OnlyAvailablePred = &Pred;
226 }
227 }
228 return OnlyAvailablePred;
229 }
230
231 void ResourcePriorityQueue::push(SUnit *SU) {
232 // Look at all of the successors of this node. Count the number of nodes that
233 // this node is the sole unscheduled node for.
234 unsigned NumNodesBlocking = 0;
235 for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
236 I != E; ++I)
237 if (getSingleUnscheduledPred(I->getSUnit()) == SU)
238 ++NumNodesBlocking;
239
240 NumNodesSolelyBlocking[SU->NodeNum] = NumNodesBlocking;
241 Queue.push_back(SU);
242 }
243
244 /// Check if scheduling of this SU is possible
245 /// in the current packet.
246 bool ResourcePriorityQueue::isResourceAvailable(SUnit *SU) {
247 if (!SU || !SU->getNode())
248 return false;
249
250 // If this is a compound instruction,
251 // it is likely to be a call. Do not delay it.
252 if (SU->getNode()->getGluedNode())
253 return true;
254
255 // First see if the pipeline could receive this instruction
256 // in the current cycle.
257 if (SU->getNode()->isMachineOpcode())
258 switch (SU->getNode()->getMachineOpcode()) {
259 default:
260 if (!ResourcesModel->canReserveResources(&TII->get(
261 SU->getNode()->getMachineOpcode())))
262 return false;
263 case TargetOpcode::EXTRACT_SUBREG:
264 case TargetOpcode::INSERT_SUBREG:
265 case TargetOpcode::SUBREG_TO_REG:
266 case TargetOpcode::REG_SEQUENCE:
267 case TargetOpcode::IMPLICIT_DEF:
268 break;
269 }
270
271 // Now see if there are no other dependencies
272 // to instructions alredy in the packet.
273 for (unsigned i = 0, e = Packet.size(); i != e; ++i)
274 for (SUnit::const_succ_iterator I = Packet[i]->Succs.begin(),
275 E = Packet[i]->Succs.end(); I != E; ++I) {
276 // Since we do not add pseudos to packets, might as well
277 // ignor order deps.
278 if (I->isCtrl())
279 continue;
280
281 if (I->getSUnit() == SU)
282 return false;
283 }
284
285 return true;
286 }
287
288 /// Keep track of available resources.
289 void ResourcePriorityQueue::reserveResources(SUnit *SU) {
290 // If this SU does not fit in the packet
291 // start a new one.
292 if (!isResourceAvailable(SU) || SU->getNode()->getGluedNode()) {
293 ResourcesModel->clearResources();
294 Packet.clear();
295 }
296
297 if (SU->getNode() && SU->getNode()->isMachineOpcode()) {
298 switch (SU->getNode()->getMachineOpcode()) {
299 default:
300 ResourcesModel->reserveResources(&TII->get(
301 SU->getNode()->getMachineOpcode()));
302 break;
303 case TargetOpcode::EXTRACT_SUBREG:
304 case TargetOpcode::INSERT_SUBREG:
305 case TargetOpcode::SUBREG_TO_REG:
306 case TargetOpcode::REG_SEQUENCE:
307 case TargetOpcode::IMPLICIT_DEF:
308 break;
309 }
310 Packet.push_back(SU);
311 }
312 // Forcefully end packet for PseudoOps.
313 else {
314 ResourcesModel->clearResources();
315 Packet.clear();
316 }
317
318 // If packet is now full, reset the state so in the next cycle
319 // we start fresh.
320 if (Packet.size() >= InstrItins->IssueWidth) {
321 ResourcesModel->clearResources();
322 Packet.clear();
323 }
324 }
325
326 signed ResourcePriorityQueue::rawRegPressureDelta(SUnit *SU, unsigned RCId) {
327 signed RegBalance = 0;
328
329 if (!SU || !SU->getNode() || !SU->getNode()->isMachineOpcode())
330 return RegBalance;
331
332 // Gen estimate.
333 for (unsigned i = 0, e = SU->getNode()->getNumValues(); i != e; ++i) {
334 EVT VT = SU->getNode()->getValueType(i);
335 if (TLI->isTypeLegal(VT)
336 && TLI->getRegClassFor(VT)
337 && TLI->getRegClassFor(VT)->getID() == RCId)
338 RegBalance += numberRCValSuccInSU(SU, RCId);
339 }
340 // Kill estimate.
341 for (unsigned i = 0, e = SU->getNode()->getNumOperands(); i != e; ++i) {
342 const SDValue &Op = SU->getNode()->getOperand(i);
343 EVT VT = Op.getNode()->getValueType(Op.getResNo());
344 if (isa(Op.getNode()))
345 continue;
346
347 if (TLI->isTypeLegal(VT) && TLI->getRegClassFor(VT)
348 && TLI->getRegClassFor(VT)->getID() == RCId)
349 RegBalance -= numberRCValPredInSU(SU, RCId);
350 }
351 return RegBalance;
352 }
353
354 /// Estimates change in reg pressure from this SU.
355 /// It is acheived by trivial tracking of defined
356 /// and used vregs in dependent instructions.
357 /// The RawPressure flag makes this function to ignore
358 /// existing reg file sizes, and report raw def/use
359 /// balance.
360 signed ResourcePriorityQueue::regPressureDelta(SUnit *SU, bool RawPressure) {
361 signed RegBalance = 0;
362
363 if (!SU || !SU->getNode() || !SU->getNode()->isMachineOpcode())
364 return RegBalance;
365
366 if (RawPressure) {
367 for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(),
368 E = TRI->regclass_end(); I != E; ++I) {
369 const TargetRegisterClass *RC = *I;
370 RegBalance += rawRegPressureDelta(SU, RC->getID());
371 }
372 }
373 else {
374 for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(),
375 E = TRI->regclass_end(); I != E; ++I) {
376 const TargetRegisterClass *RC = *I;
377 if ((RegPressure[RC->getID()] +
378 rawRegPressureDelta(SU, RC->getID()) > 0) &&
379 (RegPressure[RC->getID()] +
380 rawRegPressureDelta(SU, RC->getID()) >= RegLimit[RC->getID()]))
381 RegBalance += rawRegPressureDelta(SU, RC->getID());
382 }
383 }
384
385 return RegBalance;
386 }
387
388 // Constants used to denote relative importance of
389 // heuristic components for cost computation.
390 static const unsigned PriorityOne = 200;
391 static const unsigned PriorityTwo = 100;
392 static const unsigned PriorityThree = 50;
393 static const unsigned PriorityFour = 15;
394 static const unsigned PriorityFive = 5;
395 static const unsigned ScaleOne = 20;
396 static const unsigned ScaleTwo = 10;
397 static const unsigned ScaleThree = 5;
398 static const unsigned FactorOne = 2;
399
400 /// Returns single number reflecting benefit of scheduling SU
401 /// in the current cycle.
402 signed ResourcePriorityQueue::SUSchedulingCost(SUnit *SU) {
403 // Initial trivial priority.
404 signed ResCount = 1;
405
406 // Do not waste time on a node that is already scheduled.
407 if (SU->isScheduled)
408 return ResCount;
409
410 // Forced priority is high.
411 if (SU->isScheduleHigh)
412 ResCount += PriorityOne;
413
414 // Adaptable scheduling
415 // A small, but very parallel
416 // region, where reg pressure is an issue.
417 if (HorizontalVerticalBalance > RegPressureThreshold) {
418 // Critical path first
419 ResCount += (SU->getHeight() * ScaleTwo);
420 // If resources are available for it, multiply the
421 // chance of scheduling.
422 if (isResourceAvailable(SU))
423 ResCount <<= FactorOne;
424
425 // Consider change to reg pressure from scheduling
426 // this SU.
427 ResCount -= (regPressureDelta(SU,true) * ScaleOne);
428 }
429 // Default heuristic, greeady and
430 // critical path driven.
431 else {
432 // Critical path first.
433 ResCount += (SU->getHeight() * ScaleTwo);
434 // Now see how many instructions is blocked by this SU.
435 ResCount += (NumNodesSolelyBlocking[SU->NodeNum] * ScaleTwo);
436 // If resources are available for it, multiply the
437 // chance of scheduling.
438 if (isResourceAvailable(SU))
439 ResCount <<= FactorOne;
440
441 ResCount -= (regPressureDelta(SU) * ScaleTwo);
442 }
443
444 // These are platform specific things.
445 // Will need to go into the back end
446 // and accessed from here via a hook.
447 for (SDNode *N = SU->getNode(); N; N = N->getGluedNode()) {
448 if (N->isMachineOpcode()) {
449 const MCInstrDesc &TID = TII->get(N->getMachineOpcode());
450 if (TID.isCall())
451 ResCount += (PriorityThree + (ScaleThree*N->getNumValues()));
452 }
453 else
454 switch (N->getOpcode()) {
455 default: break;
456 case ISD::TokenFactor:
457 case ISD::CopyFromReg:
458 case ISD::CopyToReg:
459 ResCount += PriorityFive;
460 break;
461
462 case ISD::INLINEASM:
463 ResCount += PriorityFour;
464 break;
465 }
466 }
467 return ResCount;
468 }
469
470
471 /// Main resource tracking point.
472 void ResourcePriorityQueue::ScheduledNode(SUnit *SU) {
473 // Use NULL entry as an event marker to reset
474 // the DFA state.
475 if (!SU) {
476 ResourcesModel->clearResources();
477 Packet.clear();
478 return;
479 }
480
481 const SDNode *ScegN = SU->getNode();
482 // Update reg pressure tracking.
483 // First update current node.
484 if (ScegN->isMachineOpcode()) {
485 // Estimate generated regs.
486 for (unsigned i = 0, e = ScegN->getNumValues(); i != e; ++i) {
487 EVT VT = ScegN->getValueType(i);
488
489 if (TLI->isTypeLegal(VT)) {
490 const TargetRegisterClass *RC = TLI->getRegClassFor(VT);
491 if (RC)
492 RegPressure[RC->getID()] += numberRCValSuccInSU(SU, RC->getID());
493 }
494 }
495 // Estimate killed regs.
496 for (unsigned i = 0, e = ScegN->getNumOperands(); i != e; ++i) {
497 const SDValue &Op = ScegN->getOperand(i);
498 EVT VT = Op.getNode()->getValueType(Op.getResNo());
499
500 if (TLI->isTypeLegal(VT)) {
501 const TargetRegisterClass *RC = TLI->getRegClassFor(VT);
502 if (RC) {
503 if (RegPressure[RC->getID()] >
504 (numberRCValPredInSU(SU, RC->getID())))
505 RegPressure[RC->getID()] -= numberRCValPredInSU(SU, RC->getID());
506 else RegPressure[RC->getID()] = 0;
507 }
508 }
509 }
510 for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
511 I != E; ++I) {
512 if (I->isCtrl() || (I->getSUnit()->NumRegDefsLeft == 0))
513 continue;
514 --I->getSUnit()->NumRegDefsLeft;
515 }
516 }
517
518 // Reserve resources for this SU.
519 reserveResources(SU);
520
521 // Adjust number of parallel live ranges.
522 // Heuristic is simple - node with no data successors reduces
523 // number of live ranges. All others, increase it.
524 unsigned NumberNonControlDeps = 0;
525
526 for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
527 I != E; ++I) {
528 adjustPriorityOfUnscheduledPreds(I->getSUnit());
529 if (!I->isCtrl())
530 NumberNonControlDeps++;
531 }
532
533 if (!NumberNonControlDeps) {
534 if (ParallelLiveRanges >= SU->NumPreds)
535 ParallelLiveRanges -= SU->NumPreds;
536 else
537 ParallelLiveRanges = 0;
538
539 }
540 else
541 ParallelLiveRanges += SU->NumRegDefsLeft;
542
543 // Track parallel live chains.
544 HorizontalVerticalBalance += (SU->Succs.size() - numberCtrlDepsInSU(SU));
545 HorizontalVerticalBalance -= (SU->Preds.size() - numberCtrlPredInSU(SU));
546 }
547
548 void ResourcePriorityQueue::initNumRegDefsLeft(SUnit *SU) {
549 unsigned NodeNumDefs = 0;
550 for (SDNode *N = SU->getNode(); N; N = N->getGluedNode())
551 if (N->isMachineOpcode()) {
552 const MCInstrDesc &TID = TII->get(N->getMachineOpcode());
553 // No register need be allocated for this.
554 if (N->getMachineOpcode() == TargetOpcode::IMPLICIT_DEF) {
555 NodeNumDefs = 0;
556 break;
557 }
558 NodeNumDefs = std::min(N->getNumValues(), TID.getNumDefs());
559 }
560 else
561 switch(N->getOpcode()) {
562 default: break;
563 case ISD::CopyFromReg:
564 NodeNumDefs++;
565 break;
566 case ISD::INLINEASM:
567 NodeNumDefs++;
568 break;
569 }
570
571 SU->NumRegDefsLeft = NodeNumDefs;
572 }
573
574 /// adjustPriorityOfUnscheduledPreds - One of the predecessors of SU was just
575 /// scheduled. If SU is not itself available, then there is at least one
576 /// predecessor node that has not been scheduled yet. If SU has exactly ONE
577 /// unscheduled predecessor, we want to increase its priority: it getting
578 /// scheduled will make this node available, so it is better than some other
579 /// node of the same priority that will not make a node available.
580 void ResourcePriorityQueue::adjustPriorityOfUnscheduledPreds(SUnit *SU) {
581 if (SU->isAvailable) return; // All preds scheduled.
582
583 SUnit *OnlyAvailablePred = getSingleUnscheduledPred(SU);
584 if (OnlyAvailablePred == 0 || !OnlyAvailablePred->isAvailable)
585 return;
586
587 // Okay, we found a single predecessor that is available, but not scheduled.
588 // Since it is available, it must be in the priority queue. First remove it.
589 remove(OnlyAvailablePred);
590
591 // Reinsert the node into the priority queue, which recomputes its
592 // NumNodesSolelyBlocking value.
593 push(OnlyAvailablePred);
594 }
595
596
597 /// Main access point - returns next instructions
598 /// to be placed in scheduling sequence.
599 SUnit *ResourcePriorityQueue::pop() {
600 if (empty())
601 return 0;
602
603 std::vector::iterator Best = Queue.begin();
604 if (!DisableDFASched) {
605 signed BestCost = SUSchedulingCost(*Best);
606 for (std::vector::iterator I = Queue.begin(),
607 E = Queue.end(); I != E; ++I) {
608 if (*I == *Best)
609 continue;
610
611 if (SUSchedulingCost(*I) > BestCost) {
612 BestCost = SUSchedulingCost(*I);
613 Best = I;
614 }
615 }
616 }
617 // Use default TD scheduling mechanism.
618 else {
619 for (std::vector::iterator I = llvm::next(Queue.begin()),
620 E = Queue.end(); I != E; ++I)
621 if (Picker(*Best, *I))
622 Best = I;
623 }
624
625 SUnit *V = *Best;
626 if (Best != prior(Queue.end()))
627 std::swap(*Best, Queue.back());
628
629 Queue.pop_back();
630
631 return V;
632 }
633
634
635 void ResourcePriorityQueue::remove(SUnit *SU) {
636 assert(!Queue.empty() && "Queue is empty!");
637 std::vector::iterator I = std::find(Queue.begin(), Queue.end(), SU);
638 if (I != prior(Queue.end()))
639 std::swap(*I, Queue.back());
640
641 Queue.pop_back();
642 }
643
644
645 #ifdef NDEBUG
646 void ResourcePriorityQueue::dump(ScheduleDAG *DAG) const {}
647 #else
648 void ResourcePriorityQueue::dump(ScheduleDAG *DAG) const {
649 ResourcePriorityQueue q = *this;
650 while (!q.empty()) {
651 SUnit *su = q.pop();
652 dbgs() << "Height " << su->getHeight() << ": ";
653 su->dump(DAG);
654 }
655 }
656 #endif
0 //===- ScheduleDAGVLIW.cpp - SelectionDAG list scheduler for VLIW -*- C++ -*-=//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This implements a top-down list scheduler, using standard algorithms.
10 // The basic approach uses a priority queue of available nodes to schedule.
11 // One at a time, nodes are taken from the priority queue (thus in priority
12 // order), checked for legality to schedule, and emitted if legal.
13 //
14 // Nodes may not be legal to schedule either due to structural hazards (e.g.
15 // pipeline or resource constraints) or because an input to the instruction has
16 // not completed execution.
17 //
18 //===----------------------------------------------------------------------===//
19
20 #define DEBUG_TYPE "pre-RA-sched"
21 #include "ScheduleDAGSDNodes.h"
22 #include "llvm/CodeGen/LatencyPriorityQueue.h"
23 #include "llvm/CodeGen/ScheduleHazardRecognizer.h"
24 #include "llvm/CodeGen/SchedulerRegistry.h"
25 #include "llvm/CodeGen/SelectionDAGISel.h"
26 #include "llvm/Target/TargetRegisterInfo.h"
27 #include "llvm/Target/TargetData.h"
28 #include "llvm/Target/TargetInstrInfo.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/raw_ostream.h"
32 #include "llvm/ADT/Statistic.h"
33 #include "llvm/CodeGen/ResourcePriorityQueue.h"
34 #include
35 using namespace llvm;
36
37 STATISTIC(NumNoops , "Number of noops inserted");
38 STATISTIC(NumStalls, "Number of pipeline stalls");
39
40 static RegisterScheduler
41 VLIWScheduler("vliw-td", "VLIW scheduler",
42 createVLIWDAGScheduler);
43
44 namespace {
45 //===----------------------------------------------------------------------===//
46 /// ScheduleDAGVLIW - The actual DFA list scheduler implementation. This
47 /// supports / top-down scheduling.
48 ///
49 class ScheduleDAGVLIW : public ScheduleDAGSDNodes {
50 private:
51 /// AvailableQueue - The priority queue to use for the available SUnits.
52 ///
53 SchedulingPriorityQueue *AvailableQueue;
54
55 /// PendingQueue - This contains all of the instructions whose operands have
56 /// been issued, but their results are not ready yet (due to the latency of
57 /// the operation). Once the operands become available, the instruction is
58 /// added to the AvailableQueue.
59 std::vector PendingQueue;
60
61 /// HazardRec - The hazard recognizer to use.
62 ScheduleHazardRecognizer *HazardRec;
63
64 /// AA - AliasAnalysis for making memory reference queries.
65 AliasAnalysis *AA;
66
67 public:
68 ScheduleDAGVLIW(MachineFunction &mf,
69 AliasAnalysis *aa,
70 SchedulingPriorityQueue *availqueue)
71 : ScheduleDAGSDNodes(mf), AvailableQueue(availqueue), AA(aa) {
72
73 const TargetMachine &tm = mf.getTarget();
74 HazardRec = tm.getInstrInfo()->CreateTargetHazardRecognizer(&tm, this);
75 }
76
77 ~ScheduleDAGVLIW() {
78 delete HazardRec;
79 delete AvailableQueue;
80 }
81
82 void Schedule();
83
84 private:
85 void releaseSucc(SUnit *SU, const SDep &D);
86 void releaseSuccessors(SUnit *SU);
87 void scheduleNodeTopDown(SUnit *SU, unsigned CurCycle);
88 void listScheduleTopDown();
89 };
90 } // end anonymous namespace
91
92 /// Schedule - Schedule the DAG using list scheduling.
93 void ScheduleDAGVLIW::Schedule() {
94 DEBUG(dbgs()
95 << "********** List Scheduling BB#" << BB->getNumber()
96 << " '" << BB->getName() << "' **********\n");
97
98 // Build the scheduling graph.
99 BuildSchedGraph(AA);
100
101 AvailableQueue->initNodes(SUnits);
102
103 listScheduleTopDown();
104
105 AvailableQueue->releaseState();
106 }
107
108 //===----------------------------------------------------------------------===//
109 // Top-Down Scheduling
110 //===----------------------------------------------------------------------===//
111
112 /// releaseSucc - Decrement the NumPredsLeft count of a successor. Add it to
113 /// the PendingQueue if the count reaches zero. Also update its cycle bound.
114 void ScheduleDAGVLIW::releaseSucc(SUnit *SU, const SDep &D) {
115 SUnit *SuccSU = D.getSUnit();
116
117 #ifndef NDEBUG
118 if (SuccSU->NumPredsLeft == 0) {
119 dbgs() << "*** Scheduling failed! ***\n";
120 SuccSU->dump(this);
121 dbgs() << " has been released too many times!\n";
122 llvm_unreachable(0);
123 }
124 #endif
125 --SuccSU->NumPredsLeft;
126
127 SuccSU->setDepthToAtLeast(SU->getDepth() + D.getLatency());
128
129 // If all the node's predecessors are scheduled, this node is ready
130 // to be scheduled. Ignore the special ExitSU node.
131 if (SuccSU->NumPredsLeft == 0 && SuccSU != &ExitSU) {
132 PendingQueue.push_back(SuccSU);
133 }
134 }
135
136 void ScheduleDAGVLIW::releaseSuccessors(SUnit *SU) {
137 // Top down: release successors.
138 for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
139 I != E; ++I) {
140 assert(!I->isAssignedRegDep() &&
141 "The list-td scheduler doesn't yet support physreg dependencies!");
142
143 releaseSucc(SU, *I);
144 }
145 }
146
147 /// scheduleNodeTopDown - Add the node to the schedule. Decrement the pending
148 /// count of its successors. If a successor pending count is zero, add it to
149 /// the Available queue.
150 void ScheduleDAGVLIW::scheduleNodeTopDown(SUnit *SU, unsigned CurCycle) {
151 DEBUG(dbgs() << "*** Scheduling [" << CurCycle << "]: ");
152 DEBUG(SU->dump(this));
153
154 Sequence.push_back(SU);
155 assert(CurCycle >= SU->getDepth() && "Node scheduled above its depth!");
156 SU->setDepthToAtLeast(CurCycle);
157
158 releaseSuccessors(SU);
159 SU->isScheduled = true;
160 AvailableQueue->ScheduledNode(SU);
161 }
162
163 /// listScheduleTopDown - The main loop of list scheduling for top-down
164 /// schedulers.
165 void ScheduleDAGVLIW::listScheduleTopDown() {
166 unsigned CurCycle = 0;
167
168 // Release any successors of the special Entry node.
169 releaseSuccessors(&EntrySU);
170
171 // All leaves to AvailableQueue.
172 for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
173 // It is available if it has no predecessors.
174 if (SUnits[i].Preds.empty()) {
175 AvailableQueue->push(&SUnits[i]);
176 SUnits[i].isAvailable = true;
177 }
178 }
179
180 // While AvailableQueue is not empty, grab the node with the highest
181 // priority. If it is not ready put it back. Schedule the node.
182 std::vector NotReady;
183 Sequence.reserve(SUnits.size());
184 while (!AvailableQueue->empty() || !PendingQueue.empty()) {
185 // Check to see if any of the pending instructions are ready to issue. If
186 // so, add them to the available queue.
187 for (unsigned i = 0, e = PendingQueue.size(); i != e; ++i) {
188 if (PendingQueue[i]->getDepth() == CurCycle) {
189 AvailableQueue->push(PendingQueue[i]);
190 PendingQueue[i]->isAvailable = true;
191 PendingQueue[i] = PendingQueue.back();
192 PendingQueue.pop_back();
193 --i; --e;
194 }
195 else {
196 assert(PendingQueue[i]->getDepth() > CurCycle && "Negative latency?");
197 }
198 }
199
200 // If there are no instructions available, don't try to issue anything, and
201 // don't advance the hazard recognizer.
202 if (AvailableQueue->empty()) {
203 // Reset DFA state.
204 AvailableQueue->ScheduledNode(0);
205 ++CurCycle;
206 continue;
207 }
208
209 SUnit *FoundSUnit = 0;
210
211 bool HasNoopHazards = false;
212 while (!AvailableQueue->empty()) {
213 SUnit *CurSUnit = AvailableQueue->pop();
214
215 ScheduleHazardRecognizer::HazardType HT =
216 HazardRec->getHazardType(CurSUnit, 0/*no stalls*/);
217 if (HT == ScheduleHazardRecognizer::NoHazard) {
218 FoundSUnit = CurSUnit;
219 break;
220 }
221
222 // Remember if this is a noop hazard.
223 HasNoopHazards |= HT == ScheduleHazardRecognizer::NoopHazard;
224
225 NotReady.push_back(CurSUnit);
226 }
227
228 // Add the nodes that aren't ready back onto the available list.
229 if (!NotReady.empty()) {
230 AvailableQueue->push_all(NotReady);
231 NotReady.clear();
232 }
233
234 // If we found a node to schedule, do it now.
235 if (FoundSUnit) {
236 scheduleNodeTopDown(FoundSUnit, CurCycle);
237 HazardRec->EmitInstruction(FoundSUnit);
238
239 // If this is a pseudo-op node, we don't want to increment the current
240 // cycle.
241 if (FoundSUnit->Latency) // Don't increment CurCycle for pseudo-ops!
242 ++CurCycle;
243 } else if (!HasNoopHazards) {
244 // Otherwise, we have a pipeline stall, but no other problem, just advance
245 // the current cycle and try again.
246 DEBUG(dbgs() << "*** Advancing cycle, no work to do\n");
247 HazardRec->AdvanceCycle();
248 ++NumStalls;
249 ++CurCycle;
250 } else {
251 // Otherwise, we have no instructions to issue and we have instructions
252 // that will fault if we don't do this right. This is the case for
253 // processors without pipeline interlocks and other cases.
254 DEBUG(dbgs() << "*** Emitting noop\n");
255 HazardRec->EmitNoop();
256 Sequence.push_back(0); // NULL here means noop
257 ++NumNoops;
258 ++CurCycle;
259 }
260 }
261
262 #ifndef NDEBUG
263 VerifySchedule(/*isBottomUp=*/false);
264 #endif
265 }
266
267 //===----------------------------------------------------------------------===//
268 // Public Constructor Functions
269 //===----------------------------------------------------------------------===//
270
271 /// createVLIWDAGScheduler - This creates a top-down list scheduler.
272 ScheduleDAGSDNodes *
273 llvm::createVLIWDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) {
274 return new ScheduleDAGVLIW(*IS->MF, IS->AA, new ResourcePriorityQueue(IS));
275 }
224224 return createBURRListDAGScheduler(IS, OptLevel);
225225 if (TLI.getSchedulingPreference() == Sched::Hybrid)
226226 return createHybridListDAGScheduler(IS, OptLevel);
227 if (TLI.getSchedulingPreference() == Sched::VLIW)
228 return createVLIWDAGScheduler(IS, OptLevel);
227229 assert(TLI.getSchedulingPreference() == Sched::ILP &&
228230 "Unknown sched type!");
229231 return createILPListDAGScheduler(IS, OptLevel);
12971297 // Needed for DYNAMIC_STACKALLOC expansion.
12981298 unsigned StackRegister = TM.getRegisterInfo()->getStackRegister();
12991299 setStackPointerRegisterToSaveRestore(StackRegister);
1300 setSchedulingPreference(Sched::VLIW);
13001301 }
13011302
13021303
2323 #include "llvm/CodeGen/MachineMemOperand.h"
2424 #include "llvm/CodeGen/PseudoSourceValue.h"
2525 #define GET_INSTRINFO_CTOR
26 #include "llvm/CodeGen/DFAPacketizer.h"
2627 #include "HexagonGenInstrInfo.inc"
28 #include "HexagonGenDFAPacketizer.inc"
2729
2830 #include
2931
468470 }
469471
470472
473
471474 bool HexagonInstrInfo::isPredicable(MachineInstr *MI) const {
472475 bool isPred = MI->getDesc().isPredicable();
473476
556559
557560 return true;
558561 }
562
559563
560564
561565 int HexagonInstrInfo::
14491453 return false;
14501454 }
14511455 }
1456
1457 DFAPacketizer *HexagonInstrInfo::
1458 CreateTargetScheduleState(const TargetMachine *TM,
1459 const ScheduleDAG *DAG) const {
1460 const InstrItineraryData *II = TM->getInstrItineraryData();
1461 return TM->getSubtarget().createDFAPacketizer(II);
1462 }
1463
1464 bool HexagonInstrInfo::isSchedulingBoundary(const MachineInstr *MI,
1465 const MachineBasicBlock *MBB,
1466 const MachineFunction &MF) const {
1467 // Debug info is never a scheduling boundary. It's necessary to be explicit
1468 // due to the special treatment of IT instructions below, otherwise a
1469 // dbg_value followed by an IT will result in the IT instruction being
1470 // considered a scheduling hazard, which is wrong. It should be the actual
1471 // instruction preceding the dbg_value instruction(s), just like it is
1472 // when debug info is not present.
1473 if (MI->isDebugValue())
1474 return false;
1475
1476 // Terminators and labels can't be scheduled around.
1477 if (MI->getDesc().isTerminator() || MI->isLabel() || MI->isInlineAsm())
1478 return true;
1479
1480 return false;
1481 }
134134 isProfitableToDupForIfCvt(MachineBasicBlock &MBB,unsigned NumCycles,
135135 const BranchProbability &Probability) const;
136136
137 virtual DFAPacketizer*
138 CreateTargetScheduleState(const TargetMachine *TM,
139 const ScheduleDAG *DAG) const;
140
141 virtual bool isSchedulingBoundary(const MachineInstr *MI,
142 const MachineBasicBlock *MBB,
143 const MachineFunction &MF) const;
137144 bool isValidOffset(const int Opcode, const int Offset) const;
138145 bool isValidAutoIncImm(const EVT VT, const int Offset) const;
139146 bool isMemOp(const MachineInstr *MI) const;
5151 // Initialize scheduling itinerary for the specified CPU.
5252 InstrItins = getInstrItineraryForCPU(CPUString);
5353
54 // Max issue per cycle == bundle width.
55 InstrItins.IssueWidth = 4;
56
5457 if (EnableMemOps)
5558 UseMemOps = true;
5659 else
1515 HexagonGenAsmWriter.inc \
1616 HexagonGenDAGISel.inc HexagonGenSubtargetInfo.inc \
1717 HexagonGenCallingConv.inc \
18 HexagonGenDFAPacketizer.inc \
1819 HexagonAsmPrinter.cpp
1920
2021 DIRS = TargetInfo MCTargetDesc
None ; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
0 ; RUN: llc -march=hexagon -mcpu=hexagonv4 -disable-dfa-sched < %s | FileCheck %s
11 ; CHECK: r[[T0:[0-9]+]] = #7
22 ; CHECK: memw(r29 + #0) = r[[T0]]
33 ; CHECK: r0 = #1
None ; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
0 ; RUN: llc -march=hexagon -mcpu=hexagonv4 -disable-dfa-sched < %s | FileCheck %s
11
22 @num = external global i32
33 @acc = external global i32
44 @val = external global i32
55
6 ; CHECK: CONST32(#num)
67 ; CHECK: CONST32(#acc)
78 ; CHECK: CONST32(#val)
8 ; CHECK: CONST32(#num)
99
1010 define void @foo() nounwind {
1111 entry: