Llvm Machine Instruction Scheduler

Contents Related to TableGen

MCSubtargetInfo::InitMCProcessorInfo
 
MCSubtargetInfo::getSchedModelForCPU
in lib/Target/X86/X86GenSubtargetInfo.inc
static inline MCSubtargetInfo *createX86MCSubtargetInfoImpl(const Triple &TT, StringRef CPU, StringRef TuneCPU, StringRef FS) {
  return new X86GenMCSubtargetInfo(TT, CPU, TuneCPU, FS, X86FeatureKV, X86SubTypeKV, 
                      X86WriteProcResTable, X86WriteLatencyTable, X86ReadAdvanceTable, 
                      nullptr, nullptr, nullptr);
}
 
X86SubTypeKV
extern const llvm::SubtargetSubTypeKV X86SubTypeKV[] = {
 { "alderlake", { { { 0xddf1474c3ae6200cULL, 0x3dd41028341acULL, 0x0ULL, 0x0ULL, } } }, { { { 0x0ULL, 0x1440000000000000ULL, 0x281c13bULL, 0x0ULL, } } }, &AlderlakePModel },

{ "generic", { { { 0x10000000ULL, 0x180000000000ULL, 0x0ULL, 0x0ULL, } } }, { { { 0x0ULL, 0x400000000000000ULL, 0x2804102ULL, 0x0ULL, } } }, &SandyBridgeModel },
 
static const llvm::MCSchedModel SandyBridgeModel = {
  4, // IssueWidth
  168, // MicroOpBufferSize
  28, // LoopMicroOpBufferSize
  5, // LoadLatency
  MCSchedModel::DefaultHighLatency,
  16, // MispredictPenalty
  false, // PostRAScheduler
  false, // CompleteModel
  8, // Processor ID
  SandyBridgeModelProcResources,
  SandyBridgeModelSchedClasses,
  13,
  1631,
  nullptr, // No Itinerary
  nullptr // No extra processor descriptor
};

static const llvm::MCSchedClassDesc SandyBridgeModelSchedClasses[] = {

Common

If a block has only one SchedRegion, then the RegionBegin will be the first MI in the block, the RegionEnd will be the last MI in the block.
The scheduler will do schedule one by one, each time the scheduler will only schedule one SchedRegion.
When build SchedGraph, the algorithm will traverse the SchedRegion backwards.
The following code initialize hasReservedResource and isUnbuffered in su.

    if (SchedModel.hasInstrSchedModel()) {
      const MCSchedClassDesc *SC = getSchedClass(SU);
      for (const MCWriteProcResEntry &PRE :
           make_range(SchedModel.getWriteProcResBegin(SC),
                      SchedModel.getWriteProcResEnd(SC))) {
        switch (SchedModel.getProcResource(PRE.ProcResourceIdx)->BufferSize) {
        case 0:
          SU->hasReservedResource = true;
          break;
        case 1:
          SU->isUnbuffered = true;
          break;
        default:
          break;
        }
      }
}

Following example show the relationship between MI and SUNIT:
Op1 Dest1, Src1, Src2 (Sunit1)
Op2 Dest2, Dest1, Src2(Sunit2)
Sunit1 will in the preds list of Sunit2, Sunit2 is in the succs list of Sunit1.
The type of dependence between Sunit1 and Sunit2 will be Data(Regular data dependence (aka true-dependence)).
Op1 Dest1, Src1, Src2 (Sunit1)
Op2 Dest1, Src1, Src2(Sunit2)
Sunit1 will in the preds list of Sunit2, Sunit2 is in the succs list of Sunit1.
The type of dependence between Sunit1 and Sunit2 will be Output(A register output-dependence (aka WAW)).
Op1 Dest1, Src1, Src2 (Sunit1)
Op2 Src1, Src3, Src2(Sunit2)
Sunit1 will in the preds list of Sunit2, Sunit2 is in the succs list of Sunit1.
The type of dependence between Sunit1 and Sunit2 will be Anti(A register anti-dependence (aka WAR)).
The relationship between Sunit1 and Sunit2 is represented by SDep. preds and succs in a sunit is comprised of SDep.
SUnit::ComputeDepth will return the max latency from RegionBegin to the current sunit.
SUnit::ComputeHeight will return the max latency from RegionEnd to the current sunit.

Bot Schedule

BotReadyCycle is updated by ScheduleDAGMI::releasePred as shown in the following code:

  if (PredSU->BotReadyCycle < SU->BotReadyCycle + PredEdge->getLatency())
PredSU->BotReadyCycle = SU->BotReadyCycle + PredEdge->getLatency();

When to schedule the node, BotReadyCycle may be assigned to current cycle.

    SU->BotReadyCycle = std::max(SU->BotReadyCycle, Bot.getCurrCycle());

When the PredSU’s NumSuccsLeft equal to zero, all the sunits which depend on it have been scheduled, and it will be put into pending queue or available queue. The following code in SchedBoundary::releaseNode show the mechanism to decide which queue will be selected to put the sunit(PredSU):

  bool HazardDetected = (!IsBuffered && ReadyCycle > CurrCycle) ||
                        checkHazard(SU) || (Available.size() >= ReadyListLimit);

Process

Firstly, pick the sunit that can be emitted. It means that the hardware resource is enough for the sunit to run and the current cycle must be larger than ReadyCycle when !IsBuffered

SUnit *SU = SchedImpl->pickNode(IsTopNode);

Secondly, put he MI corresponding to the sunit to the MachineBlock.

scheduleMI(SU, IsTopNode);

Thirdly, allocate the hardware recourse to the current sunit. It means that the current sunit will occupy some hardware resource.

SchedImpl->schedNode(SU, IsTopNode);

Finally, put the other suints related to the current sunit to the queues if possible.

updateQueues(SU, IsTopNode);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值