如何通过clang -emit-llvm保留未使用的C/C++结构体定义
解决未使用结构体不生成LLVM IR的问题
核心逻辑:clang的延迟类型生成机制
clang对未被引用的结构体,仅在语义分析阶段完成类型解析,但不会生成对应的LLVM IR——因为IR生成阶段默认只处理实际被使用的类型,以此减少冗余代码。
源码修改关键点
要强制生成所有结构体的LLVM IR,需修改clang中类型生成的触发逻辑,核心涉及以下几个位置:
1. 主动遍历AST生成类型
在clang/lib/CodeGen/CodeGenModule.cpp中,CodeGenModule是IR生成的核心管理类。默认仅当类型被GetOrCreateLLVMType主动请求时才会生成IR,你可以修改EmitGlobalDecls或类似入口函数,遍历所有已完成定义的结构体,主动触发IR生成:
// 适配clang源码结构的示例代码 for (const auto *Record : getASTContext().getRecords()) { if (Record->isCompleteDefinition() && !Record->isAnonymousStructOrUnion()) { GetOrCreateLLVMType(QualType(Record, 0)); } }
2. 语义分析阶段标记类型需生成IR
在clang/lib/Sema/SemaDecl.cpp的Sema::ActOnTagDecl函数中,处理结构体/联合体声明的逻辑默认会跳过未被使用的类型。你需要修改此处,强制标记所有完成定义的结构体为"需要生成IR",确保后续流程不会忽略它们。
3. 避免LLVM后端消除未使用类型
LLVM后端可能会移除未被引用的类型定义,生成类型后需强制将其加入模块的全局类型列表:
llvm::Type *LLVMType = GetOrCreateLLVMType(TargetType); if (auto *StructTy = dyn_cast<llvm::StructType>(LLVMType)) { if (!StructTy->isLiteral()) { getModule().addTypeName(StructTy->getName(), StructTy); } }
无需修改源码的替代方案
如果不想改动clang源码,可以给结构体添加__attribute__((used))属性,强制clang保留其IR定义:
struct __attribute__((used)) A { void *ptr; int m_buf; }; struct __attribute__((used)) B { struct A a; int m_val; };
编译时使用clang -g -S -emit-llvm,即使结构体未被main函数使用,也会生成对应的LLVM IR。针对大型代码库,可通过clang插件或预处理脚本批量添加该属性,开销远低于手动修改代码。
内容的提问来源于stack exchange,提问作者Yinwhe
相关产品推荐
相关产品推荐

