llvm后端通过schedmodel统一建模硬件时序,声明指令延迟、执行端口、发射带宽等,供instructionscheduler、machinecombiner、mca等共享使用;其核心由procresources(定义并发执行资源)和schedwriteres(绑定指令类与资源消耗及latency)构成,取代已弃用的itinerarydata。

LLVM后端用SchedModel描述指令延迟和调度资源
LLVM后端不靠硬编码或魔法数字表达硬件时序,而是通过目标定义中的SchedModel(调度模型)结构体统一建模:每条指令的执行延迟、占用的执行端口、发射带宽、流水线阶段等全部在此声明。这个模型被InstructionSchedular、MachineCombiner、MCA等组件共享使用,是静态调度决策的唯一事实来源。
它不是注释或文档,而是参与编译流程的实际数据——修改后必须重新生成TargetInfo和Subtarget代码(通常靠llvm-tblgen从.td文件生成)。
ProcResources和SchedWriteRes定义物理资源约束
在XXXSchedule.td中,你必须显式定义两类关键表:
-
ProcResources:列出CPU所有可并行使用的执行资源,比如ALU0、FPU1、AGU、DivUnit,每个带一个NumUnits字段表示该资源的并发能力(如NumUnits = 2表示双发射ALU) -
SchedWriteRes:为每条InstRW(instruction read-write)条目绑定指令类与资源消耗,例如一条VADDPS可能同时写FPU0(1单位)和FPRegFile(1单位),且Latency = 3
注意:Latency不是“这条指令耗时3周期”,而是“它的结果最早在3周期后可用于后续依赖指令”;而NumMicroOps影响发射率,但不直接决定延迟。
为什么ItineraryData已被弃用?
旧版LLVM(ItineraryData按流水线阶段逐拍描述指令行为,但这种写法僵硬、难维护、无法表达现代超标量处理器的资源竞争语义。自LLVM 8起,ItineraryData仅保留在少数遗留后端中,新后端必须用ProcResources+SchedWriteRes组合建模。
典型错误包括:
- 把
Latency设成指令总执行时间(错),应设为**数据可用延迟**(即def-use距离) - 漏写
ProcResources中某资源的NumUnits,导致调度器误判为独占资源 - 在
SchedWriteRes里对同一指令类重复定义不同Latency,tblgen会静默取最后一个,引发不可预测调度
验证调度模型是否生效的最简方法
别等跑完整个编译流程——用llc -march=xxx -mcpu=yyy -debug-only=misched看调度器日志,或更直接地:
- 加
-mca-analysis -mca-report=6,用MCA工具分析一段汇编,输出各周期资源占用和瓶颈 - 用
llc -view-sched-dags生成.dot图,检查DDG中边的latency权重是否与SchedWriteRes一致 - 修改
SchedWriteRes中某条指令的Latency,观察llc -print-machineinstrs输出的指令重排是否变化
真实硬件上最易被忽略的一点:调度模型只管“静态可调度性”,它不模拟分支预测失败、缓存未命中、TLB miss这些运行时事件——那些得靠MCA+trace驱动分析,不能指望SchedModel覆盖。











