HexagonMachineScheduler.h revision 7ae51be2a3a56be5cf0ee4557aa13a069c96a241
13e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin//===-- HexagonMachineScheduler.h - Custom Hexagon MI scheduler. ----===// 23e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin// 33e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin// The LLVM Compiler Infrastructure 43e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin// 53e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin// This file is distributed under the University of Illinois Open Source 63e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin// License. See LICENSE.TXT for details. 73e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin// 83e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin//===----------------------------------------------------------------------===// 93e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin// 103e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin// Custom Hexagon MI scheduler. 113e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin// 123e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin//===----------------------------------------------------------------------===// 133e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 143e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#ifndef HEXAGONASMPRINTER_H 153e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#define HEXAGONASMPRINTER_H 163e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 173e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/CodeGen/LiveIntervalAnalysis.h" 183e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/CodeGen/MachineScheduler.h" 193e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/CodeGen/Passes.h" 203e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/CodeGen/RegisterClassInfo.h" 213e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/CodeGen/RegisterPressure.h" 223e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/CodeGen/ResourcePriorityQueue.h" 233e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/CodeGen/ScheduleDAGInstrs.h" 243e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/CodeGen/ScheduleHazardRecognizer.h" 253e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/Analysis/AliasAnalysis.h" 263e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/Target/TargetInstrInfo.h" 273e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/Support/CommandLine.h" 283e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/Support/Debug.h" 293e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/Support/ErrorHandling.h" 303e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/Support/raw_ostream.h" 313e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/ADT/OwningPtr.h" 323e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#include "llvm/ADT/PriorityQueue.h" 333e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 343e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinusing namespace llvm; 353e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 363e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin//===----------------------------------------------------------------------===// 373e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin// MachineSchedStrategy - Interface to a machine scheduling algorithm. 383e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin//===----------------------------------------------------------------------===// 393e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 403e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinnamespace llvm { 413e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinclass VLIWMachineScheduler; 423e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 437ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin/// MachineSchedStrategy - Interface used by VLIWMachineScheduler to drive 447ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin/// the selected scheduling algorithm. 453e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin/// 467ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin/// TODO: Move this to ScheduleDAGInstrs.h 473e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinclass MachineSchedStrategy { 483e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinpublic: 493e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin virtual ~MachineSchedStrategy() {} 503e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 513e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Initialize the strategy after building the DAG for a new region. 523e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin virtual void initialize(VLIWMachineScheduler *DAG) = 0; 533e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 543e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Pick the next node to schedule, or return NULL. Set IsTopNode to true to 553e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// schedule the node at the top of the unscheduled region. Otherwise it will 563e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// be scheduled at the bottom. 573e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin virtual SUnit *pickNode(bool &IsTopNode) = 0; 583e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 597ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// Notify MachineSchedStrategy that VLIWMachineScheduler has 607ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// scheduled a node. 613e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin virtual void schedNode(SUnit *SU, bool IsTopNode) = 0; 623e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 633e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// When all predecessor dependencies have been resolved, free this node for 643e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// top-down scheduling. 653e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin virtual void releaseTopNode(SUnit *SU) = 0; 663e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// When all successor dependencies have been resolved, free this node for 673e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// bottom-up scheduling. 683e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin virtual void releaseBottomNode(SUnit *SU) = 0; 693e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin}; 703e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 713e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin//===----------------------------------------------------------------------===// 727ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin// ConvergingVLIWScheduler - Implementation of the standard 737ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin// MachineSchedStrategy. 743e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin//===----------------------------------------------------------------------===// 753e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 763e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin/// ReadyQueue encapsulates vector of "ready" SUnits with basic convenience 773e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin/// methods for pushing and removing nodes. ReadyQueue's are uniquely identified 783e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin/// by an ID. SUnit::NodeQueueId is a mask of the ReadyQueues the SUnit is in. 793e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinclass ReadyQueue { 803e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned ID; 813e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin std::string Name; 823e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin std::vector<SUnit*> Queue; 833e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 843e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinpublic: 853e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin ReadyQueue(unsigned id, const Twine &name): ID(id), Name(name.str()) {} 863e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 873e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned getID() const { return ID; } 883e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 893e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin StringRef getName() const { return Name; } 903e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 913e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin // SU is in this queue if it's NodeQueueID is a superset of this ID. 923e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin bool isInQueue(SUnit *SU) const { return (SU->NodeQueueId & ID); } 933e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 943e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin bool empty() const { return Queue.empty(); } 953e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 963e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned size() const { return Queue.size(); } 973e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 983e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin typedef std::vector<SUnit*>::iterator iterator; 993e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1003e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin iterator begin() { return Queue.begin(); } 1013e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1023e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin iterator end() { return Queue.end(); } 1033e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1043e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin iterator find(SUnit *SU) { 1053e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin return std::find(Queue.begin(), Queue.end(), SU); 1063e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 1073e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1083e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void push(SUnit *SU) { 1093e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin Queue.push_back(SU); 1103e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin SU->NodeQueueId |= ID; 1113e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 1123e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1133e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void remove(iterator I) { 1143e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin (*I)->NodeQueueId &= ~ID; 1153e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin *I = Queue.back(); 1163e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin Queue.pop_back(); 1173e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 1183e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1193e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void dump() { 1203e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin dbgs() << Name << ": "; 1213e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin for (unsigned i = 0, e = Queue.size(); i < e; ++i) 1223e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin dbgs() << Queue[i]->NodeNum << " "; 1233e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin dbgs() << "\n"; 1243e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 1253e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin}; 1263e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1273e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinclass VLIWResourceModel { 1283e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// ResourcesModel - Represents VLIW state. 1293e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Not limited to VLIW targets per say, but assumes 1303e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// definition of DFA by a target. 1313e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin DFAPacketizer *ResourcesModel; 1323e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1333e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin const InstrItineraryData *InstrItins; 1343e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1353e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Local packet/bundle model. Purely 1363e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// internal to the MI schedulre at the time. 1373e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin std::vector<SUnit*> Packet; 1383e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1393e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Total packets created. 1403e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned TotalPackets; 1413e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1423e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinpublic: 1433e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin VLIWResourceModel(MachineSchedContext *C, const InstrItineraryData *IID) : 1443e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin InstrItins(IID), TotalPackets(0) { 1453e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin const TargetMachine &TM = C->MF->getTarget(); 1463e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin ResourcesModel = TM.getInstrInfo()->CreateTargetScheduleState(&TM,NULL); 1473e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1487ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin // This hard requirement could be relaxed, 1497ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin // but for now do not let it proceed. 1507ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin assert(ResourcesModel && "Unimplemented CreateTargetScheduleState."); 1517ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 1527ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin Packet.resize(InstrItins->SchedModel->IssueWidth); 1537ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin Packet.clear(); 1547ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin ResourcesModel->clearResources(); 1557ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin } 1567ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 1577ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin VLIWResourceModel(const TargetMachine &TM) : 1587ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin InstrItins(TM.getInstrItineraryData()), TotalPackets(0) { 1597ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin ResourcesModel = TM.getInstrInfo()->CreateTargetScheduleState(&TM,NULL); 1607ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 1617ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin // This hard requirement could be relaxed, 1627ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin // but for now do not let it proceed. 1633e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin assert(ResourcesModel && "Unimplemented CreateTargetScheduleState."); 1643e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1653e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin Packet.resize(InstrItins->SchedModel->IssueWidth); 1663e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin Packet.clear(); 1673e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin ResourcesModel->clearResources(); 1683e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 1693e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1703e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin ~VLIWResourceModel() { 1713e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin delete ResourcesModel; 1723e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 1733e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1743e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void resetPacketState() { 1753e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin Packet.clear(); 1763e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 1773e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1783e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void resetDFA() { 1793e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin ResourcesModel->clearResources(); 1803e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 1813e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1827ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin void reset() { 1837ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin Packet.clear(); 1847ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin ResourcesModel->clearResources(); 1857ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin } 1867ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 1873e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin bool isResourceAvailable(SUnit *SU); 1887ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin bool reserveResources(SUnit *SU); 1893e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned getTotalPackets() const { return TotalPackets; } 1903e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin}; 1913e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1923e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinclass VLIWMachineScheduler : public ScheduleDAGInstrs { 1933e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// AA - AliasAnalysis for making memory reference queries. 1943e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin AliasAnalysis *AA; 1953e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1963e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin RegisterClassInfo *RegClassInfo; 1973e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin MachineSchedStrategy *SchedImpl; 1983e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 1993e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin MachineBasicBlock::iterator LiveRegionEnd; 2003e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2013e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Register pressure in this region computed by buildSchedGraph. 2023e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin IntervalPressure RegPressure; 2033e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin RegPressureTracker RPTracker; 2043e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2053e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// List of pressure sets that exceed the target's pressure limit before 2063e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// scheduling, listed in increasing set ID order. Each pressure set is paired 2073e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// with its max pressure in the currently scheduled regions. 2083e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin std::vector<PressureElement> RegionCriticalPSets; 2093e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2103e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// The top of the unscheduled zone. 2113e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin MachineBasicBlock::iterator CurrentTop; 2123e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin IntervalPressure TopPressure; 2133e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin RegPressureTracker TopRPTracker; 2143e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2153e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// The bottom of the unscheduled zone. 2163e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin MachineBasicBlock::iterator CurrentBottom; 2173e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin IntervalPressure BotPressure; 2183e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin RegPressureTracker BotRPTracker; 2193e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2203e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#ifndef NDEBUG 2213e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// The number of instructions scheduled so far. Used to cut off the 2223e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// scheduler at the point determined by misched-cutoff. 2233e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned NumInstrsScheduled; 2243e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#endif 2253e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2263e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Total packets in the region. 2273e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned TotalPackets; 2283e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2293e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin const MachineLoopInfo *MLI; 2303e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinpublic: 2313e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin VLIWMachineScheduler(MachineSchedContext *C, MachineSchedStrategy *S): 2323e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin ScheduleDAGInstrs(*C->MF, *C->MLI, *C->MDT, /*IsPostRA=*/false, C->LIS), 2333e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin AA(C->AA), RegClassInfo(C->RegClassInfo), SchedImpl(S), 2343e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin RPTracker(RegPressure), CurrentTop(), TopRPTracker(TopPressure), 2353e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin CurrentBottom(), BotRPTracker(BotPressure), MLI(C->MLI) { 2363e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#ifndef NDEBUG 2373e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin NumInstrsScheduled = 0; 2383e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#endif 2393e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin TotalPackets = 0; 2403e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 2413e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2423e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin virtual ~VLIWMachineScheduler() { 2433e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin delete SchedImpl; 2443e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 2453e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2463e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin MachineBasicBlock::iterator top() const { return CurrentTop; } 2473e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin MachineBasicBlock::iterator bottom() const { return CurrentBottom; } 2483e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2493e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Implement the ScheduleDAGInstrs interface for handling the next scheduling 2503e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// region. This covers all instructions in a block, while schedule() may only 2513e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// cover a subset. 2523e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void enterRegion(MachineBasicBlock *bb, 2533e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin MachineBasicBlock::iterator begin, 2543e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin MachineBasicBlock::iterator end, 2553e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned endcount); 2563e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2573e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Schedule - This is called back from ScheduleDAGInstrs::Run() when it's 2583e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// time to do some work. 2593e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void schedule(); 2603e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2613e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned CurCycle; 2623e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2633e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Get current register pressure for the top scheduled instructions. 2643e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin const IntervalPressure &getTopPressure() const { return TopPressure; } 2653e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin const RegPressureTracker &getTopRPTracker() const { return TopRPTracker; } 2663e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2673e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Get current register pressure for the bottom scheduled instructions. 2683e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin const IntervalPressure &getBotPressure() const { return BotPressure; } 2693e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin const RegPressureTracker &getBotRPTracker() const { return BotRPTracker; } 2703e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2713e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// Get register pressure for the entire scheduling region before scheduling. 2723e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin const IntervalPressure &getRegPressure() const { return RegPressure; } 2733e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2743e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin const std::vector<PressureElement> &getRegionCriticalPSets() const { 2753e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin return RegionCriticalPSets; 2763e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 2773e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2783e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// getIssueWidth - Return the max instructions per scheduling group. 2793e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned getIssueWidth() const { 2803e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin return (InstrItins && InstrItins->SchedModel) 2813e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin ? InstrItins->SchedModel->IssueWidth : 1; 2823e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 2833e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2843e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin /// getNumMicroOps - Return the number of issue slots required for this MI. 2853e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin unsigned getNumMicroOps(MachineInstr *MI) const { 2867ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin return 1; 2877ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin //if (!InstrItins) return 1; 2887ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin //int UOps = InstrItins->getNumMicroOps(MI->getDesc().getSchedClass()); 2897ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin //return (UOps >= 0) ? UOps : TII->getNumMicroOps(InstrItins, MI); 2903e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin } 2913e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2923e59040810d0e6e04269ac8f781fa44df6088458Sergei Larinprivate: 2933e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void scheduleNodeTopDown(SUnit *SU); 2943e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void listScheduleTopDown(); 2953e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2963e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void initRegPressure(); 2973e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void updateScheduledPressure(std::vector<unsigned> NewMaxPressure); 2983e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 2993e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void moveInstruction(MachineInstr *MI, MachineBasicBlock::iterator InsertPos); 3003e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin bool checkSchedLimit(); 3013e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 3023e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void releaseRoots(); 3033e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 3043e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void releaseSucc(SUnit *SU, SDep *SuccEdge); 3053e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void releaseSuccessors(SUnit *SU); 3063e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void releasePred(SUnit *SU, SDep *PredEdge); 3073e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void releasePredecessors(SUnit *SU); 3083e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 3093e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin void placeDebugValues(); 3103e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin}; 3117ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3127ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin/// ConvergingVLIWScheduler shrinks the unscheduled zone using heuristics 3137ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin/// to balance the schedule. 3147ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larinclass ConvergingVLIWScheduler : public MachineSchedStrategy { 3157ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3167ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// Store the state used by ConvergingVLIWScheduler heuristics, required 3177ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// for the lifetime of one invocation of pickNode(). 3187ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin struct SchedCandidate { 3197ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin // The best SUnit candidate. 3207ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin SUnit *SU; 3217ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3227ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin // Register pressure values for the best candidate. 3237ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin RegPressureDelta RPDelta; 3247ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3257ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin // Best scheduling cost. 3267ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin int SCost; 3277ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3287ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin SchedCandidate(): SU(NULL), SCost(0) {} 3297ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin }; 3307ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// Represent the type of SchedCandidate found within a single queue. 3317ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin enum CandResult { 3327ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin NoCand, NodeOrder, SingleExcess, SingleCritical, SingleMax, MultiPressure, 3337ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin BestCost}; 3347ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3357ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// Each Scheduling boundary is associated with ready queues. It tracks the 3367ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// current cycle in whichever direction at has moved, and maintains the state 3377ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// of "hazards" and other interlocks at the current cycle. 3387ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin struct SchedBoundary { 3397ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin VLIWMachineScheduler *DAG; 3407ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3417ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin ReadyQueue Available; 3427ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin ReadyQueue Pending; 3437ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin bool CheckPending; 3447ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3457ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin ScheduleHazardRecognizer *HazardRec; 3467ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin VLIWResourceModel *ResourceModel; 3477ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3487ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin unsigned CurrCycle; 3497ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin unsigned IssueCount; 3507ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3517ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// MinReadyCycle - Cycle of the soonest available instruction. 3527ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin unsigned MinReadyCycle; 3537ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3547ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin // Remember the greatest min operand latency. 3557ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin unsigned MaxMinLatency; 3567ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3577ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// Pending queues extend the ready queues with the same ID and the 3587ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// PendingFlag set. 3597ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin SchedBoundary(unsigned ID, const Twine &Name): 3607ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin DAG(0), Available(ID, Name+".A"), 3617ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin Pending(ID << ConvergingVLIWScheduler::LogMaxQID, Name+".P"), 3627ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin CheckPending(false), HazardRec(0), ResourceModel(0), 3637ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin CurrCycle(0), IssueCount(0), 3647ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin MinReadyCycle(UINT_MAX), MaxMinLatency(0) {} 3657ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3667ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin ~SchedBoundary() { 3677ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin delete ResourceModel; 3687ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin delete HazardRec; 3697ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin } 3707ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3717ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin bool isTop() const { 3727ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin return Available.getID() == ConvergingVLIWScheduler::TopQID; 3737ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin } 3747ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3757ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin bool checkHazard(SUnit *SU); 3767ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3777ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin void releaseNode(SUnit *SU, unsigned ReadyCycle); 3787ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3797ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin void bumpCycle(); 3807ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3817ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin void bumpNode(SUnit *SU); 3827ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3837ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin void releasePending(); 3847ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3857ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin void removeReady(SUnit *SU); 3867ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3877ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin SUnit *pickOnlyChoice(); 3887ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin }; 3897ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3907ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin VLIWMachineScheduler *DAG; 3917ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin const TargetRegisterInfo *TRI; 3927ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3937ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin // State of the top and bottom scheduled instruction boundaries. 3947ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin SchedBoundary Top; 3957ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin SchedBoundary Bot; 3967ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 3977ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larinpublic: 3987ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin /// SUnit::NodeQueueId: 0 (none), 1 (top), 2 (bot), 3 (both) 3997ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin enum { 4007ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin TopQID = 1, 4017ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin BotQID = 2, 4027ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin LogMaxQID = 2 4037ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin }; 4047ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 4057ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin ConvergingVLIWScheduler(): 4067ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin DAG(0), TRI(0), Top(TopQID, "TopQ"), Bot(BotQID, "BotQ") {} 4077ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 4087ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin virtual void initialize(VLIWMachineScheduler *dag); 4097ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 4107ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin virtual SUnit *pickNode(bool &IsTopNode); 4117ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 4127ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin virtual void schedNode(SUnit *SU, bool IsTopNode); 4137ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 4147ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin virtual void releaseTopNode(SUnit *SU); 4157ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 4167ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin virtual void releaseBottomNode(SUnit *SU); 4177ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 4187ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larinprotected: 4197ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin SUnit *pickNodeBidrectional(bool &IsTopNode); 4207ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 4217ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin int SchedulingCost(ReadyQueue &Q, 4227ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin SUnit *SU, SchedCandidate &Candidate, 4237ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin RegPressureDelta &Delta, bool verbose); 4247ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 4257ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin CandResult pickNodeFromQueue(ReadyQueue &Q, 4267ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin const RegPressureTracker &RPTracker, 4277ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin SchedCandidate &Candidate); 4287ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin#ifndef NDEBUG 4297ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin void traceCandidate(const char *Label, const ReadyQueue &Q, SUnit *SU, 4307ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin PressureElement P = PressureElement()); 4317ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin#endif 4327ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin}; 4337ae51be2a3a56be5cf0ee4557aa13a069c96a241Sergei Larin 4343e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin} // namespace 4353e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 4363e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin 4373e59040810d0e6e04269ac8f781fa44df6088458Sergei Larin#endif 438