必须先初始化MLIRContext并加载dialect,再以ModuleOp为起点设置有效插入点,否则OpBuilder会静默失败或崩溃;示例中两次setInsertionPoint确保constOp正确插入func body。

直接用 OpBuilder 生成第一段 IR,关键不是“怎么建”,而是“在哪建、以谁为上下文、插到哪”。没选对插入点或没初始化好 MLIRContext,OpBuilder 会静默失败或崩溃——这不是 bug,是设计使然。
必须先有 MLIRContext 和 ModuleOp
所有 IR 构建都依赖一个活的 MLIRContext。不能 new 一个空 context 就开干;它需要注册 dialect(比如 arith、func),否则后续 op 创建会报 unknown dialect 错误。
-
MLIRContext必须显式启用所需 dialect:context.loadDialect<:arithdialect func::funcdialect>()</:arithdialect> - 推荐从
ModuleOp入手:它自带 context,且天然提供顶层 Block —— 这是你唯一能安全调用OpBuilder::create的起点 - 别试图在裸指针或未初始化的
Block*上构造OpBuilder;哪怕指针非空,若其getParent()为空或 context 不匹配,build调用会 segfault
创建 ModuleOp 后立即获取 Block 并设插入点
ModuleOp 自带一个匿名 Block,但它的 begin() 是 end 迭代器(空 block)。你得先确保插入点有效,否则 create 什么也插不进。
- 用
module.getBody()->push_back(newBlock)或更稳妥地:OpBuilder builder(module.getBody()); builder.create<:funcop>(...)</:funcop> - 如果想插在 module 开头,用
builder.setInsertionPointToStart(module.getBody());插末尾就用setInsertionPointToEnd - 错误示范:
OpBuilder builder(module.getBody()->begin())—— 此时begin() == end(),迭代器无效,UB
用 OpBuilder 创建第一个 func + constant 示例
下面这段 C++ 代码能跑通,生成最简可执行 IR:
auto context = std::make_unique<MLIRContext>();
context->loadDialect<arith::ArithDialect, func::FuncDialect, builtin::BuiltinDialect>();
OpBuilder builder(context.get());
auto module = builder.create<builtin::ModuleOp>(UnknownLoc::get(context.get()));
// 切换 builder 到 module body
builder.setInsertionPointToStart(module.getBody());
// 创建 func @main()
auto funcType = FunctionType::get(context.get(), {}, {}, {});
auto func = builder.create<func::FuncOp>(UnknownLoc::get(context.get()), "main", funcType);
func.setPrivate();
// 切换 builder 到 func body
auto *entryBlock = func.addEntryBlock(builder, UnknownLoc::get(context.get()), {}, {});
builder.setInsertionPointToStart(entryBlock);
// 插入第一个 op:arith.constant
auto constOp = builder.create<arith::ConstantOp>(
UnknownLoc::get(context.get()),
builder.getF64FloatAttr(3.14)
);
注意:这里用了两次 setInsertionPoint* —— 第一次进 module,第二次进 func body。漏掉任一环节,constOp 就不会出现在 IR 中,也不会报错,只会静默丢失。
容易被忽略的 Location 和 Type 绑定
UnknownLoc 能跑,但一旦要做 error reporting 或 debug,必须传真实 FileLineColLoc;而 arith::ConstantOp 的类型不是由值推导的,必须显式提供:builder.getF64FloatAttr(3.14) 返回的是 Attribute,op 内部靠 getType() 拿 result type,所以你得确保 attr 类型和 op 声明一致。用 IntegerAttr 却传 F64 会 assertion fail。
真正卡住新手的,往往不是语法,而是 context 没 load dialect、插入点悬空、location/type 没对齐这三处。跑通第一段 IR 后,再补 dialect 注册和 location 构造,比从一堆报错里反推要快得多。

















