LLVM-Learn-Work1 -指令操作

8 篇文章 3 订阅
7 篇文章 5 订阅

LLVM -Learn-Work1

2022-04-27 16:33:55

sizaf

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. 写入文件
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值