如何让LLVM C-API的LLVMDumpModule导出带值名称的模块?
问题描述
使用Rust结合LLVM及LLVM C-API开发自定义编译器时,调试调用LLVMDumpModule()输出LLVM IR,发现所有自定义值名称(如函数名my_func)被替换为数字编号,导致调试难度陡增。LLVM C++ API的dumpModule可通过参数控制显示值名称,但C-API无直接对应设置。
最小复现代码(Rust + llvm-sys):
extern crate llvm_sys as llvm; use std::ffi::CString; fn c_str(s: &str) -> *const i8 { CString::new(s).unwrap().as_ptr() } fn main() { unsafe { let ctx = llvm::LLVMContextCreate(); let mod_ = llvm::LLVMModuleCreateWithNameInContext(c_str("main_ctx"), ctx); // 创建i64()类型的函数 let func_type = llvm::LLVMFunctionType(llvm::LLVMInt64TypeInContext(ctx), std::ptr::null_mut(), 0, 0); llvm::LLVMAddFunction(mod_, c_str("my_func"), func_type); llvm::LLVMDumpModule(mod_); } }
预期输出:
define i64 @my_func()
实际输出:
define i64 @1()
解决方案
LLVM C-API虽未给LLVMDumpModule()提供参数,但可通过以下两种方式实现显示值名称的需求:
方法1:自定义打印选项输出IR
LLVMDumpModule()本质是向标准错误流输出默认配置的IR,我们可以用LLVMPrintModuleToStringWithFlags指定打印标志,手动输出结果:
extern crate llvm_sys as llvm; use std::ffi::{CString, CStr}; use std::io::{self, Write}; fn c_str(s: &str) -> *const i8 { CString::new(s).unwrap().as_ptr() } fn main() { unsafe { let ctx = llvm::LLVMContextCreate(); let mod_ = llvm::LLVMModuleCreateWithNameInContext(c_str("main_ctx"), ctx); let func_type = llvm::LLVMFunctionType(llvm::LLVMInt64TypeInContext(ctx), std::ptr::null_mut(), 0, 0); llvm::LLVMAddFunction(mod_, c_str("my_func"), func_type); // 启用值名称打印标志 let print_flags = llvm::LLVMPrintNames; let ir_str_ptr = llvm::LLVMPrintModuleToStringWithFlags(mod_, print_flags); let ir_str = CStr::from_ptr(ir_str_ptr).to_str().unwrap(); // 输出到标准错误流,模拟LLVMDumpModule的行为 writeln!(io::stderr(), "{ir_str}").unwrap(); // 清理内存 llvm::LLVMDisposeMessage(ir_str_ptr); llvm::LLVMDisposeModule(mod_); llvm::LLVMContextDispose(ctx); } }
方法2:全局设置打印标志
如果希望所有LLVMDumpModule()调用都生效,可通过LLVMSetPrintModuleFlags全局配置:
extern crate llvm_sys as llvm; use std::ffi::CString; fn c_str(s: &str) -> *const i8 { CString::new(s).unwrap().as_ptr() } fn main() { unsafe { // 全局开启值名称打印 llvm::LLVMSetPrintModuleFlags(llvm::LLVMPrintNames); let ctx = llvm::LLVMContextCreate(); let mod_ = llvm::LLVMModuleCreateWithNameInContext(c_str("main_ctx"), ctx); let func_type = llvm::LLVMFunctionType(llvm::LLVMInt64TypeInContext(ctx), std::ptr::null_mut(), 0, 0); llvm::LLVMAddFunction(mod_, c_str("my_func"), func_type); // 现在LLVMDumpModule会显示自定义名称 llvm::LLVMDumpModule(mod_); llvm::LLVMDisposeModule(mod_); llvm::LLVMContextDispose(ctx); } }
关键说明
LLVMPrintNames是控制显示值自定义名称的核心标志,开启后IR会保留你设置的名称(如@my_func)。- 若需同时显示调试信息,可组合
LLVMPrintDebugInfo标志,或直接用LLVMPrintAll开启所有打印选项。 - 使用
LLVMPrintModuleToStringWithFlags返回的字符串必须用LLVMDisposeMessage释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Jonas
相关产品推荐
相关产品推荐

