编写LLVM Pass分析IR代码,求解变量d的最终值遇阻
解决LLVM Pass中跟踪变量d最终值的问题
嘿,我来帮你搞定这个LLVM Pass里的数值分析问题!你的核心需求是跟踪这段IR中变量%d的最终值,其实关键在于跟踪临时寄存器(比如%1、%2)的定义溯源——因为最后一条store的源操作数是%2,咱们得一步步拆解它的由来。
首先先明确这段IR的执行流程,先把代码贴出来:
%d = alloca i32, align 4 store i32 0, i32* %d, align 4 %1 = load i32* %d, align 4 %2 = add nsw i32 %1, 2 store i32 %2, i32* %d, align 4
核心思路:维护一个值映射表
你需要在Pass里维护一个类似值-常量映射的结构(LLVM里推荐用DenseMap<Value*, ConstantInt*>),用来记录每个Value(包括栈变量%d和临时寄存器%1、%2)对应的已知常量值。然后按指令顺序逐个处理,更新这个映射表:
- 处理第一条store指令:你已经做对了——取出操作数0的
ConstantInt(值为0),把%d对应的映射值设为0。 - 处理load指令(%1 = load i32 %d)*:
- 识别这是
LoadInst,获取它的指针操作数%d。 - 从映射表里查找
%d对应的常量值(也就是0),把临时寄存器%1的映射值设为0。
- 识别这是
- 处理add指令(%2 = add nsw i32 %1, 2):
- 识别这是
BinaryOperator(或者直接AddInst),获取两个操作数:%1和常量2。 - 从映射表里取出
%1的值0,和操作数1的ConstantInt值2做加法,得到结果2。 - 把临时寄存器
%2的映射值设为2。
- 识别这是
- 处理最后一条store指令:
- 识别这是
StoreInst,获取源操作数%2和指针操作数%d。 - 从映射表里取出
%2对应的常量值2,更新%d的映射值为2——这就是%d的最终值了!
- 识别这是
具体代码实现的关键片段示例
这里给你一个简化的代码片段,展示怎么用LLVM API实现这个逻辑:
// 在你的Pass的runOnFunction方法里 DenseMap<Value*, ConstantInt*> valueMap; for (BasicBlock &BB : F) { for (Instruction &I : BB) { if (StoreInst *SI = dyn_cast<StoreInst>(&I)) { Value *src = SI->getValueOperand(); Value *ptr = SI->getPointerOperand(); // 尝试获取源操作数的常量值 if (ConstantInt *CI = dyn_cast<ConstantInt>(src)) { valueMap[ptr] = CI; } else { // 如果源是临时寄存器,查映射表 auto it = valueMap.find(src); if (it != valueMap.end()) { valueMap[ptr] = it->second; } } } else if (LoadInst *LI = dyn_cast<LoadInst>(&I)) { Value *ptr = LI->getPointerOperand(); auto it = valueMap.find(ptr); if (it != valueMap.end()) { valueMap[&I] = it->second; // 把load的结果(当前指令)映射到对应常量 } } else if (AddInst *AI = dyn_cast<AddInst>(&I)) { ConstantInt *lhsCI = nullptr, *rhsCI = nullptr; // 检查左操作数是不是常量,或者在映射表里 if (ConstantInt *CI = dyn_cast<ConstantInt>(AI->getOperand(0))) { lhsCI = CI; } else { auto it = valueMap.find(AI->getOperand(0)); if (it != valueMap.end()) lhsCI = it->second; } // 检查右操作数 if (ConstantInt *CI = dyn_cast<ConstantInt>(AI->getOperand(1))) { rhsCI = CI; } else { auto it = valueMap.find(AI->getOperand(1)); if (it != valueMap.end()) rhsCI = it->second; } // 如果两个操作数都有常量值,计算结果 if (lhsCI && rhsCI) { APInt result = lhsCI->getValue() + rhsCI->getValue(); valueMap[&I] = ConstantInt::get(AI->getType(), result); } } } } // 最后获取%d的最终值 auto dIt = valueMap.find(dValue); // dValue是你找到的alloca指令对应的Value* if (dIt != valueMap.end()) { errs() << "d的最终值是: " << dIt->second->getSExtValue() << "\n"; }
注意事项
- 这段IR是SSA形式,每个临时寄存器只定义一次,所以按顺序处理基本块里的指令就没问题。
- 如果遇到无法溯源的变量(比如来自函数参数、外部全局变量的加载),映射表里会没有记录,这时候你可以标记为“未知值”,但你的例子里所有操作都是封闭的,所以不会有这个问题。
- 要注意指令的类型判断,比如
dyn_cast的使用,确保你正确识别了StoreInst、LoadInst、AddInst等指令。
内容的提问来源于stack exchange,提问作者KTB
相关产品推荐
相关产品推荐

