type 是 ir 类型(如 i32),用于 selectiondag 合法化;operandtype 是字符串枚举(如 riscvopnd::imm12),控制汇编解析与编码;constraints 仅影响汇编打印/解析,不参与指令选择。

Operand 的 Type 和 OperandType 字段容易混淆
定义一个操作数时,Type 是 TableGen 类型系统里的 IR 类型(如 i32、f64、ptr),它参与 SelectionDAG 合法化和类型推导;而 OperandType 是字符串标识符,对应 MCInstrDesc.h 中的 enum OperandType 值(如 MCOI::OPERAND_IMMEDIATE 或自定义的 RISCVOpnd::imm12),只用于汇编打印、编码/解码阶段的 dispatch 控制。
常见错误是把 Type 当成汇编器能识别的约束——它不是。比如写 Operand<i32>:$src</i32> 并不能阻止用户在 .s 文件里传入浮点立即数;真正起约束作用的是 OperandType 配合 AsmParser 里的语法检查逻辑。
-
Type影响 DAG 节点生成和合法化:若 IR 操作数是i16,但指令只支持i32,legalizer 会自动插入ANY_EXTEND或报错 -
OperandType决定XXXAsmParser::ParseOperand是否接受该 token:例如RISCVOpnd::imm12对应解析函数中对立即数范围 [-2048, 2047] 的校验 - 自定义
OperandType必须在XXX.td中用def声明,并通过OperandNamespace关联到具体命名空间(如RISCVOpnd)
Constraints 字段只在 AsmParser 阶段生效,不参与指令选择
Constraints 是 Instruction 类里的字段,值为字符串列表(如 ["$src = $dst"]),它**仅被 XXXAsmPrinter 和 XXXAsmParser 使用**,用于生成或验证汇编文本,完全不参与 SelectionDAG 的 Pattern 匹配或寄存器分配。
典型误用是以为写 Constraints = ["$src != $dst"] 就能防止指令选择器生成 src/dst 相同的机器指令——不会。这种语义必须靠 Predicates 或 Pattern 中的条件表达式实现,比如:
def ADDrr : RISCVInst {
let Predicates = [HasStdExtA];
let Constraints = "$src1 = $dst";
}
上面的 Constraints 只影响汇编输出格式(比如 add t0, t0, t1),而 Predicates 才控制该指令是否参与匹配。
- 多个约束用逗号分隔:
Constraints = ["$src1 = $dst", "$src2 in [x1, x2, x3]"] - 约束中引用的操作数名必须与
outs/ins中声明的变量名一致,大小写敏感 - 若约束失败,
AsmParser报错信息形如error: invalid operand for instruction 'add': operand '$src1' must equal '$dst'
用 MCOperandPredicate 实现动态语法约束
当简单等式或枚举无法表达约束逻辑(比如“立即数必须是 4 的倍数”或“寄存器必须属于 CSR 组”),就得用 MCOperandPredicate。
它是一段 C++ 代码片段,在 XXXAsmParser.cpp 的 validateInstruction 流程中被调用,接收 const MCInst &Inst 和操作数索引,返回 bool。TableGen 会把它内联进生成的 parser 代码里。
- 定义方式:
let MCOperandPredicate = [{ return isAligned(Imm); }];(注意花括号和分号) - 作用域内可访问
Inst、OpNo、getImm()/getReg()等方法 - 不能调用非 inline 函数或依赖全局状态;所有逻辑必须编译期确定,否则 TableGen 报错
- 调试时可在
XXXAsmParser::ValidateInstruction插入errs()
Pattern 匹配中的类型约束靠 SDTypeConstraint 和 PatFrag
指令选择阶段(SelectionDAG → MachineInstr)的约束,和汇编语法无关,而是由 Pat 或 PatFrag 中嵌套的 SDTypeConstraint 控制。例如:
def : Pat;
这里 i32:$lhs 表示要求 DAG 节点的 ValueType 必须是 MVT::i32;若 IR 传来的是 i64,该 pattern 不会匹配,转而触发 legalizer 插入截断或扩展节点。
- 更细粒度可用
SDTCisInt、SDTCisFP、SDTCisSameMemOperand等预定义约束 - 自定义类型约束需在
TargetSelectionDAG.td中用def声明,CxxCode 字段返回布尔表达式 -
PatFrag可封装常用子图(如地址计算),其内部SDTypeConstraint会递归应用到所有匹配子节点
真正难缠的是跨操作数联合约束(比如“两个操作数不能同时是立即数”),这类必须拆成多个 Pat + Predicates 组合,或退回到自定义 ComplexPattern ——这时候你已经绕不开手写 C++ 了。











