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

Sizaif

Keep learning and progress!

LLVM -Learn-Work3

@2022-05-03 18:54:36

@sizaif

Work3:插入一个函数并调用。函数用于检查加法结果,如果大于 100,则取

余 100。此函数会修改加法结果。(函数操作)

//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. 创建一个全局变量fdd_res,

  2. 添加store指令, 将fadd指令的结果存储到全局变量中,

  3. 构造函数,读取全局变量的值,如果大于100,则对100取余,否则什么都不做

  4. 修改printf函数第三个参数为全局变量fadd_res

第二种一种思路:

  1. 构造函数work_fn,其函数传参(fadd)的结果值
  2. 函数拿到其值,做取余操作,并返回结果
  3. 主函数存储work_fn返回结果,并修改printf函数的参数。

二) 思路一执行

2.1) 读取IR

LLVMContext context;
IRBuilder<> builder(context);
std::unique_ptr<Module> M;
std::unique_ptr<MIRParser> MIR;

SMDiagnostic Err;
/**
 * #include "llvm/IRReader/IRReader.h"
 * 2022-04-26 03:04:32
 * TODO:
 * from IR file get Moudle class
 * */
M = parseIRFile(StringRef(argv[1]),Err,context);
if(M){
    std::cout<<"debug: 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) 找到fadd指令与fadd后一个指令

/**
    * 2022-04-26 03:25:52
    * TODO:
    * 获取main函数
    * */
   auto main_fn = M->getFunction(StringRef("main"));
   
   /**
    * 2022-04-28 02:14:46
    * TODO:
    * 找到fadd指令,与fadd的后一个指令
    * */
   Instruction *in_fadd,*in_prt;
   for (inst_iterator I = inst_begin(*main_fn), E = inst_end(*main_fn); I != E; ++I){
       if(I->isBinaryOp() && I->getOpcode()==Instruction::FAdd){
           // outs() << *I << "\n";
           in_fadd = &*I;
           in_prt = &*(I.operator++());
       }   
   }

2.3) 创建全局变量,添加必要的指令

   /**
    * 2022-04-28 02:42:32
    * TODO:
    * %20 = load double, double* %5, align 8
    * %21 = fadd double %19, %20
    * 1. 创建全局变量fadd_res
    * 2. 存入常量100
    * 3. 将ADD结果存入内存中
    * */
   auto f32 = builder.getDoubleTy();
// 创建初始值0与100
   auto const_100 = ConstantFP::get(f32,double(100));
auto const_0 = ConstantFP::get(f32,double(0));
   auto in_alloc02 = new GlobalVariable(*M,
                                        f32,
                                        false,
                                        GlobalValue::PrivateLinkage,
                                        const_0,
                                        "fadd_res");
// 设置对齐方式
   in_alloc02->setAlignment(MaybeAlign(8));

   // 插入基本指令,将FADD结果,存到fadd_res中
   builder.SetInsertPoint(in_prt);
   auto in_alloc01 = builder.CreateAlloca(f32,0,"ina1");
   auto in_store01 = builder.CreateStore(const_100,in_alloc01);
   auto in_store02 = builder.CreateStore(in_fadd,in_alloc02);

2.4) 构造函数读取结果进行修改

/**
 * 2022-05-03 16:33:58
 * TODO:
 * 新建一个函数:
 * void work03_fn(){
 *  if(fdd_res > 100)
 *      fdd_res = fdd_res %100;
 * }
 * */
// 创建函数
auto fn_prototype = FunctionType::get(builder.getVoidTy(), true);
auto work03_fn = Function::Create(fn_prototype,
                                  Function::ExternalLinkage,
                                  "work03_fn",
                                  M.get());
// 创建基本块        
auto work03_fn_defaut= BasicBlock::Create(context, "work03_fn_defaut", work03_fn);
auto work03_fn_change = BasicBlock::Create(context, "work03_fn_change", work03_fn);
auto work03_fn_nothing = BasicBlock::Create(context, "work03_fn_nothing", work03_fn);

// 默认基本块 指令操作
builder.SetInsertPoint(work03_fn_defaut);
auto work03_de_load_01 = builder.CreateLoad(f32,in_alloc02);
auto work03_de_fcmp_01 = builder.CreateFCmpUGT(work03_de_load_01,const_100);
auto work03_de_br_01 = builder.CreateCondBr(work03_de_fcmp_01,
                                            work03_fn_change,
                                            work03_fn_nothing);
// 取余 指令操作
builder.SetInsertPoint(work03_fn_change);
auto work03_ch_load_01 = builder.CreateLoad(f32,in_alloc02);
auto work03_ch_frem_01 = builder.CreateFRem(work03_ch_load_01,const_100);
auto work03_ch_store_01 = builder.CreateStore(work03_ch_frem_01,in_alloc02);
builder.CreateRetVoid();

// 第三个基本块什么都不做
builder.SetInsertPoint(work03_fn_nothing);
builder.CreateRetVoid();

2.5) 修改printf参数

/**
 * 2022-05-03 18:27:56
 * TODO:
 * 在调用prtinf 函数之前插入调用函数指令
 * 以及读取fadd_res, 修改printf 第三个参数
 * */
builder.SetInsertPoint(in_prt);
builder.CreateCall(work03_fn);
auto in_load03 = builder.CreateLoad(f32,in_alloc02);
in_prt->setOperand(3,in_load03);

2.6) Module验证与存到文件

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

/**
 * #include "llvm/Bitcode/BitcodeWriter.h"
 * 2022-05-03 12:55:33
 * TODO:
 * 将修改后的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.7) 全部源码

/**
 * 2022-05-03 16:16:19
 * sizaif
 * Work3:插入一个函数并调用。函数用于检查加法结果,如果大于 100,则取余 100。此函数会修改加法结果。(函数操作)
 * clang++ $(llvm-config --cxxflags --ldflags --system-libs --libs)  -o main main.cpp
 * ./main main.ll
 * lli aftermain.bc
 * */

#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <llvm/IR/IRBuilder.h>
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/CodeGen/MIRParser/MIRParser.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/SourceMgr.h"
#include <llvm/Support/raw_os_ostream.h>
#include "llvm/Bitcode/BitcodeWriter.h"

#include <iostream>
#include <string>
#include <fstream>
#include <cstdio>

using namespace llvm;


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

 
    LLVMContext context;
    IRBuilder<> builder(context);
    std::unique_ptr<Module> M;
    std::unique_ptr<MIRParser> MIR;

    SMDiagnostic Err;
    /**
     * #include "llvm/IRReader/IRReader.h"
     * 2022-04-26 03:04:32
     * TODO:
     * from IR file get Moudle class
     * */
    M = parseIRFile(StringRef(argv[1]),Err,context);
    if(M){
        std::cout<<"debug: 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
     * TODO:
     * 获取main函数
     * */
    auto main_fn = M->getFunction(StringRef("main"));
    
    /**
     * 2022-04-28 02:14:46
     * TODO:
     * 找到fadd指令,与fadd的后一个指令
     * */
    Instruction *in_fadd,*in_prt;
    for (inst_iterator I = inst_begin(*main_fn), E = inst_end(*main_fn); I != E; ++I){
        if(I->isBinaryOp() && I->getOpcode()==Instruction::FAdd){
            // outs() << *I << "\n";
            in_fadd = &*I;
            in_prt = &*(I.operator++());
        }   
    }
    
    /**
     * 2022-04-28 02:42:32
     * TODO:
     * %20 = load double, double* %5, align 8
     * %21 = fadd double %19, %20
     * 1. 创建全局变量fadd_res
     * 2. 存入常量100
     * 3. 将ADD结果存入内存中
     * */
    auto f32 = builder.getDoubleTy();
    auto const_100 = ConstantFP::get(f32,double(100));

    // 创建初始值0
    auto const_0 = ConstantFP::get(f32,double(0));
    auto in_alloc02 = new GlobalVariable(*M,f32,false,GlobalValue::PrivateLinkage,const_0,"fadd_res");
    // 设置对齐方式
    in_alloc02->setAlignment(MaybeAlign(8));

    // 插入基本指令,将FADD结果,存到fadd_res中
    builder.SetInsertPoint(in_prt);
    auto in_alloc01 = builder.CreateAlloca(f32,0,"ina1");
    auto in_store01 = builder.CreateStore(const_100,in_alloc01);
    auto in_store02 = builder.CreateStore(in_fadd,in_alloc02);
    

    /**
     * 2022-05-03 16:33:58
     * TODO:
     * 新建一个函数:
     * void work03_fn(){
     *  if(fdd_res > 100)
     *      fdd_res = fdd_res %100;
     * }
     * */
    // 创建函数
    auto fn_prototype = FunctionType::get(builder.getVoidTy(), true);
    auto work03_fn = Function::Create(fn_prototype,Function::ExternalLinkage,"work03_fn",M.get());
    // 创建基本块        
    auto work03_fn_defaut= BasicBlock::Create(context, "work03_fn_defaut", work03_fn);
    auto work03_fn_change = BasicBlock::Create(context, "work03_fn_change", work03_fn);
    auto work03_fn_nothing = BasicBlock::Create(context, "work03_fn_nothing", work03_fn);
    // 默认基本块 指令操作
    builder.SetInsertPoint(work03_fn_defaut);
    auto work03_de_load_01 = builder.CreateLoad(f32,in_alloc02);
    auto work03_de_fcmp_01 = builder.CreateFCmpUGT(work03_de_load_01,const_100);
    auto work03_de_br_01 = builder.CreateCondBr(work03_de_fcmp_01,work03_fn_change,work03_fn_nothing);

    // 取余 指令操作
    builder.SetInsertPoint(work03_fn_change);
    auto work03_ch_load_01 = builder.CreateLoad(f32,in_alloc02);
    auto work03_ch_frem_01 = builder.CreateFRem(work03_ch_load_01,const_100);
    auto work03_ch_store_01 = builder.CreateStore(work03_ch_frem_01,in_alloc02);
    builder.CreateRetVoid();

    // 第三个基本块什么都不做
    builder.SetInsertPoint(work03_fn_nothing);
    builder.CreateRetVoid();


    /**
     * 2022-05-03 18:27:56
     * TODO:
     * 在调用prtinf 函数之前插入调用函数指令
     * 以及读取fadd_res, 修改printf 第三个参数
     * */
    builder.SetInsertPoint(in_prt);
    builder.CreateCall(work03_fn);
    auto in_load03 = builder.CreateLoad(f32,in_alloc02);
    in_prt->setOperand(3,in_load03);
    
    
    // M->print(outs(),nullptr);


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

    /**
     * #include "llvm/Bitcode/BitcodeWriter.h"
     * 2022-05-03 12:55:33
     * TODO:
     * 将修改后的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.8) 效果

修改后IR如下:

./main main.ll
debug: M is not null
debug: Module verify is ok 
; ModuleID = 'main.ll'
source_filename = "t.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, %struct._IO_codecvt*, %struct._IO_wide_data*, %struct._IO_FILE*, i8*, i64, i32, [20 x i8] }
%struct._IO_marker = type opaque
%struct._IO_codecvt = type opaque
%struct._IO_wide_data = type opaque

@.str = private unnamed_addr constant [22 x i8] c"plz input two numbers\00", align 1
@stdin = external dso_local global %struct._IO_FILE*, align 8
@.str.1 = private unnamed_addr constant [21 x i8] c"%.2f + %.2f = %.2f \0A\00", align 1
@fadd_res = private global double 0.000000e+00, align 8

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i64, align 8
  %3 = alloca i8*, align 8
  %4 = alloca double, align 8
  %5 = alloca double, align 8
  store i32 0, i32* %1, align 4
  %6 = call i32 @puts(i8* noundef getelementptr inbounds ([22 x i8], [22 x i8]* @.str, i64 0, i64 0))
  store i64 100, i64* %2, align 8
  %7 = load i64, i64* %2, align 8
  %8 = call noalias i8* @malloc(i64 noundef %7) #4
  store i8* %8, i8** %3, align 8
  %9 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8
  %10 = call i64 @getline(i8** noundef %3, i64* noundef %2, %struct._IO_FILE* noundef %9)
  %11 = load i8*, i8** %3, align 8
  %12 = call double @atof(i8* noundef %11) #5
  store double %12, double* %4, align 8
  %13 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8
  %14 = call i64 @getline(i8** noundef %3, i64* noundef %2, %struct._IO_FILE* noundef %13)
  %15 = load i8*, i8** %3, align 8
  %16 = call double @atof(i8* noundef %15) #5
  store double %16, double* %5, align 8
  %17 = load double, double* %4, align 8
  %18 = load double, double* %5, align 8
  %19 = load double, double* %4, align 8
  %20 = load double, double* %5, align 8
  %21 = fadd double %19, %20
  %ina1 = alloca double, align 8
  store double 1.000000e+02, double* %ina1, align 8
  store double %21, double* @fadd_res, align 8
  call void (...) @work03_fn()
  %22 = load double, double* @fadd_res, align 8
  %23 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([21 x i8], [21 x i8]* @.str.1, i64 0, i64 0), double noundef %17, double noundef %18, double noundef %22)
  %24 = load i8*, i8** %3, align 8
  call void @free(i8* noundef %24) #4
  ret i32 0
}

declare dso_local i32 @puts(i8* noundef) #1

; Function Attrs: nounwind
declare dso_local noalias i8* @malloc(i64 noundef) #2

declare dso_local i64 @getline(i8** noundef, i64* noundef, %struct._IO_FILE* noundef) #1

; Function Attrs: nounwind readonly willreturn
declare dso_local double @atof(i8* noundef) #3

declare dso_local i32 @printf(i8* noundef, ...) #1

; Function Attrs: nounwind
declare dso_local void @free(i8* noundef) #2

define void @work03_fn(...) {
work03_fn_defaut:
  %0 = load double, double* @fadd_res, align 8
  %1 = fcmp ugt double %0, 1.000000e+02
  br i1 %1, label %work03_fn_change, label %work03_fn_nothing

work03_fn_change:                                 ; preds = %work03_fn_defaut
  %2 = load double, double* @fadd_res, align 8
  %3 = frem double %2, 1.000000e+02
  store double %3, double* @fadd_res, align 8
  ret void

work03_fn_nothing:                                ; preds = %work03_fn_defaut
  ret void
}

attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #2 = { nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #3 = { nounwind readonly willreturn "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #4 = { nounwind }
attributes #5 = { nounwind readonly willreturn }

!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}

image-20220503203858855

三) 思路二执行

2.1) -2.2) 同上

添加相关必要指令

/**
 * 2022-04-28 02:42:32
 * TODO:
 * 1. 创建常量100
 * 2. 插入基本指令,存储最终的修改fadd结果
 * */
auto f32 = builder.getDoubleTy();
auto const_100 = ConstantFP::get(f32,double(100));    
// 插入基本指令,存储最终的修改fadd结果
builder.SetInsertPoint(in_prt);
auto in_alloc02 = builder.CreateAlloca(f32,0,"ia01");

2.3) 构造函数

/**
 * 2022-05-03 22:05:01
 * TODO:
 * 新建一个函数:
 * double work03_fn(double fdd_res){
 *  if(fdd_res > 100)
 *     return  fdd_res = fdd_res %100;
 * }else{
 *  return fdd_res;
 * }
 * */

// 创建函数的参数
std::vector<Type*>parms;
parms.push_back(f32);
ArrayRef<Type*>fn_parm(parms);
// 创建函数
auto fn_prototype = FunctionType::get(builder.getDoubleTy(),fn_parm,true);
auto work03_fn = Function::Create(fn_prototype,Function::ExternalLinkage,"work03_fn",M.get());
// 创建传的实参
std::vector<Value*>args;
args.push_back(in_fadd);
ArrayRef<Value*> argRef(args);

// 创建基本块       
auto work03_fn_defaut= BasicBlock::Create(context, "work03_fn_defaut", work03_fn);
auto work03_fn_change = BasicBlock::Create(context, "work03_fn_change", work03_fn);
auto work03_fn_nothing = BasicBlock::Create(context, "work03_fn_nothing", work03_fn);

// 默认基本块 指令操作
builder.SetInsertPoint(work03_fn_defaut);
// 拿到函数参数
auto work03_de_alloc_01 = builder.CreateAlloca(f32,0,"ial02");
Function::arg_iterator argsit = work03_fn->arg_begin();
auto work03_de_p1 = argsit;
auto work03_de_store_01 = builder.CreateStore(work03_de_p1,work03_de_alloc_01);
// 比较大小
auto work03_de_load_01 = builder.CreateLoad(f32,work03_de_alloc_01);
auto work03_de_fcmp_01 = builder.CreateFCmpUGT(work03_de_load_01,const_100);
auto work03_de_br_01 = builder.CreateCondBr(work03_de_fcmp_01,work03_fn_change,work03_fn_nothing);

// 取余 指令操作
builder.SetInsertPoint(work03_fn_change);
auto work03_ch_load_01 = builder.CreateLoad(f32,work03_de_alloc_01);
auto work03_ch_frem_01 = builder.CreateFRem(work03_ch_load_01,const_100);
auto work03_ch_store_01 = builder.CreateStore(work03_ch_frem_01,work03_de_alloc_01);
auto work03_ch_load02 = builder.CreateLoad(f32,work03_de_alloc_01);
builder.CreateRet(work03_ch_load02);

// 第三个基本块 不做修改,返回从参数种拿到的值
builder.SetInsertPoint(work03_fn_nothing);
auto work03_no_load01 = builder.CreateLoad(f32,work03_de_alloc_01);
builder.CreateRet(work03_no_load01);

2.4) 修改printf函数

/**
 * 2022-05-03 18:27:56
 * TODO:
 * 在调用prtinf 函数之前插入调用函数指令
 * 以及读取fadd_res, 修改printf 第三个参数
 * */
builder.SetInsertPoint(in_prt);
auto in_call_01 = builder.CreateCall(work03_fn,argRef);
auto in_store03 = builder.CreateStore(in_call_01,in_alloc02);
auto in_load03 = builder.CreateLoad(f32,in_alloc02);
in_prt->setOperand(3,in_load03);

2.5)-2.6) 验证与写入

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

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

2.7) 全部源码

/**
 * 2022-05-03 16:16:19
 * sizaif
 * Work3:插入一个函数并调用。函数用于检查加法结果,如果大于 100,则取余 100。此函数会修改加法结果。(函数操作)
 * 
 * clang++ $(llvm-config --cxxflags --ldflags --system-libs --libs)  -o main2 main2.cpp
 * ./main2 main.ll
 * lli aftermain2.bc
 * */

#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <llvm/IR/IRBuilder.h>
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/CodeGen/MIRParser/MIRParser.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/SourceMgr.h"
#include <llvm/Support/raw_os_ostream.h>
#include "llvm/Bitcode/BitcodeWriter.h"

#include <iostream>
#include <string>
#include <fstream>
#include <cstdio>

using namespace llvm;


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

 
    LLVMContext context;
    IRBuilder<> builder(context);
    std::unique_ptr<Module> M;
    std::unique_ptr<MIRParser> MIR;

    SMDiagnostic Err;
    /**
     * #include "llvm/IRReader/IRReader.h"
     * 2022-04-26 03:04:32
     * TODO:
     * from IR file get Moudle class
     * */
    M = parseIRFile(StringRef(argv[1]),Err,context);
    if(M){
        std::cout<<"debug: 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
     * TODO:
     * 获取main函数
     * */
    auto main_fn = M->getFunction(StringRef("main"));
    
    /**
     * 2022-04-28 02:14:46
     * TODO:
     * 找到fadd指令,与fadd的后一个指令
     * */
    Instruction *in_fadd,*in_prt;
    for (inst_iterator I = inst_begin(*main_fn), E = inst_end(*main_fn); I != E; ++I){
        if(I->isBinaryOp() && I->getOpcode()==Instruction::FAdd){
            // outs() << *I << "\n";
            in_fadd = &*I;
            in_prt = &*(I.operator++());
        }   
    }
    
    /**
     * 2022-04-28 02:42:32
     * TODO:
     * 1. 创建常量100
     * 2. 插入基本指令,存储最终的修改fadd结果
     * */
    auto f32 = builder.getDoubleTy();
    auto const_100 = ConstantFP::get(f32,double(100));    
    // 插入基本指令,存储最终的修改fadd结果
    builder.SetInsertPoint(in_prt);
    auto in_alloc02 = builder.CreateAlloca(f32,0,"ia01");

    

    /**
     * 2022-05-03 22:05:01
     * TODO:
     * 新建一个函数:
     * double work03_fn(double fdd_res){
     *  if(fdd_res > 100)
     *     return  fdd_res = fdd_res %100;
     * }else{
     *  return fdd_res;
     * }
     * */
    
    // 创建函数的参数
    std::vector<Type*>parms;
    parms.push_back(f32);
    ArrayRef<Type*>fn_parm(parms);
    // 创建函数
    auto fn_prototype = FunctionType::get(builder.getDoubleTy(),fn_parm,true);
    auto work03_fn = Function::Create(fn_prototype,Function::ExternalLinkage,"work03_fn",M.get());
    // 创建传的实参
    std::vector<Value*>args;
    args.push_back(in_fadd);
    ArrayRef<Value*> argRef(args);
    
    // 创建基本块       
    auto work03_fn_defaut= BasicBlock::Create(context, "work03_fn_defaut", work03_fn);
    auto work03_fn_change = BasicBlock::Create(context, "work03_fn_change", work03_fn);
    auto work03_fn_nothing = BasicBlock::Create(context, "work03_fn_nothing", work03_fn);
    
    // 默认基本块 指令操作
    builder.SetInsertPoint(work03_fn_defaut);
    // 拿到函数参数
    auto work03_de_alloc_01 = builder.CreateAlloca(f32,0,"ial02");
    Function::arg_iterator argsit = work03_fn->arg_begin();
    auto work03_de_p1 = argsit;
    auto work03_de_store_01 = builder.CreateStore(work03_de_p1,work03_de_alloc_01);
    // 比较大小
    auto work03_de_load_01 = builder.CreateLoad(f32,work03_de_alloc_01);
    auto work03_de_fcmp_01 = builder.CreateFCmpUGT(work03_de_load_01,const_100);
    auto work03_de_br_01 = builder.CreateCondBr(work03_de_fcmp_01,work03_fn_change,work03_fn_nothing);

    // 取余 指令操作
    builder.SetInsertPoint(work03_fn_change);
    auto work03_ch_load_01 = builder.CreateLoad(f32,work03_de_alloc_01);
    auto work03_ch_frem_01 = builder.CreateFRem(work03_ch_load_01,const_100);
    auto work03_ch_store_01 = builder.CreateStore(work03_ch_frem_01,work03_de_alloc_01);
    auto work03_ch_load02 = builder.CreateLoad(f32,work03_de_alloc_01);
    builder.CreateRet(work03_ch_load02);

    // 第三个基本块 不做修改,返回从参数种拿到的值
    builder.SetInsertPoint(work03_fn_nothing);
    auto work03_no_load01 = builder.CreateLoad(f32,work03_de_alloc_01);
    builder.CreateRet(work03_no_load01);


    /**
     * 2022-05-03 18:27:56
     * TODO:
     * 在调用prtinf 函数之前插入调用函数指令
     * 以及读取fadd_res, 修改printf 第三个参数
     * */
    builder.SetInsertPoint(in_prt);
    auto in_call_01 = builder.CreateCall(work03_fn,argRef);
    auto in_store03 = builder.CreateStore(in_call_01,in_alloc02);
    auto in_load03 = builder.CreateLoad(f32,in_alloc02);
    in_prt->setOperand(3,in_load03);
    
    
    // M->print(outs(),nullptr);


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

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


    return 0;
}

2.8) 效果

修改后IR代码如下:

; ModuleID = 'main.ll'
source_filename = "t.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

%struct._IO_FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct._IO_FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, %struct._IO_codecvt*, %struct._IO_wide_data*, %struct._IO_FILE*, i8*, i64, i32, [20 x i8] }
%struct._IO_marker = type opaque
%struct._IO_codecvt = type opaque
%struct._IO_wide_data = type opaque

@.str = private unnamed_addr constant [22 x i8] c"plz input two numbers\00", align 1
@stdin = external dso_local global %struct._IO_FILE*, align 8
@.str.1 = private unnamed_addr constant [21 x i8] c"%.2f + %.2f = %.2f \0A\00", align 1

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i64, align 8
  %3 = alloca i8*, align 8
  %4 = alloca double, align 8
  %5 = alloca double, align 8
  store i32 0, i32* %1, align 4
  %6 = call i32 @puts(i8* noundef getelementptr inbounds ([22 x i8], [22 x i8]* @.str, i64 0, i64 0))
  store i64 100, i64* %2, align 8
  %7 = load i64, i64* %2, align 8
  %8 = call noalias i8* @malloc(i64 noundef %7) #4
  store i8* %8, i8** %3, align 8
  %9 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8
  %10 = call i64 @getline(i8** noundef %3, i64* noundef %2, %struct._IO_FILE* noundef %9)
  %11 = load i8*, i8** %3, align 8
  %12 = call double @atof(i8* noundef %11) #5
  store double %12, double* %4, align 8
  %13 = load %struct._IO_FILE*, %struct._IO_FILE** @stdin, align 8
  %14 = call i64 @getline(i8** noundef %3, i64* noundef %2, %struct._IO_FILE* noundef %13)
  %15 = load i8*, i8** %3, align 8
  %16 = call double @atof(i8* noundef %15) #5
  store double %16, double* %5, align 8
  %17 = load double, double* %4, align 8
  %18 = load double, double* %5, align 8
  %19 = load double, double* %4, align 8
  %20 = load double, double* %5, align 8
  %21 = fadd double %19, %20
  %ia01 = alloca double, align 8
  %22 = call double (double, ...) @work03_fn(double %21)
  store double %22, double* %ia01, align 8
  %23 = load double, double* %ia01, align 8
  %24 = call i32 (i8*, ...) @printf(i8* noundef getelementptr inbounds ([21 x i8], [21 x i8]* @.str.1, i64 0, i64 0), double noundef %17, double noundef %18, double noundef %23)
  %25 = load i8*, i8** %3, align 8
  call void @free(i8* noundef %25) #4
  ret i32 0
}

declare dso_local i32 @puts(i8* noundef) #1

; Function Attrs: nounwind
declare dso_local noalias i8* @malloc(i64 noundef) #2

declare dso_local i64 @getline(i8** noundef, i64* noundef, %struct._IO_FILE* noundef) #1

; Function Attrs: nounwind readonly willreturn
declare dso_local double @atof(i8* noundef) #3

declare dso_local i32 @printf(i8* noundef, ...) #1

; Function Attrs: nounwind
declare dso_local void @free(i8* noundef) #2

define double @work03_fn(double %0, ...) {
work03_fn_defaut:
  %ial02 = alloca double, align 8
  store double %0, double* %ial02, align 8
  %1 = load double, double* %ial02, align 8
  %2 = fcmp ugt double %1, 1.000000e+02
  br i1 %2, label %work03_fn_change, label %work03_fn_nothing

work03_fn_change:                                 ; preds = %work03_fn_defaut
  %3 = load double, double* %ial02, align 8
  %4 = frem double %3, 1.000000e+02
  store double %4, double* %ial02, align 8
  %5 = load double, double* %ial02, align 8
  ret double %5

work03_fn_nothing:                                ; preds = %work03_fn_defaut
  %6 = load double, double* %ial02, align 8
  ret double %6
}

attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #2 = { nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #3 = { nounwind readonly willreturn "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #4 = { nounwind }
attributes #5 = { nounwind readonly willreturn }

!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"uwtable", i32 1}
!2 = !{i32 7, !"frame-pointer", i32 2}
!3 = !{!"clang version 14.0.0"}

image-20220503220827827

四) 总结

  1. 涉及到创建全局变量操作, 创建时需要初始化其值。

一种时直接构造创建,或使用Module类中getOrInsertGlobal方法。

auto in_alloc02 = new GlobalVariable(*M,f32,false,GlobalValue::PrivateLinkage,const_0,"fadd_res");

GlobalVariable::GlobalVariable(Module &M, Type *Ty, bool constant,
                               LinkageTypes Link, Constant *InitVal,
                               const Twine &Name, GlobalVariable *Before,
                               ThreadLocalMode TLMode,
                               Optional<unsigned> AddressSpace,
                               bool isExternallyInitialized)
// Overload to construct a global variable using its constructor's defaults.
Constant *Module::getOrInsertGlobal(StringRef Name, Type *Ty) {
  return getOrInsertGlobal(Name, Ty, [&] {
    return new GlobalVariable(*this, Ty, false, GlobalVariable::ExternalLinkage,
                              nullptr, Name);
  });
}
  1. 创建函数操作,

    1. 先指定返回类型与函数的参数
    2. 构造函数
    3. 创建基本块
    4. 遍历函数的参数并读取
    5. 基本块插入指令
    6. 添加返回指令,即使函数为void,也应添加ret void指令

评论吧



本站总访问量为 访客数为

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