Data Flow Graph
基本概念
Data Flow Graph又叫數據流程圖,表示在一個函數中的數據流動的方向。比如一個指令1定義了一個新變量%a,而另一個指令2用到了變量%a,此時就存在從指令1到指令2的邊。llvm IR的表示形式是SSA,簡單的來說SSA表示形式就是一個變量只能定義一次。
x = y + 1;
x = y + 2;
y = 3;
上面的形式就不是SSA的表示形式,因爲x被定義(賦值)了兩次,可以通過修改使其變成SSA的表示形式:
x1 = y + 1;
x2 = y + 2;
y = 3;
實驗過程
在具體的實驗中,我們遍歷函數中的每一個指令,判斷該指令是否爲load,store指令,把load和store指令與其他指令區別開來是因爲在IR中只有store和load指令直接與內存直接接觸。
case llvm::Instruction::Load:
{
LoadInst* linst = dyn_cast<LoadInst>(curII);
Value* loadValPtr = linst->getPointerOperand();
edges.push_back(edge(node(loadValPtr, getValueName(loadValPtr)), node(curII, getValueName(curII))));
break;
}
case llvm::Instruction::Store: {
StoreInst* sinst = dyn_cast<StoreInst>(curII);
Value* storeValPtr = sinst->getPointerOperand();
Value* storeVal = sinst->getValueOperand();
edges.push_back(edge(node(storeVal, getValueName(storeVal)), node(curII, getValueName(curII))));
edges.push_back(edge(node(curII, getValueName(curII)), node(storeValPtr, getValueName(storeValPtr))));
break;
}
對於其餘的指令,遍歷每一個指令的操作數,判斷其是不是一個指令,如果是指令的話,就添加相應的邊。
for (Instruction::op_iterator op = curII->op_begin(), opEnd = curII->op_end(); op != opEnd; ++op)
{
Instruction* tempIns;
if (dyn_cast<Instruction>(*op))
{
edges.push_back(edge(node(op->get(), getValueName(op->get())), node(curII, getValueName(curII))));
}
}
具體代碼請參考我的github