llvm后端指令通过tablegen的class抽象通用结构,如myinst类封装操作数、编码、汇编模板与dag模式;用multiclass+defm生成寄存器/立即数变体;pattern需严格匹配类型与语法,否则指令选择失效;.td修改后须手动触发构建并验证cmake配置与路径。

怎么用 class 定义指令的通用结构
LLVM 后端中,指令格式不是逐条硬编码的,而是通过 class 抽象出共性:操作数类型、编码位宽、汇编字符串模板、DAG 模式匹配骨架等。最常见的是继承自 Instruction 的类,比如:
class MyInst<dag outs dag ins string asmstr list> pattern, Format f>
: Instruction<outs ins asmstr pattern> {
let Size = 4;
let Form = f;
bits Inst;
let Inst{31-26} = 0x2a; // opcode field
}</outs></dag>
注意三点:
– dag outs/ins 必须显式声明,否则生成的 XXXGenInstrInfo.inc 里缺操作数信息,导致指令选择失败;
– Format 是自定义枚举(常定义在 MyArch.td 顶部),它最终会映射到 XXX::Form 枚举值,供 getFormat() 调用;
– let Inst{...} = ... 这种位域赋值语法只在 TableGen 中合法,C++ 后端不识别,别误当 C++ 写。
def 实例化时怎么处理寄存器 vs 立即数变体
同一语义的指令(如 ADD)常有多个编码形式:ADDrr(寄存器-寄存器)、ADDri(寄存器-立即数)。直接写多个 def 易重复,推荐用 multiclass + defm:
multiclass AddInst<string opc registerclass rc> {
def rr : MyInst;
def ri : MyInst;
}
defm ADD : AddInst;</string>
关键点:
– i32imm 是预定义的 Operand 类,不是随便写的字符串,拼错会导致 llvm-tblgen 报 Unknown type 'i32imm';
– !strconcat 里不能有空格或换行,否则汇编字符串生成异常;
– defm ADD 展开后实际生成 ADDrr 和 ADDri 两个 def,名字是拼接出来的,别手动再写一遍 def ADDrr,否则重复定义报错。
一款AI视频创作工具,主要用于蛙蛙写作辅助AI写文,帮助获取创意灵感,提供拆书、小说转剧本、视频生成等功能,是一款功能全面的AI智能写作工具,适合需要提升相关任务效率的用户。
为什么 Pattern 写错会导致指令选择完全跳过
Pattern 字段决定该指令能否被 DAG 匹配器选中。常见失效原因:
-
RC:$rs1中的RC必须和ins声明中的寄存器类完全一致,大小写敏感,gpr≠GPR; - 使用
(add ...)时,左侧必须是ValueType(如i32),不能漏写,(add $a, $b)无效,得写成(add i32:$a, i32:$b); - 立即数模式必须用
imm:$imm或i32imm:$imm,不能只写$imm,否则匹配器找不到对应 operand; - 若指令需特殊合法化(如大立即数拆分),
Pattern里不能强行匹配,得配合ComplexPattern或后端 custom lowering。
验证方式:运行 llvm-tblgen MyArch.td -print-records | grep -A5 ADDrr,检查输出中 Pattern 字段是否按预期展开,有没有 UNDEF 或空值。
生成的 XXXGenInstrInfo.inc 里没看到你定义的指令?
这通常不是 TableGen 语法错误,而是构建系统未触发重生成。LLVM 不会自动监听 .td 文件变更:
- 修改
MyArch.td后,必须显式重新运行make或ninja,且确保目标是MyArchCodeGen或全量构建; - 检查
lib/Target/MyArch/CMakeLists.txt是否包含add_llvm_target(MyArchCodeGen ...),漏掉这句,llvm-tblgen根本不会被调用; - 临时验证:手动执行
llvm-tblgen MyArch.td -I /path/to/llvm/include -I /path/to/llvm/lib/Target -o MyArchGenInstrInfo.inc,看输出文件是否含你定义的ADDrr枚举值; - 如果手动命令能生成但构建系统不生效,大概率是
CMakeLists.txt里tablegen规则路径写错了,比如-I缺少include目录,导致#include "MyArchGenInstrInfo.inc"在编译时报找不到文件。
TableGen 的“定义即实现”是假象——它只负责生成代码,不保证这些代码被编译进后端。路径、依赖、CMake 配置,三者缺一不可。










