抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

LLVM -Learn-Work1

@2022-04-27 16:33:55

@sizaif

Work1:将其浮点数加法改为减法。(指令操作)

//main.c
#define _GNU_SOURCE 
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
 puts("plz input two numbers");
 size_t bufsize = 100;
 char* buf = malloc(bufsize);
 getline(&buf, &bufsize, stdin);
 double f1 = atof(buf);
 getline(&buf, &bufsize, stdin);
 double f2 = atof(buf);
 printf("%.2f + %.2f = %.2f \n", f1, f2, f1+f2);
 free(buf);
 return 0;
}

一) 思路

  1. 使用Clang生成IR文件

    clang -emit-llvm -S main.c -o main.ll
  2. IR文件中读取到Module类

  3. 拿到main函数

  4. 找到fadd指令,构造新的fsub指令,添加到当前fadd指令后,并删除fadd指令

    1. 法一:

      通过main函数拿到所有的BasicBlockList()

      遍历所有basicblock块的所有指令(Instruction) 查找fadd 指令

    2. 法二:

      使用指令迭代器(inst_iterator),遍历所有main函数的指令找到fadd

  5. 验证修改后的Module

  6. 存入到新的IR文件中,执行lli aftermain.bc

二) 执行

2.1) 从IR文件中读取到Module类

/**
 * 2022-04-26 03:20:02
 * 从IR中获取Module类
 * */
M = parseIRFile(StringRef(argv[1]),Err,context);
if(M){
    std::cout<<"M is not null"<<std::endl;
    // M->print(llvm::outs(),nullptr);
}
else{
    std::cout<<"M is null"<<std::endl;
    Err.print(argv[0],errs());
}

2.2) 拿到main函数

/**
 * 2022-04-26 03:25:52
 * 获取main函数
 * */
auto main_fn = M->getFunction(StringRef("main"));

2.3) 找到fadd指令,构造fsub替换掉

法一:

/**
 * 2022-04-26 16:56:34
 * 方法一: 通过获得basicblock块list 进而获得指令
 * 遍历查询inst指令,找到fadd
 * %19 = load double, double* %4, align 8
 * %20 = load double, double* %5, align 8
 * %21 = fadd double %19, %20
 * */
auto bkl = &main_fn->getBasicBlockList();
for (auto it = bkl->begin(); it != bkl->end();it++)
{
    auto instl = &it->getInstList();
    for(auto inst = instl->begin(); inst != instl->end();inst++){
        if(inst->isBinaryOp() && inst->getOpcode() == Instruction::FAdd ){
            new_inst = BinaryOperator::CreateFSub(
            inst->getOperand(0),
            inst->getOperand(1),
            "");
            old_inst = &*inst;
        }
    }
}

法二:

/**
 * 2022-04-27 15:52:04
 * 方法二: 指令迭代器遍历查找
 * */
Instruction *old_inst,*new_inst;
for (inst_iterator I = inst_begin(*main_fn), E = inst_end(*main_fn); I != E; ++I){
    if(I->isBinaryOp() && I->getOpcode()==Instruction::FAdd){
        new_inst = BinaryOperator::CreateFSub(
        I->getOperand(0),
        I->getOperand(1),
        "");
        old_inst = &*I;
    }
}

/**
 * 2022-05-02 11:49:30
 * #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 * 指令替换
 * */
outs() <<" new op: "<< *new_inst<<" \n";
outs() <<" old op: "<< *old_inst << " \n";
ReplaceInstWithInst(old_inst,new_inst);

2.4) 验证修改后的Module

/**
 * #include "llvm/IR/Verifier.h"
 * 2022-05-02 11:43:34
 * 修改完Module后进行验证Module的完整性
 * verifyModule(*M,&errs()): true if the module is broken. 
 * 即如果验证正确返回一个false, 若存在问题则返回true
 * */
if(!llvm::verifyModule(*M,&errs())){
    outs()<<"verify is ok \n";
    // M->print(outs(),nullptr);
}

2.5) 存入到新的IR文件中,执行lli aftermain.ll

/**
 * 将修改后的IR 存储到文件中, 执行
 * */
std::error_code EC;
llvm::raw_fd_ostream OS("aftermain.bc", EC,llvm::sys::fs::OpenFlags());
llvm::WriteBitcodeToFile(*M,OS,true);
OS.flush();

2.6) 全部源码


/**
 * 2022-04-26 01:02:37
 * sizaif
 * 
 * clang++ $(llvm-config --cxxflags --ldflags --system-libs --libs)  -o main main.cpp
 * ./main main.ll
 * lli aftermain.bc
 * */

#include <llvm/IR/IRBuilder.h>
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/SourceMgr.h"
#include <llvm/Support/raw_os_ostream.h>
#include "llvm/Support/WithColor.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Bitcode/BitcodeWriter.h"

#include <iostream>
#include <string>
#include <fstream>
using namespace llvm;


int main(int argc,char **argv){

    /**
     * #include <llvm/IR/IRBuilder.h>
     * #include "llvm/IR/LLVMContext.h"
     * #include "llvm/IR/Module.h"
     * #include "llvm/Support/SourceMgr.h"
     * 初始化
     * */

    LLVMContext context;
    IRBuilder<> builder(context);
    std::unique_ptr<Module> M;
    SMDiagnostic Err;

    /**
     * 2022-04-26 03:20:02
     * 从IR中获取Module类
     * */
    M = parseIRFile(StringRef(argv[1]),Err,context);
    if(M){
        std::cout<<"M is not null"<<std::endl;
        // M->print(llvm::outs(),nullptr);
    }
    else{
        std::cout<<"M is null"<<std::endl;
        Err.print(argv[0],errs());
    }

    /**
     * 2022-04-26 03:25:52
     * 获取main函数
     * */
    auto main_fn = M->getFunction("main");
    /**
     * #include "llvm/IR/InstIterator.h"
     * 2022-04-27 15:52:04
     * 方法二: 指令迭代器遍历查找,找到fadd指令
     * 
     * */    
    Instruction *old_inst,*new_inst;
    // for (inst_iterator I = inst_begin(*main_fn), E = inst_end(*main_fn); I != E; ++I){
    //     if(I->isBinaryOp() && I->getOpcode()==Instruction::FAdd){
    //         new_inst = BinaryOperator::CreateFSub(
    //         I->getOperand(0),
    //         I->getOperand(1),
    //         "");
    //         old_inst = &*I;
    //     }
    // }

    /**
     * 
     * 2022-04-26 16:56:34
     * 方法一: 通过获得basicblock块list 进而获得指令
     * 遍历查询inst指令,找到fadd
     * %19 = load double, double* %4, align 8
     * %20 = load double, double* %5, align 8
     * %21 = fadd double %19, %20
     * */
    auto bkl = &main_fn->getBasicBlockList();
    for (auto it = bkl->begin(); it != bkl->end();it++)
    {
        auto instl = &it->getInstList();
        for(auto inst = instl->begin(); inst != instl->end();inst++){
            if(inst->isBinaryOp() && inst->getOpcode() == Instruction::FAdd ){
                new_inst = BinaryOperator::CreateFSub(
                inst->getOperand(0),
                inst->getOperand(1),
                "");
                old_inst = &*inst;
            }
        }

    }
    /**
     * #include "llvm/Transforms/Utils/BasicBlockUtils.h"
     * 2022-05-02 11:49:30
     * 指令替换
     * */
    outs() <<" new op: "<< *new_inst<<" \n";
    outs() <<" old op: "<< *old_inst << " \n";
    outs()<<"before replace InstructionCount(): " <<main_fn->getInstructionCount()<<"\n";
    ReplaceInstWithInst(old_inst,new_inst);
    outs()<<"after replace InstructionCount(): " <<main_fn->getInstructionCount()<<"\n";

    /**
     * #include "llvm/IR/Verifier.h"
     * 2022-05-02 11:43:34
     * 修改完Module后进行验证Module的完整性
     * verifyModule(*M,&errs()): true if the module is broken. 
     * */
    if(!llvm::verifyModule(*M,&errs())){
        outs()<<"verify is ok \n";
        M->print(outs(),nullptr);
    }

    /**
     * #include "llvm/Bitcode/BitcodeWriter.h"
     * 2022-05-02 12:11:57
     * 将修改后的IR 存储到文件中, 执行
     * */
    std::error_code EC;
    llvm::raw_fd_ostream OS("aftermain.bc", EC,llvm::sys::fs::OpenFlags());
    llvm::WriteBitcodeToFile(*M,OS,true);
    OS.flush();

    return 0;
}

2.7) 效果

image-20220502120500759

image-20220502120522500

image-20220503160351943

三) 总结

指令操作

核心是首先要找到对应的指令所在的位置;

构建新的指令,替换掉原来的指令操作,

a)构建新的操作指令使用BinaryOperator::CreateXXX 不需要指定插入位置

	如果使用`BinaryOperator::Create`<font color='cornflowerblue'>则需要指定插入位置</font>

b)替换指令操作使用ReplaceInstWithInst()

设计头文件`"llvm/Transforms/Utils/BasicBlockUtils.h"`

相应的替换操作还有很多, 像`ReplaceInstWithValue`

c)将修改后的文件以bitcode形式存放到文件中, 写入之前最好进行Module的验证

这个过程中涉及到:

1. 文件读入到Module类;
2. 迭代器的使用
3. 获取指令的操作数
4. 创建新的指令
5. 指令替换
6. Module验证
7. 写入文件

评论吧



本站总访问量为 访客数为

鲁 ICP 备 20018157 号-1
Copyright 2021 - 2022 sizaif. All Rights Reserved