llvm:Data Flow Graph

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

你可能感兴趣的:(llvm,llvm)