Back to home page

EIC code displayed by LXR

 
 

    


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