clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
172 lines
8.1 KiB
C++
172 lines
8.1 KiB
C++
//======----------- WindowScheduler.cpp - window scheduler -------------======//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// An implementation of the Window Scheduling software pipelining algorithm.
|
|
//
|
|
// The concept of the window algorithm was first unveiled in Steven Muchnick's
|
|
// book, "Advanced Compiler Design And Implementation", and later elaborated
|
|
// upon in Venkatraman Govindaraju's report, "Implementation of Software
|
|
// Pipelining Using Window Scheduling".
|
|
//
|
|
// The window algorithm can be perceived as a modulo scheduling algorithm with a
|
|
// stage count of 2. It boasts a higher scheduling success rate in targets with
|
|
// severe resource conflicts when compared to the classic Swing Modulo
|
|
// Scheduling (SMS) algorithm. To align with the LLVM scheduling framework, we
|
|
// have enhanced the original window algorithm. The primary steps are as
|
|
// follows:
|
|
//
|
|
// 1. Instead of duplicating the original MBB twice as mentioned in the
|
|
// literature, we copy it three times, generating TripleMBB and the
|
|
// corresponding TripleDAG.
|
|
//
|
|
// 2. We establish a scheduling window on TripleMBB and execute list scheduling
|
|
// within it.
|
|
//
|
|
// 3. After multiple list scheduling, we select the best outcome and expand it
|
|
// into the final scheduling result.
|
|
//
|
|
// To cater to the needs of various targets, we have developed the window
|
|
// scheduler in a form that is easily derivable. We recommend employing this
|
|
// algorithm in targets with severe resource conflicts, and it can be utilized
|
|
// either before or after the Register Allocator (RA).
|
|
//
|
|
// The default implementation provided here is before RA. If it is to be used
|
|
// after RA, certain critical algorithm functions will need to be derived.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef LLVM_CODEGEN_WINDOWSCHEDULER_H
|
|
#define LLVM_CODEGEN_WINDOWSCHEDULER_H
|
|
|
|
#include "llvm/CodeGen/MachineLoopInfo.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/MachineScheduler.h"
|
|
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
|
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
|
|
|
namespace llvm {
|
|
|
|
enum WindowSchedulingFlag {
|
|
WS_Off, /// Turn off window algorithm.
|
|
WS_On, /// Use window algorithm after SMS algorithm fails.
|
|
WS_Force /// Use window algorithm instead of SMS algorithm.
|
|
};
|
|
|
|
/// The main class in the implementation of the target independent window
|
|
/// scheduler.
|
|
class WindowScheduler {
|
|
protected:
|
|
MachineSchedContext *Context = nullptr;
|
|
MachineFunction *MF = nullptr;
|
|
MachineBasicBlock *MBB = nullptr;
|
|
MachineLoop &Loop;
|
|
const TargetSubtargetInfo *Subtarget = nullptr;
|
|
const TargetInstrInfo *TII = nullptr;
|
|
const TargetRegisterInfo *TRI = nullptr;
|
|
MachineRegisterInfo *MRI = nullptr;
|
|
|
|
/// To innovatively identify the dependencies between MIs across two trips, we
|
|
/// construct a DAG for a new MBB, which is created by copying the original
|
|
/// MBB three times. We refer to this new MBB as 'TripleMBB' and the
|
|
/// corresponding DAG as 'TripleDAG'.
|
|
/// If the dependencies are more than two trips, we avoid applying window
|
|
/// algorithm by identifying successive phis in the old MBB.
|
|
std::unique_ptr<ScheduleDAGInstrs> TripleDAG;
|
|
/// OriMIs keeps the MIs removed from the original MBB.
|
|
SmallVector<MachineInstr *> OriMIs;
|
|
/// TriMIs keeps the MIs of TripleMBB, which is used to restore TripleMBB.
|
|
SmallVector<MachineInstr *> TriMIs;
|
|
/// TriToOri keeps the mappings between the MI clones in TripleMBB and their
|
|
/// original MI.
|
|
DenseMap<MachineInstr *, MachineInstr *> TriToOri;
|
|
/// OriToCycle keeps the mappings between the original MI and its issue cycle.
|
|
DenseMap<MachineInstr *, int> OriToCycle;
|
|
/// SchedResult keeps the result of each list scheduling, and the format of
|
|
/// the tuple is <MI pointer, Cycle, Stage, Order ID>.
|
|
SmallVector<std::tuple<MachineInstr *, int, int, int>, 256> SchedResult;
|
|
/// SchedPhiNum records the number of phi in the original MBB, and the
|
|
/// scheduling starts with MI after phis.
|
|
unsigned SchedPhiNum = 0;
|
|
/// SchedInstrNum records the MIs involved in scheduling in the original MBB,
|
|
/// excluding debug instructions.
|
|
unsigned SchedInstrNum = 0;
|
|
/// BestII and BestOffset record the characteristics of the best scheduling
|
|
/// result and are used together with SchedResult as the final window
|
|
/// scheduling result.
|
|
unsigned BestII = UINT_MAX;
|
|
unsigned BestOffset = 0;
|
|
/// BaseII is the II obtained when the window offset is SchedPhiNum. This
|
|
/// offset is the initial position of the sliding window.
|
|
unsigned BaseII = 0;
|
|
|
|
public:
|
|
WindowScheduler(MachineSchedContext *C, MachineLoop &ML);
|
|
virtual ~WindowScheduler() {}
|
|
|
|
bool run();
|
|
|
|
protected:
|
|
/// Two types of ScheduleDAGs are needed, one for creating dependency graphs
|
|
/// only, and the other for list scheduling as determined by the target.
|
|
virtual ScheduleDAGInstrs *
|
|
createMachineScheduler(bool OnlyBuildGraph = false);
|
|
/// Initializes the algorithm and determines if it can be executed.
|
|
virtual bool initialize();
|
|
/// Add some related processing before running window scheduling.
|
|
virtual void preProcess();
|
|
/// Add some related processing after running window scheduling.
|
|
virtual void postProcess();
|
|
/// Back up the MIs in the original MBB and remove them from MBB.
|
|
void backupMBB();
|
|
/// Erase the MIs in current MBB and restore the original MIs.
|
|
void restoreMBB();
|
|
/// Make three copies of the original MBB to generate a new TripleMBB.
|
|
virtual void generateTripleMBB();
|
|
/// Restore the order of MIs in TripleMBB after each list scheduling.
|
|
virtual void restoreTripleMBB();
|
|
/// Give the folding position in the window algorithm, where different
|
|
/// heuristics can be used. It determines the performance and compilation time
|
|
/// of the algorithm.
|
|
virtual SmallVector<unsigned> getSearchIndexes(unsigned SearchNum,
|
|
unsigned SearchRatio);
|
|
/// Calculate MIs execution cycle after list scheduling.
|
|
virtual int calculateMaxCycle(ScheduleDAGInstrs &DAG, unsigned Offset);
|
|
/// Calculate the stall cycle between two trips after list scheduling.
|
|
virtual int calculateStallCycle(unsigned Offset, int MaxCycle);
|
|
/// Analyzes the II value after each list scheduling.
|
|
virtual unsigned analyseII(ScheduleDAGInstrs &DAG, unsigned Offset);
|
|
/// Phis are scheduled separately after each list scheduling.
|
|
virtual void schedulePhi(int Offset, unsigned &II);
|
|
/// Get the final issue order of all scheduled MIs including phis.
|
|
DenseMap<MachineInstr *, int> getIssueOrder(unsigned Offset, unsigned II);
|
|
/// Update the scheduling result after each list scheduling.
|
|
virtual void updateScheduleResult(unsigned Offset, unsigned II);
|
|
/// Check whether the final result of window scheduling is valid.
|
|
virtual bool isScheduleValid() { return BestOffset != SchedPhiNum; }
|
|
/// Using the scheduling infrastructure to expand the results of window
|
|
/// scheduling. It is usually necessary to add prologue and epilogue MBBs.
|
|
virtual void expand();
|
|
/// Update the live intervals for all registers used within MBB.
|
|
virtual void updateLiveIntervals();
|
|
/// Estimate a II value at which all MIs will be scheduled successfully.
|
|
int getEstimatedII(ScheduleDAGInstrs &DAG);
|
|
/// Gets the iterator range of MIs in the scheduling window.
|
|
iterator_range<MachineBasicBlock::iterator> getScheduleRange(unsigned Offset,
|
|
unsigned Num);
|
|
/// Get the issue cycle of the new MI based on the cycle of the original MI.
|
|
int getOriCycle(MachineInstr *NewMI);
|
|
/// Get the original MI from which the new MI is cloned.
|
|
MachineInstr *getOriMI(MachineInstr *NewMI);
|
|
/// Get the scheduling stage, where the stage of the new MI is identical to
|
|
/// the original MI.
|
|
unsigned getOriStage(MachineInstr *OriMI, unsigned Offset);
|
|
/// Gets the register in phi which is generated from the current MBB.
|
|
Register getAntiRegister(MachineInstr *Phi);
|
|
};
|
|
} // namespace llvm
|
|
#endif
|