ods中单体约束直接写在字段声明后(如anytensorofrank),多实体约束需用let constraints独立声明并设hascustomverify=1,所有约束必须编译期可求值。

直接在 ODS(Operation Definition Specification)中用 Constraint 声明,而不是写 C++ 验证逻辑——这是最轻量、最符合 MLIR 设计意图的方式。
怎么在 ODS 里写单体类型约束
单体约束作用于单个操作数、结果或属性,直接写在对应字段声明后面。比如要求第一个操作数必须是 2D tensor:
- 用
AnyTensorOfRank表达固定秩约束,它来自OpBase.td内置的约束模板 - 若需更细粒度(如 shape 已知),可用
SameTypeAsOperand或自定义Def类型约束 - 注意:不能在约束里写运行时逻辑,所有约束必须能在 TableGen 编译期求值
示例(ODS 片段):
def Toy_TransposeOp : Toy_Op {
let arguments = (ins TensorType:$input);
let results = (outs AnyTensorOfRank:$output);
}
多实体约束怎么声明(比如 input/output shape 一致)
多实体约束无法塞进单个字段声明,必须提出来作为独立 let constraints = [...] 块。这类约束本质是 PredOpTrait 实例,由 TableGen 翻译成 C++ 的 verifyInvariants 调用。
- 常见写法是调用预定义谓词,如
ShapeIsSameAsOperand(要求 result #0 和 operand #1 shape 相同) - 若预定义不够用,需在
.td文件里用def定义新Constraint,并实现其CxxCode字段 - 别漏掉
let hasCustomVerify = 1;,否则生成的 C++ 不会插入验证逻辑
示例:
def Toy_ReshapeOp : Toy_Op {
let arguments = (ins TensorType:$input, TensorType:$shape);
let results = (outs TensorType:$output);
let constraints = [
ShapeIsSameAsOperand, // output shape == shape operand
SameTypeAsOperand // input & shape must have same element type
];
let hasCustomVerify = 1;
}
为什么 getOperand(0).getType() 在 verify 里拿不到完整 shape
因为 ODS 生成的 verifyInvariants 默认只做静态结构检查,不触发 shape 推导。如果 operand 类型是 tensor<?x ?xf32> 这种动态 shape,getType() 返回的 ShapedType 就不含具体维度。
- 真正需要 shape 信息的验证(比如 reshape 后 volume 不变),得手动在 C++ 中调用
inferReturnTypes或getShapeForValue - 更稳妥的做法是把 shape 约束拆到两个层面:ODS 做 type 兼容性检查(如 rank、element type),C++ 做 runtime shape 校验
- 别指望
Constraint自动帮你推 shape——它不是分析器,只是编译期断言容器
真正容易被忽略的是约束的“生效时机”:ODS 约束只在 IR 构建和解析阶段起作用,对已存在的 IR(比如 pass 修改后)不做重检。如果你在自定义 pass 里改了 operand 类型但没同步更新 result,ODS 约束不会自动报错,得靠后续的 verify 或 canonicalize 显式触发。











