|
|
|||
File indexing completed on 2026-05-10 08:43:38
0001 //======----------- WindowScheduler.cpp - window scheduler -------------======// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 // 0009 // An implementation of the Window Scheduling software pipelining algorithm. 0010 // 0011 // The concept of the window algorithm was first unveiled in Steven Muchnick's 0012 // book, "Advanced Compiler Design And Implementation", and later elaborated 0013 // upon in Venkatraman Govindaraju's report, "Implementation of Software 0014 // Pipelining Using Window Scheduling". 0015 // 0016 // The window algorithm can be perceived as a modulo scheduling algorithm with a 0017 // stage count of 2. It boasts a higher scheduling success rate in targets with 0018 // severe resource conflicts when compared to the classic Swing Modulo 0019 // Scheduling (SMS) algorithm. To align with the LLVM scheduling framework, we 0020 // have enhanced the original window algorithm. The primary steps are as 0021 // follows: 0022 // 0023 // 1. Instead of duplicating the original MBB twice as mentioned in the 0024 // literature, we copy it three times, generating TripleMBB and the 0025 // corresponding TripleDAG. 0026 // 0027 // 2. We establish a scheduling window on TripleMBB and execute list scheduling 0028 // within it. 0029 // 0030 // 3. After multiple list scheduling, we select the best outcome and expand it 0031 // into the final scheduling result. 0032 // 0033 // To cater to the needs of various targets, we have developed the window 0034 // scheduler in a form that is easily derivable. We recommend employing this 0035 // algorithm in targets with severe resource conflicts, and it can be utilized 0036 // either before or after the Register Allocator (RA). 0037 // 0038 // The default implementation provided here is before RA. If it is to be used 0039 // after RA, certain critical algorithm functions will need to be derived. 0040 // 0041 //===----------------------------------------------------------------------===// 0042 #ifndef LLVM_CODEGEN_WINDOWSCHEDULER_H 0043 #define LLVM_CODEGEN_WINDOWSCHEDULER_H 0044 0045 #include "llvm/CodeGen/MachineLoopInfo.h" 0046 #include "llvm/CodeGen/MachineRegisterInfo.h" 0047 #include "llvm/CodeGen/MachineScheduler.h" 0048 #include "llvm/CodeGen/ScheduleDAGInstrs.h" 0049 #include "llvm/CodeGen/TargetSubtargetInfo.h" 0050 0051 namespace llvm { 0052 0053 enum WindowSchedulingFlag { 0054 WS_Off, /// Turn off window algorithm. 0055 WS_On, /// Use window algorithm after SMS algorithm fails. 0056 WS_Force /// Use window algorithm instead of SMS algorithm. 0057 }; 0058 0059 /// The main class in the implementation of the target independent window 0060 /// scheduler. 0061 class WindowScheduler { 0062 protected: 0063 MachineSchedContext *Context = nullptr; 0064 MachineFunction *MF = nullptr; 0065 MachineBasicBlock *MBB = nullptr; 0066 MachineLoop &Loop; 0067 const TargetSubtargetInfo *Subtarget = nullptr; 0068 const TargetInstrInfo *TII = nullptr; 0069 const TargetRegisterInfo *TRI = nullptr; 0070 MachineRegisterInfo *MRI = nullptr; 0071 0072 /// To innovatively identify the dependencies between MIs across two trips, we 0073 /// construct a DAG for a new MBB, which is created by copying the original 0074 /// MBB three times. We refer to this new MBB as 'TripleMBB' and the 0075 /// corresponding DAG as 'TripleDAG'. 0076 /// If the dependencies are more than two trips, we avoid applying window 0077 /// algorithm by identifying successive phis in the old MBB. 0078 std::unique_ptr<ScheduleDAGInstrs> TripleDAG; 0079 /// OriMIs keeps the MIs removed from the original MBB. 0080 SmallVector<MachineInstr *> OriMIs; 0081 /// TriMIs keeps the MIs of TripleMBB, which is used to restore TripleMBB. 0082 SmallVector<MachineInstr *> TriMIs; 0083 /// TriToOri keeps the mappings between the MI clones in TripleMBB and their 0084 /// original MI. 0085 DenseMap<MachineInstr *, MachineInstr *> TriToOri; 0086 /// OriToCycle keeps the mappings between the original MI and its issue cycle. 0087 DenseMap<MachineInstr *, int> OriToCycle; 0088 /// SchedResult keeps the result of each list scheduling, and the format of 0089 /// the tuple is <MI pointer, Cycle, Stage, Order ID>. 0090 SmallVector<std::tuple<MachineInstr *, int, int, int>, 256> SchedResult; 0091 /// SchedPhiNum records the number of phi in the original MBB, and the 0092 /// scheduling starts with MI after phis. 0093 unsigned SchedPhiNum = 0; 0094 /// SchedInstrNum records the MIs involved in scheduling in the original MBB, 0095 /// excluding debug instructions. 0096 unsigned SchedInstrNum = 0; 0097 /// BestII and BestOffset record the characteristics of the best scheduling 0098 /// result and are used together with SchedResult as the final window 0099 /// scheduling result. 0100 unsigned BestII = UINT_MAX; 0101 unsigned BestOffset = 0; 0102 /// BaseII is the II obtained when the window offset is SchedPhiNum. This 0103 /// offset is the initial position of the sliding window. 0104 unsigned BaseII = 0; 0105 0106 public: 0107 WindowScheduler(MachineSchedContext *C, MachineLoop &ML); 0108 virtual ~WindowScheduler() {} 0109 0110 bool run(); 0111 0112 protected: 0113 /// Two types of ScheduleDAGs are needed, one for creating dependency graphs 0114 /// only, and the other for list scheduling as determined by the target. 0115 virtual ScheduleDAGInstrs * 0116 createMachineScheduler(bool OnlyBuildGraph = false); 0117 /// Initializes the algorithm and determines if it can be executed. 0118 virtual bool initialize(); 0119 /// Add some related processing before running window scheduling. 0120 virtual void preProcess(); 0121 /// Add some related processing after running window scheduling. 0122 virtual void postProcess(); 0123 /// Back up the MIs in the original MBB and remove them from MBB. 0124 void backupMBB(); 0125 /// Erase the MIs in current MBB and restore the original MIs. 0126 void restoreMBB(); 0127 /// Make three copies of the original MBB to generate a new TripleMBB. 0128 virtual void generateTripleMBB(); 0129 /// Restore the order of MIs in TripleMBB after each list scheduling. 0130 virtual void restoreTripleMBB(); 0131 /// Give the folding position in the window algorithm, where different 0132 /// heuristics can be used. It determines the performance and compilation time 0133 /// of the algorithm. 0134 virtual SmallVector<unsigned> getSearchIndexes(unsigned SearchNum, 0135 unsigned SearchRatio); 0136 /// Calculate MIs execution cycle after list scheduling. 0137 virtual int calculateMaxCycle(ScheduleDAGInstrs &DAG, unsigned Offset); 0138 /// Calculate the stall cycle between two trips after list scheduling. 0139 virtual int calculateStallCycle(unsigned Offset, int MaxCycle); 0140 /// Analyzes the II value after each list scheduling. 0141 virtual unsigned analyseII(ScheduleDAGInstrs &DAG, unsigned Offset); 0142 /// Phis are scheduled separately after each list scheduling. 0143 virtual void schedulePhi(int Offset, unsigned &II); 0144 /// Get the final issue order of all scheduled MIs including phis. 0145 DenseMap<MachineInstr *, int> getIssueOrder(unsigned Offset, unsigned II); 0146 /// Update the scheduling result after each list scheduling. 0147 virtual void updateScheduleResult(unsigned Offset, unsigned II); 0148 /// Check whether the final result of window scheduling is valid. 0149 virtual bool isScheduleValid() { return BestOffset != SchedPhiNum; } 0150 /// Using the scheduling infrastructure to expand the results of window 0151 /// scheduling. It is usually necessary to add prologue and epilogue MBBs. 0152 virtual void expand(); 0153 /// Update the live intervals for all registers used within MBB. 0154 virtual void updateLiveIntervals(); 0155 /// Estimate a II value at which all MIs will be scheduled successfully. 0156 int getEstimatedII(ScheduleDAGInstrs &DAG); 0157 /// Gets the iterator range of MIs in the scheduling window. 0158 iterator_range<MachineBasicBlock::iterator> getScheduleRange(unsigned Offset, 0159 unsigned Num); 0160 /// Get the issue cycle of the new MI based on the cycle of the original MI. 0161 int getOriCycle(MachineInstr *NewMI); 0162 /// Get the original MI from which the new MI is cloned. 0163 MachineInstr *getOriMI(MachineInstr *NewMI); 0164 /// Get the scheduling stage, where the stage of the new MI is identical to 0165 /// the original MI. 0166 unsigned getOriStage(MachineInstr *OriMI, unsigned Offset); 0167 /// Gets the register in phi which is generated from the current MBB. 0168 Register getAntiRegister(MachineInstr *Phi); 0169 }; 0170 } // namespace llvm 0171 #endif
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|