LLVM_pass应用3 获取对应操作符上下文即CFG和DFG

文章目录

  • 1. 跳转指令br的cfg和dfg
  • 2 . 加法add和比较cmp指令的cfg和dfg
  • 3. 框架依然按照应用1中的使用,见下面链接
  • 4. FirstPass.cpp主代码
  • 5. 测试代码跟前两应用一样
  • 实验结果
  • 总结:

本文介绍通过llvm的pass分析源码对应IR指令集中的操作符的上下文流程
这样就方便我们通过遍历得到整个代码的cfg和dfg, 对于NLP转图处理有很大的帮助

1. 跳转指令br的cfg和dfg

LLVM_pass应用3 获取对应操作符上下文即CFG和DFG_第1张图片

2 . 加法add和比较cmp指令的cfg和dfg

LLVM_pass应用3 获取对应操作符上下文即CFG和DFG_第2张图片

3. 框架依然按照应用1中的使用,见下面链接

基础知识和框架请看

4. FirstPass.cpp主代码

代码主干

遍历函数
	遍历basicblock
		遍历statement
			找到目标操作符
				打印目标操作符所在行代码
				打印目标操作符数据流上级
				打印目标操作符数据流下级
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "list"

using namespace llvm;

namespace {

    //定义 First 类继承自 FunctionPass
    struct First : public FunctionPass {
        static char ID; // Pass ID
        std::string str;
        First() : FunctionPass(ID) {}
        std::list<Instruction *>::iterator itor_former;  //定义迭代器
        int num_function = 0; // 用来记录多少个函数



        bool runOnFunction(Function &F) override {  //这里是一个函数一个函数的往里面传的数据
            errs() << F.getName() << "\n"; //显示函数名称
            errs() << "num_function=" << num_function <<"\n"; //num_function=0
            num_function++;

            // 打印call func的句子
            for (User *U : F.users()) {
                if (Instruction *Inst = dyn_cast<Instruction>(U)) {
                    errs() << "F is used in instruction:";
                    errs() << *Inst << "\n";
                }
            }  
            // raw_string_ostream rso(str);
            // StringRef name("Graph.dot"); //生成图
            // std::ofstream output_CFG_file(
            //     "output.txt"); //定义输出文件
            // output_CFG_file << "hello world:"; // 向文件内输出
            // output_CFG_file.close();

            
            //遍历函数中的basicblock
            for (Function::iterator BB = F.begin(); BB != F.end(); ++BB) {
                errs() << "块的长度 size:BB->size() "<< BB->size() <<"\n";//显示basicblock的名字和大小

                //在BB中遍历statement
                for(BasicBlock::iterator i = BB->begin(); i!=BB->end(); i++){
                    // 打印块内statement所有数据
                    // errs() << "每一行的数据和地址" << &*i ; //打印ir块里面的所有行,和地址
                    // errs() << "  *i:" << *i ; //打印ir块里面的所有行,和地址
                    // errs() << "  操作符i->getOpcodeName(): " << i->getOpcodeName()  << "\n"; //打印ir块里面的所有行,和地址

                    //dyn_cast<>操作符是一个“检查转换”操作。它检查操作数是否属于指定的类型
                    //判断本行中是否包含操作符add,打印这行数据
                    Instruction *inst = dyn_cast<Instruction>(i); 
                    if(inst->getOpcode() == Instruction :: Add || inst->getOpcode() == Instruction::Br || inst->getOpcode() == Instruction::ICmp){ 
                        for(User *U :inst ->users())
                        {
                            // 打印add行
                            // errs() <<"dyn_cast(U)"<<*dyn_cast(U) << "\n";
                            if(Instruction *Inst = dyn_cast<Instruction>(U))
                            {
                                //%13 = add nsw i32 %12, 2add
                                errs()<<"\n操作符定位到 of add/icmp used in : "<<*inst << "  " << inst->getOpcodeName() <<"\n";
                                
                                errs()<<"操作符下一级 : "<<*Inst << "\n"; 
                            }
                        }

                        // 输出其所使用的所有operands(操作数)就是加数被加数 
                        // %16 = add nsw i32 %15, 1  
                        // %15 = load i32, i32* %7, align 4和i32 1
                        for(Use &U :inst ->operands())
                        {
                            Value *v =U.get();
                            errs()<<"input of add originate from : " <<*v<<"\n";
                        }      
                    }
                }
                // for (BasicBlock *SuccBB : successors(curBB)) {
                //     errs() << "&*(SuccBB->begin()):" << &*(SuccBB->begin()) << "\n";  
                // }
            }
            return false;
        }
    };
}
 
char First::ID = 0;  //初始化 Pass ID
 
//最后注册 FirstPass, 指定命令行参数为 First
static RegisterPass <First>X("First", "First Pass");

5. 测试代码跟前两应用一样

#include 

int fun1(){
    printf("%s\n", "hello");
    return 25;
}
int fun2(){
    printf("%s\n", "fun2");
    return 23;
}
int main(int argc, char const *argv[]){
    int b=0;
    int i = 0;
    for (i = 0; i < 23; ++i){
        b+=2;
    }
    printf("%d\n", b);
    return 0;
}

转化为ir文件或者bc文件应用1中有涉及

  • hello.bc .c文件的字节码文件, 生成命令是clang -c -emit-llvm hello.c -o hello.bc
  • hello.ll .c文件的IR文件,指令集,生成命令clang -O0 -S -emit-llvm input.c -o input.ll

实验结果

zjq@DESKTOP-O28RVV3:test2_$ cat run.sh
cd build/ && make && cd ..
opt -load build/libFirstPass.so -First hello.ll
zjq@DESKTOP-O28RVV3:test2_$ source run.sh
[100%] Built target FirstPass
WARNING: You're attempting to print out a bitcode file.
This is inadvisable as it may cause display problems. If
you REALLY want to taste LLVM bitcode first-hand, you
can force output with the `-f' option.

fun1
num_function=0
块的长度 size:BB->size() 2
fun2
num_function=1
F is used in instruction:  %18 = call i32 @fun2()
块的长度 size:BB->size() 2
main
num_function=2
块的长度 size:BB->size() 12
input of add originate from :
; <label>:8:                                      ; preds = %14, %2
  %9 = load i32, i32* %7, align 4
  %10 = icmp slt i32 %9, 23
  br i1 %10, label %11, label %17

块的长度 size:BB->size() 3

操作符定位到 of add/icmp used in :   %10 = icmp slt i32 %9, 23  icmp
操作符下一级 :   br i1 %10, label %11, label %17
input of add originate from :   %9 = load i32, i32* %7, align 4
input of add originate from : i32 23
input of add originate from :   %10 = icmp slt i32 %9, 23
input of add originate from :
; <label>:17:                                     ; preds = %8
  %18 = call i32 @fun2()
  %19 = load i32, i32* %6, align 4
  %20 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.3, i32 0, i32 0), i32 %19)
  ret i32 0

input of add originate from :
; <label>:11:                                     ; preds = %8
  %12 = load i32, i32* %6, align 4
  %13 = add nsw i32 %12, 2
  store i32 %13, i32* %6, align 4
  br label %14

块的长度 size:BB->size() 4

操作符定位到 of add/icmp used in :   %13 = add nsw i32 %12, 2  add
操作符下一级 :   store i32 %13, i32* %6, align 4
input of add originate from :   %12 = load i32, i32* %6, align 4
input of add originate from : i32 2
input of add originate from :
; <label>:14:                                     ; preds = %11
  %15 = load i32, i32* %7, align 4
  %16 = add nsw i32 %15, 1
  store i32 %16, i32* %7, align 4
  br label %8

块的长度 size:BB->size() 4

操作符定位到 of add/icmp used in :   %16 = add nsw i32 %15, 1  add
操作符下一级 :   store i32 %16, i32* %7, align 4
input of add originate from :   %15 = load i32, i32* %7, align 4
input of add originate from : i32 1
input of add originate from :
; <label>:8:                                      ; preds = %14, %2
  %9 = load i32, i32* %7, align 4
  %10 = icmp slt i32 %9, 23
  br i1 %10, label %11, label %17

块的长度 size:BB->size() 4
zjq@DESKTOP-O28RVV3:test2_$

总结:

通过代码中定位操作符,然后得到对应操作符的上下文关系, cfg和dfg非常方便
具体细节代码中有注释
具体流程请跳转到1\2两节

你可能感兴趣的:(LLVM_clang)