index是MLIR中平台无关的抽象索引类型,专用于位置表达,不具固定位宽,禁止位运算与指针算术,强制用于memref维度和函数索引参数,lowering至LLVM时映射为目标平台指针宽整数。

index类型不是整数类型,而是独立的抽象索引类型
在 MLIR 中,index 类型和 iN 整数类型(如 i32、i64)语义上完全不同——它不表示具体位宽的整数,而是一个**平台无关、无固定大小的抽象索引**,专用于表示容器维度、循环下标、内存偏移等“位置”概念。编译器后端会根据目标平台自动将其映射为合适的整数类型(比如 x86-64 下常为 i64,嵌入式 RISC-V 32 位平台可能为 i32),但你在 MLIR IR 层无需、也不应假设其位宽。
不能直接对 index 类型做位运算或指针算术
index 类型支持加减、比较、乘法(用于线性化索引),但明确禁止位操作(如 shl、and、trunc、zext)和指针运算(如 getelementptr 的 offset 部分必须是 index,但你不能拿 index 去做地址掩码)。这是因为它的设计目标是表达“逻辑位置”,而非“内存布局细节”。一旦你尝试:arith.shl %i, %c2 : index, i32,MLIR verifier 会直接报错:'arith.shl' op requires same type for all operands and result(类型不匹配),因为 shl 只接受整数类型,不接受 index。
- 合法操作:
arith.addi %i, %c1 : index、arith.muli %i, %j : index、cf.br %cond, ^bb1, ^bb2(条件分支用index比较结果) - 非法操作:
arith.andi %i, %c3 : index、arith.trunci %i : index to i32、memref.load %m[%i] : memref, i32(错误:offset 必须是index,不能是i32)
函数签名和 memref 维度声明强制使用 index
MLIR 的方言(dialect)对 index 有硬性约束。例如:memref 类型的维度大小必须用 index 字面量或值表示:memref 合法,但 memref 中的动态维度 size 运行时值必须是 index;linalg.generic 的迭代空间 bound 也必须是 index;函数形参若用于索引(如 func.func @foo(%dim : index) -> (i32)),就不能写成 i64——即使你确定它在后端就是 64 位。这种约束迫使你在 IR 层保持抽象层级一致,避免过早绑定硬件细节。
转换到 LLVM IR 时 index 会被 lowering 为具体整数类型
当你用 mlir-translate --mlir-to-llvmir 或通过 LLVMConversionTarget pass 将 MLIR lowering 到 LLVM IR 时,index 类型不会保留。它会被映射为当前 target machine 的指针宽度对应整数类型:默认是 i64(64 位系统),但可通过 --mlir-disable-lower-index(不推荐)或自定义 conversion pattern 干预。这意味着:你在 MLIR 中写的 %i = arith.constant 5 : index,最终生成的 LLVM IR 是 %0 = llvm.mlir.constant(5 : i64) : i64。这个 lowering 是单向且不可逆的——LLVM IR 没有 index 概念,所以一旦离开 MLIR 层,你就失去了该类型的语义保护。
最易被忽略的一点是:跨 dialect 边界传递值时,比如从 affine loop 的 induction variable(index)传给一个自定义方言的 op,如果该 op 的 operand type 声明为 i32,就会在验证阶段失败。你必须显式插入 arith.index_cast(仅限于 index ↔ 具体整数类型之间,且需保证值域安全),而不是用通用的 arith.exti 或 arith.trunci。这个 cast 不产生运行时开销,但它是 MLIR 类型系统强制你承认“抽象→具体”这一语义跃迁的仪式感所在。

















